-
Notifications
You must be signed in to change notification settings - Fork 62
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
Should devicechange fire when the device info changes? #966
Comments
I agree that the event should be fired on a page when the result of enumerateDevices() changes for that page. |
I agree the current spec is a bit restrictive. |
I'm not in favor of changing when The spec is in much better shape than current implementations, so I caution against making inferences from observations of current browsers:
Exposure tied to permission is legacy. In the spec and Safari it's instead tied to calling getUserMedia, which is much simpler. From testing with this demo page, Safari only fires this event if the app calls enumerateDevices first, a bug?
It sounds like Safari here is taking advantage of the following note: Apps can use permissions.query for that. I don't think the app is owed a Once implementations align, it should simplify things a lot for developers, and there should be no need to want getUserMedia to fire the |
To me, the primary use case for Many VC sites rely on it for that: they either auto-switch to the headset mic upon insertion, or trigger a toast message with a button to conveniently and immediately switch to the headset mic. Firing it for other reasons may interfere with that. For example: a user puts on their AirPods while joining a meeting or meeting lobby (not uncommon). If getUserMedia always fires |
Insertion detection is possibly the primary/most common use case, but not the only one. |
Once all browsers implement the spec correctly, it should be normal to expect:
I see no value in ever firing
What sort of changes? The text mentions changes to the "the system default", which can be a signal that a user may wish to (auto) switch, so belongs on the list IMHO. Anything else? |
If an application is interested in tracking changes to the result to enumerateDevices(), it can just call enumerateDevices() in a loop to detect them. Firing devicechange is a better way to avoid this inefficient way of doing it.
The result of enumerateDevices() might change (depending on UA choice of implementation) due to:
All these changes are detectable by polling enumerateDevices(), and should be available via devicechange to avoid having applications inefficiently enumerating devices in a loop. None of this implies firing devicechange every time gUM is called, which I see as an orthogonal issue. An application can call gUM multiple times while the result of enumerateDevices is visible. If the result of enumerateDevices() doesn't change as a consequence of those calls I see no reason to fire devicechange. |
I haven't heard why an application might be interested in more general device availability. Also you haven't addressed my concern that this interferes with detection of device switching, which you agreed "is possibly the primary/most common use case". Without a valid use case, I'd say let them poll. |
I have, and now so have you. I'm aware of applications that want to know when the set of devices change to decide if/when to make a new getUserMedia call or to provide a notification to the user (e.g., to request permission again).
Why/how does it interfere with detection of device switching? |
AFAIK, Safari behaviour does not seem to interfere with this. It seems convenient for web developpers that devicechange event is fired whenever an in-webpage device picker UI would need to be updated. This includes changes to |
I'm asking about the use case, the real-world problem that requires this change that isn't possible today. Earlier I clarified two reasons why the observable set may change:
I trust it's clear that if the same event fires for both 1 and 2 then that interferes with detecting 1. The problem use case I gave was getUserMedia racing with the user putting on their headset. Number 2 is the norm frankly. Most devices (cellphones) have more than one device of a kind. In the spec, apps should assume they don't have the full set of information ahead of gUM (like in Safari), and not need an event to tell them this.
Asking for getUserMedia twice is an anti-pattern. This is why we have constraints — and why Firefox has a picker — to help pick the correct device up front. Per-device permission models work poorly otherwise. I'm not going to call out specific VC apps, but you know who you are.
Using enumerateDevices to detect permission is also an antipattern. Hopefully this clarifies why I'm opposed to this change. |
In that use case, what we are after is a way for the web application to know what triggered the devicechange event. To help the web application, there are different approaches we could consider, for instance:
|
I've already mentioned it. Update the UI to reflect available devices, notify the user, know when/if to call getUserMedia again. Is your position that those are use cases we should not support via devicechange? We support them anyway via calling enumerateDevices() in a loop.
Why? The preferred pattern is to use plan events, like
What is wrong about calling gUM more than once? And what is wrong about updating a UI that lists available devices based on a change in the result of enumerateDevices()?
enumerateDevices() would be used to examine the updated state, just like with any other plain event. Not specifically to check permissions. |
I would prefer to keep |
I guess we could also ensure enumerateDevices expose the set of devices without devicechange event at the time getUserMedia resolves. This still seems much more brittle and difficult to reason about. |
Agreed, I'd like if possible to keep allowing web apps to just resort on enumerateDevices to figure out what is happening. |
I think @youennf is on to our disconnect: he says what I want never worked. That is a key insight.
Yes.
That's not a satisfying answer, because apps will try even if they cannot compute it accurately, which seems like a design flaw. In Firefox and Chrome, the app knows that a user-initiated action MUST have happened or it wouldn't have received the event. In Safari it doesn't have this information.
I count that as a valid user-initiated action worth reacting to (e.g. macOS seems to reorder defaults in response me taking my AirPods out).
Here you've stumped me. Yes, it's possible that with 3 or more devices of a kind, removal of a 3rd device upon joining a meeting might be misinterpreted as insertion of the 2nd. Your argument is basically: it won't work anyway. :) But it probably works MOST of the time, right? In any case, I prefer: it won't work anyway, so let's fix it. Not, it won't work anyway, so let's not.
Yes. Let's talk about how complicated writing said code already is, and what a web compat nightmare it must be. Take this fiddle, but keep AirPods in their case before opening it, then put them on. This is on macOS Ventura: Firefox:
Chrome:
Safari:
I think it's quite hard to reason about both this application code and browser behaviors here, and I suspect there's a lot we could do to improve this situation. To start, just to cut down on races, it might help to mandate that browsers delay firing a |
I'd like for someone to show how an app can do that and cover all the edge-cases we've discussed so far (racing with gUM's device exposure gate, racing with enumerateDevices itself, relying on pre-gUM vs post-gUM baseline, handling pre-gUM insertion (from 0→1 devices). The more I think about all the edge-cases I'm not confident apps will be able to decode device insertion correctly in all cases. Do we need a discrete |
Races are still possible even if you restrict the event to insertion/removal. Sometimes they can be outside the UA (e.g., at the OS level, different processes can have different views of the set of devices). We can mitigate them with mechanisms like @youennf's proposal to delay firing a
I'm open to having another event type, but I don't think that will completely solve the generic problem of races. Being able to present the correct choices in a UI when the set of available devices changes (no races) looks like a more important concern IMO. |
I don't think it's accurate to say there are unavoidable races here. They're API races we designed. See #972.
Then devicechange is not the event for them: It clearly says the event denotes a change in devices available to the "User Agent" (i.e. an OS change), not to the web page. |
The proposal is to change the spec to make it denote a change in devices available to web page since that is more useful to Web applications. |
|
Also, a change in devices available to the user agent covers more than just physical insertion/removal. |
When do labels change at the OS level?
When is this NOT user-action driven? Insertion and removal (already antiquated USB terms in a Bluetooth world) already cover this since that's obviously all browsers can observe. As long as the user acted, it's a reasonable app decision to assume intent and respond to those actions, e.g. if done during a live call or a selection screen.
Again, when is this NOT user-action driven?
It's not entirely separate, since in #972 I also show specifically how Safari's decision to fire What's proposed here would essentially declare Safari correct and the other browsers wrong, when the spec says the opposite. I'm happy the way the spec is already written, and look forward to more implementations aligning to solving its primary use case better. Regarding the problem use case of in-content UX not being updated, I'd like to understand specifically where the existing event falls short, and why you can't work around it. |
This happens to me fairly frequently when the camera in my external monitor disappears while in use when the driver (or maybe USB bus?) crashes. When this happens the OS fires an event when the camera disconnects, and another when it reconnects. The events are the same ones fired when a camera is connected/disconnected manually by the user. |
Thanks, it's interesting to explore real use cases. My first reaction is that this says it's a bug if it's not user-initiated. But then I suppose similar situations may happen if I temporarily move out of Bluetooth range during a meeting. But in both cases, if this happens, I think most people would find it valid for apps to try to auto-switch back to the device when it comes back, so even if it's not 100% user-initiated, it seems desirable to categorize it as a devicechange worth reacting to. |
This was discussed in https://www.w3.org/2023/10/17-webrtc-minutes.html:
|
This issue had an associated resolution in WebRTC June 18 2024 meeting – 18 June 2024 (Should devicechange fire when the device info changes?):
|
I noticed a browser inconsistency in the way the
'devicechange'
event gets fired. But I think the spec isn't very clear which browser is behaving correctly.These days all browsers reduct the information available by querying
enumerateDevices()
as long as the page has for example no permission to access the microphone. However this changes after a successful call togetUserMedia()
. This behavior seems to be similar across all browser.But only Safari fires a
'devicechange'
event when it exposes thelabel
of a device as a result of a permission change. This inconsistency can be easily worked around by callingenumerateDevices()
again after each call togetUserMedia()
but it doesn't work if the user changes the page permission in the browser settings.The spec currently says ...
At least on my MacBook Chrome is the only browser which actually adds a device after the user has granted permissions to see the full list of devices. It shows the default device twice. However it doesn't fire a
'devicechange'
event.Firefox only changes the
label
which I would argue means the device is still the same and therefore'devicechange'
shouldn't fire at least in the way it is defined today.Safari changes all properties including
deviceId
andgroupId
which could be interpreted as a completely new device. It consequently fires a'devicechange'
event.As a developer building applications using this API I would love all browsers to fire a
'devicechange'
event whenever anything changes in the device list includinglabel
changes.The text was updated successfully, but these errors were encountered: