TextToSpeech по bluetooth SCO

Я пытаюсь направить свой вывод TTS на внешнее устройство Bluetooth SCO (отлично работает с локальным динамиком и микрофоном), но он не воспроизводится.

Я устанавливаю маршрут для AudioManager следующим образом -

AudioManager audioManager = (AudioManager) getSystemService(Context.AUDIO_SERVICE);
audioManager.startBluetoothSco();
audioManager.setBluetoothScoOn(true);

Высказывания разыгрываются таким методом -

private void say(String text, String utteranceId) {
    Log.d(TAG, "Saying: " + text);
    final Bundle ttsParams = new Bundle();
    ttsParams.putInt(TextToSpeech.Engine.KEY_PARAM_STREAM, AudioManager.STREAM_VOICE_CALL);
    mTextToSpeech.speak(text, TextToSpeech.QUEUE_FLUSH, ttsParams,  utteranceId);
}

Нет звука из динамика. Если я не установил для BluetoothScoOn значение true, он отлично работает со встроенным динамиком.


person vsky    schedule 28.04.2018    source источник


Ответы (1)


Используйте этот класс:

public abstract class BluetoothHeadsetUtils {
    private AudioManager mAudioManager;
    private BluetoothAdapter mBluetoothAdapter;
    private BluetoothHeadset mBluetoothHeadset;
    private BluetoothDevice mConnectedHeadset;
    private Context mContext;
    private CountDownTimer mCountDown;
    private BroadcastReceiver mHeadsetBroadcastReceiver;
    private BluetoothProfile.ServiceListener mHeadsetProfileListener;
    private boolean mIsCountDownOn;
    private boolean mIsOnHeadsetSco;
    private boolean mIsStarted;
    private boolean receiverRegistered;

    public BluetoothHeadsetUtils(final Context context) {

        mHeadsetBroadcastReceiver = new BroadcastReceiver() {
            public void onReceive(final Context context, final Intent intent) {
                final String action = intent.getAction();
                if (action.equals(BluetoothHeadset.ACTION_CONNECTION_STATE_CHANGED)) {
                    final int intExtra = intent.getIntExtra(BluetoothHeadset.EXTRA_STATE, BluetoothHeadset
                            .STATE_DISCONNECTED);
                    if (intExtra == BluetoothHeadset.STATE_CONNECTED) {
                        BluetoothHeadsetUtils.this.mConnectedHeadset = intent.getParcelableExtra(BluetoothDevice
                                .EXTRA_DEVICE);
                        BluetoothHeadsetUtils.this.mIsCountDownOn = true;
                        BluetoothHeadsetUtils.this.mCountDown.start();
                        BluetoothHeadsetUtils.this.onHeadsetConnected();
                    } else if (intExtra == BluetoothHeadset.STATE_DISCONNECTED) {
                        if (BluetoothHeadsetUtils.this.mIsCountDownOn) {
                            BluetoothHeadsetUtils.this.mIsCountDownOn = false;
                            BluetoothHeadsetUtils.this.mCountDown.cancel();
                        }
                        BluetoothHeadsetUtils.this.mConnectedHeadset = null;
                        BluetoothHeadsetUtils.this.onHeadsetDisconnected();
                    }
                } else {
                    final int intExtra2 = intent.getIntExtra(BluetoothHeadset.EXTRA_STATE, BluetoothHeadset
                            .STATE_AUDIO_DISCONNECTED);
                    if (intExtra2 == BluetoothHeadset.STATE_AUDIO_CONNECTED) {
                        BluetoothHeadsetUtils.this.mIsOnHeadsetSco = true;
                        if (BluetoothHeadsetUtils.this.mIsCountDownOn) {
                            BluetoothHeadsetUtils.this.mIsCountDownOn = false;
                            BluetoothHeadsetUtils.this.mCountDown.cancel();
                        }
                        BluetoothHeadsetUtils.this.onScoAudioConnected();
                        return;
                    }
                    if (intExtra2 == BluetoothHeadset.STATE_AUDIO_DISCONNECTED) {
                        BluetoothHeadsetUtils.this.mIsOnHeadsetSco = false;
                        BluetoothHeadsetUtils.this.mBluetoothHeadset.stopVoiceRecognition(BluetoothHeadsetUtils.this
                                .mConnectedHeadset);
                        BluetoothHeadsetUtils.this.onScoAudioDisconnected();
                    }
                }
            }
        };
        mHeadsetProfileListener = new BluetoothProfile.ServiceListener() {
            public void onServiceConnected(final int n, final BluetoothProfile bluetoothProfile) {
                BluetoothHeadsetUtils.this.mBluetoothHeadset = (BluetoothHeadset) bluetoothProfile;
                final List<BluetoothDevice> connectedDevices = BluetoothHeadsetUtils.this.mBluetoothHeadset
                        .getConnectedDevices();
                if (connectedDevices.size() > 0) {
                    BluetoothHeadsetUtils.this.mConnectedHeadset = connectedDevices.get(0);
                    BluetoothHeadsetUtils.this.onHeadsetConnected();
                    BluetoothHeadsetUtils.this.mIsCountDownOn = true;
                    BluetoothHeadsetUtils.this.mCountDown.start();
                } else {
                    BluetoothHeadsetUtils.this.noHeadsetConnected();
                }
                IntentFilter filter = new IntentFilter();
                filter.addAction(BluetoothHeadset.ACTION_CONNECTION_STATE_CHANGED);
                filter.addAction(BluetoothHeadset.ACTION_AUDIO_STATE_CHANGED);
                BluetoothHeadsetUtils.this.mContext.registerReceiver(BluetoothHeadsetUtils.this
                        .mHeadsetBroadcastReceiver, filter);
                receiverRegistered = true;
            }

            public void onServiceDisconnected(final int n) {
                BluetoothHeadsetUtils.this.stop();
            }
        };

        mCountDown = new CountDownTimer(10000L, 1000L) {
            public void onFinish() {
                BluetoothHeadsetUtils.this.mIsCountDownOn = false;
                onTimeout();
            }

            public void onTick(final long n) {
                BluetoothHeadsetUtils.this.mBluetoothHeadset.startVoiceRecognition(BluetoothHeadsetUtils.this
                        .mConnectedHeadset);
            }
        };
        mContext = context;
        mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
        mAudioManager = (AudioManager) this.mContext.getSystemService(Context.AUDIO_SERVICE);
    }

