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…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user