Spaces:
Sleeping
Sleeping
File size: 2,065 Bytes
cf93910 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 | import { useEffect, useRef, useState, useCallback } from 'react';
export interface WebcamState {
videoRef: React.RefObject<HTMLVideoElement | null>;
isReady: boolean;
error: string | null;
facingMode: 'user' | 'environment';
switchCamera: () => void;
}
/**
* Hook to access the device webcam.
* Supports front/back camera toggle for mobile devices.
*/
export function useWebcam(): WebcamState {
const videoRef = useRef<HTMLVideoElement | null>(null);
const streamRef = useRef<MediaStream | null>(null);
const [isReady, setIsReady] = useState(false);
const [error, setError] = useState<string | null>(null);
const [facingMode, setFacingMode] = useState<'user' | 'environment'>('user');
const startCamera = useCallback(async (mode: 'user' | 'environment') => {
// Stop any existing stream first
streamRef.current?.getTracks().forEach(t => t.stop());
setIsReady(false);
setError(null);
try {
const stream = await navigator.mediaDevices.getUserMedia({
video: { width: { ideal: 1280 }, height: { ideal: 720 }, facingMode: mode },
audio: false,
});
streamRef.current = stream;
if (videoRef.current) {
videoRef.current.srcObject = stream;
videoRef.current.onloadedmetadata = () => {
videoRef.current?.play();
setIsReady(true);
};
}
} catch (err) {
const msg = err instanceof Error ? err.message : String(err);
setError(
msg.includes('Permission')
? 'Camera permission denied. Please allow camera access and reload.'
: `Camera error: ${msg}`
);
}
}, []);
// Start camera on mount and whenever facingMode changes
useEffect(() => {
startCamera(facingMode);
return () => {
streamRef.current?.getTracks().forEach(t => t.stop());
};
}, [facingMode, startCamera]);
const switchCamera = useCallback(() => {
setFacingMode(prev => (prev === 'user' ? 'environment' : 'user'));
}, []);
return { videoRef, isReady, error, facingMode, switchCamera };
}
|