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

Commit 2be3cada authored by Michal Belusiak's avatar Michal Belusiak
Browse files

BassClientService: Sort scan results for source sync by fails counter

Until now, it was sorted by priority flag and by RSSI. That solution
had the disadvantage that if two broadcasters with the best range,
fails all the time, then any other broadcaster will not be sync.

This change add sorting by sync failure counter between priority
flag and RSSI. Each time when sync fails or lost, counter in increased.
It is cleared when new searching is started.

Bug: 365613358
Bug: 370639684
Test: atest BassClientServiceTest
Change-Id: I8350482009f7a77a5ca02ff981c85b2afb6bcc0b
parent 7b456c17
Loading
Loading
Loading
Loading
+54 −33
Original line number Original line Diff line number Diff line
@@ -27,6 +27,7 @@ import static com.android.bluetooth.flags.Flags.leaudioBroadcastAssistantPeriphe
import static com.android.bluetooth.flags.Flags.leaudioBroadcastExtractPeriodicScannerFromStateMachine;
import static com.android.bluetooth.flags.Flags.leaudioBroadcastExtractPeriodicScannerFromStateMachine;
import static com.android.bluetooth.flags.Flags.leaudioBroadcastMonitorSourceSyncStatus;
import static com.android.bluetooth.flags.Flags.leaudioBroadcastMonitorSourceSyncStatus;
import static com.android.bluetooth.flags.Flags.leaudioBroadcastResyncHelper;
import static com.android.bluetooth.flags.Flags.leaudioBroadcastResyncHelper;
import static com.android.bluetooth.flags.Flags.leaudioSortScansToSyncByFails;


