How to Use MediaStreams in React

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;

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s