useAudioDevice hook + permission mngmnt

This commit is contained in:
Jose B
2023-08-17 14:35:36 -05:00
parent 33ab54a626
commit 7f7a13416d
3 changed files with 137 additions and 44 deletions

View File

@@ -5,6 +5,7 @@ import { Dashboard } from "../dashboard";
import useWebRTC from "../useWebRTC"; import useWebRTC from "../useWebRTC";
import useTranscript from "../useTranscript"; import useTranscript from "../useTranscript";
import { useWebSockets } from "../useWebSockets"; import { useWebSockets } from "../useWebSockets";
import useAudioDevice from "../useAudioDevice";
import "../../styles/button.css"; import "../../styles/button.css";
const App = () => { const App = () => {
@@ -24,6 +25,13 @@ const App = () => {
const transcript = useTranscript(); const transcript = useTranscript();
const webRTC = useWebRTC(stream, transcript.response?.id); const webRTC = useWebRTC(stream, transcript.response?.id);
const webSockets = useWebSockets(transcript.response?.id); const webSockets = useWebSockets(transcript.response?.id);
const {
loading,
permissionOk,
audioDevices,
requestPermission,
getAudioStream,
} = useAudioDevice();
return ( return (
<div className="flex flex-col items-center h-[100svh] bg-gradient-to-r from-[#8ec5fc30] to-[#e0c3fc42]"> <div className="flex flex-col items-center h-[100svh] bg-gradient-to-r from-[#8ec5fc30] to-[#e0c3fc42]">
@@ -32,16 +40,18 @@ const App = () => {
<p className="text-gray-500">Capture The Signal, Not The Noise</p> <p className="text-gray-500">Capture The Signal, Not The Noise</p>
</div> </div>
{permissionOk ? (
<>
<Recorder <Recorder
setStream={setStream} setStream={setStream}
onStop={() => { onStop={() => {
webRTC?.peer?.send(JSON.stringify({ cmd: "STOP" })); webRTC?.peer?.send(JSON.stringify({ cmd: "STOP" }));
setStream(null); setStream(null);
}} }}
getAudioStream={getAudioStream}
audioDevices={audioDevices}
/> />
<hr />
<Dashboard <Dashboard
transcriptionText={webSockets.transcriptText} transcriptionText={webSockets.transcriptText}
finalSummary={webSockets.finalSummary} finalSummary={webSockets.finalSummary}
@@ -49,6 +59,35 @@ const App = () => {
stream={stream} stream={stream}
disconnected={disconnected} disconnected={disconnected}
/> />
</>
) : (
<>
<div className="flex flex-col items-center justify-center w-fit bg-white px-6 py-8 mt-8 rounded-xl">
<h1 className="text-2xl font-bold text-blue-500">
Audio Permissions
</h1>
{loading ? (
<p className="text-gray-500 text-center mt-5">
Checking permission...
</p>
) : (
<>
<p className="text-gray-500 text-center mt-5">
Reflector needs access to your microphone to work.
<br />
Please grant permission to continue.
</p>
<button
className="mt-4 bg-blue-500 hover:bg-blue-700 text-white font-bold py-2 px-4 rounded m-auto"
onClick={requestPermission}
>
Grant Permission
</button>
</>
)}
</div>
</>
)}
</div> </div>
); );
}; };

View File

@@ -15,24 +15,11 @@ const AudioInputsDropdown = (props) => {
const [ddOptions, setDdOptions] = useState([]); const [ddOptions, setDdOptions] = useState([]);
useEffect(() => { useEffect(() => {
const init = async () => { setDdOptions(props.audioDevices);
// Request permission to use audio inputs props.setDeviceId(
await navigator.mediaDevices props.audioDevices.length > 0 ? props.audioDevices[0].value : null,
.getUserMedia({ audio: true }) );
.then((stream) => stream.getTracks().forEach((t) => t.stop())); }, [props.audioDevices]);
const devices = await navigator.mediaDevices.enumerateDevices();
const audioDevices = devices
.filter((d) => d.kind === "audioinput" && d.deviceId != "")
.map((d) => ({ value: d.deviceId, label: d.label }));
if (audioDevices.length < 1) return console.log("no audio input devices");
setDdOptions(audioDevices);
props.setDeviceId(audioDevices[0].value);
};
init();
}, []);
const handleDropdownChange = (e) => { const handleDropdownChange = (e) => {
props.setDeviceId(e.value); props.setDeviceId(e.value);
@@ -131,17 +118,13 @@ export default function Recorder(props) {
setIsRecording(false); setIsRecording(false);
document.getElementById("play-btn").disabled = false; document.getElementById("play-btn").disabled = false;
} else { } else {
const stream = await navigator.mediaDevices.getUserMedia({ const stream = await props.getAudioStream(deviceId);
audio: {
deviceId,
noiseSuppression: false,
echoCancellation: false,
},
});
await record.startRecording(stream);
props.setStream(stream); props.setStream(stream);
if (stream) {
await record.startRecording(stream);
setIsRecording(true); setIsRecording(true);
} }
}
}; };
const handlePlayClick = () => { const handlePlayClick = () => {
@@ -158,7 +141,11 @@ export default function Recorder(props) {
return ( return (
<div className="relative flex flex-col items-center justify-center max-w-[75vw] w-full"> <div className="relative flex flex-col items-center justify-center max-w-[75vw] w-full">
<div className="flex my-2 mx-auto"> <div className="flex my-2 mx-auto">
<AudioInputsDropdown setDeviceId={setDeviceId} disabled={isRecording} /> <AudioInputsDropdown
audioDevices={props.audioDevices}
setDeviceId={setDeviceId}
disabled={isRecording}
/>
&nbsp; &nbsp;
<button <button
className="w-20" className="w-20"

View File

@@ -0,0 +1,67 @@
import { useEffect, useState } from "react";
const useAudioDevice = () => {
const [permissionOk, setPermissionOk] = useState(false);
const [audioDevices, setAudioDevices] = useState([]);
const [loading, setLoading] = useState(true);
const requestPermission = () => {
navigator.mediaDevices
.getUserMedia({
audio: true,
})
.then(() => {
setPermissionOk(true);
updateDevices();
})
.catch(() => {
setPermissionOk(false);
})
.finally(() => {
setLoading(false);
});
};
const getAudioStream = async (deviceId) => {
try {
const stream = await navigator.mediaDevices.getUserMedia({
audio: {
deviceId,
noiseSuppression: false,
echoCancellation: false,
},
});
return stream;
} catch (e) {
setPermissionOk(false);
setAudioDevices([]);
return null;
}
};
const updateDevices = async () => {
const devices = await navigator.mediaDevices.enumerateDevices();
const _audioDevices = devices
.filter(
(d) => d.kind === "audioinput" && d.deviceId != "" && d.label != "",
)
.map((d) => ({ value: d.deviceId, label: d.label }));
setPermissionOk(_audioDevices.length > 0);
setAudioDevices(_audioDevices);
};
useEffect(() => {
requestPermission();
}, []);
return {
permissionOk,
audioDevices,
getAudioStream,
requestPermission,
loading,
};
};
export default useAudioDevice;