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

Commit 4bb26bb3 authored by Grzegorz Kołodziejczyk's avatar Grzegorz Kołodziejczyk
Browse files

le_audio: Schedule broadcast, unicast callbacks on MainLoop

While handling callback for registered clients a concurent call of
notifying would cause exception and eventually will drop this call. To
avoid dropping notification of registered for callback clients a
schedule on MainLoop is introduced.

Tag: #bug
Bug: 332847049
Test: atest LeAudioServiceTest LeAudioBroadcastServiceTest
Change-Id: Ib91e1c6429f5f9979b445b881364302186214a92
parent bbf35af7
Loading
Loading
Loading
Loading
+71 −28
Original line number Diff line number Diff line
@@ -1042,7 +1042,10 @@ public class LeAudioService extends ProfileService {
                    TAG,
                    "createBroadcast reached maximum allowed broadcasts number: "
                            + getMaximumNumberOfBroadcasts());
            notifyBroadcastStartFailed(BluetoothStatusCodes.ERROR_LOCAL_NOT_ENOUGH_RESOURCES);
            mHandler.post(
                    () ->
                            notifyBroadcastStartFailed(
                                    BluetoothStatusCodes.ERROR_LOCAL_NOT_ENOUGH_RESOURCES));
            return;
        }

@@ -1172,8 +1175,11 @@ public class LeAudioService extends ProfileService {

        LeAudioBroadcastDescriptor descriptor = mBroadcastDescriptors.get(broadcastId);
        if (descriptor == null) {
            mHandler.post(
                    () ->
                            notifyBroadcastUpdateFailed(
                    broadcastId, BluetoothStatusCodes.ERROR_LE_BROADCAST_INVALID_BROADCAST_ID);
                                    broadcastId,
                                    BluetoothStatusCodes.ERROR_LE_BROADCAST_INVALID_BROADCAST_ID));
            Log.e(TAG, "updateBroadcast: No valid descriptor for broadcastId: " + broadcastId);
            return;
        }
@@ -1243,8 +1249,10 @@ public class LeAudioService extends ProfileService {

        LeAudioBroadcastDescriptor descriptor = mBroadcastDescriptors.get(broadcastId);
        if (descriptor == null) {
            mHandler.post(
                    () ->
                            notifyOnBroadcastStopFailed(
                    BluetoothStatusCodes.ERROR_LE_BROADCAST_INVALID_BROADCAST_ID);
                                    BluetoothStatusCodes.ERROR_LE_BROADCAST_INVALID_BROADCAST_ID));
            Log.e(TAG, "stopBroadcast: No valid descriptor for broadcastId: " + broadcastId);
            return;
        }
@@ -1265,8 +1273,10 @@ public class LeAudioService extends ProfileService {

        LeAudioBroadcastDescriptor descriptor = mBroadcastDescriptors.get(broadcastId);
        if (descriptor == null) {
            mHandler.post(
                    () ->
                            notifyOnBroadcastStopFailed(
                    BluetoothStatusCodes.ERROR_LE_BROADCAST_INVALID_BROADCAST_ID);
                                    BluetoothStatusCodes.ERROR_LE_BROADCAST_INVALID_BROADCAST_ID));
            Log.e(TAG, "destroyBroadcast: No valid descriptor for broadcastId: " + broadcastId);
            return;
        }
