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

Commit dabc40f0 authored by Michal Belusiak (xWF)'s avatar Michal Belusiak (xWF) Committed by Gerrit Code Review
Browse files

Merge changes I95176393,Idee9165d into main

* changes:
  Bass: Broadcast resync helper, simplified sink pause detection
  Bass: Broadcast resync helper, out of range case
parents 3999f9e3 b08f8c0e
Loading
Loading
Loading
Loading
+105 −106
Original line number Diff line number Diff line
@@ -123,8 +123,8 @@ public class BassClientService extends ProfileService {
    private static final int BROADCAST_STATE_STREAMING = 6;

    @VisibleForTesting static final int MESSAGE_SYNC_TIMEOUT = 1;
    @VisibleForTesting static final int MESSAGE_BIG_CHECK_START = 2;
    @VisibleForTesting static final int MESSAGE_BIG_CHECK_STOP = 3;
    @VisibleForTesting static final int MESSAGE_BIG_MONITOR_TIMEOUT = 2;
    @VisibleForTesting static final int MESSAGE_BROADCAST_MONITOR_TIMEOUT = 3;

    /* 1 minute timeout for primary device reconnection in Private Broadcast case */
    private static final int DIALING_OUT_TIMEOUT_MS = 60000;
@@ -132,19 +132,14 @@ public class BassClientService extends ProfileService {
    // 30 secs timeout for keeping PSYNC active when searching is stopped
    private static final Duration sSyncActiveTimeout = Duration.ofSeconds(30);

    // 6 seconds to start BIG check. It has to be greater than kPeriodicSyncTimeout
    private static final Duration sBigCheckStart = Duration.ofSeconds(6);
    // 30 minutes timeout for monitoring BIG resynchronization
    private static final Duration sBigMonitorTimeout = Duration.ofMinutes(30);

    // 2 second for check if BIG exist
    private static final Duration sBigCheckStop = Duration.ofSeconds(2);

    // 5 minutes timeout for monitoring BIG resynchronization
    private static final Duration sBigMonitorTimeout = Duration.ofMinutes(5);
    // 5 minutes timeout for monitoring broadcaster
    private static final Duration sBroadcasterMonitorTimeout = Duration.ofMinutes(5);

    private enum PauseType {
        HOST_INTENTIONAL,
        SINK_UNKNOWN,
        SINK_INTENTIONAL,
        SINK_UNINTENTIONAL
    }

@@ -171,7 +166,6 @@ public class BassClientService extends ProfileService {
    private final Map<BluetoothDevice, BluetoothLeBroadcastMetadata> mBroadcastMetadataMap =
            new ConcurrentHashMap<>();
    private final HashSet<BluetoothDevice> mPausedBroadcastSinks = new HashSet<>();
    private final HashSet<Integer> mBigInfoReportExistForBroadcast = new HashSet<>();
    private final Map<Integer, PauseType> mPausedBroadcastIds = new HashMap<>();
    private final Deque<AddSourceData> mPendingAddSources = new ArrayDeque<>();
    private final Map<Integer, HashSet<BluetoothDevice>> mLocalBroadcastReceivers =
@@ -219,52 +213,35 @@ public class BassClientService extends ProfileService {
                    switch (msg.what) {
                        case MESSAGE_SYNC_TIMEOUT:
                            {
                                if (!leaudioBroadcastResyncHelper()) {
                                    clearAllSyncData();
                                    break;
                                }
                                log("MESSAGE_SYNC_TIMEOUT");
                                int broadcastId = msg.arg1;
                                stopBigMonitoring(broadcastId, false);
                                synchronized (mSearchScanCallbackLock) {
                                    // when searching is stopped then clear all sync data
                                    if (mSearchScanCallback == null) {
                                clearAllSyncData();
                                    }
                                }
                                break;
                            }
                        case MESSAGE_BIG_CHECK_START:
                        case MESSAGE_BROADCAST_MONITOR_TIMEOUT:
                            {
                                log("MESSAGE_BIG_CHECK_START");
                                log("MESSAGE_BROADCAST_MONITOR_TIMEOUT");
                                int broadcastId = msg.arg1;
                                mBigInfoReportExistForBroadcast.remove(broadcastId);
                                mHandler.removeMessages(MESSAGE_BIG_CHECK_STOP);
                                Message newMsg = mHandler.obtainMessage(MESSAGE_BIG_CHECK_STOP);
                                newMsg.arg1 = broadcastId;
                                mHandler.sendMessageDelayed(newMsg, sBigCheckStop.toMillis());
                                List<Integer> activeSyncedSrc =
                                        new ArrayList<>(getActiveSyncedSources());
                                if (activeSyncedSrc.contains(
                                        getSyncHandleForBroadcastId(broadcastId))) {
                                    break;
                                }
                        case MESSAGE_BIG_CHECK_STOP:
                                log("Notify broadcast source lost, broadcast id: " + broadcastId);
                                mCallbacks.notifySourceLost(broadcastId);
                                // fall through
                            }
                        case MESSAGE_BIG_MONITOR_TIMEOUT:
                            {
                                log("MESSAGE_BIG_CHECK_STOP");
                                log("MESSAGE_BIG_MONITOR_TIMEOUT");
                                int broadcastId = msg.arg1;
                                if (mBigInfoReportExistForBroadcast.contains(broadcastId)) {
                                    mPausedBroadcastIds.put(
                                            broadcastId, PauseType.SINK_INTENTIONAL);
                                    logPausedBroadcastsAndSinks();
                                } else {
                                    mPausedBroadcastIds.put(
                                            broadcastId, PauseType.SINK_UNINTENTIONAL);
                                    cacheSuspendingSources(broadcastId);
                                stopSourceReceivers(broadcastId);
                                synchronized (mSearchScanCallbackLock) {
                                    // when searching is stopped then clear all sync data
                                    if (mSearchScanCallback == null) {
                                        clearAllSyncData();
                                    }
                                }
                                // Timer starts even if pause is SINK_INTENTIONAL to keep sync in
                                // case that buds send SyncInfo Request
                                mHandler.removeMessages(MESSAGE_SYNC_TIMEOUT);
                                log("Started timeout for canceling syncs");
                                Message newMsg = mHandler.obtainMessage(MESSAGE_SYNC_TIMEOUT);
                                newMsg.arg1 = broadcastId;
                                mHandler.sendMessageDelayed(newMsg, sBigMonitorTimeout.toMillis());
                                break;
                            }
                        default:
@@ -1045,28 +1022,35 @@ public class BassClientService extends ProfileService {
                && !isLocalBroadcast(receiveState)
                && !isEmptyBluetoothDevice(receiveState.getSourceDevice())
                && !isHostPauseType(broadcastId)) {
            boolean isPlaying = false;
            boolean isReadyToAutoResync = false;
            if (receiveState.getPaSyncState()
                    == BluetoothLeBroadcastReceiveState.PA_SYNC_STATE_SYNCHRONIZED) {
                isReadyToAutoResync = true;
            } else {
                for (int i = 0; i < receiveState.getNumSubgroups(); i++) {
                    Long syncState = receiveState.getBisSyncState().get(i);
                    /* Synced to BIS */
                    if (syncState != BassConstants.BIS_SYNC_NOT_SYNC_TO_BIS
                            && syncState != BassConstants.BIS_SYNC_FAILED_SYNC_TO_BIG) {
                    isPlaying = true;
                        isReadyToAutoResync = true;
                        break;
                    }
                }
            }

            if (isPlaying) {
            if (isReadyToAutoResync) {
                stopBigMonitoring(broadcastId, false);
            } else if (!mPausedBroadcastIds.containsKey(broadcastId)) {
                if (mCachedBroadcasts.containsKey(broadcastId)) {
                    addSelectSourceRequest(broadcastId, true);
                    mPausedBroadcastIds.put(broadcastId, PauseType.SINK_UNKNOWN);
                    logPausedBroadcastsAndSinks();
                    mHandler.removeMessages(MESSAGE_BIG_CHECK_START);
                    Message newMsg = mHandler.obtainMessage(MESSAGE_BIG_CHECK_START);
                    mPausedBroadcastIds.put(broadcastId, PauseType.SINK_UNINTENTIONAL);
                    cacheSuspendingSources(broadcastId);

                    mHandler.removeMessages(MESSAGE_BIG_MONITOR_TIMEOUT);
                    Message newMsg = mHandler.obtainMessage(MESSAGE_BIG_MONITOR_TIMEOUT);
                    newMsg.arg1 = broadcastId;
                    mHandler.sendMessageDelayed(newMsg, sBigCheckStart.toMillis());
                    log("Started MESSAGE_BIG_MONITOR_TIMEOUT");
                    mHandler.sendMessageDelayed(newMsg, sBigMonitorTimeout.toMillis());
                }
            }
        } else if (isEmptyBluetoothDevice(receiveState.getSourceDevice())) {
@@ -1093,7 +1077,7 @@ public class BassClientService extends ProfileService {
            /* Assistant become inactive */
            if (mIsAssistantActive
                    && mPausedBroadcastSinks.isEmpty()
                    && !isAnySinkPauseType(broadcastId)) {
                    && !isSinkUnintentionalPauseType(broadcastId)) {
                mIsAssistantActive = false;
                mUnicastSourceStreamStatus = Optional.empty();
                leAudioService.activeBroadcastAssistantNotification(false);
@@ -2057,15 +2041,18 @@ public class BassClientService extends ProfileService {
                        null);
                addActiveSyncedSource(syncHandle);

                if (!leaudioBroadcastResyncHelper()) {
                    synchronized (mSearchScanCallbackLock) {
                    // when searching is stopped then start timer to stop active sync
                        // when searching is stopped then start timer to stop active syncs
                        if (mSearchScanCallback == null) {
                            mHandler.removeMessages(MESSAGE_SYNC_TIMEOUT);
                        log("Started timeout for canceling syncs");
                        Message newMsg = mHandler.obtainMessage(MESSAGE_SYNC_TIMEOUT);
                        newMsg.arg1 = broadcastId;
                        mHandler.sendMessageDelayed(newMsg, sSyncActiveTimeout.toMillis());
                            log("Started MESSAGE_SYNC_TIMEOUT");
                            mHandler.sendEmptyMessageDelayed(
                                    MESSAGE_SYNC_TIMEOUT, sSyncActiveTimeout.toMillis());
                        }
                    }
                } else {
                    mHandler.removeMessages(MESSAGE_BROADCAST_MONITOR_TIMEOUT);
                }

                // update valid sync handle in mPeriodicAdvCallbacksMap
@@ -2113,17 +2100,26 @@ public class BassClientService extends ProfileService {
                        }
                    }
                }
                stopBigMonitoring(broadcastId, false);
                synchronized (mSourceSyncRequestsQueue) {
                    int failsCounter = mSyncFailureCounter.getOrDefault(broadcastId, 0) + 1;
                    mSyncFailureCounter.put(broadcastId, failsCounter);
                }
                synchronized (mSearchScanCallbackLock) {
                if (isSinkUnintentionalPauseType(broadcastId)) {
                    if (!mHandler.hasMessages(MESSAGE_BROADCAST_MONITOR_TIMEOUT)) {
                        Message newMsg = mHandler.obtainMessage(MESSAGE_BROADCAST_MONITOR_TIMEOUT);
                        newMsg.arg1 = broadcastId;
                        log("Started MESSAGE_BROADCAST_MONITOR_TIMEOUT");
                        mHandler.sendMessageDelayed(newMsg, sBroadcasterMonitorTimeout.toMillis());
                    }
                    addSelectSourceRequest(broadcastId, true);
                } else {
                    // Clear from cache to make possible sync again (only during active searching)
                    synchronized (mSearchScanCallbackLock) {
                        if (mSearchScanCallback != null) {
                            mCachedBroadcasts.remove(broadcastId);
                        }
                    }
                }
                mPeriodicAdvCallbacksMap.remove(BassConstants.INVALID_SYNC_HANDLE);
            }
            handleSelectSourceRequest();
@@ -2186,24 +2182,33 @@ public class BassClientService extends ProfileService {
        public void onSyncLost(int syncHandle) {
            int broadcastId = getBroadcastIdForSyncHandle(syncHandle);
            log("OnSyncLost: syncHandle=" + syncHandle + ", broadcastID=" + broadcastId);
            clearAllDataForSyncHandle(syncHandle);
            if (broadcastId != BassConstants.INVALID_BROADCAST_ID) {
                if (leaudioBroadcastMonitorSourceSyncStatus()) {
                    log("Notify broadcast source lost, broadcast id: " + broadcastId);
                    mCallbacks.notifySourceLost(broadcastId);
                }
                stopBigMonitoring(broadcastId, false);
                synchronized (mSourceSyncRequestsQueue) {
                    int failsCounter = mSyncFailureCounter.getOrDefault(broadcastId, 0) + 1;
                    mSyncFailureCounter.put(broadcastId, failsCounter);
                }
                if (isSinkUnintentionalPauseType(broadcastId)) {
                    if (!mHandler.hasMessages(MESSAGE_BROADCAST_MONITOR_TIMEOUT)) {
                        Message newMsg = mHandler.obtainMessage(MESSAGE_BROADCAST_MONITOR_TIMEOUT);
                        newMsg.arg1 = broadcastId;
                        log("Started MESSAGE_BROADCAST_MONITOR_TIMEOUT");
                        mHandler.sendMessageDelayed(newMsg, sBroadcasterMonitorTimeout.toMillis());
                    }
            clearAllDataForSyncHandle(syncHandle);
                    addSelectSourceRequest(broadcastId, true);
                } else {
                    // Clear from cache to make possible sync again (only during active searching)
                    synchronized (mSearchScanCallbackLock) {
                        if (mSearchScanCallback != null) {
                            mCachedBroadcasts.remove(broadcastId);
                        }
                    }
                    if (leaudioBroadcastMonitorSourceSyncStatus()) {
                        log("Notify broadcast source lost, broadcast id: " + broadcastId);
                        mCallbacks.notifySourceLost(broadcastId);
                    }
                }
            }
        }

        @Override
@@ -2238,13 +2243,10 @@ public class BassClientService extends ProfileService {
                log("Notify broadcast source found");
                mCallbacks.notifySourceFound(metaData);
            }
            if (mPausedBroadcastIds.containsKey(broadcastId)) {
                mBigInfoReportExistForBroadcast.add(broadcastId);
                if (mPausedBroadcastIds.get(broadcastId).equals(PauseType.SINK_UNINTENTIONAL)) {
            if (isSinkUnintentionalPauseType(broadcastId)) {
                resumeReceiversSourceSynchronization();
            }
        }
        }

        @Override
        public void onSyncTransferred(BluetoothDevice device, int status) {
@@ -3233,7 +3235,7 @@ public class BassClientService extends ProfileService {
                    }

                    if (!mPausedBroadcastSinks.contains(device)
                            || isAnySinkPauseType(receiveState.getBroadcastId())) {
                            || isSinkUnintentionalPauseType(receiveState.getBroadcastId())) {
                        // Remove device if not paused yet
                        sourcesToRemove.put(device, receiveState.getSourceId());
                    }
@@ -3435,14 +3437,14 @@ public class BassClientService extends ProfileService {
                        + mPausedBroadcastSinks);
    }

    private boolean isAnySinkPauseType(int broadcastId) {
    private boolean isHostPauseType(int broadcastId) {
        return (mPausedBroadcastIds.containsKey(broadcastId)
                && !mPausedBroadcastIds.get(broadcastId).equals(PauseType.HOST_INTENTIONAL));
                && mPausedBroadcastIds.get(broadcastId).equals(PauseType.HOST_INTENTIONAL));
    }

    private boolean isHostPauseType(int broadcastId) {
    private boolean isSinkUnintentionalPauseType(int broadcastId) {
        return (mPausedBroadcastIds.containsKey(broadcastId)
                && mPausedBroadcastIds.get(broadcastId).equals(PauseType.HOST_INTENTIONAL));
                && mPausedBroadcastIds.get(broadcastId).equals(PauseType.SINK_UNINTENTIONAL));
    }

    public void stopBigMonitoring() {
@@ -3450,9 +3452,8 @@ public class BassClientService extends ProfileService {
            return;
        }
        log("stopBigMonitoring");
        mHandler.removeMessages(MESSAGE_SYNC_TIMEOUT);
        mHandler.removeMessages(MESSAGE_BIG_CHECK_START);
        mHandler.removeMessages(MESSAGE_BIG_CHECK_STOP);
        mHandler.removeMessages(MESSAGE_BIG_MONITOR_TIMEOUT);
        mHandler.removeMessages(MESSAGE_BROADCAST_MONITOR_TIMEOUT);

        mPausedBroadcastSinks.clear();

@@ -3479,9 +3480,8 @@ public class BassClientService extends ProfileService {
        while (iterator.hasNext()) {
            int pausedBroadcastId = iterator.next();
            if (!isAnyReceiverSyncedToBroadcast(pausedBroadcastId)) {
                mHandler.removeMessages(MESSAGE_SYNC_TIMEOUT);
                mHandler.removeMessages(MESSAGE_BIG_CHECK_START);
                mHandler.removeMessages(MESSAGE_BIG_CHECK_STOP);
                mHandler.removeMessages(MESSAGE_BIG_MONITOR_TIMEOUT);
                mHandler.removeMessages(MESSAGE_BROADCAST_MONITOR_TIMEOUT);
                iterator.remove();
                synchronized (mSearchScanCallbackLock) {
                    // when searching is stopped then stop active sync
@@ -3499,9 +3499,8 @@ public class BassClientService extends ProfileService {
            return;
        }
        log("stopBigMonitoring broadcastId: " + broadcastId + ", hostInitiated: " + hostInitiated);
        mHandler.removeMessages(MESSAGE_SYNC_TIMEOUT);
        mHandler.removeMessages(MESSAGE_BIG_CHECK_START);
        mHandler.removeMessages(MESSAGE_BIG_CHECK_STOP);
        mHandler.removeMessages(MESSAGE_BIG_MONITOR_TIMEOUT);
        mHandler.removeMessages(MESSAGE_BROADCAST_MONITOR_TIMEOUT);
        if (hostInitiated) {
            mPausedBroadcastIds.put(broadcastId, PauseType.HOST_INTENTIONAL);
        } else {
+260 −715

File changed.

Preview size limit exceeded, changes collapsed.