Added volume slider to audio sharing

This commit is contained in:
Mitchell McCaffrey 2020-07-18 12:11:02 +10:00
parent 44e6a34aba
commit 343c516473
3 changed files with 87 additions and 47 deletions

View File

@ -1,21 +1,23 @@
import React from "react"; import React from "react";
import { Text } from "theme-ui"; import { Text, Flex } from "theme-ui";
import Stream from "./Stream"; import Stream from "./Stream";
function Nickname({ nickname, stream }) { function Nickname({ nickname, stream }) {
return ( return (
<Text <Flex sx={{ flexDirection: "column" }}>
as="p" <Text
my={1} as="p"
variant="body2" my={1}
sx={{ variant="body2"
position: "relative", sx={{
}} position: "relative",
> }}
{nickname} >
{nickname}
</Text>
{stream && <Stream stream={stream} nickname={nickname} />} {stream && <Stream stream={stream} nickname={nickname} />}
</Text> </Flex>
); );
} }

View File

@ -1,14 +1,17 @@
import React, { useState, useRef, useEffect } from "react"; import React, { useState, useRef, useEffect } from "react";
import { Text, IconButton, Box } from "theme-ui"; import { Text, IconButton, Box, Slider, Flex } from "theme-ui";
import StreamMuteIcon from "../../icons/StreamMuteIcon";
import Banner from "../Banner"; import Banner from "../Banner";
function Stream({ stream, nickname }) { function Stream({ stream, nickname }) {
const [streamMuted, setStreamMuted] = useState(false); const [streamVolume, setStreamVolume] = useState(1);
const [showStreamInteractBanner, setShowStreamInteractBanner] = useState( const [showStreamInteractBanner, setShowStreamInteractBanner] = useState(
false false
); );
const audioRef = useRef(); const audioRef = useRef();
const streamMuted = streamVolume === 0;
useEffect(() => { useEffect(() => {
if (audioRef.current) { if (audioRef.current) {
@ -21,7 +24,7 @@ function Stream({ stream, nickname }) {
}) })
.catch(() => { .catch(() => {
// Unable to autoplay // Unable to autoplay
setStreamMuted(true); setStreamVolume(0);
setShowStreamInteractBanner(true); setShowStreamInteractBanner(true);
}); });
} }
@ -31,49 +34,63 @@ function Stream({ stream, nickname }) {
if (audioRef.current) { if (audioRef.current) {
if (streamMuted) { if (streamMuted) {
audioRef.current.play().then(() => { audioRef.current.play().then(() => {
setStreamMuted(false); setStreamVolume(1);
setShowStreamInteractBanner(false); setShowStreamInteractBanner(false);
}); });
} else { } else {
setStreamMuted(true); setStreamVolume(0);
} }
} }
} }
function handleVolumeChange(event) {
const volume = parseFloat(event.target.value);
setStreamVolume(volume);
}
// Use an audio context gain node to control volume to go past 100%
const audioGainRef = useRef();
useEffect(() => {
if (stream) {
let audioContext = new AudioContext();
let source = audioContext.createMediaStreamSource(stream);
let gainNode = audioContext.createGain();
gainNode.gain.volume = 1;
source.connect(gainNode);
gainNode.connect(audioContext.destination);
audioGainRef.current = gainNode;
}
}, [stream]);
useEffect(() => {
if (audioGainRef.current) {
audioGainRef.current.gain.value = streamVolume;
}
}, [streamVolume]);
return ( return (
<> <>
<IconButton <Flex sx={{ alignItems: "center", height: "24px" }}>
sx={{ <IconButton
width: "14px", aria-label={streamMuted ? "Unmute Player" : "Mute Player"}
height: "14px", title={streamMuted ? "Unmute Player" : "Mute Player"}
padding: 0, onClick={() => {
marginLeft: "2px", if (stream) {
position: "absolute", toggleMute();
bottom: "-2px", }
}} }}
aria-label={streamMuted ? "Unmute Player" : "Mute Player"}
title={streamMuted ? "Unmute Player" : "Mute Player"}
onClick={() => {
if (stream) {
toggleMute();
}
}}
>
<svg
xmlns="http://www.w3.org/2000/svg"
height="14"
viewBox="0 0 24 24"
width="14"
fill="currentcolor"
> >
{streamMuted ? ( <StreamMuteIcon muted={streamMuted} />
<path d="M3.63 3.63c-.39.39-.39 1.02 0 1.41L7.29 8.7 7 9H4c-.55 0-1 .45-1 1v4c0 .55.45 1 1 1h3l3.29 3.29c.63.63 1.71.18 1.71-.71v-4.17l4.18 4.18c-.49.37-1.02.68-1.6.91-.36.15-.58.53-.58.92 0 .72.73 1.18 1.39.91.8-.33 1.55-.77 2.22-1.31l1.34 1.34c.39.39 1.02.39 1.41 0 .39-.39.39-1.02 0-1.41L5.05 3.63c-.39-.39-1.02-.39-1.42 0zM19 12c0 .82-.15 1.61-.41 2.34l1.53 1.53c.56-1.17.88-2.48.88-3.87 0-3.83-2.4-7.11-5.78-8.4-.59-.23-1.22.23-1.22.86v.19c0 .38.25.71.61.85C17.18 6.54 19 9.06 19 12zm-8.71-6.29l-.17.17L12 7.76V6.41c0-.89-1.08-1.33-1.71-.7zM16.5 12c0-1.77-1.02-3.29-2.5-4.03v1.79l2.48 2.48c.01-.08.02-.16.02-.24z" /> </IconButton>
) : ( <Slider
<path d="M3 10v4c0 .55.45 1 1 1h3l3.29 3.29c.63.63 1.71.18 1.71-.71V6.41c0-.89-1.08-1.34-1.71-.71L7 9H4c-.55 0-1 .45-1 1zm13.5 2c0-1.77-1.02-3.29-2.5-4.03v8.05c1.48-.73 2.5-2.25 2.5-4.02zM14 4.45v.2c0 .38.25.71.6.85C17.18 6.53 19 9.06 19 12s-1.82 5.47-4.4 6.5c-.36.14-.6.47-.6.85v.2c0 .63.63 1.07 1.21.85C18.6 19.11 21 15.84 21 12s-2.4-7.11-5.79-8.4c-.58-.23-1.21.22-1.21.85z" /> value={streamVolume}
)} min={0}
</svg> max={2}
</IconButton> step={0.1}
{stream && <audio ref={audioRef} playsInline muted={streamMuted} />} onChange={handleVolumeChange}
/>
{stream && <audio ref={audioRef} playsInline muted={streamMuted} />}
</Flex>
<Banner <Banner
isOpen={showStreamInteractBanner} isOpen={showStreamInteractBanner}
onRequestClose={() => setShowStreamInteractBanner(false)} onRequestClose={() => setShowStreamInteractBanner(false)}

View File

@ -0,0 +1,21 @@
import React from "react";
function StreamMuteIcon({ muted }) {
return (
<svg
xmlns="http://www.w3.org/2000/svg"
height="24"
viewBox="0 0 24 24"
width="24"
fill="currentcolor"
>
{muted ? (
<path d="M3.63 3.63c-.39.39-.39 1.02 0 1.41L7.29 8.7 7 9H4c-.55 0-1 .45-1 1v4c0 .55.45 1 1 1h3l3.29 3.29c.63.63 1.71.18 1.71-.71v-4.17l4.18 4.18c-.49.37-1.02.68-1.6.91-.36.15-.58.53-.58.92 0 .72.73 1.18 1.39.91.8-.33 1.55-.77 2.22-1.31l1.34 1.34c.39.39 1.02.39 1.41 0 .39-.39.39-1.02 0-1.41L5.05 3.63c-.39-.39-1.02-.39-1.42 0zM19 12c0 .82-.15 1.61-.41 2.34l1.53 1.53c.56-1.17.88-2.48.88-3.87 0-3.83-2.4-7.11-5.78-8.4-.59-.23-1.22.23-1.22.86v.19c0 .38.25.71.61.85C17.18 6.54 19 9.06 19 12zm-8.71-6.29l-.17.17L12 7.76V6.41c0-.89-1.08-1.33-1.71-.7zM16.5 12c0-1.77-1.02-3.29-2.5-4.03v1.79l2.48 2.48c.01-.08.02-.16.02-.24z" />
) : (
<path d="M3 10v4c0 .55.45 1 1 1h3l3.29 3.29c.63.63 1.71.18 1.71-.71V6.41c0-.89-1.08-1.34-1.71-.71L7 9H4c-.55 0-1 .45-1 1zm13.5 2c0-1.77-1.02-3.29-2.5-4.03v8.05c1.48-.73 2.5-2.25 2.5-4.02zM14 4.45v.2c0 .38.25.71.6.85C17.18 6.53 19 9.06 19 12s-1.82 5.47-4.4 6.5c-.36.14-.6.47-.6.85v.2c0 .63.63 1.07 1.21.85C18.6 19.11 21 15.84 21 12s-2.4-7.11-5.79-8.4c-.58-.23-1.21.22-1.21.85z" />
)}
</svg>
);
}
export default StreamMuteIcon;