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 :-)
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With