Bug 198148 - mediaDevices.enumerateDevices() returns empty deviceId
Summary: mediaDevices.enumerateDevices() returns empty deviceId
Status: RESOLVED WORKSFORME
Alias: None
Product: WebKit
Classification: Unclassified
Component: WebRTC (show other bugs)
Version: Safari 12
Hardware: iPhone / iPad iOS 12
: P2 Normal
Assignee: Nobody
URL:
Keywords: InRadar
Depends on:
Blocks:
 
Reported: 2019-05-22 17:05 PDT by aksuta
Modified: 2019-05-27 15:36 PDT (History)
4 users (show)

See Also:


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description aksuta 2019-05-22 17:05:54 PDT
On Safari 12.3:

navigator.mediaDevices.enumerateDevices().then(function(devices) {devices.forEach(function(device) {alert("object: " + JSON.stringify(device));})})
produces following:
object: {"deviceId":"";"kind":"audioinput","label":"","groupId":""}
object: {"deviceId":"";"kind":"videoinput","label":"","groupId":""}
Comment 1 Radar WebKit Bug Importer 2019-05-23 17:11:53 PDT
<rdar://problem/51089109>
Comment 2 youenn fablet 2019-05-24 08:32:43 PDT
Hi aksuta,
this is expected.
See related bug 195093 for more information.

*** This bug has been marked as a duplicate of bug 195093 ***
Comment 3 aksuta 2019-05-26 13:32:44 PDT
My bad, I did not include getusermedia call in bugreport, it is present in the code. 
This happens after getUserMedia is called and granted. e.g.
if (Modernizr.getusermedia) {
   if (navigator.mediaDevices && navigator.mediaDevices.enumerateDevices) {								 
     navigator.mediaDevices.enumerateDevices().then(function(devices) {devices.forEach(function(device) {alert("object: " + JSON.stringify(device));})}).catch(function(err) {}); }
} else {fallback();}
Comment 4 youenn fablet 2019-05-26 13:49:03 PDT
Can you try the following and verify this is working as expected?

let devices = await navigator.mediaDevices.enumerateDevices();
// device ids should be empty
alert(JSON.stringify(devices));

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

devices = await navigator.mediaDevices.enumerateDevices();
// device ids should not be empty
alert(JSON.stringify(devices));
Comment 5 aksuta 2019-05-26 15:10:33 PDT
Hi Youenn, thanks for quick response.

I've modified your code snippet due to my project setup, but, I think, the idea is still same:

navigator.mediaDevices.enumerateDevices().then(function(devices) {devices.forEach(function(device) {alert("before object: " + JSON.stringify(device));})}).catch(function(err) {alert('before catch',err)});
		// device ids should be empty
navigator.mediaDevices.getUserMedia();
// device ids should not be empty
navigator.mediaDevices.enumerateDevices().then(function(devices) {devices.forEach(function(device) {alert("after object: " + JSON.stringify(device));})}).catch(function(err) {alert('after catch',err)});

Output is as follows:
before object: {"deviceId":"";"kind":"audioinput","label":"","groupId":""}
before object: {"deviceId":"";"kind":"videoinput","label":"","groupId":""}
before object: {"deviceId":"";"kind":"videoinput","label":"","groupId":""}
after object: {"deviceId":"";"kind":"audioinput","label":"","groupId":""}
after object: {"deviceId":"";"kind":"videoinput","label":"","groupId":""}
after object: {"deviceId":"";"kind":"videoinput","label":"","groupId":""}


PS 
navigator.mediaDevices.getUserMedia().then(function(ret){alert("after getUserMedia", ret)}).catch(function(err){alert('catch in getUserMedia', err)}); 
results in alerting "catch in getUserMedia". 

If I use Modernizr.getusermedia it returns true, but with same empty deviceIds.
Comment 6 youenn fablet 2019-05-26 22:18:20 PDT
This is expected.
You need to change your snippet to trigger a successful getUserMedia call: device ids will be exposed once the page got access to camera or microphone at least once.

Note though that device IDs previously exposed can be given to getUserMedia() even though the devices are not listed by enumerateDevices.

(In reply to aksuta from comment #5)
> Hi Youenn, thanks for quick response.
> 
> I've modified your code snippet due to my project setup, but, I think, the
> idea is still same:
> 
> navigator.mediaDevices.enumerateDevices().then(function(devices)
> {devices.forEach(function(device) {alert("before object: " +
> JSON.stringify(device));})}).catch(function(err) {alert('before
> catch',err)});
> 		// device ids should be empty
> navigator.mediaDevices.getUserMedia();
> // device ids should not be empty
> navigator.mediaDevices.enumerateDevices().then(function(devices)
> {devices.forEach(function(device) {alert("after object: " +
> JSON.stringify(device));})}).catch(function(err) {alert('after catch',err)});
> 
> Output is as follows:
> before object: {"deviceId":"";"kind":"audioinput","label":"","groupId":""}
> before object: {"deviceId":"";"kind":"videoinput","label":"","groupId":""}
> before object: {"deviceId":"";"kind":"videoinput","label":"","groupId":""}
> after object: {"deviceId":"";"kind":"audioinput","label":"","groupId":""}
> after object: {"deviceId":"";"kind":"videoinput","label":"","groupId":""}
> after object: {"deviceId":"";"kind":"videoinput","label":"","groupId":""}
> 
> 
> PS 
> navigator.mediaDevices.getUserMedia().then(function(ret){alert("after
> getUserMedia", ret)}).catch(function(err){alert('catch in getUserMedia',
> err)}); 
> results in alerting "catch in getUserMedia". 
> 
> If I use Modernizr.getusermedia it returns true, but with same empty
> deviceIds.
Comment 7 Eric Carlson 2019-05-27 08:32:15 PDT
navigator.mediaDevices.getUserMedia() fails because you don’t have any constraints. The something like navigator.mediaDevices.getUserMedia({ video : true })

After you fix this, you will also have to modify your example to wait for the getUserMedia promise to resolve before calling enumerateMediaDevices()
Comment 8 aksuta 2019-05-27 15:36:12 PDT
Awesome, it worked for me, thanks a lot!