forked from Shiloh/remnantchat
parent
69da8fed2f
commit
f20f32f6a6
@ -2,12 +2,22 @@ import { useEffect, useRef } from 'react'
|
||||
import Paper from '@mui/material/Paper'
|
||||
|
||||
import { PeerNameDisplay } from 'components/PeerNameDisplay'
|
||||
import { VideoStreamType } from 'models/chat'
|
||||
|
||||
import { SelectedPeerStream } from './RoomVideoDisplay'
|
||||
|
||||
interface PeerVideoProps {
|
||||
isSelfVideo?: boolean
|
||||
numberOfVideos: number
|
||||
onVideoClick?: (
|
||||
userId: string,
|
||||
videoStreamType: VideoStreamType,
|
||||
videoStream: MediaStream
|
||||
) => void
|
||||
selectedPeerStream: SelectedPeerStream | null
|
||||
userId: string
|
||||
videoStream: MediaStream
|
||||
videoStreamType: VideoStreamType
|
||||
}
|
||||
|
||||
// Adapted from https://www.geeksforgeeks.org/find-the-next-perfect-square-greater-than-a-given-number/
|
||||
@ -20,8 +30,11 @@ const nextPerfectSquare = (base: number) => {
|
||||
export const PeerVideo = ({
|
||||
isSelfVideo,
|
||||
numberOfVideos,
|
||||
onVideoClick,
|
||||
userId,
|
||||
selectedPeerStream,
|
||||
videoStream,
|
||||
videoStreamType,
|
||||
}: PeerVideoProps) => {
|
||||
const videoRef = useRef<HTMLVideoElement>(null)
|
||||
|
||||
@ -35,6 +48,10 @@ export const PeerVideo = ({
|
||||
|
||||
const sizePercent = 100 / Math.sqrt(nextPerfectSquare(numberOfVideos - 1))
|
||||
|
||||
const handleVideoClick = () => {
|
||||
onVideoClick?.(userId, videoStreamType, videoStream)
|
||||
}
|
||||
|
||||
return (
|
||||
<Paper
|
||||
sx={{
|
||||
@ -42,19 +59,27 @@ export const PeerVideo = ({
|
||||
flexDirection: 'column',
|
||||
flexShrink: 1,
|
||||
justifyContent: 'center',
|
||||
margin: '0.5em',
|
||||
margin: '0 0.5em 0.5em 0.5em',
|
||||
overflow: 'auto',
|
||||
py: 2,
|
||||
...(selectedPeerStream
|
||||
? {
|
||||
height: 'calc(100% - 0.5em)',
|
||||
}
|
||||
: {
|
||||
width: `calc(${sizePercent}% - 1em)`,
|
||||
height: `calc(${sizePercent}% - 1em)`,
|
||||
}),
|
||||
}}
|
||||
elevation={10}
|
||||
>
|
||||
<video
|
||||
playsInline
|
||||
ref={videoRef}
|
||||
onClick={handleVideoClick}
|
||||
style={{
|
||||
borderRadius: '.25em',
|
||||
cursor: 'pointer',
|
||||
overflow: 'auto',
|
||||
marginLeft: 'auto',
|
||||
marginRight: 'auto',
|
||||
|
@ -1,18 +1,25 @@
|
||||
import { Fragment, useContext } from 'react'
|
||||
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 } from 'models/chat'
|
||||
import { Peer, VideoStreamType } from 'models/chat'
|
||||
|
||||
import { PeerVideo } from './PeerVideo'
|
||||
|
||||
type PeerWithVideo = {
|
||||
interface PeerWithVideo {
|
||||
peer: Peer
|
||||
videoStream?: MediaStream
|
||||
screenStream?: MediaStream
|
||||
}
|
||||
|
||||
export interface SelectedPeerStream {
|
||||
peerId: string
|
||||
videoStreamType: VideoStreamType
|
||||
videoStream: MediaStream
|
||||
}
|
||||
|
||||
export interface RoomVideoDisplayProps {
|
||||
userId: string
|
||||
}
|
||||
@ -20,6 +27,8 @@ export interface RoomVideoDisplayProps {
|
||||
export const RoomVideoDisplay = ({ userId }: RoomVideoDisplayProps) => {
|
||||
const shellContext = useContext(ShellContext)
|
||||
const roomContext = useContext(RoomContext)
|
||||
const [selectedPeerStream, setSelectedPeerStream] =
|
||||
useState<SelectedPeerStream | null>(null)
|
||||
|
||||
const { peerList } = shellContext
|
||||
const {
|
||||
@ -29,6 +38,31 @@ export const RoomVideoDisplay = ({ userId }: RoomVideoDisplayProps) => {
|
||||
selfScreenStream,
|
||||
} = roomContext
|
||||
|
||||
useEffect(() => {
|
||||
if (!selectedPeerStream) 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)
|
||||
}, [
|
||||
peerScreenStreams,
|
||||
peerVideoStreams,
|
||||
selectedPeerStream,
|
||||
selfScreenStream,
|
||||
selfVideoStream,
|
||||
])
|
||||
|
||||
const peersWithVideo: PeerWithVideo[] = peerList.reduce(
|
||||
(acc: PeerWithVideo[], peer: Peer) => {
|
||||
const videoStream = peerVideoStreams[peer.peerId]
|
||||
@ -57,6 +91,18 @@ export const RoomVideoDisplay = ({ userId }: RoomVideoDisplayProps) => {
|
||||
return sum
|
||||
}, 0)
|
||||
|
||||
const handleVideoClick = (
|
||||
peerId: string,
|
||||
videoStreamType: VideoStreamType,
|
||||
videoStream: MediaStream
|
||||
) => {
|
||||
if (selectedPeerStream?.videoStream === videoStream) {
|
||||
setSelectedPeerStream(null)
|
||||
} else {
|
||||
setSelectedPeerStream({ peerId, videoStreamType, videoStream })
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
<Paper
|
||||
className="RoomVideoDisplay"
|
||||
@ -66,27 +112,58 @@ export const RoomVideoDisplay = ({ userId }: RoomVideoDisplayProps) => {
|
||||
alignContent: 'center',
|
||||
alignItems: 'center',
|
||||
display: 'flex',
|
||||
flexDirection: numberOfVideos === 1 ? 'column' : 'row',
|
||||
flexGrow: 1,
|
||||
flexWrap: 'wrap',
|
||||
justifyContent: 'center',
|
||||
flexDirection: 'column',
|
||||
overflow: 'auto',
|
||||
width: '75%',
|
||||
width: '85%',
|
||||
}}
|
||||
>
|
||||
{selectedPeerStream && (
|
||||
<Box sx={{ height: 'calc(85% - 1em)', mb: 'auto' }}>
|
||||
<PeerVideo
|
||||
numberOfVideos={numberOfVideos}
|
||||
onVideoClick={handleVideoClick}
|
||||
userId={userId}
|
||||
selectedPeerStream={selectedPeerStream}
|
||||
videoStream={selectedPeerStream.videoStream}
|
||||
videoStreamType={selectedPeerStream.videoStreamType}
|
||||
/>
|
||||
</Box>
|
||||
)}
|
||||
<Box
|
||||
sx={{
|
||||
alignContent: 'center',
|
||||
alignItems: 'center',
|
||||
display: 'flex',
|
||||
flexDirection: 'row',
|
||||
flexGrow: 1,
|
||||
flexWrap: selectedPeerStream ? 'nowrap' : 'wrap',
|
||||
overflow: 'auto',
|
||||
width: '100%',
|
||||
...(selectedPeerStream && {
|
||||
height: '15%',
|
||||
maxHeight: '15%',
|
||||
}),
|
||||
}}
|
||||
>
|
||||
{selfVideoStream && (
|
||||
<PeerVideo
|
||||
isSelfVideo
|
||||
numberOfVideos={numberOfVideos}
|
||||
onVideoClick={handleVideoClick}
|
||||
userId={userId}
|
||||
selectedPeerStream={selectedPeerStream}
|
||||
videoStream={selfVideoStream}
|
||||
videoStreamType={VideoStreamType.WEBCAM}
|
||||
/>
|
||||
)}
|
||||
{selfScreenStream && (
|
||||
<PeerVideo
|
||||
numberOfVideos={numberOfVideos}
|
||||
onVideoClick={handleVideoClick}
|
||||
userId={userId}
|
||||
selectedPeerStream={selectedPeerStream}
|
||||
videoStream={selfScreenStream}
|
||||
videoStreamType={VideoStreamType.SCREEN_SHARE}
|
||||
/>
|
||||
)}
|
||||
{peersWithVideo.map(peerWithVideo => (
|
||||
@ -94,19 +171,26 @@ export const RoomVideoDisplay = ({ userId }: RoomVideoDisplayProps) => {
|
||||
{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>
|
||||
)
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user