AudioManager.startBluetoothSco()在安卓棒棒糖上崩溃

11
当在清单中针对API级别18或更高版本调用AudioManager.startBluetoothSCO()时,文档指出建立原始音频连接,而如果针对API 17或更低版本,则使用虚拟语音呼叫。在API级别20(Android L Preview)之前,无论目标API是什么,这都可以正常工作。然而,在使用最新的Android Lollipop版本LPX13D并针对API级别18或更高版本时,会出现以下堆栈跟踪的崩溃:
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)
如果在Android Lollipop上以API级别17或更低版本为目标,则一切正常。

我认为问题的根源在于Android音频代码的更改,这发生在API 21级中的AudioService.java文件的第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);
}

似乎SCO_MODE_UNDEFINED应该改为SCO_MODE_RAW。如果您查看文件,可以看到在一些地方检查了SCO_MODE_RAW,但实际上没有传递任何内容。是否有其他人遇到此崩溃?有人知道比将目标SDK降级到17更好的解决方法吗?如果没有,请点亮我向Google提交的bug report,以增加它被关注的机会 :-)

即使我没有遇到崩溃,设备似乎也无法从蓝牙麦克风路由音频。 - Learn OpenGL ES
我有同样的问题,麦克风没有路由,有解决方法吗? - Shofiqul Alam
3个回答

4

正如 @xsveda 所写,如果没有连接耳机,您将在 Lollipop 上收到 NPE。

您可以先尝试检查蓝牙耳机连接:

mAudioManager.isWiredHeadsetOn()

根据文档描述,isWiredHeadsetOn() (文档链接)已经被弃用,并且只用于检查耳机是否连接。

之后,您可以使用startBluetoothSco()进行连接。对我来说,我使用了以下代码:

用于启动的代码如下:

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

这是停止的命令:

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

希望这有所帮助。

0

目前对我来说似乎有效的方法是忽略 NullPointerException

private void tryConnectAudio() {
    verifyBluetoothSupport();
    try {
        mAudioManager.startBluetoothSco();
    } catch (NullPointerException e) {
        // TODO This is a temp workaround for Lollipop
        Log.d(TAG, "startBluetoothSco() failed. no bluetooth device connected.");
    }
}

@Julian Claudino,这对我有用,并且可以通过蓝牙麦克风进行路由,请确保蓝牙设备被识别并连接:

private void verifyBluetoothSupport() {
    getActivity().registerReceiver(new BroadcastReceiver() {
        @Override
        public void onReceive(Context context, Intent intent) {
            int state = intent.getIntExtra(AudioManager.EXTRA_SCO_AUDIO_STATE, -1);
            Log.d(TAG, "Audio SCO state: " + state);
            if (AudioManager.SCO_AUDIO_STATE_CONNECTED == state) {
                Toast.makeText(getActivity(), "Bluetooth Connected", Toast.LENGTH_SHORT).show();
                getActivity().unregisterReceiver(this);
            }
        }
    }, new IntentFilter(AudioManager.ACTION_SCO_AUDIO_STATE_UPDATED));
}

希望这能帮助到某个人!

0

经过几天的绝望,我找到了一个简单的解决方法:

startBluetoothSco() 只有在没有蓝牙设备连接时才会抛出 NPE,因此可以捕获并忽略它,因为“没有人可以交谈”。如果例如连接了 BT 耳机,则 SCO 将成功启动并且播放正常!


这似乎是比将目标SDK设置为17更好的解决方法,但是经过进一步调查,我发现两种解决方法中都无法通过蓝牙麦克风路由音频,而是通过手机麦克风输出。如果您的手机和蓝牙设备靠得很近,可能很容易忽略这一点。 - Julian Claudino

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接