AudioManager.startBluetoothSco() аварийно завершает работу на Android Lollipop

При вызове AudioManager.startBluetoothSCO() во время при таргетинге на уровень API 18 или выше в манифесте в документации указано, что устанавливается необработанное аудиосоединение, а при таргетинге на API 17 или ниже используется виртуальный голосовой вызов.

До уровня API 20 (предварительная версия Android L) это работало нормально, ориентируясь на любой API. Однако при использовании последней сборки Android Lollipop LPX13D и нацеливании на уровень API 18 или выше я получаю сбой со следующей трассировкой стека:

E/AndroidRuntime(31705): причина: java.lang.NullPointerException: попытка вызвать виртуальный метод java.lang.String android.bluetooth.BluetoothDevice.getAddress() для нулевой ссылки на объект E/AndroidRuntime(31705): at android.os.Parcel.readException(Parcel.java:1546) E/AndroidRuntime(31705): в android.os.Parcel.readException(Parcel.java:1493) E/AndroidRuntime(31705): в android.media.IAudioService$ Stub$Proxy.startBluetoothSco(IAudioService.java:1587) E/AndroidRuntime(31705): в android.media.AudioManager.startBluetoothSco(AudioManager.java:1468)

Если я нацеливаюсь на уровень API 17 или ниже на Android Lollipop, все работает, как и ожидалось.

Я считаю, что источник проблемы заключается в изменении аудиокода Android, которое произошло на уровне API 21 в строке 2392 файла AudioService.java:

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, чтобы увеличить вероятность того, что это будет просмотрено :-)


person Julian Claudino    schedule 29.10.2014    source источник
comment
Даже если я не получаю сбой, устройство, похоже, не направляет звук с микрофона Bluetooth.   -  person Learn OpenGL ES    schedule 26.02.2015
comment
у меня такая же проблема,микрофон не работает,как решить?   -  person Shofiqul Alam    schedule 18.04.2015


Ответы (3)


Как писал @xsveda, если гарнитура не подключена, вы получите NPE на Lollipop.

Вы можете сначала попробовать проверить подключение bluetooth-гарнитуры:

mAudioManager.isWiredHeadsetOn()

Как описано в документе, isWiredHeadsetOn() (ссылка на документ) устарела и используется только для проверки, подключена ли гарнитура или нет.

И после этого вы можете использовать startBluetoothSco() подключение. Что касается меня, я использовал этот код:

Этот для начала:

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

Это для остановки:

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

Надеюсь, поможет.

person busylee    schedule 12.12.2014

После нескольких дней отчаяния я нашел простой обходной путь:

startBluetoothSco() выдает NPE только в том случае, если нет подключенного Bluetooth-устройства, поэтому его можно поймать и проигнорировать, поскольку «не с кем поговорить». Если, например, подключена BT-гарнитура, SCO запускается успешно и воспроизведение работает!

person xsveda    schedule 13.11.2014
comment
Это кажется лучшим обходным путем, чем установка целевого SDK на 17, однако при дальнейшем расследовании я заметил, что с обоими обходными путями звук не направляется через микрофон Bluetooth, а вместо этого выходит через микрофон телефона. Это легко пропустить, если ваш телефон и устройство Bluetooth находятся рядом друг с другом. - person Julian Claudino; 13.11.2014

На данный момент то, что, похоже, работает для меня, это игнорирование 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, это работает для меня и маршрутизации через микрофон Bluetooth, убедитесь, что устройство Bluetooth распознано и подключено:

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));
}

Надеюсь, это поможет кому-то!

person Danpe    schedule 14.11.2014