refactor: move audio logic to new hook
This commit is contained in:
parent
166fc9ff84
commit
9c18f40d61
@ -12,7 +12,6 @@ import {
|
|||||||
ReceivedMessage,
|
ReceivedMessage,
|
||||||
UnsentMessage,
|
UnsentMessage,
|
||||||
isMessageReceived,
|
isMessageReceived,
|
||||||
Peer,
|
|
||||||
} from 'models/chat'
|
} from 'models/chat'
|
||||||
import { funAnimalName } from 'fun-animal-names'
|
import { funAnimalName } from 'fun-animal-names'
|
||||||
import { getPeerName } from 'components/PeerNameDisplay'
|
import { getPeerName } from 'components/PeerNameDisplay'
|
||||||
@ -23,6 +22,7 @@ import { PeerRoom } from 'services/PeerRoom'
|
|||||||
import { messageTranscriptSizeLimit } from 'config/messaging'
|
import { messageTranscriptSizeLimit } from 'config/messaging'
|
||||||
|
|
||||||
import { usePeerRoomAction } from './usePeerRoomAction'
|
import { usePeerRoomAction } from './usePeerRoomAction'
|
||||||
|
import { useRoomAudio } from './useRoomAudio'
|
||||||
|
|
||||||
interface UseRoomConfig {
|
interface UseRoomConfig {
|
||||||
roomId: string
|
roomId: string
|
||||||
@ -49,19 +49,19 @@ export function useRoom(
|
|||||||
const [newMessageAudio] = useState(
|
const [newMessageAudio] = useState(
|
||||||
() => new AudioService(process.env.PUBLIC_URL + '/sounds/new-message.aac')
|
() => new AudioService(process.env.PUBLIC_URL + '/sounds/new-message.aac')
|
||||||
)
|
)
|
||||||
const [isSpeakingToRoom, setIsSpeakingToRoom] = useState(false)
|
|
||||||
const [peerAudios, setPeerAudios] = useState<
|
|
||||||
Record<string, HTMLAudioElement>
|
|
||||||
>({})
|
|
||||||
const [audioStream, setAudioStream] = useState<MediaStream | null>()
|
|
||||||
|
|
||||||
const setMessageLog = (messages: Message[]) => {
|
const setMessageLog = (messages: Message[]) => {
|
||||||
_setMessageLog(messages.slice(-messageTranscriptSizeLimit))
|
_setMessageLog(messages.slice(-messageTranscriptSizeLimit))
|
||||||
}
|
}
|
||||||
const [audioDevices, setAudioDevices] = useState<MediaDeviceInfo[]>([])
|
|
||||||
const [selectedAudioDeviceId, setSelectedAudioDeviceId] = useState<
|
const {
|
||||||
string | null
|
audioDevices,
|
||||||
>(null)
|
isSpeakingToRoom,
|
||||||
|
setIsSpeakingToRoom,
|
||||||
|
handleAudioDeviceSelect,
|
||||||
|
handleAudioForNewPeer,
|
||||||
|
handleAudioForLeavingPeer,
|
||||||
|
} = useRoomAudio({ peerRoom })
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
return () => {
|
return () => {
|
||||||
@ -77,16 +77,6 @@ export function useRoom(
|
|||||||
}
|
}
|
||||||
}, [shellContext])
|
}, [shellContext])
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
;(async () => {
|
|
||||||
if (!audioStream) return
|
|
||||||
|
|
||||||
const devices = await window.navigator.mediaDevices.enumerateDevices()
|
|
||||||
const audioDevices = devices.filter(({ kind }) => kind === 'audioinput')
|
|
||||||
setAudioDevices(audioDevices)
|
|
||||||
})()
|
|
||||||
}, [audioStream])
|
|
||||||
|
|
||||||
const [sendPeerId, receivePeerId] = usePeerRoomAction<string>(
|
const [sendPeerId, receivePeerId] = usePeerRoomAction<string>(
|
||||||
peerRoom,
|
peerRoom,
|
||||||
PeerActions.PEER_NAME
|
PeerActions.PEER_NAME
|
||||||
@ -99,11 +89,6 @@ export function useRoom(
|
|||||||
const [sendPeerMessage, receivePeerMessage] =
|
const [sendPeerMessage, receivePeerMessage] =
|
||||||
usePeerRoomAction<UnsentMessage>(peerRoom, PeerActions.MESSAGE)
|
usePeerRoomAction<UnsentMessage>(peerRoom, PeerActions.MESSAGE)
|
||||||
|
|
||||||
const [sendAudioChange, receiveAudioChange] = usePeerRoomAction<AudioState>(
|
|
||||||
peerRoom,
|
|
||||||
PeerActions.AUDIO_CHANGE
|
|
||||||
)
|
|
||||||
|
|
||||||
const sendMessage = async (message: string) => {
|
const sendMessage = async (message: string) => {
|
||||||
if (isMessageSending) return
|
if (isMessageSending) return
|
||||||
|
|
||||||
@ -165,20 +150,6 @@ export function useRoom(
|
|||||||
setMessageLog([...messageLog, { ...message, timeReceived: Date.now() }])
|
setMessageLog([...messageLog, { ...message, timeReceived: Date.now() }])
|
||||||
})
|
})
|
||||||
|
|
||||||
receiveAudioChange((audioState, peerId) => {
|
|
||||||
const newPeerList = shellContext.peerList.map(peer => {
|
|
||||||
const newPeer: Peer = { ...peer }
|
|
||||||
|
|
||||||
if (peer.peerId === peerId) {
|
|
||||||
newPeer.audioState = audioState
|
|
||||||
}
|
|
||||||
|
|
||||||
return newPeer
|
|
||||||
})
|
|
||||||
|
|
||||||
shellContext.setPeerList(newPeerList)
|
|
||||||
})
|
|
||||||
|
|
||||||
peerRoom.onPeerJoin((peerId: string) => {
|
peerRoom.onPeerJoin((peerId: string) => {
|
||||||
shellContext.showAlert(`Someone has joined the room`, {
|
shellContext.showAlert(`Someone has joined the room`, {
|
||||||
severity: 'success',
|
severity: 'success',
|
||||||
@ -188,10 +159,7 @@ export function useRoom(
|
|||||||
setNumberOfPeers(newNumberOfPeers)
|
setNumberOfPeers(newNumberOfPeers)
|
||||||
shellContext.setNumberOfPeers(newNumberOfPeers)
|
shellContext.setNumberOfPeers(newNumberOfPeers)
|
||||||
|
|
||||||
if (audioStream) {
|
handleAudioForNewPeer(peerId)
|
||||||
peerRoom.addStream(audioStream, peerId)
|
|
||||||
}
|
|
||||||
|
|
||||||
;(async () => {
|
;(async () => {
|
||||||
try {
|
try {
|
||||||
const promises: Promise<any>[] = [sendPeerId(userId, peerId)]
|
const promises: Promise<any>[] = [sendPeerId(userId, peerId)]
|
||||||
@ -229,9 +197,7 @@ export function useRoom(
|
|||||||
setNumberOfPeers(newNumberOfPeers)
|
setNumberOfPeers(newNumberOfPeers)
|
||||||
shellContext.setNumberOfPeers(newNumberOfPeers)
|
shellContext.setNumberOfPeers(newNumberOfPeers)
|
||||||
|
|
||||||
if (audioStream) {
|
handleAudioForLeavingPeer(peerId)
|
||||||
peerRoom.removeStream(audioStream, peerId)
|
|
||||||
}
|
|
||||||
|
|
||||||
if (peerExist) {
|
if (peerExist) {
|
||||||
const peerListClone = [...shellContext.peerList]
|
const peerListClone = [...shellContext.peerList]
|
||||||
@ -240,78 +206,6 @@ export function useRoom(
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
peerRoom.onPeerStream((stream, peerId) => {
|
|
||||||
const audio = new Audio()
|
|
||||||
audio.srcObject = stream
|
|
||||||
audio.autoplay = true
|
|
||||||
|
|
||||||
setPeerAudios({ ...peerAudios, [peerId]: audio })
|
|
||||||
})
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
;(async () => {
|
|
||||||
if (isSpeakingToRoom) {
|
|
||||||
if (!audioStream) {
|
|
||||||
const newSelfStream = await navigator.mediaDevices.getUserMedia({
|
|
||||||
audio: selectedAudioDeviceId
|
|
||||||
? { deviceId: selectedAudioDeviceId }
|
|
||||||
: true,
|
|
||||||
video: false,
|
|
||||||
})
|
|
||||||
|
|
||||||
peerRoom.addStream(newSelfStream)
|
|
||||||
sendAudioChange(AudioState.PLAYING)
|
|
||||||
shellContext.setAudioState(AudioState.PLAYING)
|
|
||||||
setAudioStream(newSelfStream)
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if (audioStream) {
|
|
||||||
for (const audioTrack of audioStream.getTracks()) {
|
|
||||||
audioTrack.stop()
|
|
||||||
audioStream.removeTrack(audioTrack)
|
|
||||||
}
|
|
||||||
|
|
||||||
peerRoom.removeStream(audioStream, peerRoom.getPeers())
|
|
||||||
sendAudioChange(AudioState.STOPPED)
|
|
||||||
shellContext.setAudioState(AudioState.STOPPED)
|
|
||||||
setAudioStream(null)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
})()
|
|
||||||
}, [
|
|
||||||
isSpeakingToRoom,
|
|
||||||
peerAudios,
|
|
||||||
peerRoom,
|
|
||||||
audioStream,
|
|
||||||
selectedAudioDeviceId,
|
|
||||||
sendAudioChange,
|
|
||||||
shellContext,
|
|
||||||
])
|
|
||||||
|
|
||||||
const handleAudioDeviceSelect = async (audioDevice: MediaDeviceInfo) => {
|
|
||||||
const { deviceId } = audioDevice
|
|
||||||
setSelectedAudioDeviceId(deviceId)
|
|
||||||
|
|
||||||
if (!audioStream) return
|
|
||||||
|
|
||||||
for (const audioTrack of audioStream.getTracks()) {
|
|
||||||
audioTrack.stop()
|
|
||||||
audioStream.removeTrack(audioTrack)
|
|
||||||
}
|
|
||||||
|
|
||||||
peerRoom.removeStream(audioStream, peerRoom.getPeers())
|
|
||||||
|
|
||||||
const newSelfStream = await navigator.mediaDevices.getUserMedia({
|
|
||||||
audio: {
|
|
||||||
deviceId,
|
|
||||||
},
|
|
||||||
video: false,
|
|
||||||
})
|
|
||||||
|
|
||||||
peerRoom.addStream(newSelfStream)
|
|
||||||
setAudioStream(newSelfStream)
|
|
||||||
}
|
|
||||||
|
|
||||||
return {
|
return {
|
||||||
audioDevices,
|
audioDevices,
|
||||||
peerRoom,
|
peerRoom,
|
||||||
|
148
src/components/Room/useRoomAudio.ts
Normal file
148
src/components/Room/useRoomAudio.ts
Normal file
@ -0,0 +1,148 @@
|
|||||||
|
import { useContext, useEffect, useState } from 'react'
|
||||||
|
|
||||||
|
import { ShellContext } from 'contexts/ShellContext'
|
||||||
|
import { PeerActions } from 'models/network'
|
||||||
|
import { AudioState, Peer } from 'models/chat'
|
||||||
|
import { PeerRoom } from 'services/PeerRoom'
|
||||||
|
|
||||||
|
import { usePeerRoomAction } from './usePeerRoomAction'
|
||||||
|
|
||||||
|
interface UseRoomAudioConfig {
|
||||||
|
peerRoom: PeerRoom
|
||||||
|
}
|
||||||
|
|
||||||
|
export function useRoomAudio({ peerRoom }: UseRoomAudioConfig) {
|
||||||
|
const shellContext = useContext(ShellContext)
|
||||||
|
const [isSpeakingToRoom, setIsSpeakingToRoom] = useState(false)
|
||||||
|
const [peerAudios, setPeerAudios] = useState<
|
||||||
|
Record<string, HTMLAudioElement>
|
||||||
|
>({})
|
||||||
|
const [audioStream, setAudioStream] = useState<MediaStream | null>()
|
||||||
|
|
||||||
|
const [audioDevices, setAudioDevices] = useState<MediaDeviceInfo[]>([])
|
||||||
|
const [selectedAudioDeviceId, setSelectedAudioDeviceId] = useState<
|
||||||
|
string | null
|
||||||
|
>(null)
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
;(async () => {
|
||||||
|
if (!audioStream) return
|
||||||
|
|
||||||
|
const devices = await window.navigator.mediaDevices.enumerateDevices()
|
||||||
|
const audioDevices = devices.filter(({ kind }) => kind === 'audioinput')
|
||||||
|
setAudioDevices(audioDevices)
|
||||||
|
})()
|
||||||
|
}, [audioStream])
|
||||||
|
|
||||||
|
const [sendAudioChange, receiveAudioChange] = usePeerRoomAction<AudioState>(
|
||||||
|
peerRoom,
|
||||||
|
PeerActions.AUDIO_CHANGE
|
||||||
|
)
|
||||||
|
|
||||||
|
receiveAudioChange((audioState, peerId) => {
|
||||||
|
const newPeerList = shellContext.peerList.map(peer => {
|
||||||
|
const newPeer: Peer = { ...peer }
|
||||||
|
|
||||||
|
if (peer.peerId === peerId) {
|
||||||
|
newPeer.audioState = audioState
|
||||||
|
}
|
||||||
|
|
||||||
|
return newPeer
|
||||||
|
})
|
||||||
|
|
||||||
|
shellContext.setPeerList(newPeerList)
|
||||||
|
})
|
||||||
|
|
||||||
|
peerRoom.onPeerStream((stream, peerId) => {
|
||||||
|
const audio = new Audio()
|
||||||
|
audio.srcObject = stream
|
||||||
|
audio.autoplay = true
|
||||||
|
|
||||||
|
setPeerAudios({ ...peerAudios, [peerId]: audio })
|
||||||
|
})
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
;(async () => {
|
||||||
|
if (isSpeakingToRoom) {
|
||||||
|
if (!audioStream) {
|
||||||
|
const newSelfStream = await navigator.mediaDevices.getUserMedia({
|
||||||
|
audio: selectedAudioDeviceId
|
||||||
|
? { deviceId: selectedAudioDeviceId }
|
||||||
|
: true,
|
||||||
|
video: false,
|
||||||
|
})
|
||||||
|
|
||||||
|
peerRoom.addStream(newSelfStream)
|
||||||
|
sendAudioChange(AudioState.PLAYING)
|
||||||
|
shellContext.setAudioState(AudioState.PLAYING)
|
||||||
|
setAudioStream(newSelfStream)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (audioStream) {
|
||||||
|
for (const audioTrack of audioStream.getTracks()) {
|
||||||
|
audioTrack.stop()
|
||||||
|
audioStream.removeTrack(audioTrack)
|
||||||
|
}
|
||||||
|
|
||||||
|
peerRoom.removeStream(audioStream, peerRoom.getPeers())
|
||||||
|
sendAudioChange(AudioState.STOPPED)
|
||||||
|
shellContext.setAudioState(AudioState.STOPPED)
|
||||||
|
setAudioStream(null)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})()
|
||||||
|
}, [
|
||||||
|
isSpeakingToRoom,
|
||||||
|
peerAudios,
|
||||||
|
peerRoom,
|
||||||
|
audioStream,
|
||||||
|
selectedAudioDeviceId,
|
||||||
|
sendAudioChange,
|
||||||
|
shellContext,
|
||||||
|
])
|
||||||
|
|
||||||
|
const handleAudioDeviceSelect = async (audioDevice: MediaDeviceInfo) => {
|
||||||
|
const { deviceId } = audioDevice
|
||||||
|
setSelectedAudioDeviceId(deviceId)
|
||||||
|
|
||||||
|
if (!audioStream) return
|
||||||
|
|
||||||
|
for (const audioTrack of audioStream.getTracks()) {
|
||||||
|
audioTrack.stop()
|
||||||
|
audioStream.removeTrack(audioTrack)
|
||||||
|
}
|
||||||
|
|
||||||
|
peerRoom.removeStream(audioStream, peerRoom.getPeers())
|
||||||
|
|
||||||
|
const newSelfStream = await navigator.mediaDevices.getUserMedia({
|
||||||
|
audio: {
|
||||||
|
deviceId,
|
||||||
|
},
|
||||||
|
video: false,
|
||||||
|
})
|
||||||
|
|
||||||
|
peerRoom.addStream(newSelfStream)
|
||||||
|
setAudioStream(newSelfStream)
|
||||||
|
}
|
||||||
|
|
||||||
|
const handleAudioForNewPeer = (peerId: string) => {
|
||||||
|
if (audioStream) {
|
||||||
|
peerRoom.addStream(audioStream, peerId)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const handleAudioForLeavingPeer = (peerId: string) => {
|
||||||
|
if (audioStream) {
|
||||||
|
peerRoom.removeStream(audioStream, peerId)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
audioDevices,
|
||||||
|
isSpeakingToRoom,
|
||||||
|
setIsSpeakingToRoom,
|
||||||
|
handleAudioDeviceSelect,
|
||||||
|
handleAudioForNewPeer,
|
||||||
|
handleAudioForLeavingPeer,
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user