Skip to content

Instantly share code, notes, and snippets.

@pdaug
Created May 20, 2025 13:45
Show Gist options
  • Select an option

  • Save pdaug/2e3c0aea6a78954e08480df953266ec3 to your computer and use it in GitHub Desktop.

Select an option

Save pdaug/2e3c0aea6a78954e08480df953266ec3 to your computer and use it in GitHub Desktop.
import { useEffect, useRef, useState } from "react";
// type
export type AudioDeviceOption = { id: string; value: string; label: string };
const useAudioDevice = function () {
const audioStreamRef = useRef<MediaStream | null>(null);
const [audioInputOptions, setAudioInputOptions] = useState<AudioDeviceOption[]>([]);
const [audioOutputOptions, setAudioOutputOptions] = useState<AudioDeviceOption[]>([]);
useEffect(function () {
if (audioStreamRef.current) return;
navigator.mediaDevices
.getUserMedia({ audio: true })
.then(function (stream) {
audioStreamRef.current = stream;
return;
})
.catch(function (err) {
console.error("[hooks/useAudioDevice.tsx]", err);
return;
});
return;
}, []);
useEffect(function () {
const devices = navigator.mediaDevices.enumerateDevices();
devices
.then(function (result) {
if (!result || !Array.isArray(result)) return;
const newAudioInput = new Array<AudioDeviceOption>();
const newAudioOutput = new Array<AudioDeviceOption>();
result.forEach(function (device) {
if (device.kind === "audioinput")
newAudioInput.push({
id: device.deviceId,
value: device.deviceId,
label: device.label,
});
if (device.kind === "audiooutput")
newAudioOutput.push({
id: device.deviceId,
value: device.deviceId,
label: device.label,
});
return;
});
setAudioInputOptions(newAudioInput);
setAudioOutputOptions(newAudioOutput);
return;
})
.catch(function (err) {
console.error("[hooks/useAudioDevice.tsx]", err);
return;
});
return;
}, []);
const setAudioInputDevice = async function (deviceId: string): Promise<MediaStream | null> {
try {
const stream = await navigator.mediaDevices.getUserMedia({
audio: { deviceId: { exact: deviceId } },
});
audioStreamRef.current = stream;
return stream;
} catch (err) {
console.error("[hooks/useAudioDevice.tsx]", err);
return null;
}
};
const setAudioOutputDevice = async function (element: HTMLMediaElement, deviceId: string): Promise<boolean> {
try {
if (typeof element.setSinkId !== "function") {
console.error("[hooks/useAudioDevice.tsx]", "browser_not_supported");
return false;
}
await element.setSinkId(deviceId);
return true;
} catch (err) {
console.error("[hooks/useAudioDevice.tsx]", err);
return false;
}
};
return { audioStreamRef, audioInputOptions, audioOutputOptions, setAudioInputDevice, setAudioOutputDevice };
};
export default useAudioDevice;
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment