Capturing Media Content on the Web

clock icon June 3, 2019

Media consumption on the web has been on a steady rise for over a decade. With that in mind, certain measures need to be taken into consideration when presenting media on the web, including how the media is captured. In this post, I’ll explore two APIs on the web that can be used to capture media (video, audio) on the web: getUserMedia and MediaRecorder API.


Capturing Media Content with getUserMedia()

The MediaDevices.getUserMedia() method is used to obtain access to the user’s media input. It requests for user permission the first time it is called and returns a promise that resolves to a MediaStream object. If the user does not grant permission or media is not found, an error is thrown which should be handled. Browser support is good in major browsers as can be seen:


To access the method, you access the  MediaDevices  object like so:

if (navigator.mediaDevices) {
  let stream = await navigator.mediaDevices.getUserMedia(constraints);
  const video = document.getElementById(‘video’);
  video.srcObject = stream;
  video.volume = 0;
}

As with everything on the web these days, you start off with feature detection. If the object is available, you make a call to  getUserMedia()  passing in a set of constraints (more on this in a bit). This prompts the user for permission to use the requested media source and once accepted, it returns a promise that resolves to a media stream. The stream can be passed to the HTML5 video  srcObject  property. Because of the new chrome’s autoplay policy, we set the volume to 0.  Here is the result:



That stream has been going on for about a while now as you can see from the time.


The getUserMedia() method accepts a set of constraints which is basically an object with properties. The constraint object contains the type of media to request and any additional requirements needed for that media type. An example of a simple constraint object is like so:

const constraints = {
  video: true,
  audio: true
};

Additional information can be specified for each media type:

const constraints = {
  video: {
    width: 1280,
    height: 720
  },
  audio: {
    echoCancellation: true
  }
};

A full list of constraints can be found on MDN.


On mobile, you can also switch between front and rear camera. For front camera:

video: { facingMode: "user" }

And for the rear camera, it can be accessed by:

video: { facingMode: { exact: “environment” } }

A word of note:

getUserMedia() is an API that raises a few privacy concerns so it can only be used in secure environments (https). The user also has to grant permission at least on the first visit before the web application can gain access to the media input. Browsers also show an indicator of some sort to the user to show that the camera or microphone is in use. Below is what the indicator looks like in Edge:


Recording Media Content on the Web

A media stream, on its own, is not very useful. It has to be shared in a format that can be consumed by the internet. One thing you can do on the web is record a video or audio that can be downloaded and shared. This can be done quite easily using the     MediaRecorder()  API. The MediaRecorder()  API provides an interface that makes it trivial to start recording media. It is created using the MediaRecorder()  constructor which takes in a MediaStream as an argument.

let mediaRecorder = new MediaRecorder(stream);

This creates a new MediaRecorder() object. Starting/stopping a new recording is as easy as:

mediaRecorder.start();
mediaRecorder.stop();

It also exposes methods to pause, resume, and request the current recording data as well as events when data is available or recording is paused or resumed. I built a video recorder demo using the MediaRecorder() API alongside getUserMedia(). The interface contains a video stream and buttons to start/stop recording. Once the recording is stopped, it prompts the user to enter a name for the recording and downloads the recorded video. The full source code can be found on GitHub.


This is a trivial example and does not touch on the complexities of recording and serving media on the web. There are other factors that will be taking into account in a production environment and have not been covered for the sake of simplicity.


Please like, star the project on GitHub, and share if you found this useful. I’ll also like to hear your thoughts so please do reach out if you have questions, suggestions or improvements. Thanks for reading.