diff --git a/src/lib/audio/sounds.svelte.ts b/src/lib/audio/sounds.svelte.ts index 00ff015..8e1c054 100644 --- a/src/lib/audio/sounds.svelte.ts +++ b/src/lib/audio/sounds.svelte.ts @@ -27,6 +27,10 @@ export const SOUND_EVENTS = [ { id: 'userBanned', group: 'Your channel', name: 'Someone in your channel was banned', ts: 'CLIENT_WAS_BANNED_CURRENT_CHANNEL', keys: ['banned_server_currentchannel'] }, { id: 'recordingStarted', group: 'Your channel', name: 'Someone started recording', ts: 'CLIENT_RECORDING_START', keys: ['recording_started'] }, { id: 'recordingStopped', group: 'Your channel', name: 'Someone stopped recording', ts: 'CLIENT_RECORDING_STOP', keys: ['recording_stopped'] }, + { id: 'shareStarted', group: 'Screen sharing', name: 'A screen share started (yours or in your channel)', ts: 'MUMH5_SHARE_STARTED', keys: ['share_started', 'stream_started'] }, + { id: 'shareStopped', group: 'Screen sharing', name: 'A screen share stopped', ts: 'MUMH5_SHARE_STOPPED', keys: ['share_stopped', 'stream_stopped'] }, + { id: 'viewerJoined', group: 'Screen sharing', name: 'Someone started watching your screen', ts: 'MUMH5_VIEWER_JOINED', keys: ['viewer_joined'] }, + { id: 'viewerLeft', group: 'Screen sharing', name: 'Someone stopped watching your screen', ts: 'MUMH5_VIEWER_LEFT', keys: ['viewer_left'] }, { id: 'message', group: 'Chat', name: 'Channel message', ts: 'CHAT_RECEIVED_MESSAGE_CHANNEL', keys: ['chat_message_inbound', 'message'] }, { id: 'privateMessage', group: 'Chat', name: 'Direct message', ts: 'CHAT_RECEIVED_MESSAGE_CLIENT', keys: ['private', 'direct', 'pm'] }, { id: 'messageSent', group: 'Chat', name: 'You sent a message', ts: 'CHAT_SENT_MESSAGE_CHANNEL', keys: ['chat_message_outbound', 'sent'], off: true }, @@ -79,6 +83,10 @@ const TONES: Record = { userBanned: [[294, 0, 0.12], [220, 0.13, 0.16]], recordingStarted: [[1175, 0, 0.08], [1175, 0.12, 0.08]], recordingStopped: [[880, 0, 0.12]], + shareStarted: [[523, 0, 0.07], [784, 0.08, 0.07], [1047, 0.16, 0.12]], + shareStopped: [[1047, 0, 0.07], [784, 0.08, 0.07], [523, 0.16, 0.12]], + viewerJoined: [[880, 0, 0.05], [1109, 0.06, 0.08]], + viewerLeft: [[1109, 0, 0.05], [880, 0.06, 0.08]], message: [[1047, 0, 0.06]], privateMessage: [[1047, 0, 0.05], [1319, 0.07, 0.07]], messageSent: [[1319, 0, 0.04]], diff --git a/src/lib/share.svelte.ts b/src/lib/share.svelte.ts index 09a1a76..0414836 100644 --- a/src/lib/share.svelte.ts +++ b/src/lib/share.svelte.ts @@ -9,6 +9,7 @@ import { desktop, isWeb } from './native.ts'; import { proxyStun } from './web.svelte.ts'; import { store } from './settings.svelte.ts'; import { ui } from './ui.svelte.ts'; +import { sounds } from './audio/sounds.svelte.ts'; // Every viewer is a separate upload from the sharer const MAX_VIEWERS = 8; @@ -44,6 +45,10 @@ class ScreenShare { private watchPc: RTCPeerConnection | null = null; private watchTimer: ReturnType | undefined; private assemblers = new WeakMap(); + // Viewers whose connection came up, so leaving is only announced for those + private live = new Set(); + // When we entered the channel: streams already running there are not announced with a sound + private enteredAt = new WeakMap(); // Plugin data needs a 1.4 server; older ones would not pass the signals on supported(s: Session): boolean { @@ -114,6 +119,7 @@ class ScreenShare { this.stream = stream; this.send(s, this.others(s), SHARE.on); s.setSharing(s.client.session!, true); + sounds.play('shareStarted'); } private release(): void { @@ -127,6 +133,7 @@ class ScreenShare { stop(): void { const s = this.host; + if (this.stream) sounds.play('shareStopped'); if (s?.client) { this.send(s, this.others(s), SHARE.off); if (s.client.session != null) s.setSharing(s.client.session, false); @@ -137,12 +144,14 @@ class ScreenShare { private dropPeers(): void { for (const pc of this.peers.values()) pc.close(); this.peers.clear(); + this.live.clear(); this.viewers = 0; } private dropPeer(session: number): void { this.peers.get(session)?.close(); this.peers.delete(session); + if (this.live.delete(session)) sounds.play('viewerLeft'); this.viewers = this.peers.size; } @@ -195,7 +204,11 @@ class ScreenShare { this.peers.set(viewer, pc); this.viewers = this.peers.size; pc.addEventListener('connectionstatechange', () => { - if ((pc.connectionState === 'failed' || pc.connectionState === 'closed') && this.peers.get(viewer) === pc) this.dropPeer(viewer); + if (this.peers.get(viewer) !== pc) return; + if (pc.connectionState === 'connected' && !this.live.has(viewer)) { + this.live.add(viewer); + sounds.play('viewerJoined'); + } else if (pc.connectionState === 'failed' || pc.connectionState === 'closed') this.dropPeer(viewer); }); for (const track of stream.getTracks()) { const sender = pc.addTrack(track, stream); @@ -241,8 +254,12 @@ class ScreenShare { // Only people in our channel take part if (!msg || !s.client || !this.inMyChannel(s, sender)) return; switch (msg.type) { - case SHARE.on: s.setSharing(sender, true); break; + case SHARE.on: + if (!s.sharing[sender] && Date.now() - (this.enteredAt.get(s) ?? 0) > 3000) sounds.play('shareStarted'); + s.setSharing(sender, true); + break; case SHARE.off: + if (s.sharing[sender]) sounds.play('shareStopped'); s.setSharing(sender, false); if (this.watching?.host === s && this.watching.session === sender) this.endWatch(); break; @@ -260,6 +277,7 @@ class ScreenShare { entered(s: Session): void { if (!this.supported(s)) return; const self = s.client!.session!; + this.enteredAt.set(s, Date.now()); s.clearSharing(); if (this.watching?.host === s) this.unwatch(); if (this.host === s) { @@ -277,6 +295,8 @@ class ScreenShare { if (this.host === s) this.send(s, [user.session], SHARE.on); return; } + // A sharer who left or disconnected: their stream is over for us + if (s.sharing[user.session]) sounds.play('shareStopped'); s.setSharing(user.session, false); if (this.host === s) this.dropPeer(user.session); if (this.watching?.host === s && this.watching.session === user.session) this.endWatch(); diff --git a/src/ui/VoiceStage.svelte b/src/ui/VoiceStage.svelte index 4e7a00b..d4da0c5 100644 --- a/src/ui/VoiceStage.svelte +++ b/src/ui/VoiceStage.svelte @@ -190,7 +190,7 @@ {/if} {#if mine} - You are sharing your screen{mine.getAudioTracks().length ? ' with sound' : ''}{share.viewers ? `, ${share.viewers} watching` : ''} + {share.viewers} watching {/if}