@@ -2376,7 +2386,10 @@ public class LeAudioService extends ProfileService {
            }

            if (descriptor.isActive()) {
                notifyGroupStatusChanged(groupId, LeAudioStackEvent.GROUP_STATUS_ACTIVE);
                mHandler.post(
                        () ->
                                notifyGroupStatusChanged(
                                        groupId, LeAudioStackEvent.GROUP_STATUS_ACTIVE));
                updateInbandRingtoneForTheGroup(groupId);
            }
        } finally {
@@ -2430,7 +2443,10 @@ public class LeAudioService extends ProfileService {
            Log.d(TAG, "Clear for group: " + groupId);
            descriptor.mHasFallbackDeviceWhenGettingInactive = false;
            clearLostDevicesWhileStreaming(descriptor);
            notifyGroupStatusChanged(groupId, LeAudioStackEvent.GROUP_STATUS_INACTIVE);
            mHandler.post(
                    () ->
                            notifyGroupStatusChanged(
                                    groupId, LeAudioStackEvent.GROUP_STATUS_INACTIVE));
            updateInbandRingtoneForTheGroup(groupId);
        } finally {
            mGroupReadLock.unlock();
@@ -2916,7 +2932,7 @@ public class LeAudioService extends ProfileService {
            }

            descriptor.mCodecStatus = status;
            notifyUnicastCodecConfigChanged(groupId, status);
            mHandler.post(() -> notifyUnicastCodecConfigChanged(groupId, status));

            if (descriptor.isActive()) {
                // Audio framework needs to be notified so it get new codec config
@@ -2940,8 +2956,11 @@ public class LeAudioService extends ProfileService {
                        }

                        if (descriptor.isInactive()) {
                            mHandler.post(
                                    () ->
                                            notifyGroupStatusChanged(
                                    groupId, BluetoothLeAudio.GROUP_STATUS_INACTIVE);
                                                    groupId,
                                                    BluetoothLeAudio.GROUP_STATUS_INACTIVE));
                        }
                    }
                    boolean availableContextChanged =
@@ -3077,7 +3096,11 @@ public class LeAudioService extends ProfileService {
            if (success) {
                Log.d(TAG, "Broadcast broadcastId: " + broadcastId + " created.");
                mBroadcastDescriptors.put(broadcastId, new LeAudioBroadcastDescriptor());
                notifyBroadcastStarted(broadcastId, BluetoothStatusCodes.REASON_LOCAL_APP_REQUEST);
                mHandler.post(
                        () ->
                                notifyBroadcastStarted(
                                        broadcastId,
                                        BluetoothStatusCodes.REASON_LOCAL_APP_REQUEST));
                // Start sending the actual stream
                startBroadcast(broadcastId);

@@ -3097,7 +3120,7 @@ public class LeAudioService extends ProfileService {
                    updateBroadcastActiveDevice(null, mActiveBroadcastAudioDevice, false);
                }

                notifyBroadcastStartFailed(BluetoothStatusCodes.ERROR_UNKNOWN);
                mHandler.post(() -> notifyBroadcastStartFailed(BluetoothStatusCodes.ERROR_UNKNOWN));
            }

            mAwaitingBroadcastCreateResponse = false;
@@ -3121,7 +3144,10 @@ public class LeAudioService extends ProfileService {
            }

            // TODO: Improve reason reporting or extend the native stack event with reason code
            notifyOnBroadcastStopped(broadcastId, BluetoothStatusCodes.REASON_LOCAL_APP_REQUEST);
            mHandler.post(
                    () ->
                            notifyOnBroadcastStopped(
                                    broadcastId, BluetoothStatusCodes.REASON_LOCAL_APP_REQUEST));
            BassClientService bassClientService = getBassClientService();
            if (bassClientService != null) {
                bassClientService.stopReceiversSourceSynchronization(broadcastId);
@@ -3152,8 +3178,11 @@ public class LeAudioService extends ProfileService {
                    Log.d(TAG, "Broadcast broadcastId: " + broadcastId + " stopped.");

                    // Playback stopped
                    notifyPlaybackStopped(broadcastId,
                            BluetoothStatusCodes.REASON_LOCAL_APP_REQUEST);
                    mHandler.post(
                            () ->
                                    notifyPlaybackStopped(
                                            broadcastId,
                                            BluetoothStatusCodes.REASON_LOCAL_APP_REQUEST));

                    transitionFromBroadcastToUnicast();
                    destroyBroadcast(broadcastId);
@@ -3170,8 +3199,11 @@ public class LeAudioService extends ProfileService {
                    }

                    // Playback paused
                    notifyPlaybackStopped(broadcastId,
                            BluetoothStatusCodes.REASON_LOCAL_STACK_REQUEST);
                    mHandler.post(
                            () ->
                                    notifyPlaybackStopped(
                                            broadcastId,
                                            BluetoothStatusCodes.REASON_LOCAL_STACK_REQUEST));

                    if (!Flags.leaudioBroadcastAssistantPeripheralEntrustment()) {
                        if (bassClientService != null) {
@@ -3188,8 +3220,11 @@ public class LeAudioService extends ProfileService {
                    Log.d(TAG, "Broadcast broadcastId: " + broadcastId + " streaming.");

                    // Stream resumed
                    notifyPlaybackStarted(broadcastId,
                            BluetoothStatusCodes.REASON_LOCAL_STACK_REQUEST);
                    mHandler.post(
                            () ->
                                    notifyPlaybackStarted(
                                            broadcastId,
                                            BluetoothStatusCodes.REASON_LOCAL_STACK_REQUEST));

                    clearBroadcastTimeoutCallback();

@@ -3233,7 +3268,10 @@ public class LeAudioService extends ProfileService {
                    return;
                }
                descriptor.mMetadata = stackEvent.broadcastMetadata;
                notifyBroadcastMetadataChanged(broadcastId, stackEvent.broadcastMetadata);
                mHandler.post(
                        () ->
                                notifyBroadcastMetadataChanged(
                                        broadcastId, stackEvent.broadcastMetadata));
            }
        } else if (stackEvent.type == LeAudioStackEvent.EVENT_TYPE_NATIVE_INITIALIZED) {
            mLeAudioNativeIsInitialized = true;
@@ -3249,7 +3287,10 @@ public class LeAudioService extends ProfileService {
        } else if (stackEvent.type == LeAudioStackEvent.EVENT_TYPE_UNICAST_MONITOR_MODE_STATUS) {
            handleUnicastStreamStatusChange(stackEvent.valueInt1, stackEvent.valueInt2);
        } else if (stackEvent.type == LeAudioStackEvent.EVENT_TYPE_GROUP_STREAM_STATUS_CHANGED) {
            notifyGroupStreamStatusChanged(stackEvent.valueInt1, stackEvent.valueInt2);
            mHandler.post(
                    () ->
                            notifyGroupStreamStatusChanged(
                                    stackEvent.valueInt1, stackEvent.valueInt2));
        }
    }

@@ -4085,7 +4126,7 @@ public class LeAudioService extends ProfileService {
            }
            deviceDescriptor.mGroupId = groupId;

            notifyGroupNodeAdded(device, groupId);
            mHandler.post(() -> notifyGroupNodeAdded(device, groupId));
        } finally {
            mGroupWriteLock.unlock();
        }
@@ -4165,7 +4206,7 @@ public class LeAudioService extends ProfileService {
                    updateFallbackUnicastGroupIdForBroadcast(LE_AUDIO_GROUP_ID_INVALID);
                }
            }
            notifyGroupNodeRemoved(device, groupId);
            mHandler.post(() -> notifyGroupNodeRemoved(device, groupId));
        } finally {
            mGroupReadLock.unlock();
        }
@@ -4314,7 +4355,8 @@ public class LeAudioService extends ProfileService {
            int n = mBroadcastCallbacks.beginBroadcast();
            for (int i = 0; i < n; i++) {
                try {
                    mBroadcastCallbacks.getBroadcastItem(i)
                    mBroadcastCallbacks
                            .getBroadcastItem(i)
                            .onBroadcastUpdateFailed(reason, broadcastId);
                } catch (RemoteException e) {
                    continue;
@@ -4330,7 +4372,8 @@ public class LeAudioService extends ProfileService {
            int n = mBroadcastCallbacks.beginBroadcast();
            for (int i = 0; i < n; i++) {
                try {
                    mBroadcastCallbacks.getBroadcastItem(i)
                    mBroadcastCallbacks
                            .getBroadcastItem(i)
                            .onBroadcastMetadataChanged(broadcastId, metadata);
                } catch (RemoteException e) {
                    continue;
@@ -4559,7 +4602,7 @@ public class LeAudioService extends ProfileService {
                    updateBroadcastActiveDevice(null, mActiveBroadcastAudioDevice, false);
                }

                notifyBroadcastStartFailed(BluetoothStatusCodes.ERROR_TIMEOUT);
                mHandler.post(() -> notifyBroadcastStartFailed(BluetoothStatusCodes.ERROR_TIMEOUT));
            }
        }
    }
+18 −0
Original line number Diff line number Diff line
@@ -355,6 +355,8 @@ public class LeAudioBroadcastServiceTest {
        state_event.valueInt1 = broadcastId;
        mService.messageFromNative(state_event);

        TestUtils.waitForLooperToFinishScheduledTask(mService.getMainLooper());

        Assert.assertTrue(mOnBroadcastStoppedCalled);
        Assert.assertFalse(mOnBroadcastStopFailedCalled);
    }
@@ -427,6 +429,8 @@ public class LeAudioBroadcastServiceTest {
        create_event.valueBool1 = false;
        mService.messageFromNative(create_event);

        TestUtils.waitForLooperToFinishScheduledTask(mService.getMainLooper());

        Assert.assertFalse(mOnBroadcastStartedCalled);
        Assert.assertTrue(mOnBroadcastStartFailedCalled);
    }
@@ -549,6 +553,9 @@ public class LeAudioBroadcastServiceTest {

        // Stop non-existing broadcast
        mService.stopBroadcast(broadcastId);

        TestUtils.waitForLooperToFinishScheduledTask(mService.getMainLooper());

        Assert.assertFalse(mOnBroadcastStoppedCalled);
        Assert.assertTrue(mOnBroadcastStopFailedCalled);

@@ -559,6 +566,9 @@ public class LeAudioBroadcastServiceTest {
        meta_builder.setProgramInfo("Public broadcast info");
        mService.updateBroadcast(broadcastId,
                buildBroadcastSettingsFromMetadata(meta_builder.build(), null, 1));

        TestUtils.waitForLooperToFinishScheduledTask(mService.getMainLooper());

        Assert.assertFalse(mOnBroadcastUpdatedCalled);
        Assert.assertTrue(mOnBroadcastUpdateFailedCalled);
    }
@@ -625,6 +635,8 @@ public class LeAudioBroadcastServiceTest {
        create_event.valueBool1 = true;
        mService.messageFromNative(create_event);

        TestUtils.waitForLooperToFinishScheduledTask(mService.getMainLooper());

        // Inject metadata stack event and verify if getter API works as expected
        LeAudioStackEvent state_event =
                new LeAudioStackEvent(LeAudioStackEvent.EVENT_TYPE_BROADCAST_METADATA_CHANGED);
@@ -632,6 +644,8 @@ public class LeAudioBroadcastServiceTest {
        state_event.broadcastMetadata = createBroadcastMetadata();
        mService.messageFromNative(state_event);

        TestUtils.waitForLooperToFinishScheduledTask(mService.getMainLooper());

        List<BluetoothLeBroadcastMetadata> meta_list = mService.getAllBroadcastMetadata();
        Assert.assertNotNull(meta_list);
        Assert.assertNotEquals(meta_list.size(), 0);
@@ -844,6 +858,8 @@ public class LeAudioBroadcastServiceTest {
        BluetoothLeAudioContentMetadata meta = meta_builder.build();
        BluetoothLeBroadcastSettings settings = buildBroadcastSettingsFromMetadata(meta, code, 1);

        TestUtils.waitForLooperToFinishScheduledTask(mService.getMainLooper());

        verifyBroadcastStarted(broadcastId, settings);
        mOnBroadcastStartedCalled = false;
        mOnBroadcastStartFailedCalled = false;
@@ -851,6 +867,8 @@ public class LeAudioBroadcastServiceTest {
        // verify creating another broadcast will fail
        mService.createBroadcast(settings);

        TestUtils.waitForLooperToFinishScheduledTask(mService.getMainLooper());

        Assert.assertFalse(mOnBroadcastStartedCalled);
        Assert.assertTrue(mOnBroadcastStartFailedCalled);
        Assert.assertEquals(