|
1 | 1 | import React, {useCallback} from 'react'; |
2 | | -import {Badge, IconButton, Paper, Tooltip, Typography} from '@mui/material'; |
| 2 | +import {Badge, Box, IconButton, Paper, Tooltip, Typography, Slider} from '@mui/material'; |
3 | 3 | import CancelPresentationIcon from '@mui/icons-material/CancelPresentation'; |
4 | 4 | import PresentToAllIcon from '@mui/icons-material/PresentToAll'; |
5 | 5 | import FullScreenIcon from '@mui/icons-material/Fullscreen'; |
6 | 6 | import PeopleIcon from '@mui/icons-material/People'; |
| 7 | +import VolumeMuteIcon from '@mui/icons-material/VolumeOff'; |
| 8 | +import VolumeIcon from '@mui/icons-material/VolumeUp'; |
7 | 9 | import SettingsIcon from '@mui/icons-material/Settings'; |
8 | 10 | import {useHotkeys} from 'react-hotkeys-hook'; |
9 | 11 | import {Video} from './Video'; |
@@ -97,7 +99,17 @@ export const Room = ({ |
97 | 99 | React.useEffect(() => { |
98 | 100 | if (videoElement && stream) { |
99 | 101 | videoElement.srcObject = stream; |
100 | | - videoElement.play().catch((e) => console.log('Could not play main video', e)); |
| 102 | + videoElement.play().catch((err) => { |
| 103 | + console.log('Could not play main video', err); |
| 104 | + if (err.name === 'NotAllowedError') { |
| 105 | + videoElement.muted = true; |
| 106 | + videoElement |
| 107 | + .play() |
| 108 | + .catch((retryErr) => |
| 109 | + console.log('Could not play main video with mute', retryErr) |
| 110 | + ); |
| 111 | + } |
| 112 | + }); |
101 | 113 | } |
102 | 114 | }, [videoElement, stream]); |
103 | 115 |
|
@@ -161,6 +173,15 @@ export const Room = ({ |
161 | 173 | }, |
162 | 174 | [state.clientStreams, selectedStream] |
163 | 175 | ); |
| 176 | + useHotkeys( |
| 177 | + 'm', |
| 178 | + () => { |
| 179 | + if (videoElement) { |
| 180 | + videoElement.muted = !videoElement.muted; |
| 181 | + } |
| 182 | + }, |
| 183 | + [videoElement] |
| 184 | + ); |
164 | 185 |
|
165 | 186 | const videoClasses = () => { |
166 | 187 | switch (settings.displayMode) { |
@@ -194,7 +215,6 @@ export const Room = ({ |
194 | 215 |
|
195 | 216 | {stream ? ( |
196 | 217 | <video |
197 | | - muted |
198 | 218 | ref={setVideoElement} |
199 | 219 | className={videoClasses()} |
200 | 220 | onDoubleClick={handleFullscreen} |
@@ -249,6 +269,9 @@ export const Room = ({ |
249 | 269 | <PeopleIcon fontSize="large" /> |
250 | 270 | </Badge> |
251 | 271 | </Tooltip> |
| 272 | + {(stream?.getAudioTracks().length ?? 0) > 0 && videoElement && ( |
| 273 | + <AudioControl video={videoElement} /> |
| 274 | + )} |
252 | 275 | <Tooltip title="Fullscreen" arrow> |
253 | 276 | <IconButton |
254 | 277 | onClick={() => handleFullscreen()} |
@@ -353,6 +376,51 @@ const useShowOnMouseMovement = (doShow: (s: boolean) => void) => { |
353 | 376 | ); |
354 | 377 | }; |
355 | 378 |
|
| 379 | +const AudioControl = ({video}: {video: FullScreenHTMLVideoElement}) => { |
| 380 | + // this is used to force a rerender |
| 381 | + const [, setMuted] = React.useState<boolean>(); |
| 382 | + |
| 383 | + React.useEffect(() => { |
| 384 | + const handler = () => setMuted(video.muted); |
| 385 | + video.addEventListener('volumechange', handler); |
| 386 | + setMuted(video.muted); |
| 387 | + return () => video.removeEventListener('volumechange', handler); |
| 388 | + }); |
| 389 | + |
| 390 | + return ( |
| 391 | + <Tooltip |
| 392 | + title={ |
| 393 | + <Box |
| 394 | + flexDirection="column" |
| 395 | + display="flex" |
| 396 | + alignItems="center" |
| 397 | + padding={1} |
| 398 | + paddingX={2} |
| 399 | + > |
| 400 | + <Typography>Volume</Typography> |
| 401 | + <Slider |
| 402 | + min={0} |
| 403 | + max={1} |
| 404 | + style={{width: 100}} |
| 405 | + step={0.01} |
| 406 | + defaultValue={video.volume} |
| 407 | + onChange={(_, newVolume) => (video.volume = newVolume)} |
| 408 | + /> |
| 409 | + </Box> |
| 410 | + } |
| 411 | + arrow |
| 412 | + > |
| 413 | + <IconButton size="large" onClick={() => (video.muted = !video.muted)}> |
| 414 | + {video.muted ? ( |
| 415 | + <VolumeMuteIcon fontSize="large" /> |
| 416 | + ) : ( |
| 417 | + <VolumeIcon fontSize="large" /> |
| 418 | + )} |
| 419 | + </IconButton> |
| 420 | + </Tooltip> |
| 421 | + ); |
| 422 | +}; |
| 423 | + |
356 | 424 | const useStyles = makeStyles(() => ({ |
357 | 425 | title: { |
358 | 426 | padding: 15, |
|
0 commit comments