diff --git a/src/components/Room/useRoom.ts b/src/components/Room/useRoom.ts index d064d3b..930aaea 100644 --- a/src/components/Room/useRoom.ts +++ b/src/components/Room/useRoom.ts @@ -39,6 +39,9 @@ export function useRoom( const [peerRoom] = useState( () => new PeerRoom({ password: password ?? roomId, ...roomConfig }, roomId) ) + + peerRoom.flush() + const [numberOfPeers, setNumberOfPeers] = useState(1) // Includes this peer const shellContext = useContext(ShellContext) const settingsContext = useContext(SettingsContext) @@ -158,8 +161,6 @@ export function useRoom( const newNumberOfPeers = numberOfPeers + 1 setNumberOfPeers(newNumberOfPeers) shellContext.setNumberOfPeers(newNumberOfPeers) - - handleAudioForNewPeer(peerId) ;(async () => { try { const promises: Promise[] = [sendPeerId(userId, peerId)] @@ -177,6 +178,10 @@ export function useRoom( })() }) + peerRoom.onPeerJoin((peerId: string) => { + handleAudioForNewPeer(peerId) + }) + peerRoom.onPeerLeave((peerId: string) => { const peerIndex = shellContext.peerList.findIndex( peer => peer.peerId === peerId @@ -197,8 +202,6 @@ export function useRoom( setNumberOfPeers(newNumberOfPeers) shellContext.setNumberOfPeers(newNumberOfPeers) - handleAudioForLeavingPeer(peerId) - if (peerExist) { const peerListClone = [...shellContext.peerList] peerListClone.splice(peerIndex, 1) @@ -206,6 +209,10 @@ export function useRoom( } }) + peerRoom.onPeerLeave((peerId: string) => { + handleAudioForLeavingPeer(peerId) + }) + return { audioDevices, peerRoom, diff --git a/src/components/Room/useRoomAudio.ts b/src/components/Room/useRoomAudio.ts index b4a4ecf..42e1186 100644 --- a/src/components/Room/useRoomAudio.ts +++ b/src/components/Room/useRoomAudio.ts @@ -1,4 +1,4 @@ -import { useContext, useEffect, useState } from 'react' +import { useContext, useEffect, useCallback, useState } from 'react' import { ShellContext } from 'contexts/ShellContext' import { PeerActions } from 'models/network' @@ -65,6 +65,15 @@ export function useRoomAudio({ peerRoom }: UseRoomAudioConfig) { setPeerAudios({ ...peerAudios, [peerId]: audio }) }) + const cleanupAudio = useCallback(() => { + if (!audioStream) return + + for (const audioTrack of audioStream.getTracks()) { + audioTrack.stop() + audioStream.removeTrack(audioTrack) + } + }, [audioStream]) + useEffect(() => { ;(async () => { if (isSpeakingToRoom) { @@ -83,10 +92,7 @@ export function useRoomAudio({ peerRoom }: UseRoomAudioConfig) { } } else { if (audioStream) { - for (const audioTrack of audioStream.getTracks()) { - audioTrack.stop() - audioStream.removeTrack(audioTrack) - } + cleanupAudio() peerRoom.removeStream(audioStream, peerRoom.getPeers()) sendAudioChange(AudioState.STOPPED) @@ -103,8 +109,15 @@ export function useRoomAudio({ peerRoom }: UseRoomAudioConfig) { selectedAudioDeviceId, sendAudioChange, shellContext, + cleanupAudio, ]) + useEffect(() => { + return () => { + cleanupAudio() + } + }, [cleanupAudio]) + const handleAudioDeviceSelect = async (audioDevice: MediaDeviceInfo) => { const { deviceId } = audioDevice setSelectedAudioDeviceId(deviceId) diff --git a/src/services/PeerRoom/PeerRoom.ts b/src/services/PeerRoom/PeerRoom.ts index f17c394..bd3734e 100644 --- a/src/services/PeerRoom/PeerRoom.ts +++ b/src/services/PeerRoom/PeerRoom.ts @@ -6,28 +6,76 @@ export class PeerRoom { private roomConfig: TorrentRoomConfig & BaseRoomConfig + private peerJoinHandlers: Set<(peerId: string) => void> = new Set() + + private peerLeaveHandlers: Set<(peerId: string) => void> = new Set() + + private peerStreamHandlers: Set< + (stream: MediaStream, peerId: string) => void + > = new Set() + constructor(config: TorrentRoomConfig & BaseRoomConfig, roomId: string) { this.roomConfig = config this.room = joinRoom(this.roomConfig, roomId) + + this.room.onPeerJoin((...args) => { + for (const peerJoinHandler of this.peerJoinHandlers) { + peerJoinHandler(...args) + } + }) + + this.room.onPeerLeave((...args) => { + for (const peerLeaveHandler of this.peerLeaveHandlers) { + peerLeaveHandler(...args) + } + }) + + this.room.onPeerStream((...args) => { + for (const peerStreamHandler of this.peerStreamHandlers) { + peerStreamHandler(...args) + } + }) + } + + flush = () => { + this.onPeerJoinFlush() + this.onPeerLeaveFlush() + this.onPeerStreamFlush() } leaveRoom = () => { - if (!this.room) return this.room.leave() + this.flush() } onPeerJoin: Room['onPeerJoin'] = fn => { - if (!this.room) return - this.room.onPeerJoin((...args) => fn(...args)) + this.peerJoinHandlers.add(fn) + } + + onPeerJoinFlush = () => { + this.peerJoinHandlers.forEach(handler => + this.peerJoinHandlers.delete(handler) + ) } onPeerLeave: Room['onPeerLeave'] = fn => { - if (!this.room) return - this.room.onPeerLeave((...args) => fn(...args)) + this.peerLeaveHandlers.add(fn) + } + + onPeerLeaveFlush = () => { + this.peerLeaveHandlers.forEach(handler => + this.peerLeaveHandlers.delete(handler) + ) } onPeerStream: Room['onPeerStream'] = fn => { - this.room.onPeerStream((...args) => fn(...args)) + this.peerStreamHandlers.add(fn) + } + + onPeerStreamFlush = () => { + this.peerStreamHandlers.forEach(handler => + this.peerStreamHandlers.delete(handler) + ) } getPeers: Room['getPeers'] = () => { diff --git a/tsconfig.json b/tsconfig.json index a3ebcf3..ba6f819 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -1,6 +1,6 @@ { "compilerOptions": { - "target": "es5", + "target": "es2015", "lib": ["dom", "dom.iterable", "esnext"], "allowJs": true, "skipLibCheck": true,