UNPKG

@fishjam-cloud/react-client

Version:
110 lines (109 loc) 4.92 kB
import { useCallback, useEffect, useRef, useState } from "react"; import { prepareConstraints } from "../../../devices/constraints"; import { correctDevicesOnSafari, getAvailableMedia } from "../../../devices/mediaInitializer"; import { useDeviceManager } from "./useDeviceManager"; export const useMediaDevices = ({ videoConstraints, audioConstraints, persistHandlers }) => { const [deviceList, setDeviceList] = useState([]); const [videoStream, setVideoStream] = useState(null); const [audioStream, setAudioStream] = useState(null); const [videoError, setVideoError] = useState(null); const [audioError, setAudioError] = useState(null); const [selectedCamera, setSelectedCamera] = useState(persistHandlers?.getLastDevice("video") ?? null); const [selectedMic, setSelectedMic] = useState(persistHandlers?.getLastDevice("audio") ?? null); const initializationRef = useRef(null); const selectCamera = useCallback((deviceInfo) => { setSelectedCamera(deviceInfo); persistHandlers?.saveLastDevice(deviceInfo, "video"); }, [persistHandlers]); const selectMic = useCallback((deviceInfo) => { setSelectedMic(deviceInfo); persistHandlers?.saveLastDevice(deviceInfo, "audio"); }, [persistHandlers]); const initializeDevices = useCallback(async (settings) => { if (deviceList.length) { return { stream: null, errors: null, status: "already_initialized" }; } const lastUsed = { audio: selectedMic, video: selectedCamera, }; const constraints = { video: settings?.enableVideo !== false && prepareConstraints(lastUsed.video?.deviceId, videoConstraints), audio: settings?.enableAudio !== false && prepareConstraints(lastUsed.audio?.deviceId, audioConstraints), }; const intitialize = async () => { let media = await getAvailableMedia(constraints); const fetchedDevices = await navigator.mediaDevices.enumerateDevices(); setDeviceList(fetchedDevices); if (media.stream) { media = await correctDevicesOnSafari(media.stream, media.errors, fetchedDevices, constraints, lastUsed); } const { stream, errors } = media; const videoDeviceId = stream?.getVideoTracks()[0].getSettings().deviceId; const audioDeviceId = stream?.getAudioTracks()[0].getSettings().deviceId; const videoDevice = fetchedDevices.find((device) => device.deviceId === videoDeviceId); const audioDevice = fetchedDevices.find((device) => device.deviceId === audioDeviceId); if (videoDevice) { selectCamera(videoDevice); } if (audioDevice) { selectMic(audioDevice); } setVideoStream(stream); setAudioStream(stream); setVideoError(errors.video); setAudioError(errors.audio); if (!stream) { return { status: "failed", errors, stream: null }; } else if (errors.video || errors.audio) { return { status: "initialized_with_errors", errors, stream: null }; } else { return { status: "initialized", errors: null, stream }; } }; const initializePromise = intitialize(); initializationRef.current = initializePromise; return await initializePromise; }, [deviceList, selectedMic, selectedCamera, videoConstraints, audioConstraints, selectCamera, selectMic]); useEffect(() => { const isInitialStreamIrrelevant = videoStream !== audioStream; if (isInitialStreamIrrelevant) { initializationRef.current = null; } }, [videoStream, audioStream]); const getInitialStream = useCallback(async () => { const result = await initializationRef.current; return result?.stream ?? null; }, []); const cameraManager = useDeviceManager({ mediaStream: videoStream, setMediaStream: setVideoStream, deviceError: videoError, setDeviceError: setVideoError, getInitialStream, deviceType: "video", allDevicesList: deviceList, constraints: videoConstraints, setSelectedDevice: selectCamera, selectedDevice: selectedCamera, }); const microphoneManager = useDeviceManager({ mediaStream: audioStream, setMediaStream: setAudioStream, deviceError: audioError, setDeviceError: setAudioError, getInitialStream, deviceType: "audio", allDevicesList: deviceList, constraints: audioConstraints, setSelectedDevice: selectMic, selectedDevice: selectedMic, }); return { initializeDevices, cameraManager, microphoneManager, }; };