import { ref, watch, onUnmounted } from 'vue' export function useCamera(videoRef) { const stream = ref(null) const facingMode = ref('environment') const hasMultipleCameras = ref(false) const isMirrored = ref(false) const error = ref('') const checkCameras = async () => { try { if (!navigator.mediaDevices || !navigator.mediaDevices.enumerateDevices) { return } const devices = await navigator.mediaDevices.enumerateDevices() const cameras = devices.filter(d => d.kind === 'videoinput') hasMultipleCameras.value = cameras.length > 1 } catch (e) { console.error('Error checking cameras:', e) } } const stopCamera = () => { if (stream.value) { stream.value.getTracks().forEach(t => t.stop()) stream.value = null } } const startCamera = async () => { stopCamera() error.value = '' try { const constraints = { video: { facingMode: facingMode.value, width: { ideal: 1280 }, height: { ideal: 720 } } } const mediaStream = await navigator.mediaDevices.getUserMedia(constraints) stream.value = mediaStream // Detect actual facing mode to mirror front camera correctly const videoTrack = mediaStream.getVideoTracks()[0] if (videoTrack) { const settings = videoTrack.getSettings() if (settings.facingMode) { isMirrored.value = settings.facingMode === 'user' } else { // Fallback: check label for desktop cameras or assume requested mode const label = videoTrack.label ? videoTrack.label.toLowerCase() : '' if (label.includes('front') || label.includes('facetime') || label.includes('macbook')) { isMirrored.value = true } else { isMirrored.value = facingMode.value === 'user' } } } if (videoRef.value) { videoRef.value.srcObject = mediaStream return new Promise((resolve) => { videoRef.value.onloadedmetadata = () => { videoRef.value.play().catch(e => console.error('Play error', e)) resolve() } }) } } catch (err) { if (err.name === 'NotAllowedError') { error.value = 'Camera permission denied' } else if (err.name === 'NotFoundError') { error.value = 'No camera found' } else { error.value = `Camera error: ${err.name}` } throw err // Let caller know it failed } } const switchCamera = () => { facingMode.value = facingMode.value === 'environment' ? 'user' : 'environment' } watch(facingMode, () => { if (stream.value) { // Re-start if already running startCamera().catch(() => { }) } }) onUnmounted(() => { stopCamera() }) return { stream, facingMode, hasMultipleCameras, isMirrored, error, checkCameras, startCamera, stopCamera, switchCamera } }