Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

enumerateDevices() should request permission #874

Open
bradisbell opened this issue Mar 23, 2022 · 4 comments
Open

enumerateDevices() should request permission #874

bradisbell opened this issue Mar 23, 2022 · 4 comments
Assignees

Comments

@bradisbell
Copy link

Currently, to get a media device list we must first make a call to getUserMedia(). This creates UX headaches for use cases where the user needs to pick a device first, and capture from it second. The current flow looks like this:

  1. Application awaits getUserMedia() before calling enumerateDevices().
  2. User is confused about why the application is requesting a camera and/or microphone, and hopefully approves the request.
  3. Application receives the stream from getUserMedia().
  4. Application stops all tracks.
  5. Application proceeds with enumerateDevices(), and shows the user a selection of devices to choose from.
  6. User chooses what they want.
  7. Application makes final call to getUserMedia() to get the stream.

What would be more desirable:

  1. Application awaits enumerateDevices().
  2. User is prompted to approve access to cameras and/or microphones, and hopefully approves.
  3. Application shows a user a selection of devices to choose from.
  4. User chooses what they want.
  5. Application calls getUserMedia() and gets a stream, without requiring additional approval from the user.

In other words, if the browsing context doesn't yet have audio/video capture permission before calling enumerateDevices(), that permission should be requested before enumerateDevices() resolves. And, the same permission gate for getUserMedia() should be used, so that if/when we eventually do call getUserMedia(), it's already been approved.

enumerateDevices() is already promise-based, so this seems mostly compatible with existing APIs.

Ideally, enumerateDevices() would also contain a filter option (#522) so that if an application only needed audio or video permission, they could request just what is needed.

This type of flow is important, particularly for applications where several tracks are used simultaneously. I understand in the past that there was a desire to have the user agent control device selection, but this is not a good user experience for anything outside of the a basic single-stream video conferencing application.

@youennf
Copy link
Contributor

youennf commented Jun 20, 2022

I do not think we can make enumerateDevices trigger a prompt as is:

  1. This goes against the principle of minimal exposure.
  2. Some UAs might have per-device granting access and I don't think this would work great here. @jan-ivar might have some input.
  3. This is not really backward compatible since enumerateDevices is called by many web pages that do not expect user prompts.

Last issue is solvable, we should probably move this issue to mediacapture-extensions in any case.

  • Application awaits getUserMedia() before calling enumerateDevices().
  • User is confused about why the application is requesting a camera and/or microphone, and hopefully approves the request.

I don't see why user would be confused.
On iOS, user will be prompted for each app by a TCC prompt about camera/microphone access before camera/microphone are allowed.

@bradisbell
Copy link
Author

The user gets confused because we have to request a camera/microphone stream before we can even prompt them for which camera/microphone they want to use. This isn't a hypothetical... it's a common source of confusion for our users. And, having to turn around and stop the stream we just opened is a source of further problems. Webcam light may turn on briefly, then off. System may run slower for a few seconds. Sometimes closing and re-opening cameras repeatedly can be problematic. Having to open a camera before getting a camera list is a hack. We're forced to use it because of this standard.

  1. This is not really backward compatible since enumerateDevices is called by many web pages that do not expect user prompts.

Calls to enumerateDevices() are basically useless until permission is granted. And, backwards compatibility on this very API has been broken in the past. enumerateDevices() used to return a full device list, even without permission. Prompting for permission would have been a better resolution at the time, and I believe it is the best resolution to this problem today.

Regardless, an alternative is to add some other way to request permission as an independent step to capturing or enumerating. Then, this is solved by something like this:

await navigator.mediaDevices.requestUserMediaPermission();
const devices = await navigator.mediaDevices.enumerateDevices();

@youennf
Copy link
Contributor

youennf commented Oct 27, 2022

enumerateDevices() without permission is allowing to know whether there are camera or microphones.
The permission model is usually to let user select a device in lieu of a general blanket permission.
Hence why enumerateDevice permissions is not great.

@jan-ivar
Copy link
Member

jan-ivar commented Oct 28, 2022

enumerateDevices() should request permission ... basically useless until permission is granted.

Note enumerateDevices is called by trackers in 8% of pages, dwarfing getUserMedia @ 0.6%. 💥

What would be more desirable:
... 2. User is prompted to approve access to cameras and/or microphones, and hopefully approves.

Why should users have to grant permission to all cameras to use one? That's an undesirable permission escalation from Mozilla's perspective, and the TAG agrees: "This specification exposes device information of devices other than those in use. This is for backwards compatibility and legacy reasons. Future specifications are advised to not use this model and instead follow best practices as described in the device enumeration design principles."

an alternative is to add some other way to request permission as an independent step to capturing or enumerating.

This has the same permission escalation problem.

Another alternative is to look at what Firefox implements:

  1. Application awaits getUserMedia()
  2. User is prompted to approve access to one camera and/or one microphone from a list in the prompt
  3. User chooses what they want
  4. Application gets a stream, without requiring additional approval from the user
  5. Application remembers track.getSettings().deviceId for next time

This seems to solve your problem without violating W3C design principles, so this doesn't seem to be a spec problem.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants