Play and Pause on BBC Sounds from Bluetooth Headset

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.

The controls of BBC Sounds player is in an iframe!
The controls of BBC Sounds player is in an iframe!

So I started digging out the JS codes there. There are so many JS codes there, some even have source maps!

List of files loaded at the BBC Sounds website
List of files loaded at the BBC Sounds website

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.

Breakpoints here are never triggered :(
Breakpoints here are never triggered :(

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:

Found inline JS codes in iframe.html!
Found inline JS codes in iframe.html

However, when I try to prettify the codes, Firefox gave up:

Firefox given up prettifying iframe.html
Firefox given up prettifying iframe.html

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:

(The Chromium-based) Microsoft Edge Debugger stopped at this instance of “pause()” when I trigger a pause command from my headset

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.

Apparently in IE’s debugger, you can insert breakpoint in the middle of a line

And voila, I found something interesting: the caller has some argument with the value “shortcut_key_press

IE Debugger stopped at this instance of "pause()" when I trigger a pause command from my headset
IE Debugger stopped at this instance of “pause()” when I trigger a pause command from my headset

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.

Proof-of-concept where I handled MediaPlayPause keyboard key to play/pause the audio. In the browser console, it is seen that play/pause event is triggered

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

Showing that you can insert "column breakpoints" in Firefox, but you have to set a line breakpoint first

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
Screenshot of a file called "JS_callbacks0" where it includes a "disclaimer" containing some sort of legal threat
Screenshot of “JS_callbacks0”

Quite interesting, but then again, this file seems unrelated to what I wanted, so I ignored it.

Leave a Reply

This site uses Akismet to reduce spam. Learn how your comment data is processed.