    private boolean startBluetooth() {
        return mBluetoothAdapter != null && mBluetoothAdapter.isEnabled() && mAudioManager
                .isBluetoothScoAvailableOffCall() &&
                mBluetoothAdapter.getProfileProxy(mContext, mHeadsetProfileListener, BluetoothProfile.HEADSET);
    }

    public boolean isOnHeadsetSco() {
        return mIsOnHeadsetSco;
    }

    protected void onTimeout() {
    }

    protected void noHeadsetConnected() {
    }

    protected void onHeadsetConnected() {
    }

    protected void onHeadsetDisconnected() {
    }

    protected void onScoAudioConnected() {
    }

    protected void onScoAudioDisconnected() {
    }

    @UiThread
    public boolean start() {
        if (!mIsStarted) {
            mIsStarted = true;
            mIsStarted = startBluetooth();
        }
        return mIsStarted;
    }

    @UiThread
    public void stop() {
        if (mIsStarted) {
            mIsStarted = false;
            stopBluetooth();
        }
    }

    private void stopBluetooth() {
        if (mIsCountDownOn) {
            mIsCountDownOn = false;
            mCountDown.cancel();
        }
        try {
            if (receiverRegistered) {
                mContext.unregisterReceiver(mHeadsetBroadcastReceiver);
            }
        } catch (IllegalArgumentException ignored) {
        } finally {
            receiverRegistered = false;
        }
        if (mBluetoothHeadset != null) {
            mBluetoothHeadset.stopVoiceRecognition(mConnectedHeadset);
            mBluetoothAdapter.closeProfileProxy(BluetoothProfile.HEADSET, mBluetoothHeadset);
            mBluetoothHeadset = null;
        }
        mIsOnHeadsetSco = false;
    }
}

Используйте свой метод say в обратном вызове onScoAudioConnected.

person greywolf82    schedule 28.04.2018
comment
onScoAudioConnected никогда не вызывается. Функция D / BluetoothHeadset: startVoiceRecognition () постоянно вызывается в журнале. - person vsky; 28.04.2018
comment
Обратный отсчет действительно есть. 10 тиков. - person greywolf82; 28.04.2018
comment
Даже после 10 тиков .. onScoAudioConnected никогда не вызывается - person vsky; 28.04.2018
comment
В этом случае вызывается onTimeout, с этим устройством вам не повезло - person greywolf82; 28.04.2018
comment
возможно, он использует другой API, я использую этот код каждый день, и он работает должным образом - person greywolf82; 28.04.2018