useHooks.iov4.1.2
DocsBlogGitHub
Hooks
No hooks found in any category.

useUserMedia

sensors

Installation

npx usehooks-cli@latest add use-user-media

Description

A React hook for accessing user media devices (camera and microphone) using the getUserMedia API. Provides comprehensive error handling and stream management.

Parameters

NameTypeDefaultDescription
initialConstraints?UseUserMediaConstraints-Initial media constraints for video and audio

Parameter Properties

initialConstraints properties:

NameTypeDescription
video?boolean | MediaTrackConstraintsVideo constraints or boolean to enable/disable video
audio?boolean | MediaTrackConstraintsAudio constraints or boolean to enable/disable audio

Return Type

UseUserMediaReturn
PropertyTypeDescription
streamMediaStream | nullCurrent media stream from user devices
errorstring | nullError message if media access failed
isLoadingbooleanWhether currently requesting media access
isSupportedbooleanWhether getUserMedia is supported in the browser
startCapture(constraints?: UseUserMediaConstraints) => Promise<void>Function to start media capture with optional constraints
stopCapture() => voidFunction to stop media capture and release devices

Examples

Video chat component

Basic video chat setup with camera and microphone

1import { useUserMedia } from '@usehooks.io/use-user-media'; 2import { useRef, useEffect } from 'react'; 3 4function VideoChat() { 5 const videoRef = useRef<HTMLVideoElement>(null); 6 const { 7 stream, 8 error, 9 isLoading, 10 isSupported, 11 startCapture, 12 stopCapture 13 } = useUserMedia({ video: true, audio: true }); 14 15 useEffect(() => { 16 if (videoRef.current && stream) { 17 videoRef.current.srcObject = stream; 18 } 19 }, [stream]); 20 21 if (!isSupported) { 22 return <div>getUserMedia not supported</div>; 23 } 24 25 return ( 26 <div> 27 <video ref={videoRef} autoPlay muted /> 28 29 {error && <p style={{ color: 'red' }}>Error: {error}</p>} 30 31 <button onClick={() => startCapture()} disabled={isLoading}> 32 {isLoading ? 'Starting...' : 'Start Camera'} 33 </button> 34 35 <button onClick={stopCapture}> 36 Stop Camera 37 </button> 38 </div> 39 ); 40}

Dependencies

react

Notes

  • Automatically stops previous streams when starting new capture
  • Provides detailed error messages for different failure scenarios
  • Requires HTTPS in production for security reasons
  • Automatically cleans up streams on component unmount
  • Supports both boolean and detailed MediaTrackConstraints

Implementation

1'use client'; 2 3import { useState, useCallback, useRef, useEffect } from "react"; 4 5interface UseUserMediaConstraints { 6 video?: boolean | MediaTrackConstraints; 7 audio?: boolean | MediaTrackConstraints; 8} 9 10interface UseUserMediaReturn { 11 stream: MediaStream | null; 12 error: string | null; 13 isLoading: boolean; 14 isSupported: boolean; 15 startCapture: (constraints?: UseUserMediaConstraints) => Promise<void>; 16 stopCapture: () => void; 17} 18 19const DEFAULT_CONSTRAINTS: UseUserMediaConstraints = { 20 video: true, 21 audio: true, 22}; 23 24export const useUserMedia = ( 25 initialConstraints: UseUserMediaConstraints = DEFAULT_CONSTRAINTS 26): UseUserMediaReturn => { 27 const [stream, setStream] = useState<MediaStream | null>(null); 28 const [error, setError] = useState<string | null>(null); 29 const [isLoading, setIsLoading] = useState(false); 30 const streamRef = useRef<MediaStream | null>(null); 31 32 const isSupported = 33 typeof navigator !== "undefined" && 34 "mediaDevices" in navigator && 35 "getUserMedia" in navigator.mediaDevices; 36 37 const stopCapture = useCallback(() => { 38 if (streamRef.current) { 39 streamRef.current.getTracks().forEach((track) => { 40 track.stop(); 41 }); 42 streamRef.current = null; 43 setStream(null); 44 } 45 setError(null); 46 }, []); 47 48 const startCapture = useCallback( 49 async (constraints: UseUserMediaConstraints = initialConstraints) => { 50 if (!isSupported) { 51 setError("getUserMedia is not supported in this browser"); 52 return; 53 } 54 55 // Stop any existing stream 56 stopCapture(); 57 58 setIsLoading(true); 59 setError(null); 60 61 try { 62 const mediaStream = 63 await navigator.mediaDevices.getUserMedia(constraints); 64 streamRef.current = mediaStream; 65 setStream(mediaStream); 66 } catch (err) { 67 let errorMessage = "Failed to access media devices"; 68 69 if (err instanceof Error) { 70 switch (err.name) { 71 case "NotAllowedError": 72 errorMessage = 73 "Permission denied. Please allow camera/microphone access."; 74 break; 75 case "NotFoundError": 76 errorMessage = "No camera or microphone found."; 77 break; 78 case "NotReadableError": 79 errorMessage = "Camera or microphone is already in use."; 80 break; 81 case "OverconstrainedError": 82 errorMessage = 83 "Camera or microphone constraints cannot be satisfied."; 84 break; 85 case "SecurityError": 86 errorMessage = "Security error. Make sure you're using HTTPS."; 87 break; 88 case "AbortError": 89 errorMessage = "Media access was aborted."; 90 break; 91 default: 92 errorMessage = err.message || errorMessage; 93 } 94 } 95 96 setError(errorMessage); 97 } finally { 98 setIsLoading(false); 99 } 100 }, 101 [isSupported, initialConstraints, stopCapture] 102 ); 103 104 // Cleanup on unmount 105 useEffect(() => { 106 return () => { 107 stopCapture(); 108 }; 109 }, [stopCapture]); 110 111 return { 112 stream, 113 error, 114 isLoading, 115 isSupported, 116 startCapture, 117 stopCapture, 118 }; 119}; 120 121export default useUserMedia; 122