Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit cf27729f authored by Eric Laurent's avatar Eric Laurent
Browse files

AudioService: Allow late Bluetooth profile service connection

If a Bluetooth device is connected by the Bluetooth stack
before the corresponding profile service proxy has been initialized via
the onServiceConnected callback, ignore the connecion request. When the
service connection is received later, query the Bluetooth adapter for
active devices on this profile and connected it.

Also move resetting forced usage for media upon LE devices connection from
AudioDeviceInventory.setBluetoothActiveDevice() to makeLeAudioDeviceAvailable()
for consistency with A2DP.

Bug: 295985930
Test: quickly disable/enable Bluetooth and verify music playback

Change-Id: If598db52061417c8973bed506a689c92825b798a
parent 8f752e79
Loading
Loading
Loading
Loading
+9 −1
Original line number Original line Diff line number Diff line
@@ -1765,6 +1765,14 @@ public class AudioDeviceBroker {
                    synchronized (mSetModeLock) {
                    synchronized (mSetModeLock) {
                        synchronized (mDeviceStateLock) {
                        synchronized (mDeviceStateLock) {
                            final BtDeviceInfo btInfo = (BtDeviceInfo) msg.obj;
                            final BtDeviceInfo btInfo = (BtDeviceInfo) msg.obj;
                            if (btInfo.mState == BluetoothProfile.STATE_CONNECTED
                                    && !mBtHelper.isProfilePoxyConnected(btInfo.mProfile)) {
                                AudioService.sDeviceLogger.enqueue((new EventLogger.StringEvent(
                                        "msg: MSG_L_SET_BT_ACTIVE_DEVICE "
                                            + "received with null profile proxy: "
                                            + btInfo)).printLog(TAG));
                                return;
                            }
                            @AudioSystem.AudioFormatNativeEnumForBtCodec final int codec =
                            @AudioSystem.AudioFormatNativeEnumForBtCodec final int codec =
                                    mBtHelper.getA2dpCodecWithFallbackToSBC(
                                    mBtHelper.getA2dpCodecWithFallbackToSBC(
                                            btInfo.mDevice, "MSG_L_SET_BT_ACTIVE_DEVICE");
                                            btInfo.mDevice, "MSG_L_SET_BT_ACTIVE_DEVICE");
@@ -1909,7 +1917,7 @@ public class AudioDeviceBroker {
                    final BtDeviceInfo btInfo = (BtDeviceInfo) msg.obj;
                    final BtDeviceInfo btInfo = (BtDeviceInfo) msg.obj;
                    if (btInfo.mDevice == null) break;
                    if (btInfo.mDevice == null) break;
                    AudioService.sDeviceLogger.enqueue((new EventLogger.StringEvent(
                    AudioService.sDeviceLogger.enqueue((new EventLogger.StringEvent(
                            "msg: onBluetoothActiveDeviceChange " + btInfo)).printLog(TAG));
                            "msg: MSG_L_BT_ACTIVE_DEVICE_CHANGE_EXT " + btInfo)).printLog(TAG));
                    synchronized (mDeviceStateLock) {
                    synchronized (mDeviceStateLock) {
                        mDeviceInventory.setBluetoothActiveDevice(btInfo);
                        mDeviceInventory.setBluetoothActiveDevice(btInfo);
                    }
                    }
+3 −5
Original line number Original line Diff line number Diff line
@@ -1628,11 +1628,6 @@ public class AudioDeviceInventory {
                Log.i(TAG, "setBluetoothActiveDevice " + info.toString() + " delay(ms): " + delay);
                Log.i(TAG, "setBluetoothActiveDevice " + info.toString() + " delay(ms): " + delay);
            }
            }
            mDeviceBroker.postBluetoothActiveDevice(info, delay);
            mDeviceBroker.postBluetoothActiveDevice(info, delay);
            if (info.mProfile == BluetoothProfile.HEARING_AID
                    && info.mState == BluetoothProfile.STATE_CONNECTED) {
                mDeviceBroker.setForceUse_Async(AudioSystem.FOR_MEDIA, AudioSystem.FORCE_NONE,
                                "HEARING_AID set to CONNECTED");
            }
        }
        }
        return delay;
        return delay;
    }
    }
@@ -2013,6 +2008,9 @@ public class AudioDeviceInventory {
        final int hearingAidVolIndex = mDeviceBroker.getVssVolumeForDevice(streamType,
        final int hearingAidVolIndex = mDeviceBroker.getVssVolumeForDevice(streamType,
                AudioSystem.DEVICE_OUT_HEARING_AID);
                AudioSystem.DEVICE_OUT_HEARING_AID);
        mDeviceBroker.postSetHearingAidVolumeIndex(hearingAidVolIndex, streamType);
        mDeviceBroker.postSetHearingAidVolumeIndex(hearingAidVolIndex, streamType);

        mDeviceBroker.setBluetoothA2dpOnInt(true, false /*fromA2dp*/, eventSource);

        AudioDeviceAttributes ada = new AudioDeviceAttributes(
        AudioDeviceAttributes ada = new AudioDeviceAttributes(
                AudioSystem.DEVICE_OUT_HEARING_AID, address, name);
                AudioSystem.DEVICE_OUT_HEARING_AID, address, name);
        mAudioSystem.setDeviceConnectionState(ada,
        mAudioSystem.setDeviceConnectionState(ada,
+64 −23
Original line number Original line Diff line number Diff line
@@ -43,7 +43,6 @@ import com.android.internal.annotations.GuardedBy;
import com.android.server.utils.EventLogger;
import com.android.server.utils.EventLogger;


import java.io.PrintWriter;
import java.io.PrintWriter;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashMap;
import java.util.List;
import java.util.List;
import java.util.Map;
import java.util.Map;
@@ -288,6 +287,13 @@ public class BtHelper {
        if (action.equals(BluetoothHeadset.ACTION_ACTIVE_DEVICE_CHANGED)) {
        if (action.equals(BluetoothHeadset.ACTION_ACTIVE_DEVICE_CHANGED)) {
            BluetoothDevice btDevice = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE,
            BluetoothDevice btDevice = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE,
                    android.bluetooth.BluetoothDevice.class);
                    android.bluetooth.BluetoothDevice.class);
            if (btDevice != null && !isProfilePoxyConnected(BluetoothProfile.HEADSET)) {
                AudioService.sDeviceLogger.enqueue((new EventLogger.StringEvent(
                        "onReceiveBtEvent ACTION_ACTIVE_DEVICE_CHANGED "
                                + "received with null profile proxy for device: "
                                + btDevice)).printLog(TAG));
                return;
            }
            onSetBtScoActiveDevice(btDevice);
            onSetBtScoActiveDevice(btDevice);
        } else if (action.equals(BluetoothHeadset.ACTION_AUDIO_STATE_CHANGED)) {
        } else if (action.equals(BluetoothHeadset.ACTION_AUDIO_STATE_CHANGED)) {
            int btState = intent.getIntExtra(BluetoothProfile.EXTRA_STATE, -1);
            int btState = intent.getIntExtra(BluetoothProfile.EXTRA_STATE, -1);
@@ -465,7 +471,8 @@ public class BtHelper {
    @GuardedBy("AudioDeviceBroker.this.mDeviceStateLock")
    @GuardedBy("AudioDeviceBroker.this.mDeviceStateLock")
    /*package*/ synchronized void onBtProfileDisconnected(int profile) {
    /*package*/ synchronized void onBtProfileDisconnected(int profile) {
        AudioService.sDeviceLogger.enqueue(new EventLogger.StringEvent(
        AudioService.sDeviceLogger.enqueue(new EventLogger.StringEvent(
                "BT profile " + BluetoothProfile.getProfileName(profile) + " disconnected"));
                "BT profile " + BluetoothProfile.getProfileName(profile)
                + " disconnected").printLog(TAG));
        switch (profile) {
        switch (profile) {
            case BluetoothProfile.HEADSET:
            case BluetoothProfile.HEADSET:
                mBluetoothHeadset = null;
                mBluetoothHeadset = null;
@@ -496,7 +503,11 @@ public class BtHelper {
    /*package*/ synchronized void onBtProfileConnected(int profile, BluetoothProfile proxy) {
    /*package*/ synchronized void onBtProfileConnected(int profile, BluetoothProfile proxy) {
        AudioService.sDeviceLogger.enqueue(new EventLogger.StringEvent(
        AudioService.sDeviceLogger.enqueue(new EventLogger.StringEvent(
                "BT profile " + BluetoothProfile.getProfileName(profile) + " connected to proxy "
                "BT profile " + BluetoothProfile.getProfileName(profile) + " connected to proxy "
                + proxy));
                + proxy).printLog(TAG));
        if (proxy == null) {
            Log.e(TAG, "onBtProfileConnected: null proxy for profile: " + profile);
            return;
        }
        switch (profile) {
        switch (profile) {
            case BluetoothProfile.HEADSET:
            case BluetoothProfile.HEADSET:
                onHeadsetProfileConnected((BluetoothHeadset) proxy);
                onHeadsetProfileConnected((BluetoothHeadset) proxy);
@@ -522,36 +533,64 @@ public class BtHelper {
        }
        }


        // this part is only for A2DP, LE Audio unicast and Hearing aid
        // this part is only for A2DP, LE Audio unicast and Hearing aid
        final List<BluetoothDevice> deviceList = proxy.getConnectedDevices();
        BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
        if (deviceList.isEmpty()) {
        if (adapter == null) {
            Log.e(TAG, "onBtProfileConnected: Null BluetoothAdapter when connecting profile: "
                    + BluetoothProfile.getProfileName(profile));
            return;
            return;
        }
        }
        final BluetoothDevice btDevice = deviceList.get(0);
        List<BluetoothDevice> activeDevices = adapter.getActiveDevices(profile);
        if (proxy.getConnectionState(btDevice) == BluetoothProfile.STATE_CONNECTED) {
        if (activeDevices.isEmpty() || activeDevices.get(0) == null) {
            mDeviceBroker.queueOnBluetoothActiveDeviceChanged(
            return;
                    new AudioDeviceBroker.BtDeviceChangedData(btDevice, null,
        }
                        new BluetoothProfileConnectionInfo(profile),
        AudioDeviceBroker.BtDeviceChangedData data = new AudioDeviceBroker.BtDeviceChangedData(
                        "mBluetoothProfileServiceListener"));
                activeDevices.get(0), null, new BluetoothProfileConnectionInfo(profile),
        } else {
                "mBluetoothProfileServiceListener");
            mDeviceBroker.queueOnBluetoothActiveDeviceChanged(
        AudioDeviceBroker.BtDeviceInfo info =
                    new AudioDeviceBroker.BtDeviceChangedData(null, btDevice,
                mDeviceBroker.createBtDeviceInfo(data, activeDevices.get(0),
                        new BluetoothProfileConnectionInfo(profile),
                        BluetoothProfile.STATE_CONNECTED);
                        "mBluetoothProfileServiceListener"));
        mDeviceBroker.postBluetoothActiveDevice(info, 0 /* delay */);
    }

    // @GuardedBy("mDeviceBroker.mSetModeLock")
    @GuardedBy("AudioDeviceBroker.this.mDeviceStateLock")
    /*package*/ synchronized boolean isProfilePoxyConnected(int profile) {
        switch (profile) {
            case BluetoothProfile.HEADSET:
                return mBluetoothHeadset != null;
            case BluetoothProfile.A2DP:
                return mA2dp != null;
            case BluetoothProfile.HEARING_AID:
                return mHearingAid != null;
            case BluetoothProfile.LE_AUDIO:
                return mLeAudio != null;
            case BluetoothProfile.A2DP_SINK:
            case BluetoothProfile.LE_AUDIO_BROADCAST:
            default:
                // return true for profiles that are not managed by the BtHelper because
                // the fact that the profile proxy is not connected does not affect
                // the device connection handling.
                return true;
        }
        }
    }
    }


    // @GuardedBy("mDeviceBroker.mSetModeLock")
    // @GuardedBy("mDeviceBroker.mSetModeLock")
    @GuardedBy("AudioDeviceBroker.this.mDeviceStateLock")
    @GuardedBy("AudioDeviceBroker.this.mDeviceStateLock")
    private void onHeadsetProfileConnected(BluetoothHeadset headset) {
    private void onHeadsetProfileConnected(@NonNull BluetoothHeadset headset) {
        // Discard timeout message
        // Discard timeout message
        mDeviceBroker.handleCancelFailureToConnectToBtHeadsetService();
        mDeviceBroker.handleCancelFailureToConnectToBtHeadsetService();
        mBluetoothHeadset = headset;
        mBluetoothHeadset = headset;
        BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
        BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
        List<BluetoothDevice> activeDevices = Collections.emptyList();
        if (adapter != null) {
        if (adapter != null) {
            activeDevices = adapter.getActiveDevices(BluetoothProfile.HEADSET);
            List<BluetoothDevice> activeDevices =
                    adapter.getActiveDevices(BluetoothProfile.HEADSET);
            if (activeDevices.size() > 0 && activeDevices.get(0) != null) {
                onSetBtScoActiveDevice(activeDevices.get(0));
            }
        } else {
            Log.e(TAG, "onHeadsetProfileConnected: Null BluetoothAdapter");
        }
        }
        onSetBtScoActiveDevice((activeDevices.size() > 0) ? activeDevices.get(0) : null);

        // Refresh SCO audio state
        // Refresh SCO audio state
        checkScoAudioState();
        checkScoAudioState();
        if (mScoAudioState != SCO_STATE_ACTIVATE_REQ
        if (mScoAudioState != SCO_STATE_ACTIVATE_REQ
@@ -559,7 +598,7 @@ public class BtHelper {
            return;
            return;
        }
        }
        boolean status = false;
        boolean status = false;
        if (mBluetoothHeadset != null && mBluetoothHeadsetDevice != null) {
        if (mBluetoothHeadsetDevice != null) {
            switch (mScoAudioState) {
            switch (mScoAudioState) {
                case SCO_STATE_ACTIVATE_REQ:
                case SCO_STATE_ACTIVATE_REQ:
                    status = connectBluetoothScoAudioHelper(
                    status = connectBluetoothScoAudioHelper(
@@ -715,7 +754,8 @@ public class BtHelper {
                        case BluetoothProfile.LE_AUDIO_BROADCAST:
                        case BluetoothProfile.LE_AUDIO_BROADCAST:
                            AudioService.sDeviceLogger.enqueue(new EventLogger.StringEvent(
                            AudioService.sDeviceLogger.enqueue(new EventLogger.StringEvent(
                                    "BT profile service: connecting "
                                    "BT profile service: connecting "
                                    + BluetoothProfile.getProfileName(profile) + " profile"));
                                    + BluetoothProfile.getProfileName(profile)
                                    + " profile").printLog(TAG));
                            mDeviceBroker.postBtProfileConnected(profile, proxy);
                            mDeviceBroker.postBtProfileConnected(profile, proxy);
                            break;
                            break;


@@ -734,7 +774,8 @@ public class BtHelper {
                        case BluetoothProfile.LE_AUDIO_BROADCAST:
                        case BluetoothProfile.LE_AUDIO_BROADCAST:
                            AudioService.sDeviceLogger.enqueue(new EventLogger.StringEvent(
                            AudioService.sDeviceLogger.enqueue(new EventLogger.StringEvent(
                                    "BT profile service: disconnecting "
                                    "BT profile service: disconnecting "
                                        + BluetoothProfile.getProfileName(profile) + " profile"));
                                        + BluetoothProfile.getProfileName(profile)
                                        + " profile").printLog(TAG));
                            mDeviceBroker.postBtProfileDisconnected(profile);
                            mDeviceBroker.postBtProfileDisconnected(profile);
                            break;
                            break;