Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Effective way to detect current Audio Route in Android?

My application requires the ability to know the fundamental audio route the user has selected. On iOS this is trivial, as you just register for a callback and you know exactly where the audio is going.

On Android I was pleased to see the MediaRouter class, however to my dismay it turns out there is no predictable way to determine the route type. For example, when switching to a Bluetooth A2DP device, the only identifying item is the RouteInfo.getName() method, but this returns the friendly name of the A2DP device, so it is impossible to compare against.

I also have tried using the following broadcasts:

AudioManager.ACTION_AUDIO_BECOMING_NOISY
Intent.ACTION_HEADSET_PLUG
BluetoothHeadset.ACTION_AUDIO_STATE_CHANGED
BluetoothA2dp.ACTION_PLAYING_STATE_CHANGED
BluetoothA2dp.ACTION_CONNECTION_STATE_CHANGED

However this method is error prone. For example, if you are connected to Bluetooth A2DP, then you plug in headphones, it is easy to tell the route is "Headphones", but then when un-plugging the headphones you have to guess what route is still active, by recording the connected state from all Bluetooth events.

There are also difficulties in ascertaining the initial audio route when your application starts. HEADSET_PLUG is sticky, so that's good, but nothing else is...

Any suggestions on how to approach this and accurately detect this? And why is this such a difficult task in Android?

like image 861
yano Avatar asked Nov 03 '22 03:11

yano


1 Answers

Here's a very hackish way of polling for the current route, which also supports detection of A2DP. Use at your own risk, as the interals of these classes could very well change in the future. It should work on Jellybean and Jellybean MR1, though.

String ouputDeviceName;
try {
    MediaRouter mr = (MediaRouter)getSystemService(Context.MEDIA_ROUTER_SERVICE);
    Class mediaRouterClass = Class.forName("android.media.MediaRouter");
    Method getSystemAudioRouteMethod = mediaRouterClass.getMethod("getSystemAudioRoute");
    RouteInfo ri = (RouteInfo)getSystemAudioRouteMethod.invoke(mr);

    Class mediaRouterStaticClass = Class.forName("android.media.MediaRouter$Static");
    Field staticField = mediaRouterClass.getDeclaredField("sStatic");
    Field a2dpField = mediaRouterStaticClass.getDeclaredField("mBluetoothA2dpRoute");
    AccessibleObject.setAccessible(new AccessibleObject[]{staticField}, true);
    AccessibleObject.setAccessible(new AccessibleObject[]{a2dpField}, true);
    Object a2dpRoute = a2dpField.get(staticField.get(null));
    if (a2dpRoute != mr.getSelectedRoute(MediaRouter.ROUTE_TYPE_LIVE_AUDIO)) {
        // Phone, Headphone, HDMI, etc..
        ouputDeviceName = "name: " + ri.getName().toString();
    } else {
        // Audio is routed to A2DP
        ouputDeviceName  = "name: A2DP";
    }
} catch (Exception e) {
    e.printStackTrace();
}
like image 56
Michael Avatar answered Nov 15 '22 01:11

Michael