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

Commit f8b905cd authored by Eric Laurent's avatar Eric Laurent Committed by Android (Google) Code Review
Browse files

Merge "BtHelper: clean HFP device connection" into main

parents cea78fc7 f8e87f6d
Loading
Loading
Loading
Loading
+4 −1
Original line number Diff line number Diff line
@@ -1871,7 +1871,10 @@ public class AudioDeviceBroker {
                            synchronized (mBluetoothAudioStateLock) {
                                reapplyAudioHalBluetoothState();
                            }
                            mBtHelper.onAudioServerDiedRestoreA2dp();
                            final int forceForMedia = getBluetoothA2dpEnabled()
                                    ? AudioSystem.FORCE_NONE : AudioSystem.FORCE_NO_BT_A2DP;
                            setForceUse_Async(
                                    AudioSystem.FOR_MEDIA, forceForMedia, "MSG_RESTORE_DEVICES");
                            updateCommunicationRoute("MSG_RESTORE_DEVICES");
                        }
                    }
+9 −0
Original line number Diff line number Diff line
@@ -1757,6 +1757,15 @@ public class AudioDeviceInventory {
            if (AudioService.DEBUG_DEVICES) {
                Slog.i(TAG, "deviceInfo:" + di + " is(already)Connected:" + isConnected);
            }
            // Do not report an error in case of redundant connect or disconnect request
            // as this can cause a state mismatch between BtHelper and AudioDeviceInventory
            if (connect == isConnected) {
                Log.i(TAG, "handleDeviceConnection() deviceInfo=" + di + " is already "
                        + (connect ? "" : "dis") + "connected");
                mmi.set(MediaMetrics.Property.STATE, connect
                        ? MediaMetrics.Value.CONNECT : MediaMetrics.Value.DISCONNECT).record();
                return true;
            }
            if (connect && !isConnected) {
                final int res;
                if (isForTesting) {
+75 −44
Original line number Diff line number Diff line
@@ -83,39 +83,53 @@ public class BtHelper {
    }

    // BluetoothHeadset API to control SCO connection
    @GuardedBy("BtHelper.this")
    private @Nullable BluetoothHeadset mBluetoothHeadset;

    // Bluetooth headset device
    @GuardedBy("mDeviceBroker.mDeviceStateLock")
    private @Nullable BluetoothDevice mBluetoothHeadsetDevice;

    @GuardedBy("mDeviceBroker.mDeviceStateLock")
    private final Map<BluetoothDevice, AudioDeviceAttributes> mResolvedScoAudioDevices =
            new HashMap<>();

    @GuardedBy("BtHelper.this")
    private @Nullable BluetoothHearingAid mHearingAid = null;

    @GuardedBy("BtHelper.this")
    private @Nullable BluetoothLeAudio mLeAudio = null;

    @GuardedBy("BtHelper.this")
    private @Nullable BluetoothLeAudioCodecConfig mLeAudioCodecConfig;

    // Reference to BluetoothA2dp to query for AbsoluteVolume.
    @GuardedBy("BtHelper.this")
    private @Nullable BluetoothA2dp mA2dp = null;

    @GuardedBy("BtHelper.this")
    private @Nullable BluetoothCodecConfig mA2dpCodecConfig;

    @GuardedBy("BtHelper.this")
    private @AudioSystem.AudioFormatNativeEnumForBtCodec
            int mLeAudioBroadcastCodec = AudioSystem.AUDIO_FORMAT_DEFAULT;

    // If absolute volume is supported in AVRCP device
    @GuardedBy("mDeviceBroker.mDeviceStateLock")
    private boolean mAvrcpAbsVolSupported = false;

    // Current connection state indicated by bluetooth headset
    @GuardedBy("mDeviceBroker.mDeviceStateLock")
    private int mScoConnectionState;

    // Indicate if SCO audio connection is currently active and if the initiator is
    // audio service (internal) or bluetooth headset (external)
    @GuardedBy("mDeviceBroker.mDeviceStateLock")
    private int mScoAudioState;

    // Indicates the mode used for SCO audio connection. The mode is virtual call if the request
    // originated from an app targeting an API version before JB MR2 and raw audio after that.
    @GuardedBy("mDeviceBroker.mDeviceStateLock")
    private int mScoAudioMode;

    // SCO audio state is not active
@@ -210,7 +224,7 @@ public class BtHelper {
    //----------------------------------------------------------------------
    // Interface for AudioDeviceBroker

    // Called locked by ADeviceBroker.mSetModeLock -> AudioDeviceBroker.mDeviceStateLock
    @GuardedBy("mDeviceBroker.mDeviceStateLock")
    /*package*/ synchronized void onSystemReady() {
        mScoConnectionState = android.media.AudioManager.SCO_AUDIO_STATE_ERROR;
        resetBluetoothSco();
@@ -238,17 +252,13 @@ public class BtHelper {
        }
    }

    /*package*/ synchronized void onAudioServerDiedRestoreA2dp() {
        final int forMed = mDeviceBroker.getBluetoothA2dpEnabled()
                ? AudioSystem.FORCE_NONE : AudioSystem.FORCE_NO_BT_A2DP;
        mDeviceBroker.setForceUse_Async(AudioSystem.FOR_MEDIA, forMed, "onAudioServerDied()");
    }

    /*package*/ synchronized void setAvrcpAbsoluteVolumeSupported(boolean supported) {
    @GuardedBy("mDeviceBroker.mDeviceStateLock")
    /*package*/ void setAvrcpAbsoluteVolumeSupported(boolean supported) {
        mAvrcpAbsVolSupported = supported;
        Log.i(TAG, "setAvrcpAbsoluteVolumeSupported supported=" + supported);
    }

    @GuardedBy("mDeviceBroker.mDeviceStateLock")
    /*package*/ synchronized void setAvrcpAbsoluteVolumeIndex(int index) {
        if (mA2dp == null) {
            if (AudioService.DEBUG_VOL) {
@@ -371,7 +381,7 @@ public class BtHelper {
        return codecAndChanged;
    }

    // Called locked by ADeviceBroker.mSetModeLock -> AudioDeviceBroker.mDeviceStateLock
    @GuardedBy("mDeviceBroker.mDeviceStateLock")
    /*package*/ synchronized void onReceiveBtEvent(Intent intent) {
        final String action = intent.getAction();

@@ -393,12 +403,12 @@ public class BtHelper {
    }

    /**
     * Exclusively called from AudioDeviceBroker (with mSetModeLock held)
     * Exclusively called from AudioDeviceBroker (with mDeviceStateLock held)
     * when handling MSG_L_RECEIVED_BT_EVENT in {@link #onReceiveBtEvent(Intent)}
     * as part of the serialization of the communication route selection
     */
    @GuardedBy("BtHelper.this")
    private void onScoAudioStateChanged(int state) {
    @GuardedBy("mDeviceBroker.mDeviceStateLock")
    private synchronized void onScoAudioStateChanged(int state) {
        boolean broadcast = false;
        int scoAudioState = AudioManager.SCO_AUDIO_STATE_ERROR;
        Log.i(TAG, "onScoAudioStateChanged  state: " + state
@@ -414,12 +424,14 @@ public class BtHelper {
                    broadcast = true;
                }
                if (!mDeviceBroker.isScoManagedByAudio()) {
                    mDeviceBroker.setBluetoothScoOn(true, "BtHelper.onScoAudioStateChanged");
                    mDeviceBroker.setBluetoothScoOn(
                            true, "BtHelper.onScoAudioStateChanged, state: " + state);
                }
                break;
            case BluetoothHeadset.STATE_AUDIO_DISCONNECTED:
                if (!mDeviceBroker.isScoManagedByAudio()) {
                    mDeviceBroker.setBluetoothScoOn(false, "BtHelper.onScoAudioStateChanged");
                    mDeviceBroker.setBluetoothScoOn(
                            false, "BtHelper.onScoAudioStateChanged, state: " + state);
                }
                scoAudioState = AudioManager.SCO_AUDIO_STATE_DISCONNECTED;
                // There are two cases where we want to immediately reconnect audio:
@@ -466,6 +478,7 @@ public class BtHelper {
     *
     * @return false if SCO isn't connected
     */
    @GuardedBy("mDeviceBroker.mDeviceStateLock")
    /*package*/ synchronized boolean isBluetoothScoOn() {
        if (mBluetoothHeadset == null || mBluetoothHeadsetDevice == null) {
            return false;
@@ -479,19 +492,20 @@ public class BtHelper {
        return false;
    }

    /*package*/ synchronized boolean isBluetoothScoRequestedInternally() {
    @GuardedBy("mDeviceBroker.mDeviceStateLock")
    /*package*/ boolean isBluetoothScoRequestedInternally() {
        return mScoAudioState == SCO_STATE_ACTIVE_INTERNAL
              || mScoAudioState == SCO_STATE_ACTIVATE_REQ;
    }

    // Called locked by ADeviceBroker.mSetModeLock -> AudioDeviceBroker.mDeviceStateLock
    @GuardedBy("mDeviceBroker.mDeviceStateLock")
    /*package*/ synchronized boolean startBluetoothSco(int scoAudioMode,
                @NonNull String eventSource) {
        AudioService.sDeviceLogger.enqueue(new EventLogger.StringEvent(eventSource));
        return requestScoState(BluetoothHeadset.STATE_AUDIO_CONNECTED, scoAudioMode);
    }

    // Called locked by ADeviceBroker.mSetModeLock -> AudioDeviceBroker.mDeviceStateLock
    @GuardedBy("mDeviceBroker.mDeviceStateLock")
    /*package*/ synchronized boolean stopBluetoothSco(@NonNull String eventSource) {
        AudioService.sDeviceLogger.enqueue(new EventLogger.StringEvent(eventSource));
        return requestScoState(BluetoothHeadset.STATE_AUDIO_DISCONNECTED, SCO_MODE_VIRTUAL_CALL);
@@ -551,7 +565,8 @@ public class BtHelper {
        }
    }

    /*package*/ synchronized void onBroadcastScoConnectionState(int state) {
    @GuardedBy("mDeviceBroker.mDeviceStateLock")
    /*package*/ void onBroadcastScoConnectionState(int state) {
        if (state == mScoConnectionState) {
            return;
        }
@@ -563,8 +578,8 @@ public class BtHelper {
        mScoConnectionState = state;
    }

    // Called locked by ADeviceBroker.mSetModeLock -> AudioDeviceBroker.mDeviceStateLock
    /*package*/ synchronized void resetBluetoothSco() {
    @GuardedBy("mDeviceBroker.mDeviceStateLock")
    /*package*/ void resetBluetoothSco() {
        mScoAudioState = SCO_STATE_INACTIVE;
        broadcastScoConnectionState(AudioManager.SCO_AUDIO_STATE_DISCONNECTED);
        mDeviceBroker.clearA2dpSuspended(false /* internalOnly */);
@@ -572,7 +587,7 @@ public class BtHelper {
        mDeviceBroker.setBluetoothScoOn(false, "resetBluetoothSco");
    }

    // Called locked by ADeviceBroker.mSetModeLock -> AudioDeviceBroker.mDeviceStateLock
    @GuardedBy("mDeviceBroker.mDeviceStateLock")
    /*package*/ synchronized void onBtProfileDisconnected(int profile) {
        AudioService.sDeviceLogger.enqueue(new EventLogger.StringEvent(
                "BT profile " + BluetoothProfile.getProfileName(profile)
@@ -634,9 +649,10 @@ public class BtHelper {
        }
    }

    @GuardedBy("BtHelper.this")
    MyLeAudioCallback mLeAudioCallback = null;

    // Called locked by ADeviceBroker.mSetModeLock -> AudioDeviceBroker.mDeviceStateLock
    @GuardedBy("mDeviceBroker.mDeviceStateLock")
    /*package*/ synchronized void onBtProfileConnected(int profile, BluetoothProfile proxy) {
        AudioService.sDeviceLogger.enqueue(new EventLogger.StringEvent(
                "BT profile " + BluetoothProfile.getProfileName(profile) + " connected to proxy "
@@ -773,8 +789,8 @@ public class BtHelper {
        }
    }

    // Called locked by ADeviceBroker.mSetModeLock -> AudioDeviceBroker.mDeviceStateLock
    private void onHeadsetProfileConnected(@NonNull BluetoothHeadset headset) {
    @GuardedBy("mDeviceBroker.mDeviceStateLock")
    private synchronized void onHeadsetProfileConnected(@NonNull BluetoothHeadset headset) {
        // Discard timeout message
        mDeviceBroker.handleCancelFailureToConnectToBtHeadsetService();
        mBluetoothHeadset = headset;
@@ -830,6 +846,7 @@ public class BtHelper {
        mDeviceBroker.postBroadcastScoConnectionState(state);
    }

    @GuardedBy("mDeviceBroker.mDeviceStateLock")
    @Nullable AudioDeviceAttributes getHeadsetAudioDevice() {
        if (mBluetoothHeadsetDevice == null) {
            return null;
@@ -837,6 +854,7 @@ public class BtHelper {
        return getHeadsetAudioDevice(mBluetoothHeadsetDevice);
    }

    @GuardedBy("mDeviceBroker.mDeviceStateLock")
    private @NonNull AudioDeviceAttributes getHeadsetAudioDevice(BluetoothDevice btDevice) {
        AudioDeviceAttributes deviceAttr = mResolvedScoAudioDevices.get(btDevice);
        if (deviceAttr != null) {
@@ -876,16 +894,28 @@ public class BtHelper {
        return new AudioDeviceAttributes(nativeType, address, name);
    }

    @GuardedBy("mDeviceBroker.mDeviceStateLock")
    private boolean handleBtScoActiveDeviceChange(BluetoothDevice btDevice, boolean isActive) {
        if (btDevice == null) {
            return true;
        }
        int inDevice = AudioSystem.DEVICE_IN_BLUETOOTH_SCO_HEADSET;
        AudioDeviceAttributes audioDevice = btHeadsetDeviceToAudioDevice(btDevice);
        boolean result = false;
        AudioDeviceAttributes audioDevice = null; // Only used if isActive is true
        String address = btDevice.getAddress();
        String name = getName(btDevice);
        // Handle output device
        if (isActive) {
            result |= mDeviceBroker.handleDeviceConnection(audioDevice, isActive, btDevice);
            audioDevice = btHeadsetDeviceToAudioDevice(btDevice);
            result = mDeviceBroker.handleDeviceConnection(
                    audioDevice, true /*connect*/, btDevice);
        } else {
            AudioDeviceAttributes ada = mResolvedScoAudioDevices.get(btDevice);
            if (ada != null) {
                result = mDeviceBroker.handleDeviceConnection(
                    ada, false /*connect*/, btDevice);
            } else {
                // Disconnect all possible audio device types if the disconnected device type is
                // unknown
                int[] outDeviceTypes = {
                    AudioSystem.DEVICE_OUT_BLUETOOTH_SCO,
                    AudioSystem.DEVICE_OUT_BLUETOOTH_SCO_HEADSET,
@@ -893,13 +923,15 @@ public class BtHelper {
                };
                for (int outDeviceType : outDeviceTypes) {
                    result |= mDeviceBroker.handleDeviceConnection(new AudioDeviceAttributes(
                        outDeviceType, audioDevice.getAddress(), audioDevice.getName()),
                        isActive, btDevice);
                            outDeviceType, address, name), false /*connect*/, btDevice);
                }
            }
        }
        // Handle input device
        int inDevice = AudioSystem.DEVICE_IN_BLUETOOTH_SCO_HEADSET;
        // handleDeviceConnection() && result to make sure the method get executed
        result = mDeviceBroker.handleDeviceConnection(new AudioDeviceAttributes(
                        inDevice, audioDevice.getAddress(), audioDevice.getName()),
                        inDevice, address, name),
                isActive, btDevice) && result;
        if (result) {
            if (isActive) {
@@ -916,8 +948,8 @@ public class BtHelper {
        return btDevice == null ? "(null)" : btDevice.getAnonymizedAddress();
    }

    // Called locked by ADeviceBroker.mSetModeLock -> AudioDeviceBroker.mDeviceStateLock
    /*package */ synchronized void onSetBtScoActiveDevice(BluetoothDevice btDevice) {
    @GuardedBy("mDeviceBroker.mDeviceStateLock")
    /*package */ void onSetBtScoActiveDevice(BluetoothDevice btDevice) {
        Log.i(TAG, "onSetBtScoActiveDevice: " + getAnonymizedAddress(mBluetoothHeadsetDevice)
                + " -> " + getAnonymizedAddress(btDevice));
        final BluetoothDevice previousActiveDevice = mBluetoothHeadsetDevice;
@@ -987,10 +1019,8 @@ public class BtHelper {

    //----------------------------------------------------------------------

    // @GuardedBy("mDeviceBroker.mSetModeLock")
    // @GuardedBy("AudioDeviceBroker.this.mDeviceStateLock")
    @GuardedBy("BtHelper.this")
    private boolean requestScoState(int state, int scoAudioMode) {
    @GuardedBy("mDeviceBroker.mDeviceStateLock")
    private synchronized boolean requestScoState(int state, int scoAudioMode) {
        checkScoAudioState();
        if (state == BluetoothHeadset.STATE_AUDIO_CONNECTED) {
            // Make sure that the state transitions to CONNECTING even if we cannot initiate
@@ -1154,7 +1184,8 @@ public class BtHelper {
        }
    }

    private void checkScoAudioState() {
    @GuardedBy("mDeviceBroker.mDeviceStateLock")
    private synchronized void checkScoAudioState() {
        try {
            if (mBluetoothHeadset != null
                    && mBluetoothHeadsetDevice != null
@@ -1184,7 +1215,7 @@ public class BtHelper {
        return result;
    }

    /*package*/ int getLeAudioDeviceGroupId(BluetoothDevice device) {
    /*package*/ synchronized int getLeAudioDeviceGroupId(BluetoothDevice device) {
        if (mLeAudio == null || device == null) {
            return BluetoothLeAudio.GROUP_ID_INVALID;
        }
@@ -1197,7 +1228,7 @@ public class BtHelper {
     * @return A List of Pair(String main_address, String identity_address). Note that the
     * addresses returned by BluetoothDevice can be null.
     */
    /*package*/ List<Pair<String, String>> getLeAudioGroupAddresses(int groupId) {
    /*package*/ synchronized List<Pair<String, String>> getLeAudioGroupAddresses(int groupId) {
        List<Pair<String, String>> addresses = new ArrayList<>();
        BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
        if (adapter == null || mLeAudio == null) {