I love BBC Radio 1 and I listen to it on the BBC Sounds website. But I noticed something weird. This web player is able to respond to my play/pause command from my Bluetooth headset!
This is quite weird, since not even popular websites like YouTube supported this kind of controls from a Bluetooth headset.
So I started researching.
Media Session API
I found this new Web API called Media Session API, which gives web applications the capability for media to be controlled through media keys.
However, something does not add up, this API is not available in Firefox yet. As per time of writing, it is implemented but disabled by default. Yet, I am able to control the player in Firefox through my Bluetooth headset.
Digging Codes
So I checked back the BBC Sounds web player again. One unusual condition: I need to be in “focus” around the controls area (by clicking somewhere there). If my “focus” point is not those area, my Bluetooth headset wouldn’t be able to control the play/pause. Turned out that the controls area is inside an iframe.
So I started digging out the JS codes there. There are so many JS codes there, some even have source maps!
Since initially I thought it was Media Session API, I keep looking for codes related to it, searching for keywords like “mediaSession
“, and the only place I could find is in a JS file named “bump-4.js
“. I set breakpoints here and there.
I triggered my Bluetooth headset’s play/pause, and the player did play and pause, but the breakpoints were never triggered :( This means that it is not the right file. I tried to search other files, and couldn’t really find anything interesting
Until I found this inline JS codes in iframe.html
:
However, when I try to prettify the codes, Firefox gave up:
To the Edge
So, I switched browser, I tried the Chromium-based Microsoft Edge. It could prettify thatiframe.html
and I set breakpoints around places where a call to “pause()
” was made, and it got caught here:
Hmmm, this is really Media Sessions API! But wait, Firefox does not enable this feature yet. So it must be something else.
So now I need to attach debugger in browsers where Media Session API is not yet available. And seems like I can’t do that in Firefox, as it attaches breakpoints at line-level, it fails to prettify iframe.html, and it cannot attach a breakpoint in the middle of the line ☹. (see Notes for correction)
IE to the Rescue
I turned to IE 11 for debugging. I confirmed that this play/pause behavior also works there. I then opened up its debugger, and attaches breakpoints to places where pause()
was called.
And voila, I found something interesting: the caller has some argument with the value “shortcut_key_press
“
Eureka!
So I copy-pasted the iframe.html
codes to my local VS Code, run Prettier on it, and search of instances where “shortcut_key_press
” was passed to a function, and I found the real culprit:
It is simply a keydown event handler! BBC Sounds handles a keyboard key called MediaPlayPause
. That’s it! It’s so simple! This is how the player’s play/pause can be controlled by a Bluetooth headset.
I can’t believe it was that simple. I always thought that to do this, one have to resort to some kind of a shiny Web API (like Media Session API) that aren’t supported by the older browsers.
To confirm that this method works, I made a simple proof-of-concept in this Github Gist, and yeah, my Bluetooth headset is triggering “MediaPlayPause
” keyboard key when I pressed play/pause on the headset.
In conclusion, if you want your web player to be controllable by a Bluetooth headset, you can attach a keydown event listener to your page and handles play/pause when you encounter “MediaPlayPause
” key. The other way is to use the shiny Media Session API.
Notes
P.S. Afterwards, I read up more on Firefox’s debugger and you can actually set a breakpoint in a middle of a line, but there is an extra step: you have to set a breakpoint to the line first, before you can add breakpoints to the “columns“
Other Interesting Find
When browsing through their JS codes, I found that in one of their codes, they included a legal threat 😅
This code and data form part of the BBC iPlayer content protection system. Tampering with, removal of, misuse of, or unauthorised use of this code or data constitutes circumvention of the BBC’s content protection measures and may result in legal action.
JS_callbacks0
Quite interesting, but then again, this file seems unrelated to what I wanted, so I ignored it.