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