UNPKG

@supunlakmal/hooks

Version:

A collection of reusable React hooks

72 lines 3.04 kB
import { useState, useEffect, useCallback, useRef } from 'react'; const isBrowser = typeof window !== 'undefined'; const mediaDevices = isBrowser ? navigator.mediaDevices : undefined; /** * Hook to manage access to user's media devices (camera, microphone) using getUserMedia. * * @param options Configuration options including media constraints. * @returns State and controls for the media stream. */ export function useMediaStream(options) { const [stream, setStream] = useState(null); const [isActive, setIsActive] = useState(false); const [error, setError] = useState(null); const streamRef = useRef(null); // Ref to hold the stream for cleanup const optionsRef = useRef(options); // Ref to hold options const isSupported = !!(mediaDevices === null || mediaDevices === void 0 ? void 0 : mediaDevices.getUserMedia); // Update optionsRef if options object changes identity useEffect(() => { optionsRef.current = options; }, [options]); const stopStreamTracks = useCallback((currentStream) => { if (currentStream) { currentStream.getTracks().forEach((track) => { track.stop(); }); } }, []); const stopStream = useCallback(() => { stopStreamTracks(streamRef.current); setStream(null); streamRef.current = null; setIsActive(false); // Do not clear error, it might be relevant }, [stopStreamTracks]); const startStream = useCallback(async () => { var _a, _b, _c, _d; if (!isSupported || isActive) { return; } // Stop any previous stream first stopStream(); setError(null); setIsActive(true); try { const streamInstance = await mediaDevices.getUserMedia(optionsRef.current.constraints); setStream(streamInstance); streamRef.current = streamInstance; (_b = (_a = optionsRef.current).onStream) === null || _b === void 0 ? void 0 : _b.call(_a, streamInstance); } catch (err) { console.error('Error accessing media devices:', err); const currentError = err instanceof Error ? err : new Error('Failed to access media devices'); setError(currentError); (_d = (_c = optionsRef.current).onError) === null || _d === void 0 ? void 0 : _d.call(_c, currentError); setStream(null); // Ensure stream is null on error streamRef.current = null; setIsActive(false); // No longer active if failed } }, [isSupported, isActive, stopStream]); // Cleanup on unmount useEffect(() => { return () => { if (optionsRef.current.autoStop) { stopStream(); } }; }, [stopStream]); // Use stopStream which includes the autoStop check logic via optionsRef return { stream, isActive, startStream, stopStream, error, isSupported }; } //# sourceMappingURL=useMediaStream.js.map