@supunlakmal/hooks
Version:
A collection of reusable React hooks
72 lines • 3.04 kB
JavaScript
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