Android 13’s audio output switcher will soon show cast devices
With every release, Android adds new, useful ways to organize and manage notifications. Android 11, for example, added a dedicated space in the notification panel just for media playback notifications. These media playback notifications also got an output switcher button that users could tap to quickly change what device they want their media to play on. However, the only playback devices that could be listed in the output switcher included the current device and any paired Bluetooth devices, making it not very useful. That’s set to change thanks to the Android 13 update and a new version of the Google Cast SDK.
The output switcher in Android 13 can show Google Cast devices, provided the app adds support for it. This’ll let you more quickly transfer media sessions between your phone and any cast devices on your network, such as a Nest smart speaker or smart display. You’ll be able to start playing a podcast on your phone, transfer it to your bedroom Nest Hub, and then transfer playback to your phone once you’re ready to head out the door — all without ever unlocking your phone or opening an app. You’ll even be able to add additional cast devices to your media session, letting you jam out at home with your array of smart speakers.
Seamless media transfer between cast devices is, in my opinion, long overdue. People have been asking Google to add support for this since the output switcher was introduced in Android 11. If you follow Android as closely as I do, though, you may recall reading that the output switcher already supports showing cast devices … if apps are using a recent version of the MediaRouter Jetpack library. If you remember that tidbit, then you’re probably as confused as I was when I first went down this rabbit hole. Fortunately, I think I’ve started to make sense of what happened, and the good news is that this long-awaited feature is finally making a reappearance soon.
The promised upgrade that never happened
For a bit of context, Android 11 introduced what Google calls the “Media Controls” surface in SystemUI. This is a dedicated persistent space below Quick Settings that houses media playback notifications made by media player apps. The system keeps track of previous playback sessions and even arranges sessions from multiple apps in a swipeable carousel. Apps have to specifically opt into having their media playback notifications shown in Media Controls by creating a MediaStyle notification, a notification style that was introduced in Android 5.0.
The system takes the information provided by the MediaStyle notification and renders playback controls (pre-Android 13) and audio output information. That audio output information is shown in a button in the top right corner of the media playback notification. Tapping this button will open a dialog called the output switcher that shows a list of devices to transfer media playback to.
The output switcher by default only lists local playback devices (ie. any paired Bluetooth device as well as the current device). Shortly after Android 11’s release, ArsTechnica’s Ron Amadeo spotted evidence that the output switcher can also list remote playback devices like Google Cast-enabled devices.
Apps would have to use version 1.2.0-alpha02 or later of the MediaRouter Jetpack library (or the underlying MediaRouter framework API) in order to do so, however. MediaRouter is already listed as one of the prerequisites for developing with the Cast Application Framework, so it seemed as if we’d only have to wait for developers to update their apps before we’d see cast devices in the output switcher.
Of course, it’s not as simple as just pulling in an updated version of MediaRouter, which is why Google provided guidance in the form of a blog post and a video showing how to support the new feature. Fast forward two years and several stable MediaRouter library releases, and there seemingly hasn’t been a single instance of this feature working as Google described.
The problem, I think, isn’t with third-party apps and a lack of adoption of the API. Instead, it seems like Google quietly disabled the ability for remote media routers to appear in the output switcher. I’m not sure exactly how it was disabled — my best guess is that it’s controlled by a flag in Google Play Services, which is what contains the Google Cast SDK for Android.
I have reason to believe that, by the way, because I was able to briefly get cast devices to appear in the output switcher on a Pixel 3 XL running a fresh install of Android 12. However, after selecting a cast device, SystemUI crashed and the output switcher never again showed cast devices. Every other device running Android 11, Android 12, or Android 12L that I tested never once showed cast devices in the output switcher — but every device running Android 13 did.
To test this, I used the Universal Android Music Player (UAMP), an open source project that demonstrates how to implement an audio media app. Seamless transfer isn’t supported in the main branch, but the patches are available in this pull request.
I tested this app on a Xiaomi Mi 10 Pro running Android 11, a OnePlus Nord N200 running Android 12, an ASUS Zenfone 9 and Samsung Galaxy Z Flip4 running Android 12L, and a Google Pixel 3 XL, Pixel 4, Pixel 6a, and Pixel 6 Pro running Android 13. Notably on the Pixel 6 Pro, I was able to manually activate a feature that wasn’t available on the other Android 13 test devices: Stream Expansion. I mentioned this at the beginning and even showed it off in the embedded video, but this feature lets you expand the audio to multiple cast devices. When it’s enabled, the output switcher adds a radio button next to each cast device. Selecting a button will add the corresponding cast device to the existing media session.
The feature was quite buggy for me, however. The output switcher would close and then reopen after choosing a second cast target, followed by media playback restarting on my phone. It did work, though, as I heard playback from both cast devices and saw visual confirmation that they were playing the media I casted.
The mystery of Android 13’s upgraded output switcher
At this point, you may be wondering why this only worked on devices running Android 13. Unfortunately, I’m not really sure why. It’s clear that the feature was originally meant to work on Android 11 and up, otherwise Google wouldn’t have announced it back in 2020. Maybe Google discovered it was too buggy so they disabled it until they could iron out the kinks in a later release. Or maybe some of the changes to Media Controls in Android 13 were necessary, such as the new remote playback system API (AOSP commit). Whatever the case, Google intends for this feature to relaunch with Android 13, and they’re telling developers to get ready.
With the latest release of the Google Cast SDK, Google published documentation on a new feature of the Cast SDK called Output Switcher (yes, the same name of the Android OS feature). In it, they describe how developers can enable local-to-remote, remote-to-local, and remote-to-remote media transfers. “Local” in this case refers to devices paired via Bluetooth, while “remote” refers to Cast-enabled devices. In other words, local-to-remote and remote-to-local involves transferring media between a phone/tablet and a Cast-enabled device, while remote-to-remote involves transferring media between Cast-enabled devices.
Under the hood, Output Switcher uses the MediaRouter library to switch playback between the phone/tablet and remote Cast-enabled devices. The prerequisites to support local-to-remote and remote-to-local media transfers includes using version 21.2.0 or later of the Android Sender SDK, migrating to AndroidX because of the MediaRouter dependency, setting up media notifications, and using a device running Android 13. Then, developers need to add a MediaTransferReceiver broadcast receiver to the app’s Manifest and add code to handle switching from local to remote and vice versa. This is notably what the unmerged pull request that I previously linked adds to UAMP and is how I tested local-to-remote and remote-to-local media transfers.
After enabling support for local-to-remote and remote-to-local, developers seemingly won’t have to do much to add support for remote-to-remote media transfers. This is because support for remote-to-remote media transfers is said to “roll out to Android phones automatically without needing to update your app through a Google Play services update coming soon.” This is perhaps why my attempt at using Stream Expansion was so buggy; perhaps I needed a newer version of Play Services. Speaking of Stream Expansion, Google says this functionality is “supported by the Cast platform and doesn’t require any further changes if the app is using the default UI”, which is good. Stream Expansion is only for audio apps that use the Output Switcher, though. Video apps use Stream Transfer, which doesn’t support expanding playback to multiple cast devices.
Developers that are interested in adding support for local-to-remote, remote-to-local, and/or remote-to-remote media transfers should check out Google’s documentation. It’s worth noting that to test remote-to-remote media transfers, you’ll need to gain access to this invite-only test group. OEMs can validate the remote playback API through new CTS tests, though the CDD doesn’t even require that builds support the output switcher in the first place. I spotted a few devices that don’t support the output switcher (like my LG Velvet on Android 11), but I think more devices than not support the feature.
Update (10/18/2022 @ 11:00 AM PT): Developer mxalbert1996 alerted me to the fact that this feature did go live after Google announced it back in 2020, and that they were even able to incorporate it into their app. Indeed, cast devices appear in the output switcher when using this app, but they only do so on devices running Android 13.
Thanks for reading another edition of Android Dessert Bites! This column will be on break for the next two weeks, but keep an eye out on my Android 13 changelog article as I’m working on adding a lot of new information to it. If you follow me on Twitter, you’ll get a heads up on all my discoveries as soon as I make them (well, most of them). I post endlessly about Android there, a lot of which never makes it into a blog post or podcast! My best posts, though, are my long-form Dessert Bites columns (like this one) that are cataloged on the following page: