* refactor: remove redundant function calls * feat(video): [closes #180] mute self screen stream audio
213 lines
5.6 KiB
TypeScript
213 lines
5.6 KiB
TypeScript
import { Fragment, useContext, useEffect, useState } from 'react'
|
|
import Box from '@mui/material/Box'
|
|
import Paper from '@mui/material/Paper'
|
|
|
|
import { RoomContext } from 'contexts/RoomContext'
|
|
import { ShellContext } from 'contexts/ShellContext'
|
|
import { Peer, VideoStreamType } from 'models/chat'
|
|
|
|
import { PeerVideo } from './PeerVideo'
|
|
|
|
interface PeerWithVideo {
|
|
peer: Peer
|
|
videoStream?: MediaStream
|
|
screenStream?: MediaStream
|
|
}
|
|
|
|
export interface SelectedPeerStream {
|
|
peerId: string
|
|
videoStreamType: VideoStreamType
|
|
videoStream: MediaStream
|
|
}
|
|
|
|
export interface RoomVideoDisplayProps {
|
|
userId: string
|
|
width: string
|
|
height: string
|
|
}
|
|
|
|
export const RoomVideoDisplay = ({
|
|
userId,
|
|
width,
|
|
height,
|
|
}: RoomVideoDisplayProps) => {
|
|
const shellContext = useContext(ShellContext)
|
|
const roomContext = useContext(RoomContext)
|
|
const [selectedPeerStream, setSelectedPeerStream] =
|
|
useState<SelectedPeerStream | null>(null)
|
|
|
|
const { peerList } = shellContext
|
|
const {
|
|
peerVideoStreams,
|
|
selfVideoStream,
|
|
peerScreenStreams,
|
|
selfScreenStream,
|
|
} = roomContext
|
|
|
|
const peersWithVideo: PeerWithVideo[] = peerList.reduce(
|
|
(acc: PeerWithVideo[], peer: Peer) => {
|
|
const videoStream = peerVideoStreams[peer.peerId]
|
|
const screenStream = peerScreenStreams[peer.peerId]
|
|
|
|
if (videoStream || screenStream) {
|
|
acc.push({
|
|
peer,
|
|
videoStream,
|
|
screenStream,
|
|
})
|
|
}
|
|
|
|
return acc
|
|
},
|
|
[]
|
|
)
|
|
|
|
const numberOfVideos =
|
|
(selfVideoStream ? 1 : 0) +
|
|
(selfScreenStream ? 1 : 0) +
|
|
peersWithVideo.reduce((sum, peerWithVideo) => {
|
|
if (peerWithVideo.videoStream) sum++
|
|
if (peerWithVideo.screenStream) sum++
|
|
|
|
return sum
|
|
}, 0)
|
|
|
|
useEffect(() => {
|
|
if (!selectedPeerStream) return
|
|
|
|
if (numberOfVideos < 2) {
|
|
setSelectedPeerStream(null)
|
|
return
|
|
}
|
|
|
|
const allMediaStreams = [
|
|
...Object.values(peerVideoStreams),
|
|
...Object.values(peerScreenStreams),
|
|
selfVideoStream,
|
|
selfScreenStream,
|
|
]
|
|
|
|
for (const mediaStream of allMediaStreams) {
|
|
if (mediaStream?.id === selectedPeerStream.videoStream.id) {
|
|
return
|
|
}
|
|
}
|
|
|
|
setSelectedPeerStream(null)
|
|
}, [
|
|
numberOfVideos,
|
|
peerScreenStreams,
|
|
peerVideoStreams,
|
|
selectedPeerStream,
|
|
selfScreenStream,
|
|
selfVideoStream,
|
|
])
|
|
|
|
const handleVideoClick = (
|
|
peerId: string,
|
|
videoStreamType: VideoStreamType,
|
|
videoStream: MediaStream
|
|
) => {
|
|
if (selectedPeerStream?.videoStream === videoStream) {
|
|
setSelectedPeerStream(null)
|
|
} else if (numberOfVideos > 1) {
|
|
setSelectedPeerStream({ peerId, videoStreamType, videoStream })
|
|
}
|
|
}
|
|
|
|
return (
|
|
<Paper
|
|
className="RoomVideoDisplay"
|
|
elevation={3}
|
|
square
|
|
sx={{
|
|
alignContent: 'center',
|
|
alignItems: 'center',
|
|
display: 'flex',
|
|
flexDirection: 'column',
|
|
overflow: 'auto',
|
|
padding: 1,
|
|
width: { width },
|
|
height: { height },
|
|
}}
|
|
>
|
|
{selectedPeerStream && (
|
|
<Box sx={{ height: '80%', width: '100%' }}>
|
|
<PeerVideo
|
|
numberOfVideos={numberOfVideos}
|
|
onVideoClick={handleVideoClick}
|
|
userId={selectedPeerStream.peerId}
|
|
selectedPeerStream={selectedPeerStream}
|
|
videoStream={selectedPeerStream.videoStream}
|
|
videoStreamType={selectedPeerStream.videoStreamType}
|
|
/>
|
|
</Box>
|
|
)}
|
|
<Box
|
|
sx={{
|
|
alignContent: 'center',
|
|
display: 'flex',
|
|
flexDirection: 'row',
|
|
flexGrow: 1,
|
|
flexWrap: selectedPeerStream ? 'nowrap' : 'wrap',
|
|
justifyContent: 'center',
|
|
overflow: 'auto',
|
|
width: '100%',
|
|
...(selectedPeerStream && {
|
|
height: '20%',
|
|
maxHeight: '20%',
|
|
pt: '0.5em',
|
|
}),
|
|
}}
|
|
>
|
|
{selfVideoStream && (
|
|
<PeerVideo
|
|
isSelfVideo
|
|
numberOfVideos={numberOfVideos}
|
|
onVideoClick={handleVideoClick}
|
|
userId={userId}
|
|
selectedPeerStream={selectedPeerStream}
|
|
videoStream={selfVideoStream}
|
|
videoStreamType={VideoStreamType.WEBCAM}
|
|
/>
|
|
)}
|
|
{selfScreenStream && (
|
|
<PeerVideo
|
|
isSelfScreenStream
|
|
numberOfVideos={numberOfVideos}
|
|
onVideoClick={handleVideoClick}
|
|
userId={userId}
|
|
selectedPeerStream={selectedPeerStream}
|
|
videoStream={selfScreenStream}
|
|
videoStreamType={VideoStreamType.SCREEN_SHARE}
|
|
/>
|
|
)}
|
|
{peersWithVideo.map(peerWithVideo => (
|
|
<Fragment key={peerWithVideo.peer.peerId}>
|
|
{peerWithVideo.videoStream && (
|
|
<PeerVideo
|
|
numberOfVideos={numberOfVideos}
|
|
onVideoClick={handleVideoClick}
|
|
userId={peerWithVideo.peer.userId}
|
|
selectedPeerStream={selectedPeerStream}
|
|
videoStream={peerWithVideo.videoStream}
|
|
videoStreamType={VideoStreamType.WEBCAM}
|
|
/>
|
|
)}
|
|
{peerWithVideo.screenStream && (
|
|
<PeerVideo
|
|
numberOfVideos={numberOfVideos}
|
|
onVideoClick={handleVideoClick}
|
|
userId={peerWithVideo.peer.userId}
|
|
selectedPeerStream={selectedPeerStream}
|
|
videoStream={peerWithVideo.screenStream}
|
|
videoStreamType={VideoStreamType.SCREEN_SHARE}
|
|
/>
|
|
)}
|
|
</Fragment>
|
|
))}
|
|
</Box>
|
|
</Paper>
|
|
)
|
|
}
|