Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

AudioManager.startBluetoothSco() crashes on Android Lollipop

When making a call to AudioManager.startBluetoothSCO() while targeting API level 18 or above in the Manifest, the documentation states that a raw audio connection is established, and if targeting API 17 or below a virtual voice call is used.

Up until API level 20 (Android L Preview) this worked fine, targeting any API. However, when using the latest Android Lollipop build LPX13D and targeting API level 18 or above I get a crash with the following stack trace:

E/AndroidRuntime(31705): Caused by: java.lang.NullPointerException: Attempt to invoke virtual method 'java.lang.String android.bluetooth.BluetoothDevice.getAddress()' on a null object reference E/AndroidRuntime(31705): at android.os.Parcel.readException(Parcel.java:1546) E/AndroidRuntime(31705): at android.os.Parcel.readException(Parcel.java:1493) E/AndroidRuntime(31705): at android.media.IAudioService$Stub$Proxy.startBluetoothSco(IAudioService.java:1587) E/AndroidRuntime(31705): at android.media.AudioManager.startBluetoothSco(AudioManager.java:1468)

If I target API level 17 or below on Android Lollipop everything works as expected.

I believe the source of the problem lies in a change to Android's audio code that happened in API level 21 in the file AudioService.java line 2392:

public void startBluetoothSco(IBinder cb, int targetSdkVersion) {
    int scoAudioMode =
            (targetSdkVersion < Build.VERSION_CODES.JELLY_BEAN_MR2) ?
                    SCO_MODE_VIRTUAL_CALL : SCO_MODE_UNDEFINED;
    startBluetoothScoInt(cb, scoAudioMode);
}

It looks like SCO_MODE_UNDEFINED should instead be SCO_MODE_RAW. If you look through the file you can see that SCO_MODE_RAW is checked for in a few places, but is never actually passed in anywhere.

Is anybody else experiencing this crash? Does anyone know of a better fix than downgrading the target SDK to 17? If not, could you please star the bug report I filed with Google to increase the chance that it will be looked at :-)

like image 880
Julian Claudino Avatar asked Oct 29 '14 23:10

Julian Claudino


1 Answers

As @xsveda wrote if there is no headset connected, you will receive NPE on Lollipop.

You can try to check bluetooth headset connection first:

mAudioManager.isWiredHeadsetOn()

As doc described isWiredHeadsetOn() (doc link) is depricated and uses only to check is a headset is connected or not.

And after this you can use startBluetoothSco() connection. As for me I used this code:

This one for start:

if(mAudioManager.isWiredHeadsetOn())
    mAudioManager.startBluetoothSco();

This one for stop:

if(mAudioManager.isBluetoothScoOn())
            mAudioManager.stopBluetoothSco();

Hope it helps.

like image 170
busylee Avatar answered Nov 02 '22 06:11

busylee