enumerateDevices after getUserMedia: how to find the active devices?

5.4k views Asked by At

Is there a way to detect which device (camera, microphone) is active, given a MediaStream instance?

The app I'm currently working on does simply query for such a stream and attaches it to a <video/> element:

const stream = await navigator.mediaDevices.getUserMedia({ audio: true, video: true })

const el = document.querySelector("video")
el.srcObject = stream

console.log(stream.getTracks())
// MediaStreamTrack { kind: "audio", id: "{000d071e-f936-42d8-872e-a568cd96cc2d}", label: "USB Audio Device Mono", … }
​// MediaStreamTrack { kind: "video", id: "{186427d5-b04a-4906-9177-1a088c5d4e0a}", label: "C922 Pro Stream Webcam", … 

The next step is to give the user the ability to change camera/mic. The basic code for this is:

const devices = await navigator.mediaDevices.enumerateDevices()
console.log(devices)
// MediaDeviceInfo { deviceId: "yQx5+MN7znbmkE0tV98jJHpvqrUaa6Gv5WIXF52jj0s=", kind: "videoinput", label: "C922 Pro Stream Webcam", … }
​// MediaDeviceInfo { deviceId: "dIjwtaOGQbjT2HOqfJ4xjzjXBwBxz4CEeX3a2fn0ZgA=", kind: "audioinput", label: "USB Audio Device Mono", … }​
// MediaDeviceInfo { deviceId: "/t3u7BlfExATtBC4CUmyqIo8RORDxMu9aMrJJHN0Ez0=", kind: "audioinput", label: "C922 Pro Stream Webcam Analog Stereo", … }​
// MediaDeviceInfo { deviceId: "/5pqK1599b+mKHm26zCYQ+Ql3vG0Em7xiVbqfm1C/9A=", kind: "audioinput", label: "Monitor of Built-in Audio Digital Stereo (IEC958)", … }
// MediaDeviceInfo { deviceId: "Tib/PVScFuFUQuAtYYVgtxcxeu08opGKe9MXEVmxq84=", kind: "audioinput", label: "Monitor of USB Audio Device Analog Stereo", … }

I can simply transform this list into <select/>+<option/> lists (one for each kind), let the user decide and re-request the stream with the selected deviceId (getUserMedia({ audio: { deviceId: selectedDeviceId } })).

However: the track and device ID don't match, so how do I determine which <option/> should be pre-selected? Looking at MDN, the stream's track ID is generated by the browser (which makes sense), but the MediaStream API doesn't provide much alternatives...

Surely, the answer can't be "go by the label"—I can plug in a second identical webcam and have two video devices with the same name?

2

There are 2 answers

0
Kaiido On BEST ANSWER

You can get the MediaTrackSettings currently applied on your MediaStreamTracks and check for the deviceId from there:

const used_devices = mediastream.getTracks()
  .map( (track) => track.getSettings().deviceId );
2
O. Jones On

If you do

const label = stream.getVideoTracks()[0].label

You'll get back the name of the video device. It's an attribute of the MediaStreamTrack class.

As for the default choice, here's how I have figured out which one is the default. (This stinks, but I've found no better way.)

Do a .getUserMedia({video:true, audio:true}) operation and look at the label attributes. That otherwise doltish constraint object chooses the default devices, and by the way gets the user-permission grant completed.

When I say default device, I mean the one that's set in browser settings.