Choose cameras, microphones and speakers from your web app

Modern browsers make it possible to select input and output devices including cameras, microphones and speakers.

For example:

  • On a phone, select the front or rear-facing camera.
  • On a laptop, choose the internal speakers or a speaker connected by Bluetooth.
  • For a video chat, choose internal or external microphone or camera.

All this functionality is exposed by the MediaDevices object, which is returned by navigator.mediaDevices.

MediaDevices has two methods, both implemented in Chrome 47 on desktop and Android: enumerateDevices() and getUserMedia().

Selecting an audio output device.

enumerateDevices()

Returns a Promise giving access to an array of MediaDeviceInfo objects for available devices.

The method is similar to MediaStreamTrack.getSources() but unlike that method (which was only ever implemented in Chrome) it's standards compliant and includes audio output devices. You can try this out with the demos below.

Here's some slightly simplified code from one of the demos:

navigator.mediaDevices.enumerateDevices()
    .then(gotDevices)
    .catch(errorCallback);
...
function gotDevices(deviceInfos) {

    ...

    for (var i = 0; i !== deviceInfos.length; ++i) {
    var deviceInfo = deviceInfos[i];
    var option = document.createElement('option');
    option.value = deviceInfo.deviceId;
    if (deviceInfo.kind === 'audioinput') {
        option.text = deviceInfo.label ||
        'Microphone ' + (audioInputSelect.length + 1);
        audioInputSelect.appendChild(option);
    } else if (deviceInfo.kind === 'audiooutput') {
        option.text = deviceInfo.label || 'Speaker ' +
        (audioOutputSelect.length + 1);
        audioOutputSelect.appendChild(option);
    } else if (deviceInfo.kind === 'videoinput') {
        option.text = deviceInfo.label || 'Camera ' +
        (videoSelect.length + 1);
        videoSelect.appendChild(option);
    }

    ...

}

Having retrieved the IDs of available devices with enumerateDevices(), you can use setSinkId() (defined in the Audio Output Devices API) to change the audio output destination for a video or audio element:

element.setSinkId(sinkId)
    .then(function() {
    console.log('Audio output device attached: ' + sinkId);
    })
    .catch(function(error) {
    // ...
    });

This method sets the output device for audio from the element. Once setSinkId() has been called, you can get the ID of the current output audio device for the element with the sinkId property.

getUserMedia()

This replaces navigator.getUserMedia(), but instead of using a callback, returns a Promise that gives access to a MediaStream. Developers are encouraged to use MediaDevices.getUserMedia(), but there's no plan to remove navigator.getUserMedia(): it remains part of the spec.

There's a demo at the WebRTC samples site.

Here's a fragment of code from the demo:

navigator.mediaDevices.getUserMedia(constraints)
    .then(function(stream) {
    var videoTracks = stream.getVideoTracks();
    console.log('Got stream with constraints:', constraints);
    console.log('Using video device: ' + videoTracks[0].label);
    stream.onended = function() {
        console.log('Stream ended');
    };
    window.stream = stream; // make variable available to console
    video.srcObject = stream;
    })
    .catch(function(error) {
    // ...
    }

Flag waiving

The enumerateDevices() method is 'flagless' in Chrome, whereas for MediaDevices.getUserMedia() you still need to enable Experimental Web Platform features in chrome://flags or use the following command line flag:

--enable-blink-features=GetUserMedia

Likewise for setSinkId(): enable Experimental Web Platform features or use a flag:

--enable-blink-features=AudioOutputDevices

More details about browser support below.

The future

The proposed ondevicechange event handler does what it says: the devicechange event is fired when the set of available devices changes, and in a handler you can call enumerateDevices() to get the new list of devices. This hasn't been implemented in any browser yet.

The Screen Capture draft is an extension to the Media Capture API which proposes a MediaDevices.getDisplayMedia() method that enables regions of a user's display to be used as the source of a media stream. There is also a MediaDevices extension proposal for getSupportedConstraints() , which provides information about what constraints could be used for a getUserMedia() call: audio and video capabilities supported by the browser.

Demos

Find out more