UNPKG

@jellyfish-dev/browser-media-utils

Version:

Facilitates the use of getUserMedia and enumerateDevices.

57 lines (56 loc) 2.65 kB
import { useEffect, useState } from "react"; import { isAudio, isNotGranted, isVideo, prepareReturn, toMediaTrackConstraints } from "./utils"; /** * Hook that returns the list of available devices * * @param video - boolean or MediaTrackConstraints with configuration for video device * @param audio - boolean or MediaTrackConstraints with configuration for audio device * @returns object containing devices or loading state */ export const useEnumerateDevices = (video, audio) => { const [state, setState] = useState(null); // TODO inline const enumerateDevices = async (videoParam, audioParam) => { if (!navigator?.mediaDevices) throw Error("Navigator is available only in secure contexts"); const objAudio = toMediaTrackConstraints(audioParam); const objVideo = toMediaTrackConstraints(videoParam); const booleanAudio = !!audioParam; const booleanVideo = !!videoParam; setState(() => ({ audio: booleanAudio ? { type: "Loading" } : { type: "Not requested" }, video: booleanVideo ? { type: "Loading" } : { type: "Not requested" }, })); let mediaDeviceInfos = await navigator.mediaDevices.enumerateDevices(); const videoNotGranted = mediaDeviceInfos.filter(isVideo).some(isNotGranted); const audioNotGranted = mediaDeviceInfos.filter(isAudio).some(isNotGranted); const constraints = { video: booleanVideo && videoNotGranted && objVideo, audio: booleanAudio && audioNotGranted && objAudio, }; let audioError = null; let videoError = null; try { if (constraints.audio || constraints.video) { const requestedDevices = await navigator.mediaDevices.getUserMedia(constraints); mediaDeviceInfos = await navigator.mediaDevices.enumerateDevices(); requestedDevices.getTracks().forEach((track) => { track.stop(); }); } } catch (error) { // https://developer.mozilla.org/en-US/docs/Web/API/MediaDevices/getUserMedia#exceptions videoError = booleanVideo && videoNotGranted ? error.name : null; audioError = booleanAudio && audioNotGranted ? error.name : null; } setState({ video: prepareReturn(booleanVideo, mediaDeviceInfos.filter(isVideo), videoError), audio: prepareReturn(booleanAudio, mediaDeviceInfos.filter(isAudio), audioError), }); }; useEffect(() => { enumerateDevices(video, audio); }, [video, audio]); return state; };