Look us up here for the WebRTC Fiddle of the Month, created… once a month.
Or just enroll to one of our excellent WebRTC training courses.
Tsahi: Hi everyone, and welcome to our WebRTC Fiddle of the Month, and this time we’re going to talk about pre-call and dealing with the devices, getUserMedia() and enumerateDevices(). To get started, I want to put the rationale first before we get into the fiddle itself. So let me quickly share my screen.
OK, so the whole notion here or the whole concept from this one is browser fingerprinting. Browser fingerprinting happens for a long time. It’s a cat and mouse game where advertisers and other types of companies are trying to understand who you are on the Internet. So what they do is they try to track you from one site to another and seeing where they can find you online. And in order to do that, they don’t ask you who you are.
They just check through the APIs of the browser, if you’re someone that they’ve seen elsewhere. What’s happened is that whenever a new API comes in, in the Web browser, these advertisers or are trying to see if that API can be exploited. And then browser vendors are trying to add privacy layers on top of that, so they cannot use that. And it is happening a lot inWebRTC. One place it is happening with is in enumerated devices.
What does that mean exactly? It means that I can go and check what devices you have on your machine and by that decide who you are, OK? And we can see that based on the usage. So if you go and check the Chrome API usage graphs for MediaDevicesEnumeratedDevices versus GetUserMediaSecureOrigin, you’ll see that the EnumeratedDevices happen a lot more than GetUserMedia. Now, the only rationale behind using EnumeratedDevices would be to show a user these are the devices, “you have this and this and that camera”. Which one do you want to use for this call? And then you use GetUserMedia to actually get that type of media.
OK, now this is rational, but what happens is if I put them on the same graph, you’ll see this difference.
GetUserMedia is the blue line here, which is below one percent of the pages online, which makes sense. Not every page needs WebRTC or need video calling or voice calling. And yet, EnumerateDevices is anywhere between two to four percent of the pages online. How can that be? The only reason is if you want to fingerprint users. There’s an interesting thing here. You see this bump over here that goes from one point five to four point five percent?
Philipp, is there any explanation for that huge jump here?
Philipp: What I’ve heard from the browser vendors was that there was a very popular tracking script that added EnumerateDevices. And I think that tripled the usage.
So then they partially restricted the results of EnumerateDevices in Chrome 81 as a first step. And it has gone down a bit in usage since. But it seems that people are still happy with invalid results.
Now, all of this why is this important? Because this resulted in upcoming change into a itself. This is a PSA that was discuss-webrtc in recent weeks where what Google stated is that starting with Chrome 86 EnumerateDevices() will expose device info only if a previous getUserMedia() call has successfully completed. OK, so the whole workflow of let’s get the device names and then use getUserMedia and then start the call, which was or which is the best practices up until now is going to blow up in flames.
OK, since then Google found out the that’s an issue. So they retracted. It’s not going to happen in Chrome. 86. But we believe that this will happen sooner rather than later. And because of that you need to be prepared. And being prepared means using a jsFiddle to solve the problems or to solve that in your application. OK, Philipp, can you guide us through the Fiddle you prepared for us this month?
I’ll share the screen. So it is quite a simple fiddle – 35 lines, it is what you would usually do at the beginning of your application and it is composed of two parts. First, an asynchronous function which describes the state of the whole permissions and devices, and then another function which in this case, displays some information about this state of devices and permissions. You typically copies the first part into your application and then implement the second part yourself.
So we are calling enumerateDevices(), and this is something that worked in the past and still is working in Chrome 81+. So we want to find out if the user has a camera and has a microphone.
Because if we can’t getUserMedia() with audio and video set to true, but the user does not have a camera, getUserMedia(), would return “not found” error. And we want to avoid that in order to avoid the situation where we run into an error and then need to find out, “what exactly went wrong here?” So we’re looking at that up front. OK, so that is the old part and the new stuff you need to do.
It only works in Chrome, sadly. It is using the Navigator Permissions API to query the persistent permissions status of both camera and microphone.
It is going to work in Chrome 84 as well, and we don’t know until what point in time backwards. So we’re just going to do it in chrome 86 because before it just works without problems.
Tsahi: So before we don’t care.
Philipp: Yes. And in Firefox, in Navigator Permissions API is implemented, but it doesn’t work for camera and microphone. And Safari doesn’t have this API at all.
Tsahi: OK, so what happens is this, I call enumerateDevices(), as I used to call it in the past, it would give me the names of the devices, but now it won’t.
So if I’m in the future, which is the first part of the “if” – it’s from Chrome 86 and onwards, I just go and check if I have permissions already. And in the second part, if I’m in the “old” solution, what I’m going to do is just go and check that the kind of devices that have returned are devices that are audio and video and hence I have permissions for them
Philipp: And the behavior before was that you had the label was set even before getUserMedia() was called, that is no longer true – it was the change that Google wanted to do.
Tsahi: OK, and now you return the tuple here which is has camera, has permission, has microphone.
Philipp: The second part is simply acting on that information. So if you have a camera and you have camera permission and you have a microphone and microphone permission, you can just call getUserMedia() because you don’t want to have another button that a user needs to click before you call getUserMedia(). Because what you want to avoid with all this is the browser showing a permission dialog for getUserMedia() and then the user clicking “disallow” because getting out of that state is pretty hard in Chrome.
Tsahi: Yes, that’s right. OK. And then if I either have one of them then I get to decide if that’s good enough for me.
And you did here all in messages just to let the developers that are going to use this fiddle changes to their own code.
Philipp: Yes, I mean that the most simple implementation we have.
Tsahi: OK, great.
So if you’re looking and watching this fiddle look below, there are also the links to the fiddle itself, the additional resources, the transcription of this session. If you like the fiddle then join us next month as well. And if you want to learn more, you can check out the courses and enroll to them. Thank you. And see you next month.
Philipp: Thank you.