Bug 174833

Summary: mediaDevices.enumerateDevices() is missing audioinput devices on iOS
Product: WebKit Reporter: lepinski
Component: MediaAssignee: Nobody <webkit-unassigned>
Status: NEW ---    
Severity: Normal CC: daniel, ddkilzer, eric.carlson, jond, jonlee, lepinski, luke.mizuhashi, szmydadam, webkit-bug-importer, youennf
Priority: P2 Keywords: InRadar
Version: Other   
Hardware: iPhone / iPad   
OS: iOS 11   
URL: https://s3.amazonaws.com/safari-devices-testing/index.html

Description lepinski 2017-07-25 13:47:21 PDT
In the most recent iOS 11 build (15A5327g), calling mediaDevices.enumerateDevices() in Safari returns only "iPhone Microphone" as an audioinput device, despite other input devices being present.

To reproduce:
1. Connect an external audio input to an iOS 11 device
2. In Safari, call mediaDevices.getUserMedia() to get microphone permission
3. Call mediaDevices.enumerateDevices()
4. Returned devices will only include the iPhone Microphone audioinput device, and won't include the external input device

In the latest Safari Technology Preview for macOS this external device is returned by enumerateDevices as expected.

Tested with: iPhone SE running iOS 11 (15A5327g), external device: Apogee Duet https://www.apple.com/shop/product/HC173ZM/B/apogee-duet-usb-audio-interface-for-ipad-iphone-and-mac
Comment 1 Eric Carlson 2017-08-03 12:58:52 PDT
Is the external device listed after a call to getUserMedia?

enumerateDevices only returns the default devices until the user grants device access with getUserMedia (https://webkit.org/blog/7763/a-closer-look-into-webrtc/).
Comment 2 lepinski 2017-08-03 13:06:56 PDT
The enumerateDevices call follows getUserMedia & mic approval.
Comment 3 lepinski 2017-08-30 14:52:01 PDT
I've got a URL that is useful for testing this: https://s3.amazonaws.com/safari-devices-testing/index.html

Testing with Safari on the latest iOS 11 beta (15A5368a) with an external microphone connected:

2017-08-30T21:46:06.178Z [init] starting up
2017-08-30T21:46:06.179Z [init] getting media permission...
2017-08-30T21:46:06.179Z [init] Enumerate devices
2017-08-30T21:46:09.686Z [init] got media permission; eunmerating devices
2017-08-30T21:46:10.143Z [enumerateDevices] entire source list follows: 
2017-08-30T21:46:10.144Z kind: audioinput, label=iPhone Microphone, deviceId=23C467A56D616E048AB5E367AD0586A75AD1C22A
2017-08-30T21:46:10.146Z kind: videoinput, label=Back Camera, deviceId=247A083135FAC748D0E80E7EDCA6DB84C8629BF8
2017-08-30T21:46:10.146Z kind: videoinput, label=Front Camera, deviceId=28003D98E6289A035C4F5863257634BAA8B61E78
Comment 4 Radar WebKit Bug Importer 2018-07-19 15:07:02 PDT
<rdar://problem/42402143>
Comment 5 Luke Mizuhashi 2018-08-27 13:39:01 PDT
I'm having a similar issue:

I'm writing an app that allows people with disabilities to search for places and services that are accessible to their particular requirements (vis. search for hotels that work with your accessibility device, etc.)

So, we will have a lot of end users who have computers with cameras attached via USB, more than two cameras, perhaps zero, etc.

And yet, our app needs a button to cycle through media streams. So, hard-coding around the `navigator.mediaDevices.getUserMedia({ video: { facingMode: 'user' }})` pattern won't be ideal.

We would like to use something like `navigator.mediaDevices.enumerateDevices().then(deviceInfoList => cache = deviceInfoList);`

followed by:

`someElement.on('click', () => { navigator.mediaDevices.getUserMedia({ video: { deviceId: cache.nextId() }}) }`, but because the device ID's reported by Safari change unpredictably inside a single session we are unable to use device ID reliably.

We've tested on iOS 11.4 (15F79) with Safari 5.0
Comment 6 Daniel 2020-03-11 10:44:25 PDT
I'm experiencing the same issue as above (tested on iOS 13.3.1, iPhone 7 & iPhone 8, with both a wired headset and AirPods). Using https://s3.amazonaws.com/safari-devices-testing/index.html only 'iPhone Microphone' is listed.
Comment 7 Eric Carlson 2020-03-11 10:57:19 PDT
(In reply to Daniel from comment #6)
> I'm experiencing the same issue as above (tested on iOS 13.3.1, iPhone 7 &
> iPhone 8, with both a wired headset and AirPods). Using
> https://s3.amazonaws.com/safari-devices-testing/index.html only 'iPhone
> Microphone' is listed.

Are the other devices listed after a call to getUserMedia?

enumerateDevices only returns the default devices until the user grants device access with getUserMedia to lessen the use of this API for fingerprinting (https://webkit.org/blog/7763/a-closer-look-into-webrtc/).
Comment 8 Daniel 2020-03-11 11:10:38 PDT
(In reply to Eric Carlson from comment #7)
> (In reply to Daniel from comment #6)
> > I'm experiencing the same issue as above (tested on iOS 13.3.1, iPhone 7 &
> > iPhone 8, with both a wired headset and AirPods). Using
> > https://s3.amazonaws.com/safari-devices-testing/index.html only 'iPhone
> > Microphone' is listed.
> 
> Are the other devices listed after a call to getUserMedia?
> 
> enumerateDevices only returns the default devices until the user grants
> device access with getUserMedia to lessen the use of this API for
> fingerprinting (https://webkit.org/blog/7763/a-closer-look-into-webrtc/).

List before getUserMedia():
[
 {deviceId: "", kind: "audioinput", label: "", groupId: "", toJSON: function},
 {deviceId: "", kind: "videoinput", label: "", groupId: "", toJSON: function}
]

list after getUserMedia():
[
 {deviceId: "AFBAD73FC671AF21C6FAABF0F07FD446A1C36AED", kind: "audioinput", label: "iPhone Microphone", groupId: "", toJSON: function},
 {deviceId: "7049D645D2B1E988105392107FFEA5F5D9BACECD", kind: "videoinput", label: "Front Camera", groupId: "", toJSON: function},
 {deviceId: "513F58EDA3D167900B14BFE113AAE7E1B072521C", kind: "videoinput", label: "Back Camera", groupId: "", toJSON: function}
]

The list remains the same with wired headset/airpods connected.