Skip to content

Commit eff4519

Browse files
committed
feat: system/tab audio on supported systems
1 parent 12a3e5c commit eff4519

2 files changed

Lines changed: 86 additions & 5 deletions

File tree

ui/src/Room.tsx

Lines changed: 71 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,11 @@
11
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';
33
import CancelPresentationIcon from '@mui/icons-material/CancelPresentation';
44
import PresentToAllIcon from '@mui/icons-material/PresentToAll';
55
import FullScreenIcon from '@mui/icons-material/Fullscreen';
66
import PeopleIcon from '@mui/icons-material/People';
7+
import VolumeMuteIcon from '@mui/icons-material/VolumeOff';
8+
import VolumeIcon from '@mui/icons-material/VolumeUp';
79
import SettingsIcon from '@mui/icons-material/Settings';
810
import {useHotkeys} from 'react-hotkeys-hook';
911
import {Video} from './Video';
@@ -97,7 +99,17 @@ export const Room = ({
9799
React.useEffect(() => {
98100
if (videoElement && stream) {
99101
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+
});
101113
}
102114
}, [videoElement, stream]);
103115

@@ -161,6 +173,15 @@ export const Room = ({
161173
},
162174
[state.clientStreams, selectedStream]
163175
);
176+
useHotkeys(
177+
'm',
178+
() => {
179+
if (videoElement) {
180+
videoElement.muted = !videoElement.muted;
181+
}
182+
},
183+
[videoElement]
184+
);
164185

165186
const videoClasses = () => {
166187
switch (settings.displayMode) {
@@ -194,7 +215,6 @@ export const Room = ({
194215

195216
{stream ? (
196217
<video
197-
muted
198218
ref={setVideoElement}
199219
className={videoClasses()}
200220
onDoubleClick={handleFullscreen}
@@ -249,6 +269,9 @@ export const Room = ({
249269
<PeopleIcon fontSize="large" />
250270
</Badge>
251271
</Tooltip>
272+
{(stream?.getAudioTracks().length ?? 0) > 0 && videoElement && (
273+
<AudioControl video={videoElement} />
274+
)}
252275
<Tooltip title="Fullscreen" arrow>
253276
<IconButton
254277
onClick={() => handleFullscreen()}
@@ -353,6 +376,51 @@ const useShowOnMouseMovement = (doShow: (s: boolean) => void) => {
353376
);
354377
};
355378

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+
356424
const useStyles = makeStyles(() => ({
357425
title: {
358426
padding: 15,

ui/src/useRoom.ts

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -143,10 +143,15 @@ const clientSession = async ({
143143
done();
144144
}
145145
};
146+
147+
let notified = false;
148+
const stream = new MediaStream();
146149
peer.ontrack = (event) => {
147-
const stream = new MediaStream();
148150
stream.addTrack(event.track);
149-
onTrack(stream);
151+
if (!notified) {
152+
notified = true;
153+
onTrack(stream);
154+
}
150155
};
151156

152157
return peer;
@@ -332,6 +337,14 @@ export const useRoom = (config: UIConfig): UseRoom => {
332337
try {
333338
stream.current = await navigator.mediaDevices.getDisplayMedia({
334339
video: {frameRate: loadSettings().framerate},
340+
audio: {
341+
echoCancellation: false,
342+
autoGainControl: false,
343+
noiseSuppression: false,
344+
// https://medium.com/@trystonperry/why-is-getdisplaymedias-audio-quality-so-bad-b49ba9cfaa83
345+
// @ts-expect-error
346+
googAutoGainControl: false,
347+
},
335348
});
336349
} catch (e) {
337350
console.log('Could not getDisplayMedia', e);

0 commit comments

Comments
 (0)