Tuesday, 8 December, 2020 UTC


Summary

Capturing the feed of a users camera can be a daunting undertaking involving one or multiple third party packages. Often we opt for prompting the user to upload the video or image we need, causing more steps for the user and a more difficult user experience. Luckily, there is a simple and easy solution for this scenario

What is WebRTC?

WebRTC (Web Real-Time Communication) is an open source technology released by Google in 2011. It enables Web applications and sites to capture and optionally stream audio and/or video media, as well as to exchange arbitrary data between browsers without requiring an intermediary. The set of standards that comprise WebRTC makes it possible to share data and perform teleconferencing peer-to-peer, without requiring that the user install plug-ins or any other third-party software.
There are many different use-cases for WebRTC, from basic web apps that uses the camera or microphone, to more advanced video-calling applications and screen sharing. We’ll be looking at one of the simpler use cases, streaming video in the browser

Getting started

For simplicity, we’ll just build our photo capture feature in a basic JavaScript application. We’ll start with our index.html
<!doctype html>
<html>
  <head>
    <title>WebRTC Starter</title>
  </head>
  <body>
    <div style="flex-direction: column;align-items: center;display: flex;" id="root">
      <video id="video" autoplay></video>
      
      <button 
        style="margin: 2rem 0;height: 2rem; width: 8rem;" 
        type="button" 
        id="start-button">
          Start Video
      </button>

      <button 
        hidden 
        style="margin: 2rem 0;height: 2rem; width: 8rem;" 
        type="button" 
        id="stop-button">
          Stop Video
      </button>

    </div>
    <script type="text/javascript" src="index.js"></script>
  </body>
</html>
There’s a few things going on here but this is the most important part
 <button 
   style="margin: 2rem 0; height: 2rem; width: 8rem;" 
   type="button" 
    id="start-button">
      Start Video
  </button>

 <button 
   hidden 
   style="margin: 2rem 0;height: 2rem; width: 8rem;" 
    type="button" 
    id="stop-button">
       Stop Video
 </button>

<video id="video" autoplay></video>
We have a button that we want to click to start the video, a button that is hidden that we will use to stop our video, and the video element to render our WebRTC stream. Next we move on to our JavaScript implementation

The JavaScript

First we’ll set a few variables for interacting with our video and buttons
const startButton = document.getElementById('start-button')
const stopButton = document.getElementById('stop-button')
const video = document.getElementById('video')
Next, we’ll define a couple of functions for starting and stopping our video
const playVideo = () => {
  startButton.hidden = true
  stopButton.hidden = false

  const constraints = {
    video: {
      width: 500,     
      height: 500
    }
  }

  navigator.mediaDevices.getUserMedia(constraints)
  .then((stream) => {
    video.srcObject = stream
    video.play()
  })
  .catch((err) => {
    console.log(err);
  })
}

const stopVideo = () => {
  startButton.hidden = false
  stopButton.hidden = true

  video.srcObject = null
}
Let’s unpack these functions a little.

getUserMedia()

const playVideo = () => {
  startButton.hidden = true
  stopButton.hidden = false

  const constraints = {
    video: {
      width: 500,     
      height: 500
    }
  }

  navigator.mediaDevices.getUserMedia(constraints)
  .then((stream) => {
    video.srcObject = stream
    video.play()
  })
  .catch((err) => {
    console.log(err);
  })
}
The first 2 lines are pretty clear. As we start the video we hide our start button and show out stop button. The real meat of this function is in the getUserMedia function.
getUserMedia is a function given to us by WebRTC to be called on a MediaDevices object, which we have accessed by using navigator.mediaDevices. It returns a Promise that resolves to a MediaStream object, and accepts an object of constraints for things such as height, width, etc, defined above.
When our Promise resolves, we set the srcObject of our video element to the returned MediaStream, and call the play() function. We should now see the video stream from our primary camera

Stopping the video

Now stopping the video becomes as simple as nulling out the srcObject on the video and changing which button is displayed
const stopVideo = () => {
  startButton.hidden = false
  stopButton.hidden = true

  video.srcObject = null
}
That’s it! WebRTC gives us the power to capture camera feed from the browser, using very little code. Note that this does not account for specific behavior in other browsers. We’ll go over that in a later post