1

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

1 回答 1

0
  1. 你不一定要监听电话状态,当通话结束时(CALL_STATE_IDLE)你会收到一个SCO_AUDIO_STATE_DISCONNECTED。
  2. 如果您不听耳机连接,您如何知道何时连接音频?对于蓝牙耳机实现,您可以查看将 Android RecognizerIntent 与蓝牙耳机一起使用
于 2013-08-20T18:28:49.733 回答