I’m having a ball at the moment hacking around with the MediaDevices API in preparation for an upcoming Pluralsight Course on PWA Sensors (it will appear here one day). It’s just crazy what you can do in a browser these days!

One cool trick I’ve been playing with is populating a selectbox with a list of available cameras, then letting the user select the camera that they’d like to work with.

The API has an enumerateDevices() call which is handy for tracking down everything that’s available on your system. I iterate over the returned MediaDeviceInfo objects since having their label and deviceId is handy for my next trick…

navigator.mediaDevices.enumerateDevices()
    .then(function (devices) {
        let cameras = [];
        let microphones = [];
        devices.forEach(function (device) {
            console.log(device.kind + ": " + device.label +
                " id = " + device.deviceId);
            if (device.kind === 'videoinput') {
                cameras.push(device);
            } else if (device.kind == 'audioinput') {
                microphones.push(device);
            }
        });
        self.set('cameraDevices', cameras);
        self.set('microphoneDevices', microphones);
    })
    .catch(function (err) {
        console.log(err.name + ": " + err.message);
    });
}

Now I have that those list of MediaDeviceInfo, I can put them into a dropdown and we’re off to the races:

Populate a Select with DeviceIds

But what happens if you have more than one device? My Surfacebook has a front and rear camara, and so does my mobile handset. How do you tell the API which one to use?

The magic you need is the super-handy Constraints block. Pass this into your media acquisition, and can specify exactly which DeviceId you’d like:

let constraints = {
    video: {
        deviceId: selectedCamera.deviceId
    },
    audio: false,
};

That constraints object is all the secret sauce you need. Pass those constraints in your getUserMedia call and you’re in business:

navigator.mediaDevices.getUserMedia(constraints)
.then((stream) => {
    photoPreview.srcObject = stream;
    this.set('cameraActive', true);
}, (err) => {
    console.log('User rejected camera capture permissions', err);
    this.set('captureRejected', true);
});

Can’t stop winning! But right now I need to get back to scripting my course - still have some media recording stuff to churn through (super, super fun!). I have a DevEditor progress call tomorrow and I’m way behind! Eeek!

Will post some more media recording coolness here soon.