blob: 20938400cd565dba2a04920b8334a0b560e452ec [file] [log] [blame]
simondaae9102022-12-02 16:51:31 -05001/*
2 * Copyright (C) 2022 Savoir-faire Linux Inc.
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU Affero General Public License as
6 * published by the Free Software Foundation; either version 3 of the
7 * License, or (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU Affero General Public License for more details.
13 *
14 * You should have received a copy of the GNU Affero General Public
15 * License along with this program. If not, see
16 * <https://www.gnu.org/licenses/>.
17 */
18import { Box } from '@mui/material';
simon5c677962022-12-02 16:51:54 -050019import { useRef, useState } from 'react';
simondaae9102022-12-02 16:51:31 -050020import Draggable, { DraggableEventHandler } from 'react-draggable';
21import { useNavigate } from 'react-router-dom';
22
idillon255682e2023-02-06 13:25:26 -050023import { useCallManagerContext } from '../contexts/CallManagerProvider';
idillon27dab022023-02-02 17:55:47 -050024import { useUserMediaContext } from '../contexts/UserMediaProvider';
simondaae9102022-12-02 16:51:31 -050025import { VideoElementWithSinkId } from '../utils/utils';
26import VideoStream, { VideoStreamProps } from './VideoStream';
27
28type Size = 'small' | 'medium' | 'large';
29export type VideoOverlayProps = VideoStreamProps & {
30 onClick?: DraggableEventHandler;
31 size?: Size;
32};
33
34const sizeToDimentions: Record<Size, string> = {
35 small: '25%',
36 medium: '50%',
37 large: '75%',
38};
39
40const VideoOverlay = ({ onClick, size = 'medium', ...props }: VideoOverlayProps) => {
41 const videoRef = useRef<VideoElementWithSinkId | null>(null);
42 const [dragging, setDragging] = useState(false);
43
44 return (
45 <Box position="relative" width="100%" height="100%">
46 <Draggable
47 onDrag={() => setDragging(true)}
48 onStop={(...args) => {
49 if (!dragging && onClick) {
50 onClick(...args);
51 }
52
53 setDragging(false);
54 }}
55 bounds="parent"
56 nodeRef={videoRef}
57 >
58 <VideoStream
59 ref={videoRef}
60 {...props}
61 style={{
62 position: 'absolute',
63 right: 0,
64 borderRadius: '12px',
65 maxHeight: sizeToDimentions[size],
66 maxWidth: sizeToDimentions[size],
67 zIndex: 2,
68 transition: 'max-width, max-height .2s ease-in-out',
69 ...props.style,
70 }}
71 />
72 </Draggable>
73 </Box>
74 );
75};
76
77export const RemoteVideoOverlay = ({ callConversationId }: { callConversationId: string }) => {
idillon255682e2023-02-06 13:25:26 -050078 const { remoteStreams } = useCallManagerContext();
simondaae9102022-12-02 16:51:31 -050079 const {
80 currentMediaDeviceIds: {
81 audiooutput: { id: audioOutDeviceId },
82 },
idillon27dab022023-02-02 17:55:47 -050083 } = useUserMediaContext();
simondaae9102022-12-02 16:51:31 -050084 const navigate = useNavigate();
85
86 // TODO: For now, `remoteStream` is the first remote stream in the array.
87 // There should only be one in the array, but we should make sure this is right.
88 const stream = remoteStreams?.at(0);
89
90 return (
91 <Box position="absolute" width="100%" height="100%" display="flex">
92 <Box margin={2} flexGrow={1}>
93 <VideoOverlay
94 stream={stream}
95 audioOutDeviceId={audioOutDeviceId}
96 onClick={() => {
97 navigate(`/conversation/${callConversationId}`);
98 }}
99 size={'small'}
100 />
101 </Box>
102 </Box>
103 );
104};
105
106export default VideoOverlay;