import android.annotation.RequiresPermission;
import android.annotation.RequiresPermission;
import android.annotation.SuppressLint;
import android.annotation.SuppressLint;
@@ -158,6 +159,7 @@ public class BassClientService extends ProfileService {
            new HashMap<>();
            new HashMap<>();
    private final PriorityQueue<SourceSyncRequest> mSourceSyncRequestsQueue =
    private final PriorityQueue<SourceSyncRequest> mSourceSyncRequestsQueue =
            new PriorityQueue<>(sSourceSyncRequestComparator);
            new PriorityQueue<>(sSourceSyncRequestComparator);
    private final Map<Integer, Integer> mSyncFailureCounter = new HashMap<>();
    private final Map<Integer, Integer> mBisDiscoveryCounterMap = new HashMap<>();
    private final Map<Integer, Integer> mBisDiscoveryCounterMap = new HashMap<>();
    private final List<AddSourceData> mPendingSourcesToAdd = new ArrayList<>();
    private final List<AddSourceData> mPendingSourcesToAdd = new ArrayList<>();


@@ -280,12 +282,14 @@ public class BassClientService extends ProfileService {
    }
    }


    private static class SourceSyncRequest {
    private static class SourceSyncRequest {
        private ScanResult mScanResult;
        private final ScanResult mScanResult;
        private boolean mHasPriority;
        private final boolean mHasPriority;
        private final int mSyncFailureCounter;


        SourceSyncRequest(ScanResult scanResult, boolean hasPriority) {
        SourceSyncRequest(ScanResult scanResult, boolean hasPriority, int syncFailureCounter) {
            this.mScanResult = scanResult;
            this.mScanResult = scanResult;
            this.mHasPriority = hasPriority;
            this.mHasPriority = hasPriority;
            this.mSyncFailureCounter = syncFailureCounter;
        }
        }


        public ScanResult getScanResult() {
        public ScanResult getScanResult() {
@@ -300,6 +304,10 @@ public class BassClientService extends ProfileService {
            return mHasPriority;
            return mHasPriority;
        }
        }


        public int getFailsCounter() {
            return mSyncFailureCounter;
        }

        @Override
        @Override
        public String toString() {
        public String toString() {
            return "SourceSyncRequest{"
            return "SourceSyncRequest{"
@@ -307,6 +315,8 @@ public class BassClientService extends ProfileService {
                    + mScanResult
                    + mScanResult
                    + ", mHasPriority="
                    + ", mHasPriority="
                    + mHasPriority
                    + mHasPriority
                    + ", mSyncFailureCounter="
                    + mSyncFailureCounter
                    + '}';
                    + '}';
        }
        }
    }
    }
@@ -319,6 +329,9 @@ public class BassClientService extends ProfileService {
                        return -1;
                        return -1;
                    } else if (!ssr1.hasPriority() && ssr2.hasPriority()) {
                    } else if (!ssr1.hasPriority() && ssr2.hasPriority()) {
                        return 1;
                        return 1;
                    } else if (leaudioSortScansToSyncByFails()
                            && (ssr1.getFailsCounter() != ssr2.getFailsCounter())) {
                        return Integer.compare(ssr1.getFailsCounter(), ssr2.getFailsCounter());
                    } else {
                    } else {
                        return Integer.compare(ssr2.getRssi(), ssr1.getRssi());
                        return Integer.compare(ssr2.getRssi(), ssr1.getRssi());
                    }
                    }
@@ -1046,9 +1059,8 @@ public class BassClientService extends ProfileService {
            if (isPlaying) {
            if (isPlaying) {
                stopBigMonitoring(broadcastId, false);
                stopBigMonitoring(broadcastId, false);
            } else if (!mPausedBroadcastIds.containsKey(broadcastId)) {
            } else if (!mPausedBroadcastIds.containsKey(broadcastId)) {
                ScanResult scanRes = getCachedBroadcast(broadcastId);
                if (mCachedBroadcasts.containsKey(broadcastId)) {
                if (scanRes != null) {
                    addSelectSourceRequest(broadcastId, true);
                    addSelectSourceRequest(scanRes, true);
                    mPausedBroadcastIds.put(broadcastId, PauseType.SINK_UNKNOWN);
                    mPausedBroadcastIds.put(broadcastId, PauseType.SINK_UNKNOWN);
                    logPausedBroadcastsAndSinks();
                    logPausedBroadcastsAndSinks();
                    mHandler.removeMessages(MESSAGE_BIG_CHECK_START);
                    mHandler.removeMessages(MESSAGE_BIG_CHECK_START);
@@ -1842,11 +1854,11 @@ public class BassClientService extends ProfileService {
                                        "Broadcast Source Found: Broadcast ID: " + broadcastId);
                                        "Broadcast Source Found: Broadcast ID: " + broadcastId);


                                if (broadcastId != BassConstants.INVALID_BROADCAST_ID
                                if (broadcastId != BassConstants.INVALID_BROADCAST_ID
                                        && mCachedBroadcasts.get(broadcastId) == null) {
                                        && !mCachedBroadcasts.containsKey(broadcastId)) {
                                    log("selectBroadcastSource: broadcastId " + broadcastId);
                                    log("selectBroadcastSource: broadcastId " + broadcastId);
                                    mCachedBroadcasts.put(broadcastId, result);
                                    mCachedBroadcasts.put(broadcastId, result);
                                    if (leaudioBroadcastExtractPeriodicScannerFromStateMachine()) {
                                    if (leaudioBroadcastExtractPeriodicScannerFromStateMachine()) {
                                        addSelectSourceRequest(result, false);
                                        addSelectSourceRequest(broadcastId, false);
                                    } else {
                                    } else {
                                        synchronized (mStateMachines) {
                                        synchronized (mStateMachines) {
                                            for (BassClientStateMachine sm :
                                            for (BassClientStateMachine sm :
@@ -1866,15 +1878,13 @@ public class BassClientService extends ProfileService {
                            informConnectedDeviceAboutScanOffloadStop();
                            informConnectedDeviceAboutScanOffloadStop();
                        }
                        }
                    };
                    };
            mSyncFailureCounter.clear();
            mHandler.removeMessages(MESSAGE_SYNC_TIMEOUT);
            mHandler.removeMessages(MESSAGE_SYNC_TIMEOUT);
            if (leaudioBroadcastResyncHelper()) {
            if (leaudioBroadcastResyncHelper()) {
                // Sync to the broadcasts already synced with sinks
                // Sync to the broadcasts already synced with sinks
                Set<Integer> syncedBroadcasts = getExternalBroadcastsActiveOnSinks();
                Set<Integer> syncedBroadcasts = getExternalBroadcastsActiveOnSinks();
                for (int syncedBroadcast : syncedBroadcasts) {
                for (int syncedBroadcast : syncedBroadcasts) {
                    ScanResult scanRes = getCachedBroadcast(syncedBroadcast);
                    addSelectSourceRequest(syncedBroadcast, true);
                    if (scanRes != null) {
                        addSelectSourceRequest(scanRes, true);
                    }
                }
                }
            }
            }
            // when starting scan, clear the previously cached broadcast scan results
            // when starting scan, clear the previously cached broadcast scan results
@@ -1972,10 +1982,7 @@ public class BassClientService extends ProfileService {
                    Integer broadcastId = entry.getKey();
                    Integer broadcastId = entry.getKey();
                    PauseType pauseType = entry.getValue();
                    PauseType pauseType = entry.getValue();
                    if (pauseType != PauseType.HOST_INTENTIONAL) {
                    if (pauseType != PauseType.HOST_INTENTIONAL) {
                        ScanResult scanRes = getCachedBroadcast(broadcastId);
                        addSelectSourceRequest(broadcastId, true);
                        if (scanRes != null) {
                            addSelectSourceRequest(scanRes, true);
                        }
                    }
                    }
                }
                }
            }
            }
@@ -1985,6 +1992,7 @@ public class BassClientService extends ProfileService {
    private void clearAllSyncData() {
    private void clearAllSyncData() {
        log("clearAllSyncData");
        log("clearAllSyncData");
        mSourceSyncRequestsQueue.clear();
        mSourceSyncRequestsQueue.clear();
        mSyncFailureCounter.clear();
        mPendingSourcesToAdd.clear();
        mPendingSourcesToAdd.clear();


        cancelActiveSync(null);
        cancelActiveSync(null);
@@ -2106,6 +2114,10 @@ public class BassClientService extends ProfileService {
                    }
                    }
                }
                }
                stopBigMonitoring(broadcastId, false);
                stopBigMonitoring(broadcastId, false);
                synchronized (mSourceSyncRequestsQueue) {
                    int failsCounter = mSyncFailureCounter.getOrDefault(broadcastId, 0) + 1;
                    mSyncFailureCounter.put(broadcastId, failsCounter);
                }
                synchronized (mSearchScanCallbackLock) {
                synchronized (mSearchScanCallbackLock) {
                    // Clear from cache to make possible sync again (only during active searching)
                    // Clear from cache to make possible sync again (only during active searching)
                    if (mSearchScanCallback != null) {
                    if (mSearchScanCallback != null) {
@@ -2180,6 +2192,10 @@ public class BassClientService extends ProfileService {
                    mCallbacks.notifySourceLost(broadcastId);
                    mCallbacks.notifySourceLost(broadcastId);
                }
                }
                stopBigMonitoring(broadcastId, false);
                stopBigMonitoring(broadcastId, false);
                synchronized (mSourceSyncRequestsQueue) {
                    int failsCounter = mSyncFailureCounter.getOrDefault(broadcastId, 0) + 1;
                    mSyncFailureCounter.put(broadcastId, failsCounter);
                }
            }
            }
            clearAllDataForSyncHandle(syncHandle);
            clearAllDataForSyncHandle(syncHandle);
            // Clear from cache to make possible sync again (only during active searching)
            // Clear from cache to make possible sync again (only during active searching)
@@ -2464,19 +2480,16 @@ public class BassClientService extends ProfileService {
        return broadcastName;
        return broadcastName;
    }
    }


    void addSelectSourceRequest(ScanResult scanRes, boolean hasPriority) {
    void addSelectSourceRequest(int broadcastId, boolean hasPriority) {
        sEventLogger.logd(
        sEventLogger.logd(
                TAG,
                TAG,
                "Add Select Broadcast Source, result: "
                "Add Select Broadcast Source, broadcastId: "
                        + scanRes
                        + broadcastId
                        + ", hasPriority: "
                        + ", hasPriority: "
                        + hasPriority);
                        + hasPriority);


        if (scanRes == null) {
        ScanResult scanRes = getCachedBroadcast(broadcastId);
            Log.e(TAG, "addSelectSourceRequest: Error bad parameters: scanRes cannot be null");
        if (scanRes != null) {
            return;
        }

            ScanRecord scanRecord = scanRes.getScanRecord();
            ScanRecord scanRecord = scanRes.getScanRecord();
            if (scanRecord == null) {
            if (scanRecord == null) {
                log("addSelectSourceRequest: ScanRecord empty");
                log("addSelectSourceRequest: ScanRecord empty");
@@ -2484,10 +2497,18 @@ public class BassClientService extends ProfileService {
            }
            }


            synchronized (mSourceSyncRequestsQueue) {
            synchronized (mSourceSyncRequestsQueue) {
            mSourceSyncRequestsQueue.add(new SourceSyncRequest(scanRes, hasPriority));
                if (!mSyncFailureCounter.containsKey(broadcastId)) {
                    mSyncFailureCounter.put(broadcastId, 0);
                }
                mSourceSyncRequestsQueue.add(
                        new SourceSyncRequest(
                                scanRes, hasPriority, mSyncFailureCounter.get(broadcastId)));
            }
            }


            handleSelectSourceRequest();
            handleSelectSourceRequest();
        } else {
            log("addSelectSourceRequest: ScanResult empty");
        }
    }
    }


    @SuppressLint("AndroidFrameworkRequiresPermission") // TODO: b/350563786 - Fix BASS annotation
    @SuppressLint("AndroidFrameworkRequiresPermission") // TODO: b/350563786 - Fix BASS annotation
@@ -2732,7 +2753,7 @@ public class BassClientService extends ProfileService {
                        mPendingSourcesToAdd.add(
                        mPendingSourcesToAdd.add(
                                new AddSourceData(sink, sourceMetadata, isGroupOp));
                                new AddSourceData(sink, sourceMetadata, isGroupOp));
                        if (!alreadyAdded) {
                        if (!alreadyAdded) {
                            addSelectSourceRequest(getCachedBroadcast(broadcastId), true);
                            addSelectSourceRequest(broadcastId, true);
                        }
                        }
                    }
                    }
                } else {
                } else {
+255 −42
Original line number Original line Diff line number Diff line
@@ -2377,35 +2377,11 @@ public class BassClientServiceTest {
    @Test
    @Test
    @EnableFlags(Flags.FLAG_LEAUDIO_BROADCAST_EXTRACT_PERIODIC_SCANNER_FROM_STATE_MACHINE)
    @EnableFlags(Flags.FLAG_LEAUDIO_BROADCAST_EXTRACT_PERIODIC_SCANNER_FROM_STATE_MACHINE)
    public void testSelectSource_withSameBroadcastId() {
    public void testSelectSource_withSameBroadcastId() {
        byte[] scanRecord = getScanRecord(TEST_BROADCAST_ID);
        prepareConnectedDeviceGroup();

        startSearchingForSources();
        ScanResult scanResult1 =
                new ScanResult(
                        mSourceDevice,
                        0,
                        0,
                        0,
                        0,
                        0,
                        TEST_RSSI,
                        0,
                        ScanRecord.parseFromBytes(scanRecord),
                        0);
        ScanResult scanResult2 =
                new ScanResult(
                        mSourceDevice2,
                        0,
                        0,
                        0,
                        0,
                        0,
                        TEST_RSSI,
                        0,
                        ScanRecord.parseFromBytes(scanRecord),
                        0);


        // First selectSource
        // First selectSource
        mBassClientService.addSelectSourceRequest(scanResult1, false);
        onScanResult(mSourceDevice, TEST_BROADCAST_ID);
        mInOrderMethodProxy
        mInOrderMethodProxy
                .verify(mMethodProxy)
                .verify(mMethodProxy)
                .periodicAdvertisingManagerRegisterSync(
                .periodicAdvertisingManagerRegisterSync(
@@ -2414,7 +2390,7 @@ public class BassClientServiceTest {
        onSyncEstablished(mSourceDevice, TEST_SYNC_HANDLE);
        onSyncEstablished(mSourceDevice, TEST_SYNC_HANDLE);


        // Second selectSource with the same broadcast id
        // Second selectSource with the same broadcast id
        mBassClientService.addSelectSourceRequest(scanResult2, false);
        onScanResult(mSourceDevice2, TEST_BROADCAST_ID);
        mInOrderMethodProxy
        mInOrderMethodProxy
                .verify(mMethodProxy, never())
                .verify(mMethodProxy, never())
                .periodicAdvertisingManagerRegisterSync(
                .periodicAdvertisingManagerRegisterSync(
@@ -2491,7 +2467,9 @@ public class BassClientServiceTest {
                        ScanRecord.parseFromBytes(scanRecord),
                        ScanRecord.parseFromBytes(scanRecord),
                        0);
                        0);


        mBassClientService.addSelectSourceRequest(scanResult, false);
        prepareConnectedDeviceGroup();
        startSearchingForSources();
        mCallbackCaptor.getValue().onScanResult(ScanSettings.CALLBACK_TYPE_ALL_MATCHES, scanResult);
        verify(mMethodProxy, never())
        verify(mMethodProxy, never())
                .periodicAdvertisingManagerRegisterSync(
                .periodicAdvertisingManagerRegisterSync(
                        any(), any(), anyInt(), anyInt(), any(), any());
                        any(), any(), anyInt(), anyInt(), any(), any());
@@ -2591,7 +2569,9 @@ public class BassClientServiceTest {
                        ScanRecord.parseFromBytes(scanRecord),
                        ScanRecord.parseFromBytes(scanRecord),
                        0);
                        0);


        mBassClientService.addSelectSourceRequest(scanResult, false);
        prepareConnectedDeviceGroup();
        startSearchingForSources();
        mCallbackCaptor.getValue().onScanResult(ScanSettings.CALLBACK_TYPE_ALL_MATCHES, scanResult);
        verify(mMethodProxy)
        verify(mMethodProxy)
                .periodicAdvertisingManagerRegisterSync(
                .periodicAdvertisingManagerRegisterSync(
                        any(), any(), anyInt(), anyInt(), any(), any());
                        any(), any(), anyInt(), anyInt(), any(), any());
@@ -2667,7 +2647,9 @@ public class BassClientServiceTest {
                        ScanRecord.parseFromBytes(scanRecord),
                        ScanRecord.parseFromBytes(scanRecord),
                        0);
                        0);


        mBassClientService.addSelectSourceRequest(scanResult, false);
        prepareConnectedDeviceGroup();
        startSearchingForSources();
        mCallbackCaptor.getValue().onScanResult(ScanSettings.CALLBACK_TYPE_ALL_MATCHES, scanResult);
        verify(mMethodProxy)
        verify(mMethodProxy)
                .periodicAdvertisingManagerRegisterSync(
                .periodicAdvertisingManagerRegisterSync(
                        any(), any(), anyInt(), anyInt(), any(), any());
                        any(), any(), anyInt(), anyInt(), any(), any());
@@ -3318,7 +3300,7 @@ public class BassClientServiceTest {


    @Test
    @Test
    @EnableFlags(Flags.FLAG_LEAUDIO_BROADCAST_EXTRACT_PERIODIC_SCANNER_FROM_STATE_MACHINE)
    @EnableFlags(Flags.FLAG_LEAUDIO_BROADCAST_EXTRACT_PERIODIC_SCANNER_FROM_STATE_MACHINE)
    public void testSelectSource_orderOfSyncRegistering() {
    public void testSelectSource_orderOfSyncRegisteringByPriorityAndRssi() {
        final BluetoothDevice device1 =
        final BluetoothDevice device1 =
                mBluetoothAdapter.getRemoteLeDevice(
                mBluetoothAdapter.getRemoteLeDevice(
                        "00:11:22:33:44:11", BluetoothDevice.ADDRESS_TYPE_RANDOM);
                        "00:11:22:33:44:11", BluetoothDevice.ADDRESS_TYPE_RANDOM);
@@ -3441,20 +3423,42 @@ public class BassClientServiceTest {
                        ScanRecord.parseFromBytes(scanRecord7),
                        ScanRecord.parseFromBytes(scanRecord7),
                        0);
                        0);


        prepareConnectedDeviceGroup();
        startSearchingForSources();

        // Added and executed immidiatelly as no other in queue
        // Added and executed immidiatelly as no other in queue
        mBassClientService.addSelectSourceRequest(scanResult1, false);
        mCallbackCaptor
                .getValue()
                .onScanResult(ScanSettings.CALLBACK_TYPE_ALL_MATCHES, scanResult1);
        // Added to queue with worst rssi
        // Added to queue with worst rssi
        mBassClientService.addSelectSourceRequest(scanResult2, false);
        mCallbackCaptor
                .getValue()
                .onScanResult(ScanSettings.CALLBACK_TYPE_ALL_MATCHES, scanResult2);
        // Added to queue with best rssi
        // Added to queue with best rssi
        mBassClientService.addSelectSourceRequest(scanResult3, false);
        mCallbackCaptor
                .getValue()
                .onScanResult(ScanSettings.CALLBACK_TYPE_ALL_MATCHES, scanResult3);
        // Added to queue with medium rssi
        // Added to queue with medium rssi
        mBassClientService.addSelectSourceRequest(scanResult4, false);
        mCallbackCaptor
        // Added to queue with priority and worst rssi
                .getValue()
        mBassClientService.addSelectSourceRequest(scanResult5, true);
                .onScanResult(ScanSettings.CALLBACK_TYPE_ALL_MATCHES, scanResult4);
        // Added to queue with priority and best rssi
        // Added to queue with worst rssi (increase priority after all)
        mBassClientService.addSelectSourceRequest(scanResult6, true);
        mCallbackCaptor
        // Added to queue with priority and medium rssi
                .getValue()
        mBassClientService.addSelectSourceRequest(scanResult7, true);
                .onScanResult(ScanSettings.CALLBACK_TYPE_ALL_MATCHES, scanResult5);
        // Added to queue with best rssi (increase priority after all)
        mCallbackCaptor
                .getValue()
                .onScanResult(ScanSettings.CALLBACK_TYPE_ALL_MATCHES, scanResult6);
        // Added to queue with medium rssi (increase priority after all)
        mCallbackCaptor
                .getValue()
                .onScanResult(ScanSettings.CALLBACK_TYPE_ALL_MATCHES, scanResult7);

        // Increase priority of last 3 of them
        mBassClientService.addSelectSourceRequest(broadcastId5, true);
        mBassClientService.addSelectSourceRequest(broadcastId6, true);
        mBassClientService.addSelectSourceRequest(broadcastId7, true);


        ArgumentCaptor<ScanResult> resultCaptor = ArgumentCaptor.forClass(ScanResult.class);
        ArgumentCaptor<ScanResult> resultCaptor = ArgumentCaptor.forClass(ScanResult.class);
        mInOrderMethodProxy
        mInOrderMethodProxy
@@ -3555,6 +3559,215 @@ public class BassClientServiceTest {
                .isEqualTo(broadcastId2);
                .isEqualTo(broadcastId2);
    }
    }


    @Test
    @EnableFlags({
        Flags.FLAG_LEAUDIO_SORT_SCANS_TO_SYNC_BY_FAILS,
        Flags.FLAG_LEAUDIO_BROADCAST_EXTRACT_PERIODIC_SCANNER_FROM_STATE_MACHINE
    })
    public void testSelectSource_orderOfSyncRegisteringByRssiAndFailsCounter() {
        final BluetoothDevice device1 =
                mBluetoothAdapter.getRemoteLeDevice(
                        "00:11:22:33:44:11", BluetoothDevice.ADDRESS_TYPE_RANDOM);
        final BluetoothDevice device2 =
                mBluetoothAdapter.getRemoteLeDevice(
                        "00:11:22:33:44:22", BluetoothDevice.ADDRESS_TYPE_RANDOM);
        final BluetoothDevice device3 =
                mBluetoothAdapter.getRemoteLeDevice(
                        "00:11:22:33:44:33", BluetoothDevice.ADDRESS_TYPE_RANDOM);
        final int broadcastId1 = 1111;
        final int broadcastId2 = 2222;
        final int broadcastId3 = 3333;

        byte[] scanRecord1 = getScanRecord(broadcastId1);
        byte[] scanRecord2 = getScanRecord(broadcastId2);
        byte[] scanRecord3 = getScanRecord(broadcastId3);

        ScanResult scanResult1 =
                new ScanResult(
                        device1,
                        0,
                        0,
                        0,
                        0,
                        0,
                        TEST_RSSI + 10,
                        0,
                        ScanRecord.parseFromBytes(scanRecord1),
                        0);
        ScanResult scanResult2 =
                new ScanResult(
                        device2,
                        0,
                        0,
                        0,
                        0,
                        0,
                        TEST_RSSI + 9,
                        0,
                        ScanRecord.parseFromBytes(scanRecord2),
                        0);
        ScanResult scanResult3 =
                new ScanResult(
                        device3,
                        0,
                        0,
                        0,
                        0,
                        0,
                        TEST_RSSI,
                        0,
                        ScanRecord.parseFromBytes(scanRecord3),
                        0);

        prepareConnectedDeviceGroup();
        startSearchingForSources();

        // Test using onSyncEstablishedFailed

        // Added and executed immidiatelly as no other in queue, high rssi
        mCallbackCaptor
                .getValue()
                .onScanResult(ScanSettings.CALLBACK_TYPE_ALL_MATCHES, scanResult1);
        // Added to queue, medium rssi
        mCallbackCaptor
                .getValue()
                .onScanResult(ScanSettings.CALLBACK_TYPE_ALL_MATCHES, scanResult2);
        // Added to queue, low rssi
        mCallbackCaptor
                .getValue()
                .onScanResult(ScanSettings.CALLBACK_TYPE_ALL_MATCHES, scanResult3);

        ArgumentCaptor<ScanResult> resultCaptor = ArgumentCaptor.forClass(ScanResult.class);
        mInOrderMethodProxy
                .verify(mMethodProxy)
                .periodicAdvertisingManagerRegisterSync(
                        any(), resultCaptor.capture(), anyInt(), anyInt(), any(), any());
        assertThat(
                        BassUtils.parseBroadcastId(
                                resultCaptor
                                        .getValue()
                                        .getScanRecord()
                                        .getServiceData()
                                        .get(BassConstants.BAAS_UUID)))
                .isEqualTo(broadcastId1);

        onSyncEstablishedFailed(device1, TEST_SYNC_HANDLE);
        mInOrderMethodProxy
                .verify(mMethodProxy)
                .periodicAdvertisingManagerRegisterSync(
                        any(), resultCaptor.capture(), anyInt(), anyInt(), any(), any());
        assertThat(
                        BassUtils.parseBroadcastId(
                                resultCaptor
                                        .getValue()
                                        .getScanRecord()
                                        .getServiceData()
                                        .get(BassConstants.BAAS_UUID)))
                .isEqualTo(broadcastId2);

        // Added to queue again, high rssi
        mCallbackCaptor
                .getValue()
                .onScanResult(ScanSettings.CALLBACK_TYPE_ALL_MATCHES, scanResult1);

        onSyncEstablishedFailed(device2, TEST_SYNC_HANDLE + 1);
        mInOrderMethodProxy
                .verify(mMethodProxy)
                .periodicAdvertisingManagerRegisterSync(
                        any(), resultCaptor.capture(), anyInt(), anyInt(), any(), any());
        assertThat(
                        BassUtils.parseBroadcastId(
                                resultCaptor
                                        .getValue()
                                        .getScanRecord()
                                        .getServiceData()
                                        .get(BassConstants.BAAS_UUID)))
                .isEqualTo(broadcastId3);

        onSyncEstablished(device3, TEST_SYNC_HANDLE + 2);
        mInOrderMethodProxy
                .verify(mMethodProxy)
                .periodicAdvertisingManagerRegisterSync(
                        any(), resultCaptor.capture(), anyInt(), anyInt(), any(), any());
        assertThat(
                        BassUtils.parseBroadcastId(
                                resultCaptor
                                        .getValue()
                                        .getScanRecord()
                                        .getServiceData()
                                        .get(BassConstants.BAAS_UUID)))
                .isEqualTo(broadcastId1);

        // Restart searching clears the mSyncFailureCounter
        mBassClientService.stopSearchingForSources();
        mInOrderMethodProxy
                .verify(mMethodProxy, times(2))
                .periodicAdvertisingManagerUnregisterSync(any(), any());
        startSearchingForSources();

        // Test using onSyncLost

        // Added and executed immidiatelly as no other in queue, high rssi
        mCallbackCaptor
                .getValue()
                .onScanResult(ScanSettings.CALLBACK_TYPE_ALL_MATCHES, scanResult1);
        // Added to queue, medium rssi
        mCallbackCaptor
                .getValue()
                .onScanResult(ScanSettings.CALLBACK_TYPE_ALL_MATCHES, scanResult2);
        // Added to queue, low rssi
        mCallbackCaptor
                .getValue()
                .onScanResult(ScanSettings.CALLBACK_TYPE_ALL_MATCHES, scanResult3);

        mInOrderMethodProxy
                .verify(mMethodProxy)
                .periodicAdvertisingManagerRegisterSync(
                        any(), resultCaptor.capture(), anyInt(), anyInt(), any(), any());
        assertThat(
                        BassUtils.parseBroadcastId(
                                resultCaptor
                                        .getValue()
                                        .getScanRecord()
                                        .getServiceData()
                                        .get(BassConstants.BAAS_UUID)))
                .isEqualTo(broadcastId1);

        onSyncEstablished(device1, TEST_SYNC_HANDLE);
        mInOrderMethodProxy
                .verify(mMethodProxy)
                .periodicAdvertisingManagerRegisterSync(
                        any(), resultCaptor.capture(), anyInt(), anyInt(), any(), any());
        assertThat(
                        BassUtils.parseBroadcastId(
                                resultCaptor
                                        .getValue()
                                        .getScanRecord()
                                        .getServiceData()
                                        .get(BassConstants.BAAS_UUID)))
                .isEqualTo(broadcastId2);
        onSyncLost();

        // Added to queue again, high rssi
        mCallbackCaptor
                .getValue()
                .onScanResult(ScanSettings.CALLBACK_TYPE_ALL_MATCHES, scanResult1);

        onSyncEstablished(device2, TEST_SYNC_HANDLE + 1);
        mInOrderMethodProxy
                .verify(mMethodProxy)
                .periodicAdvertisingManagerRegisterSync(
                        any(), resultCaptor.capture(), anyInt(), anyInt(), any(), any());
        assertThat(
                        BassUtils.parseBroadcastId(
                                resultCaptor
                                        .getValue()
                                        .getScanRecord()
                                        .getServiceData()
                                        .get(BassConstants.BAAS_UUID)))
                .isEqualTo(broadcastId3);
    }

    @Test
    @Test
    @DisableFlags(Flags.FLAG_LEAUDIO_BROADCAST_EXTRACT_PERIODIC_SCANNER_FROM_STATE_MACHINE)
    @DisableFlags(Flags.FLAG_LEAUDIO_BROADCAST_EXTRACT_PERIODIC_SCANNER_FROM_STATE_MACHINE)
    public void testSelectSource_invalidActiveSource() {
    public void testSelectSource_invalidActiveSource() {