Text-To-Speech over bluetooth

给你一囗甜甜゛ 提交于 2019-12-24 15:18:58

问题


I'm designing an application with Text-To-Speech and it works. Now I want to use the bluetooth headset (not AD2P) to receive audio. Reading Android documentation about startBluetoothScoOn I see:

Note that the phone application always has the priority on the usage of the SCO connection for telephony. If this method is called while the phone is in call it will be ignored. Similarly, if a call is received or sent while an application is using the SCO connection, the connection will be lost for the application and NOT returned automatically when the call ends.

Now my questions are:

  1. Do I need to listen for phone state to re-call startBluetoothScoOn when a call ends? If yes, how? I didn't find any example;
  2. Do I need to listen for headset connected/disconnected? If yes, how?

I suppose that when the calls end or my headset is turned off, the system delivers a SCO_AUDIO_STATE_DISCONNECTED, right?

Edit: I post code I'm using:

public class BluetoothHeadSetManager implements
    BluetoothProfile.ServiceListener {
BluetoothManager manager;
BluetoothHeadset bluetoothHeadset;
Context context;
HeadSetBroadcastReceiver recv;

public BluetoothHeadSetManager(Context cont, BluetoothManager manager) {
    this.manager = manager;
    this.context = cont;
    recv = null;
}

@Override
public void onServiceConnected(int profile, BluetoothProfile proxy) {
    // mBluetoothHeadset is just a headset profile,
    // it does not represent a headset device.
    bluetoothHeadset = (BluetoothHeadset) proxy;

    List<BluetoothDevice> devices = bluetoothHeadset.getConnectedDevices();
    if (devices.size() > 0)
        manager.onHeadSetConnected();

    // During the active life time of the app, a user may turn on and off
    // the headset.
    // So register for broadcast of connection states.
    if (recv == null) {
        recv = new HeadSetBroadcastReceiver();
        context.registerReceiver(recv, new IntentFilter(
                BluetoothDevice.ACTION_ACL_CONNECTED));
        context.registerReceiver(recv, new IntentFilter(
                BluetoothDevice.ACTION_ACL_DISCONNECTED));
    }
}

public void close() {
    if (recv != null)
        context.unregisterReceiver(recv);
    if (bluetoothHeadset != null)
        BluetoothAdapter.getDefaultAdapter().closeProfileProxy(
                BluetoothProfile.HEADSET, bluetoothHeadset);
}

@Override
public void onServiceDisconnected(int arg0) {
    Logger.getInstance().writeLog("onServiceDisconnected called");
    if (recv != null)
        context.unregisterReceiver(recv);
    manager.onHeadSetDisconnected();
}

private class HeadSetBroadcastReceiver extends BroadcastReceiver {

    @Override
    public void onReceive(Context context, Intent intent) {
        String action = intent.getAction();
        BluetoothDevice mConnectedHeadset;

        if (action.equals(BluetoothDevice.ACTION_ACL_CONNECTED)) {
            mConnectedHeadset = intent
                    .getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
            BluetoothClass bluetoothClass = mConnectedHeadset
                    .getBluetoothClass();
            if (bluetoothClass != null) {
                // Check if device is a headset. Besides the 2 below, are
                // there other
                // device classes also qualified as headset?
                int deviceClass = bluetoothClass.getDeviceClass();
                if (deviceClass == BluetoothClass.Device.AUDIO_VIDEO_HANDSFREE
                        || deviceClass == BluetoothClass.Device.AUDIO_VIDEO_WEARABLE_HEADSET) {
                    // override this if you want to do other thing when the
                    // device is connected.
                    manager.onHeadSetConnected();
                }
            }
        } else if (action.equals(BluetoothDevice.ACTION_ACL_DISCONNECTED)) {
            manager.onHeadSetDisconnected();
        }
    }
}

Sco receiver:

public class BluetoothScoReceiver extends BroadcastReceiver {
BluetoothManager manager;

public BluetoothScoReceiver(BluetoothManager manager) {
    this.manager = manager;
}

@Override
public void onReceive(Context arg0, Intent intent) {
    Bundle extras = intent.getExtras();
    if (extras == null)
        return;
    int state = extras.getInt(AudioManager.EXTRA_SCO_AUDIO_STATE);
    if (state == AudioManager.SCO_AUDIO_STATE_CONNECTED)
        manager.onScoConnected();
    else if (state == AudioManager.SCO_AUDIO_STATE_DISCONNECTED)
        manager.onScoDisconnected();
}

Main:

@Override
public void onScoConnected() {
    this.headsetReady = true;
    requestState = CONNECTED;
}

@Override
public void onScoDisconnected() {
    this.headsetReady = false;
    if (requestState == TRY_CONNECTION && headsetConnected)
        this.onHeadSetConnected(); //try again
}

@Override
public void onHeadSetConnected() {
    headsetConnected = true;
    if (requestState == TRY_CONNECTION) {
        requestState = TRY_CONNECTION;
        audioMng.setMode(AudioManager.MODE_NORMAL);
        audioMng.stopBluetoothSco();
        audioMng.setMode(AudioManager.MODE_IN_CALL);
        audioMng.startBluetoothSco();
    } else {
        requestState = TRY_CONNECTION;
        audioMng.setMode(AudioManager.MODE_IN_CALL);
        audioMng.startBluetoothSco();
    }
}

@Override
public void onHeadSetDisconnected() {
    audioMng.setMode(AudioManager.MODE_NORMAL);
    if (requestState != NOT_CONNECTED_IDLE) {
        audioMng.stopBluetoothSco();
        audioMng.setBluetoothScoOn(false);
        requestState = NOT_CONNECTED_IDLE;
    }
    headsetConnected = false;
}

@SuppressLint("InlinedApi")
@SuppressWarnings("deprecation")
@Override
public void startBluetooth() {
    Intent currentScoState;
    if (audioMng.isBluetoothScoAvailableOffCall()) {
        BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
        if (adapter == null)
            return;
        blueInit = adapter.getProfileProxy(this, headsetMng,
                BluetoothProfile.HEADSET);
        if (blueInit) {
            scoListner = new BluetoothScoReceiver(this);
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH)
                currentScoState = this
                        .registerReceiver(
                                scoListner,
                                new IntentFilter(
                                        AudioManager.ACTION_SCO_AUDIO_STATE_UPDATED));
            else
                currentScoState = this
                        .registerReceiver(
                                scoListner,
                                new IntentFilter(
                                        AudioManager.ACTION_SCO_AUDIO_STATE_CHANGED));
            Bundle extras = currentScoState.getExtras();
            if (extras == null)
                return;
            if (extras
                    .getInt(AudioManager.EXTRA_SCO_AUDIO_STATE) == AudioManager.SCO_AUDIO_STATE_CONNECTED) {
                this.headsetReady = true;
                requestState = CONNECTED;
            } else {
                this.headsetReady = false;
                requestState = NOT_CONNECTED_IDLE;
            }
        }
    }
}

@Override
public void stopBluetooth() {
    this.onHeadSetDisconnected();
    if (blueInit) {
        headsetMng.close();
        this.unregisterReceiver(scoListner);
    }
}

回答1:


  1. You do not necessarily have to listen for phone states, when the call ends (CALL_STATE_IDLE) you will receive a SCO_AUDIO_STATE_DISCONNECTED.
  2. If you do not listen for headset connected how do you know when to connect the audio? For an bluetooth headset implementation you can look at Using the Android RecognizerIntent with a bluetooth headset


来源:https://stackoverflow.com/questions/18340102/text-to-speech-over-bluetooth

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!