blob: 195f5f93f5a8990660d8e1a3882070b2bb792af9 [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
simon5c677962022-12-02 16:51:54 -050023import { useCallContext } from '../contexts/CallProvider';
simondaae9102022-12-02 16:51:31 -050024import { VideoElementWithSinkId } from '../utils/utils';
25import VideoStream, { VideoStreamProps } from './VideoStream';
26
27type Size = 'small' | 'medium' | 'large';
28export type VideoOverlayProps = VideoStreamProps & {
29 onClick?: DraggableEventHandler;
30 size?: Size;
31};
32
33const sizeToDimentions: Record<Size, string> = {
34 small: '25%',
35 medium: '50%',
36 large: '75%',
37};
38
39const VideoOverlay = ({ onClick, size = 'medium', ...props }: VideoOverlayProps) => {
40 const videoRef = useRef<VideoElementWithSinkId | null>(null);
41 const [dragging, setDragging] = useState(false);
42
43 return (
44 <Box position="relative" width="100%" height="100%">
45 <Draggable
46 onDrag={() => setDragging(true)}
47 onStop={(...args) => {
48 if (!dragging && onClick) {
49 onClick(...args);
50 }
51
52 setDragging(false);
53 }}
54 bounds="parent"
55 nodeRef={videoRef}
56 >
57 <VideoStream
58 ref={videoRef}
59 {...props}
60 style={{
61 position: 'absolute',
62 right: 0,
63 borderRadius: '12px',
64 maxHeight: sizeToDimentions[size],
65 maxWidth: sizeToDimentions[size],
66 zIndex: 2,
67 transition: 'max-width, max-height .2s ease-in-out',
68 ...props.style,
69 }}
70 />
71 </Draggable>
72 </Box>
73 );
74};
75
76export const RemoteVideoOverlay = ({ callConversationId }: { callConversationId: string }) => {
idilloncf42c652023-01-31 18:56:17 -050077 const { remoteStreams } = useCallContext();
simondaae9102022-12-02 16:51:31 -050078 const {
79 currentMediaDeviceIds: {
80 audiooutput: { id: audioOutDeviceId },
81 },
simon5c677962022-12-02 16:51:54 -050082 } = useCallContext();
simondaae9102022-12-02 16:51:31 -050083 const navigate = useNavigate();
84
85 // TODO: For now, `remoteStream` is the first remote stream in the array.
86 // There should only be one in the array, but we should make sure this is right.
87 const stream = remoteStreams?.at(0);
88
89 return (
90 <Box position="absolute" width="100%" height="100%" display="flex">
91 <Box margin={2} flexGrow={1}>
92 <VideoOverlay
93 stream={stream}
94 audioOutDeviceId={audioOutDeviceId}
95 onClick={() => {
96 navigate(`/conversation/${callConversationId}`);
97 }}
98 size={'small'}
99 />
100 </Box>
101 </Box>
102 );
103};
104
105export default VideoOverlay;