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

Commit aaf2ef04 authored by Rongxuan Liu's avatar Rongxuan Liu Committed by Gerrit Code Review
Browse files

Merge "[le audio] Remove source should trigger update first if BIS is synced" into main

parents f08989dc 4315ba6c
Loading
Loading
Loading
Loading
+2 −5
Original line number Diff line number Diff line
@@ -59,8 +59,8 @@ import com.android.bluetooth.flags.FeatureFlagsImpl;
import com.android.bluetooth.le_audio.LeAudioService;
import com.android.internal.annotations.VisibleForTesting;

import java.util.ArrayList;
import java.util.ArrayDeque;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Deque;
@@ -1583,12 +1583,9 @@ public class BassClientService extends ProfileService {
                continue;
            }

            BluetoothLeBroadcastReceiveState recvState =
                    stateMachine.getBroadcastReceiveStateForSourceId(sourceId);
            BluetoothLeBroadcastMetadata metaData =
                    stateMachine.getCurrentBroadcastMetadata(sourceId);
            if (metaData != null && recvState != null && recvState.getPaSyncState()
                    == BluetoothLeBroadcastReceiveState.PA_SYNC_STATE_SYNCHRONIZED) {
            if (metaData != null && stateMachine.isSyncedToTheSource(sourceId)) {
                sEventLogger.logd(
                        DBG,
                        TAG,
+14 −7
Original line number Diff line number Diff line
@@ -325,6 +325,19 @@ public class BassClientStateMachine extends StateMachine {
        return null;
    }

    boolean isSyncedToTheSource(int sourceId) {
        BluetoothLeBroadcastReceiveState recvState = getBroadcastReceiveStateForSourceId(sourceId);

        return recvState != null
                && (recvState.getPaSyncState()
                                == BluetoothLeBroadcastReceiveState.PA_SYNC_STATE_SYNCHRONIZED
                        || recvState.getBisSyncState().stream()
                                .anyMatch(
                                        bitmap -> {
                                            return bitmap != 0;
                                        }));
    }

    void parseBaseData(BluetoothDevice device, int syncHandle, byte[] serviceData) {
        log("parseBaseData" + Arrays.toString(serviceData));
        BaseData base = BaseData.parseBaseData(serviceData);
@@ -1759,15 +1772,9 @@ public class BassClientStateMachine extends StateMachine {
                    // Save pending source to be added once existing source got removed
                    mPendingSourceToSwitch = metaData;
                    // Remove the source first
                    BluetoothLeBroadcastReceiveState recvStateToUpdate =
                            getBroadcastReceiveStateForSourceId(sourceIdToRemove);
                    BluetoothLeBroadcastMetadata metaDataToUpdate =
                            getCurrentBroadcastMetadata(sourceIdToRemove);
                    if (metaDataToUpdate != null
                            && recvStateToUpdate != null
                            && recvStateToUpdate.getPaSyncState()
                                    == BluetoothLeBroadcastReceiveState
                                            .PA_SYNC_STATE_SYNCHRONIZED) {
                    if (metaDataToUpdate != null && isSyncedToTheSource(sourceIdToRemove)) {
                        log("SWITCH_BCAST_SOURCE force source to lost PA sync");
                        Message msg = obtainMessage(UPDATE_BCAST_SOURCE);
                        msg.arg1 = sourceIdToRemove;
+83 −0
Original line number Diff line number Diff line
@@ -751,6 +751,89 @@ public class BassClientServiceTest {
        }
    }

    /**
     * Test whether service.removeSource() does send modify source to all the state machines if
     * either PA or BIS is synced
     */
    @Test
    public void testRemoveSourceForGroupAndTriggerModifySource() {
        prepareConnectedDeviceGroup();
        BluetoothLeBroadcastMetadata meta = createBroadcastMetadata(TEST_BROADCAST_ID);
        verifyAddSourceForGroup(meta);
        for (BassClientStateMachine sm : mStateMachines.values()) {
            injectRemoteSourceStateSourceAdded(
                    sm,
                    meta,
                    TEST_SOURCE_ID,
                    BluetoothLeBroadcastReceiveState.PA_SYNC_STATE_SYNCHRONIZED,
                    meta.isEncrypted()
                            ? BluetoothLeBroadcastReceiveState.BIG_ENCRYPTION_STATE_DECRYPTING
                            : BluetoothLeBroadcastReceiveState.BIG_ENCRYPTION_STATE_NOT_ENCRYPTED,
                    null);
            doReturn(meta).when(sm).getCurrentBroadcastMetadata(eq(TEST_SOURCE_ID));
            doReturn(true).when(sm).isSyncedToTheSource(eq(TEST_SOURCE_ID));
        }

        // Remove broadcast source
        mBassClientService.removeSource(mCurrentDevice, TEST_SOURCE_ID);

        // Verify all group members getting UPDATE_BCAST_SOURCE message
        // because PA state is synced
        assertThat(mStateMachines.size()).isEqualTo(2);
        for (BassClientStateMachine sm : mStateMachines.values()) {
            ArgumentCaptor<Message> messageCaptor = ArgumentCaptor.forClass(Message.class);
            verify(sm, atLeast(1)).sendMessage(messageCaptor.capture());

            Optional<Message> msg =
                    messageCaptor.getAllValues().stream()
                            .filter(m -> m.what == BassClientStateMachine.UPDATE_BCAST_SOURCE)
                            .findFirst();
            assertThat(msg.isPresent()).isEqualTo(true);

            // Verify using the right sourceId on each device
            assertThat(msg.get().arg1).isEqualTo(TEST_SOURCE_ID);
        }

        for (BassClientStateMachine sm : mStateMachines.values()) {
            // Update receiver state
            injectRemoteSourceStateChanged(
                    sm,
                    meta,
                    TEST_SOURCE_ID,
                    BluetoothLeBroadcastReceiveState.PA_SYNC_STATE_IDLE,
                    meta.isEncrypted()
                            ? BluetoothLeBroadcastReceiveState.BIG_ENCRYPTION_STATE_DECRYPTING
                            : BluetoothLeBroadcastReceiveState.BIG_ENCRYPTION_STATE_NOT_ENCRYPTED,
                    null,
                    (long) 0x00000001);
            verify(mLeAudioService).activeBroadcastAssistantNotification(eq(true));
        }

        // Remove broadcast source
        mBassClientService.removeSource(mCurrentDevice, TEST_SOURCE_ID);

        // Verify all group members getting UPDATE_BCAST_SOURCE message if
        // bis sync state is non-zero and pa sync state is not synced
        assertThat(mStateMachines.size()).isEqualTo(2);
        for (BassClientStateMachine sm : mStateMachines.values()) {
            ArgumentCaptor<Message> messageCaptor = ArgumentCaptor.forClass(Message.class);
            verify(sm, atLeast(1)).sendMessage(messageCaptor.capture());

            Optional<Message> msg =
                    messageCaptor.getAllValues().stream()
                            .filter(m -> m.what == BassClientStateMachine.UPDATE_BCAST_SOURCE)
                            .findFirst();
            assertThat(msg.isPresent()).isEqualTo(true);

            // Verify using the right sourceId on each device
            assertThat(msg.get().arg1).isEqualTo(TEST_SOURCE_ID);
        }

        for (BassClientStateMachine sm : mStateMachines.values()) {
            injectRemoteSourceStateRemoval(sm, TEST_SOURCE_ID);
        }
    }

    /**
     * Test whether the group operation flag is set on addSource() and removed on removeSource
     */