WebRTC is constantly evolving and with it, it’s most known function getUserMedia(). With it you can get access to the device’s webcams and microphones and request a video stream, an audio stream or both.

In this article we will be focusing on the video constraints available to us when requesting a video stream through getUserMedia(). In a previous blog post we’ve focused on the audio constraints.

MediaStreamConstraints

The getUserMedia() function receives only one parameter, a MediaStreamConstraints object used to specify what kind of tracks (audio, video or both) to request, and, optionally, any requirements for each track.

Here’s a basic example of how this object is sent to the newer, promise based, getUserMedia():

var constraints = { audio:true, video:true}
navigator.mediaDevices.getUserMedia(constraints).then(function(stream) {
 /* use the stream */
}).catch(function(err) {
 /* handle the error */
});

The constraints object can have one or both of these 2 properties:

  • video – indicates whether or not a video track is required
  • audio – indicates whether or not an audio track is required

Here’s how a basic constraint object that requires both an audio and a video stream looks like (the same one used above):

var constraints = { audio:true, video:true}

If you’re just taking a picture and don’t need an audio track just set the audio property to false like this:

var constraints = { audio:false, video:true }

If true is specified for video or audio, the resulting stream is required to have that particular media track in it, else the call to getUserMedia() will result in an NotFoundError error (see common getUserMedia() Errors for more details).

MediaTrackConstraints

The audio and video properties can take 2 types of values:

  • a Boolean value (true or false) as above
  • a  MediaTrackConstraints object which provides specific properties like width and height that must be met by the track.

Video Track Constraints: Resolution

One can use the width and height properties to request a certain resolution from the webcam. In this example the browser will request a 720p (1280×720) video stream:


{
 audio: true,
 video: { width: 1280, height: 720 }
}

The browser will try to honor this, but may return a different resolution stream. From my experience this often happens because the webcam does not support the requested resolution (try requesting odd resolutions like 721×55 and see what happens). It might also be that the constraints were overridden by another getUserMedia() call from a different app on Mac (where webcam access is shared) or a different Chrome tab (shared access). Other reasons might exist too.

You can try the WebRTC camera resolution finder to see what resolutions are supported by your browser and webcam combo.

Keywords

If the resolution is important to you and the device and browser can not guarantee it then you can use the  min, max and exact keywords to help you get the best resolution from any device. These keywords apply to any MediaTrackConstraint property. 

If for example you’re doing image recognition in video streams and absolutely require 1280×720 resolution use this constraint :

 { audio: true, video: { width: { exact: 1280 }, height: { exact:720 } } } 

In the example above, if no camera exists that supports the exact resolution, then the returned promise will be rejected with OverconstrainedError, and the user will not be prompted(see common getUserMedia() Errors for details).

The following constraint also requests a of 1280×720 resolution but it also mentions 320×240 as the minimum resolution since not all webcams support 1280×720 and in some use cases it’s better to get something rather than nothing:

{
 audio: true,
 video: {
  width: { min: 320, max: 1280 },
  height: { min: 240, max: 720  }
  }
}

Values without the  min, max and exact keywords are considered ideal values, which itself is a keyword but it is not mandatory. These 2 examples do the same thing:

 { audio: true, video: { width: 1280, height: 720 } } 
 { audio: true, video: { width: { ideal: 1280 }, height: { ideal: 720 } } } 

Video Track Constraints: Getting The Front Or Rear Camera On Mobile Devices

One can use the facingMode property for the video track constraint. Accepted values are: user (front camera), environment (rear camera), left and right.

Here’s how to request a video stream that should ideally come from the back camera:

 { audio: true, video: { width: 640, height: 480, facingMode:"environment" } } 

or

 { audio: true, video: { width: 640, height: 480, facingMode:{ideal: "environment"} } } 

Here’s how to request a video stream that should absolutely come from the back camera:

 { audio: true, video: { width: 640, height: 480, facingMode:{exact: "environment"} } } 

I am not sure how well these are supported  by mobile browsers.

Video Track Constraints: Frame Rate

Since frame rate has a direct impact on video quality but also bandwidth, in some cases, like publishing a video stream over low bandwidth connections, it might be a good idea to limit the frame rate. I was able to obtain a 60fps stream from the Logitech C925E by using:

{
 audio: true,
 video: {
  width: 320,
  height:240,
  frameRate: {ideal: 60, min:10}
 }
}

Keep in mind the frame rate of a stream coming from a webcam depends a lot on the light in the room.

Using a Certain Webcam or Microphone Device

There is one constraint property that applies to both audio and video tracks: deviceId. It specifies the device ID (or an array of IDs which) which should be used for capturing that stream. The device ID is unique and will be the same across browsing sessions on the same origin. You will need to first obtain the device id using MediaDevices.enumerateDevices().

Once you know the deviceId you can ask for a specific webcam or microphone:

{
 audio: true,
 video:{
    deviceId: {exact: "the_device_id"}
  }
}

There’s also groupId, a shared id by all media sources that come from the same physical device. For example: a microphone and speaker that come from the same headset will share the same group ID.

This example allows you to switch between the available devices used for input (mic & cam) and output (speaker).

MediaDevices.getSupportedConstraints()

Chrome 53, Firefox 44 and Safari 11 added support for MediaDevices.getSupportedConstraints(). The function returns a dictionary listing the constraints supported by the user agent.

Click here to run it for your current browser.

The function seems to return a lot of false positives, track.getSettings() gives better results.

MediaStreamTrack.getSettings()

You can also check which constraints are supported by using track.getSettings(). It returns an object containing all applicable constraints, including those supported by the browser but whose defaults have not been changed through code.

Here’s how to use the function and print the result to the console:

navigator.mediaDevices.getUserMedia(constraints).then(function success(stream) {
	video.srcObject = stream;
	stream.getTracks().forEach(function(track) {
		console.log(track.getSettings());
	})
});

This code pen will write in page the result of track.getSettings() for your browser.

The function has been added in Chrome 59 and it’s also supported by Firefox and Safari 11.

Old Constraints

The specifications for the constraints object has changed in the past. Constraints using the old spec looked like this:

var constraints = {
        audio: true, 
        video: {  
                mandatory: {  minWidth: 640,  maxWidth: 640, minHeight: 480, maxHeight: 480 }
        }
}

The old spec was the only one supported by Chrome until Chrome 59 (June 2017) which added support for the new one. Older versions of Chrome can also use the new spec through adapter.js

Firefox 38+ (May 2015) and Safari 11 both support the new video constraints spec.