androidaudiobluetoothandroid-audiomanagerheadset

Android - detect where audio is being routed on app start


I am talking about STREAM_VOICE_CALL

The scenario is as follows: 1. Connect wired headset to the phone 2. Connect bluetooth headset to the phone 3. Start application that plays audio to STREAM_VOICE_CALL

The OS redirects audio of this stream automatically - to the last device that connected. So, if bluetooth headset connected after wired headset, audio will be played to the bluetooth headset, and vice versa.

So the question is: how can I know what device was most recently connected, before my app was running.

I want to mention that I have no issues with manipulations with audio devices while my app is running - I know to get all the OS events and know exactly where the audio is redirected to. The only issue is as I mentioned - how to determine what the state is.

There was a deprecated method - Audiomanager.getRouting(stream) This is exactly what I need, but I didn't find any alternative.

Thank you in advance.


Solution

  • May be a little late for you, but here is the API 11+ approach that has worked best for me:

    private static BluetoothAdapter mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
    
    private static BluetoothProfile mBtProfile;
    
    public BluetoothInformationClass() {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) {
            mBluetoothAdapter.getProfileProxy(context, getServiceListneer(), BluetoothProfile.HEADSET);
        }
    }
    /**
     * Tries to get the name of the audio route device we're being played back through.
     * There are some important behaviors to note:
     * 1)  Headphones are always the audio route when plugged in.
     * 2)  BT will be the audio route whenever ever possible except where 1 is relevant.
     *      BT can be on, but not the audio routd.  In that case we allow BT to try and fail
     *      we check its result, if it was a failure we do the final stab at things.
     *
     * @return
     */
    public static String getAudioRouteDeviceName() {
        AudioManager audioManager = (AudioManager)
        context.getSystemService(Context.AUDIO_SERVICE);
        BluetoothAdapter bluetooth = BluetoothAdapter.getDefaultAdapter();
        String audioRoute = "";
    
        if (audioManager.isWiredHeadsetOn()) {
            audioRoute = "Wired Headset";
        } else if (audioManager.isBluetoothA2dpOn()) {
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) {
                audioRoute = getApiElevenPlusName(bluetooth);
            }
        }
        if (audioRoute.equals("")) {
            if (audioManager.isSpeakerphoneOn()) {
                audioRoute = "Phone Speaker";
            } else {
                audioRoute = "Phone";
            }
        }
        return audioRoute;
    }
    
    /**
     * 11+ api's have this fancy mechanism for figuring out connected devices.  Pre 11 its a lot less stable and for now we're going to ignore it.
     * @return
     */
    @TargetApi(11)
    private BluetoothProfile.ServiceListener getServiceListneer() {
        return new BluetoothProfile.ServiceListener() {
            public void onServiceConnected(int profile, BluetoothProfile proxy) {
    
                mBtProfile = proxy;
            }
    
            public void onServiceDisconnected(int profile) {
                if (profile == BluetoothProfile.HEADSET) {
                    mBluetoothHeadset = null;
                }
                mBtProfile = null;
    
            }
        };
    }
    
    /**
     * Tries to locate the currently connected device.
     * @param bluetooth
     * @return
     */
    @TargetApi(11)
    private static String getApiElevenPlusName(BluetoothAdapter bluetooth) {
        String ret = "";
        BluetoothDevice[] devices = bluetooth.getBondedDevices().toArray(new BluetoothDevice[bluetooth.getBondedDevices().size()]);
        if (mBtProfile != null) {
            for (BluetoothDevice device : devices) {
                if (mBtProfile.getConnectionState(device) == BluetoothProfile.STATE_CONNECTED) {
                    ret += device.getName();
                }
            }
        }
        return ret;
    }
    

    Some assumptions here:

    1) Wired Headphones will generally always be preferred as an Audio Route based on my testing. Even when paired to BT headphones/car stereos etc... once you plug a wired headset in that becomes the audio route.

    2) If you can't get a name of a BT device, this approach assumes that you are not using a BT device. That assumption isn't strictly true, however this approach works on all 11+ devices, and since thats 90+% of the market it should be sufficient.