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

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

Merge "Bass: Do not notify about source lost immediately" into main

parents f4bac114 588c7b6a
Loading
Loading
Loading
Loading
+178 −59
Original line number Diff line number Diff line
@@ -124,6 +124,7 @@ public class BassClientService extends ProfileService {
    @VisibleForTesting static final int MESSAGE_SYNC_TIMEOUT = 1;
    @VisibleForTesting static final int MESSAGE_BIG_MONITOR_TIMEOUT = 2;
    @VisibleForTesting static final int MESSAGE_BROADCAST_MONITOR_TIMEOUT = 3;
    @VisibleForTesting static final int MESSAGE_SYNC_LOST_TIMEOUT = 4;

    /* 1 minute timeout for primary device reconnection in Private Broadcast case */
    private static final int DIALING_OUT_TIMEOUT_MS = 60000;
@@ -137,6 +138,9 @@ public class BassClientService extends ProfileService {
    // 5 minutes timeout for monitoring broadcaster
    private static final Duration sBroadcasterMonitorTimeout = Duration.ofMinutes(5);

    // 5 seconds timeout for sync Lost notification
    private static final Duration sSyncLostTimeout = Duration.ofSeconds(5);

    private enum PauseType {
        HOST_INTENTIONAL,
        SINK_UNINTENTIONAL
@@ -216,27 +220,65 @@ public class BassClientService extends ProfileService {
                                clearAllSyncData();
                                break;
                            }
                        default:
                            break;
                    }
                }
            };

    @VisibleForTesting public final TimeoutHandler mTimeoutHandler = new TimeoutHandler();

    @VisibleForTesting
    public final class TimeoutHandler {
        private final Map<Integer, Handler> mHandlers = new HashMap<>();

        @VisibleForTesting
        public Handler getOrCreateHandler(int broadcastId) {
            return mHandlers.computeIfAbsent(
                    broadcastId,
                    key ->
                            new Handler(Looper.getMainLooper()) {
                                @Override
                                public void handleMessage(Message msg) {
                                    switch (msg.what) {
                                        case MESSAGE_SYNC_LOST_TIMEOUT:
                                            {
                                                log("MESSAGE_SYNC_LOST_TIMEOUT");
                                                // fall through
                                            }
                                        case MESSAGE_BROADCAST_MONITOR_TIMEOUT:
                                            {
                                                log("MESSAGE_BROADCAST_MONITOR_TIMEOUT");
                                int broadcastId = msg.arg1;
                                                List<Integer> activeSyncedSrc =
                                                        new ArrayList<>(getActiveSyncedSources());
                                                if (activeSyncedSrc.contains(
                                                        getSyncHandleForBroadcastId(broadcastId))) {
                                                    break;
                                                }
                                log("Notify broadcast source lost, broadcast id: " + broadcastId);
                                                // Clear from cache to make possible sync again
                                                // (only during active searching)
                                                synchronized (mSearchScanCallbackLock) {
                                                    if (mSearchScanCallback != null) {
                                                        mCachedBroadcasts.remove(broadcastId);
                                                    }
                                                }
                                                log(
                                                        "Notify broadcast source lost, broadcast"
                                                                + " id: "
                                                                + broadcastId);
                                                mCallbacks.notifySourceLost(broadcastId);
                                                if (!isSinkUnintentionalPauseType(broadcastId)) {
                                                    break;
                                                }
                                                // fall through
                                            }
                                        case MESSAGE_BIG_MONITOR_TIMEOUT:
                                            {
                                                log("MESSAGE_BIG_MONITOR_TIMEOUT");
                                int broadcastId = msg.arg1;
                                                stopSourceReceivers(broadcastId);
                                                synchronized (mSearchScanCallbackLock) {
                                    // when searching is stopped then clear all sync data
                                                    // when searching is stopped then clear all sync
                                                    // data
                                                    if (mSearchScanCallback == null) {
                                                        clearAllSyncData();
                                                    }
@@ -246,8 +288,62 @@ public class BassClientService extends ProfileService {
                                        default:
                                            break;
                                    }
                                    Handler handler = getOrCreateHandler(broadcastId);
                                    if (!handler.hasMessagesOrCallbacks()) {
                                        mHandlers.remove(broadcastId);
                                    }
                                }
                            });
        }

        void start(int broadcastId, int msg, Duration duration) {
            Handler handler = getOrCreateHandler(broadcastId);
            log(
                    "Started timeout: "
                            + ("broadcastId: " + broadcastId)
                            + (", msg: " + msg)
                            + (", duration: " + duration));
            handler.sendEmptyMessageDelayed(msg, duration.toMillis());
        }

        void stop(int broadcastId, int msg) {
            if (!mHandlers.containsKey(broadcastId)) {
                return;
            }
            Handler handler = getOrCreateHandler(broadcastId);
            handler.removeMessages(msg);
            if (!handler.hasMessagesOrCallbacks()) {
                mHandlers.remove(broadcastId);
            }
        }

        void stopAll() {
            for (Handler handler : mHandlers.values()) {
                handler.removeCallbacksAndMessages(null);
            }
            mHandlers.clear();
        }

        void stopAll(int msg) {
            Iterator<Map.Entry<Integer, Handler>> iterator = mHandlers.entrySet().iterator();
            while (iterator.hasNext()) {
                Map.Entry<Integer, Handler> entry = iterator.next();
                Handler handler = entry.getValue();
                handler.removeMessages(msg);
                if (!handler.hasMessagesOrCallbacks()) {
                    iterator.remove();
                }
            }
        }

        boolean isStarted(int broadcastId, int msg) {
            if (!mHandlers.containsKey(broadcastId)) {
                return false;
            }
            Handler handler = getOrCreateHandler(broadcastId);
            return handler.hasMessages(msg);
        }
    }
            };

    public BassClientService(Context ctx) {
        super(ctx);
@@ -710,6 +806,7 @@ public class BassClientService extends ProfileService {
        }

        mHandler.removeCallbacksAndMessages(null);
        mTimeoutHandler.stopAll();

        setBassClientService(null);
        if (!leaudioBroadcastExtractPeriodicScannerFromStateMachine()) {
@@ -1041,11 +1138,9 @@ public class BassClientService extends ProfileService {
                    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;
                    log("Started MESSAGE_BIG_MONITOR_TIMEOUT");
                    mHandler.sendMessageDelayed(newMsg, sBigMonitorTimeout.toMillis());
                    mTimeoutHandler.stop(broadcastId, MESSAGE_BIG_MONITOR_TIMEOUT);
                    mTimeoutHandler.start(
                            broadcastId, MESSAGE_BIG_MONITOR_TIMEOUT, sBigMonitorTimeout);
                }
            }
        } else if (isEmptyBluetoothDevice(receiveState.getSourceDevice())) {
@@ -1832,8 +1927,10 @@ public class BassClientService extends ProfileService {
                                        TAG,
                                        "Broadcast Source Found: Broadcast ID: " + broadcastId);

                                if (broadcastId != BassConstants.INVALID_BROADCAST_ID
                                        && !mCachedBroadcasts.containsKey(broadcastId)) {
                                if (broadcastId == BassConstants.INVALID_BROADCAST_ID) {
                                    return;
                                }
                                if (!mCachedBroadcasts.containsKey(broadcastId)) {
                                    log("selectBroadcastSource: broadcastId " + broadcastId);
                                    mCachedBroadcasts.put(broadcastId, result);
                                    if (leaudioBroadcastExtractPeriodicScannerFromStateMachine()) {
@@ -1848,6 +1945,14 @@ public class BassClientService extends ProfileService {
                                            }
                                        }
                                    }
                                } else if (leaudioBroadcastResyncHelper()
                                        && mTimeoutHandler.isStarted(
                                                broadcastId, MESSAGE_SYNC_LOST_TIMEOUT)) {
                                    mTimeoutHandler.stop(broadcastId, MESSAGE_SYNC_LOST_TIMEOUT);
                                    mTimeoutHandler.start(
                                            broadcastId,
                                            MESSAGE_SYNC_LOST_TIMEOUT,
                                            sSyncLostTimeout);
                                }
                            }
                        }
@@ -1970,6 +2075,7 @@ public class BassClientService extends ProfileService {

    private void clearAllSyncData() {
        log("clearAllSyncData");
        mTimeoutHandler.stopAll(MESSAGE_SYNC_LOST_TIMEOUT);
        mSourceSyncRequestsQueue.clear();
        mSyncFailureCounter.clear();
        mPendingSourcesToAdd.clear();
@@ -2047,7 +2153,7 @@ public class BassClientService extends ProfileService {
                        }
                    }
                } else {
                    mHandler.removeMessages(MESSAGE_BROADCAST_MONITOR_TIMEOUT);
                    mTimeoutHandler.stop(broadcastId, MESSAGE_BROADCAST_MONITOR_TIMEOUT);
                }

                // update valid sync handle in mPeriodicAdvCallbacksMap
@@ -2100,11 +2206,12 @@ public class BassClientService extends ProfileService {
                    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());
                    if (!mTimeoutHandler.isStarted(
                            broadcastId, MESSAGE_BROADCAST_MONITOR_TIMEOUT)) {
                        mTimeoutHandler.start(
                                broadcastId,
                                MESSAGE_BROADCAST_MONITOR_TIMEOUT,
                                sBroadcasterMonitorTimeout);
                    }
                    addSelectSourceRequest(broadcastId, true);
                } else {
@@ -2183,16 +2290,23 @@ public class BassClientService extends ProfileService {
                    int failsCounter = mSyncFailureCounter.getOrDefault(broadcastId, 0) + 1;
                    mSyncFailureCounter.put(broadcastId, failsCounter);
                }
                mTimeoutHandler.stop(broadcastId, MESSAGE_SYNC_LOST_TIMEOUT);
                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());
                    if (!mTimeoutHandler.isStarted(
                            broadcastId, MESSAGE_BROADCAST_MONITOR_TIMEOUT)) {
                        mTimeoutHandler.start(
                                broadcastId,
                                MESSAGE_BROADCAST_MONITOR_TIMEOUT,
                                sBroadcasterMonitorTimeout);
                    }
                    addSelectSourceRequest(broadcastId, true);
                } else {
                    // Clear from cache to make possible sync again (only during active searching)
                    if (leaudioBroadcastResyncHelper()) {
                        mTimeoutHandler.start(
                                broadcastId, MESSAGE_SYNC_LOST_TIMEOUT, sSyncLostTimeout);
                    } else {
                        // Clear from cache to make possible sync again (only during active
                        // searching)
                        synchronized (mSearchScanCallbackLock) {
                            if (mSearchScanCallback != null) {
                                mCachedBroadcasts.remove(broadcastId);
@@ -2203,6 +2317,7 @@ public class BassClientService extends ProfileService {
                    }
                }
            }
        }

        @Override
        public void onBigInfoAdvertisingReport(int syncHandle, boolean encrypted) {
@@ -2480,7 +2595,7 @@ public class BassClientService extends ProfileService {
                        + broadcastId
                        + ", hasPriority: "
                        + hasPriority);

        mTimeoutHandler.stop(broadcastId, MESSAGE_SYNC_LOST_TIMEOUT);
        ScanResult scanRes = getCachedBroadcast(broadcastId);
        if (scanRes != null) {
            ScanRecord scanRecord = scanRes.getScanRecord();
@@ -2572,9 +2687,11 @@ public class BassClientService extends ProfileService {
                cancelActiveSync(syncHandle);
            } else {
                Boolean canceledActiveSync = false;
                int broadcstIdToLostMonitoring = BassConstants.INVALID_BROADCAST_ID;
                for (int syncHandle : activeSyncedSrc) {
                    if (!isAnyReceiverSyncedToBroadcast(getBroadcastIdForSyncHandle(syncHandle))) {
                        canceledActiveSync = true;
                        broadcstIdToLostMonitoring = getBroadcastIdForSyncHandle(syncHandle);
                        cancelActiveSync(syncHandle);
                        break;
                    }
@@ -2582,8 +2699,11 @@ public class BassClientService extends ProfileService {
                if (!canceledActiveSync) {
                    int syncHandle = activeSyncedSrc.get(0);
                    // removing the 1st synced source before proceeding to add new
                    broadcstIdToLostMonitoring = getBroadcastIdForSyncHandle(syncHandle);
                    cancelActiveSync(syncHandle);
                }
                mTimeoutHandler.start(
                        broadcstIdToLostMonitoring, MESSAGE_SYNC_LOST_TIMEOUT, sSyncLostTimeout);
            }
        }

@@ -3447,14 +3567,13 @@ public class BassClientService extends ProfileService {
            return;
        }
        log("stopBigMonitoring");
        mHandler.removeMessages(MESSAGE_BIG_MONITOR_TIMEOUT);
        mHandler.removeMessages(MESSAGE_BROADCAST_MONITOR_TIMEOUT);

        mPausedBroadcastSinks.clear();

        Iterator<Integer> iterator = mPausedBroadcastIds.keySet().iterator();
        while (iterator.hasNext()) {
            int pausedBroadcastId = iterator.next();
            mTimeoutHandler.stop(pausedBroadcastId, MESSAGE_BIG_MONITOR_TIMEOUT);
            mTimeoutHandler.stop(pausedBroadcastId, MESSAGE_BROADCAST_MONITOR_TIMEOUT);
            iterator.remove();
            synchronized (mSearchScanCallbackLock) {
                // when searching is stopped then stop active sync
@@ -3475,8 +3594,8 @@ public class BassClientService extends ProfileService {
        while (iterator.hasNext()) {
            int pausedBroadcastId = iterator.next();
            if (!isAnyReceiverSyncedToBroadcast(pausedBroadcastId)) {
                mHandler.removeMessages(MESSAGE_BIG_MONITOR_TIMEOUT);
                mHandler.removeMessages(MESSAGE_BROADCAST_MONITOR_TIMEOUT);
                mTimeoutHandler.stop(pausedBroadcastId, MESSAGE_BIG_MONITOR_TIMEOUT);
                mTimeoutHandler.stop(pausedBroadcastId, MESSAGE_BROADCAST_MONITOR_TIMEOUT);
                iterator.remove();
                synchronized (mSearchScanCallbackLock) {
                    // when searching is stopped then stop active sync
@@ -3494,8 +3613,8 @@ public class BassClientService extends ProfileService {
            return;
        }
        log("stopBigMonitoring broadcastId: " + broadcastId + ", hostInitiated: " + hostInitiated);
        mHandler.removeMessages(MESSAGE_BIG_MONITOR_TIMEOUT);
        mHandler.removeMessages(MESSAGE_BROADCAST_MONITOR_TIMEOUT);
        mTimeoutHandler.stop(broadcastId, MESSAGE_BIG_MONITOR_TIMEOUT);
        mTimeoutHandler.stop(broadcastId, MESSAGE_BROADCAST_MONITOR_TIMEOUT);
        if (hostInitiated) {
            mPausedBroadcastIds.put(broadcastId, PauseType.HOST_INTENTIONAL);
        } else {
+270 −50

File changed.

Preview size limit exceeded, changes collapsed.

+3 −2
Original line number Diff line number Diff line
@@ -316,6 +316,8 @@ public final class BluetoothLeBroadcastAssistant implements BluetoothProfile, Au
         * Callback invoked when a new Broadcast Source is found together with the {@link
         * BluetoothLeBroadcastMetadata}.
         *
         * <p>Broadcast is found when it is available for user to synchronize with it.
         *
         * @param source {@link BluetoothLeBroadcastMetadata} representing a Broadcast Source
         * @hide
         */
@@ -443,8 +445,7 @@ public final class BluetoothLeBroadcastAssistant implements BluetoothProfile, Au
        /**
         * Callback invoked when the Broadcast Source is lost together with source broadcast id.
         *
         * <p>This callback is to notify source lost due to periodic advertising sync lost. Callback
         * client can know that the source notified by {@link
         * <p>Callback client can know that the source notified by {@link
         * Callback#onSourceFound(BluetoothLeBroadcastMetadata)} before is not available any more
         * after this callback.
         *