Do you need to access the user’s webcam for video chat or the user’s microphone for a recording? In this simple tutorial, I’ll show you how to access and use the computer’s media inputs with React.
The MediaDevices interface provides access to connected media input devices like cameras and microphones.
Get access to user’s media input
After getting the user’s permission, the MediaDevices.getUserMedia() method produces a MediaStream. This stream can have multiple tracks containing the requested types of media. Examples of tracks include video and audio tracks.
The getUserMedia() method takes in a constraints parameter with two members: video and audio, describing any configuration settings for the tracks. It returns a Promise that resolves to a MediaStream object. You can set your video element’s src to the stream.
// get the user's media stream
const startStream = async () => {
let newStream = await navigator.mediaDevices
.getUserMedia({
video: true,
audio: true,
})
.then((newStream) => {
webcamVideo.current.srcObject = newStream;
setStream(stream);
});
setPlaying(true);
};
Here are some examples of preferences that you can customize in the stream:
// Requests default video and audio
{ audio: true, video: true }
// Requests video with a preference for 1280x720 camera resolution. No audio
{
audio: false,
video: { width: 1280, height: 720 }
}
// Requires minimum resolution of 1280x720
{
audio: true,
video: {
width: { min: 1280 },
height: { min: 720 }
}
}
// Browser will try to get as close to ideal as possible
{
audio: true,
video: {
width: { min: 1024, ideal: 1280, max: 1920 },
height: { min: 576, ideal: 720, max: 1080 }
}
}
// On mobile, browser will prefer front camera
{ audio: true, video: { facingMode: "user" } }
// On mobile, browser will prefer rear camera
{ audio: true, video: { facingMode: { exact: "environment" } } }
Save user’s media stream in a variable
After you get the user’s media stream from .getUserMedia(), you should save the stream in a state variable. This is so that you can manipulate the stream later (to stop it, get a track from it, etc.)
For example, if you want to stop the stream, get all of the stream’s tracks using the MediaStream.getTracks() method and call the .stop() method on them.
If you want to access the audio separately, use the MediaStream.getAudioTracks() method. To access video separately, use MediaStream.getVideoTracks().
You should also have state that controls if media input is on or off. You should use the useRef hook to control the video element in the DOM.
This is the final code:
import React, { useState, useRef } from 'react';
const App = () => {
// controls if media input is on or off
const [playing, setPlaying] = useState(false);
// controls the current stream value
const [stream, setStream] = useState(null);
// controls if audio/video is on or off (seperately from each other)
const [audio, setAudio] = useState(true);
const [video, setVideo] = useState(true);
// controls the video DOM element
const webcamVideo = useRef();
// get the user's media stream
const startStream = async () => {
let newStream = await navigator.mediaDevices
.getUserMedia({
video: true,
audio: true,
})
.then((newStream) => {
webcamVideo.current.srcObject = newStream;
setStream(stream);
});
setPlaying(true);
};
// stops the user's media stream
const stopStream = () => {
stream.getTracks().forEach((track) => track.stop());
setPlaying(false);
};
// enable/disable audio tracks in the media stream
const toggleAudio = () => {
setAudio(!audio);
stream.getAudioTracks()[0].enabled = audio;
};
// enable/disable video tracks in the media stream
const toggleVideo = () => {
setVideo(!video);
stream.getVideoTracks()[0].enabled = !video;
};
return (
<div className="container">
<video ref={localVideo} autoPlay playsInline></video>
<button
onClick={playing ? stopStream : startStream}>
Start webcam
</button>
<button onClick={toggleAudio}>Toggle Sound</button>
<button onClick={toggleVideo}>Toggle Video</button>
</div>
);
}
export default App;