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

Commit 522506ea authored by Jakub Tyszkowski's avatar Jakub Tyszkowski
Browse files

Broadcaster: Fix not notifying about the started broadcast

The existing code expects the initial broadcast state to be
STREAMING. This turns out to be wrong as the native stack currently
sends the initial state as 'PAUSED' and expects the service is to
actually trigger sending the broadcast audio stream as an additional
step.

This change fixes this by calling onBroadcastStarted() right after
the broadcast is created and then notify any playback state changes
when the native code switches to STREAMING.

Unit tests for broadcast starting and stopping are extended with
callback call verifications.

Bug: 150670922
Bug: 229695142
Fixes: 229695142
Tag: #feature
Test: atest BluetoothInstrumentationTests
Sponsor: jpawlowski@

Change-Id: I0f4618f636f22c09c5abc11373218c753fe46177
parent 76e55632
Loading
Loading
Loading
Loading
+3 −5
Original line number Diff line number Diff line
@@ -1138,6 +1138,9 @@ public class LeAudioService extends ProfileService {
            boolean success = stackEvent.valueBool1;
            if (success) {
                Log.d(TAG, "Broadcast broadcastId: " + broadcastId + " created.");
                notifyBroadcastStarted(broadcastId, BluetoothStatusCodes.REASON_LOCAL_APP_REQUEST);

                // Start sending the actual stream
                startBroadcast(broadcastId);
            } else {
                // TODO: Improve reason reporting or extend the native stack event with reason code
@@ -1201,11 +1204,6 @@ public class LeAudioService extends ProfileService {
            } else if (state == LeAudioStackEvent.BROADCAST_STATE_STREAMING) {
                if (DBG) Log.d(TAG, "Broadcast broadcastId: " + broadcastId + " streaming.");

                if (!mBroadcastsPlaybackMap.containsKey(broadcastId)) {
                    notifyBroadcastStarted(broadcastId,
                            BluetoothStatusCodes.REASON_LOCAL_APP_REQUEST);
                }

                // Stream resumed
                mBroadcastsPlaybackMap.put(broadcastId, true);
                notifyPlaybackStarted(broadcastId, BluetoothStatusCodes.REASON_LOCAL_STACK_REQUEST);
+127 −28
Original line number Diff line number Diff line
@@ -89,6 +89,65 @@ public class LeAudioBroadcastServiceTest {
    // German language code in ISO 639-3
    private static final String TEST_LANGUAGE = "deu";

    private boolean mOnBroadcastStartedCalled = false;
    private boolean mOnBroadcastStartFailedCalled = false;
    private boolean mOnBroadcastStoppedCalled = false;
    private boolean mOnBroadcastStopFailedCalled = false;
    private boolean mOnPlaybackStartedCalled = false;
    private boolean mOnPlaybackStoppedCalled = false;
    private boolean mOnBroadcastUpdatedCalled = false;
    private boolean mOnBroadcastUpdateFailedCalled = false;
    private boolean mOnBroadcastMetadataChangedCalled = false;

    private final IBluetoothLeBroadcastCallback mCallbacks =
            new IBluetoothLeBroadcastCallback.Stub() {
        @Override
        public void onBroadcastStarted(int reason, int broadcastId) {
            mOnBroadcastStartedCalled = true;
        }

        @Override
        public void onBroadcastStartFailed(int reason) {
            mOnBroadcastStartFailedCalled = true;
        }

        @Override
        public void onBroadcastStopped(int reason, int broadcastId) {
            mOnBroadcastStoppedCalled = true;
        }

        @Override
        public void onBroadcastStopFailed(int reason) {
            mOnBroadcastStopFailedCalled = true;
        }

        @Override
        public void onPlaybackStarted(int reason, int broadcastId) {
            mOnPlaybackStartedCalled = true;
        }

        @Override
        public void onPlaybackStopped(int reason, int broadcastId) {
            mOnPlaybackStoppedCalled = true;
        }

        @Override
        public void onBroadcastUpdated(int reason, int broadcastId) {
            mOnBroadcastUpdatedCalled = true;
        }

        @Override
        public void onBroadcastUpdateFailed(int reason, int broadcastId) {
            mOnBroadcastUpdateFailedCalled = true;
        }

        @Override
        public void onBroadcastMetadataChanged(int broadcastId,
                BluetoothLeBroadcastMetadata metadata) {
            mOnBroadcastMetadataChangedCalled = true;
        }
    };

    @Before
    public void setUp() throws Exception {
        mTargetContext = InstrumentationRegistry.getTargetContext();
@@ -103,6 +162,7 @@ public class LeAudioBroadcastServiceTest {
        TestUtils.setAdapterService(mAdapterService);
        doReturn(mDatabaseManager).when(mAdapterService).getDatabase();
        doReturn(true, false).when(mAdapterService).isStartedProfile(anyString());
        doReturn(true).when(mAdapterService).isLeAudioBroadcastSourceSupported();

        mAdapter = BluetoothAdapter.getDefaultAdapter();

@@ -166,17 +226,9 @@ public class LeAudioBroadcastServiceTest {
        });
    }

    @Test
    public void testCreateBroadcastNative() {
        int broadcastId = 243;
    void verifyBroadcastStarted(int broadcastId, byte[] code,
            BluetoothLeAudioContentMetadata meta) {
        int broadcast_profile = 0;
        byte[] code = {0x00, 0x01, 0x00};

        BluetoothLeAudioContentMetadata.Builder meta_builder =
                new BluetoothLeAudioContentMetadata.Builder();
        meta_builder.setLanguage("deu");
        meta_builder.setProgramInfo("Public broadcast info");
        BluetoothLeAudioContentMetadata meta = meta_builder.build();
        mService.createBroadcast(meta, code);

        verify(mNativeInterface, times(1)).createBroadcast(eq(meta.getRawMetadata()), eq(1),
@@ -188,6 +240,8 @@ public class LeAudioBroadcastServiceTest {
        create_event.valueInt1 = broadcastId;
        create_event.valueBool1 = true;
        mService.messageFromNative(create_event);

        // Verify if broadcast is auto-started on start
        verify(mNativeInterface, times(1)).startBroadcast(eq(broadcastId));

        // Notify initial paused state
@@ -205,43 +259,88 @@ public class LeAudioBroadcastServiceTest {

        // Check if metadata is requested when the broadcast starts to stream
        verify(mNativeInterface, times(1)).getBroadcastMetadata(eq(broadcastId));
        Assert.assertFalse(mOnBroadcastStartFailedCalled);
        Assert.assertTrue(mOnBroadcastStartedCalled);
    }

    void verifyBroadcastStopped(int broadcastId) {
        mService.stopBroadcast(broadcastId);
        verify(mNativeInterface, times(1)).stopBroadcast(eq(broadcastId));

        LeAudioStackEvent state_event =
                new LeAudioStackEvent(LeAudioStackEvent.EVENT_TYPE_BROADCAST_STATE);
        state_event.valueInt1 = broadcastId;
        state_event.valueInt2 = LeAudioStackEvent.BROADCAST_STATE_STOPPED;
        mService.messageFromNative(state_event);

        // Verify if broadcast is auto-destroyed on stop
        verify(mNativeInterface, times(1)).destroyBroadcast(eq(broadcastId));

        state_event = new LeAudioStackEvent(LeAudioStackEvent.EVENT_TYPE_BROADCAST_DESTROYED);
        state_event.valueInt1 = broadcastId;
        mService.messageFromNative(state_event);

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

    @Test
    public void testStartStopBroadcastNative() {
        int broadcast_profile = 0;
    public void testCreateBroadcastNative() {
        int broadcastId = 243;
        byte[] code = {0x00, 0x01, 0x00};

        mService.mBroadcastCallbacks.register(mCallbacks);

        BluetoothLeAudioContentMetadata.Builder meta_builder =
                new BluetoothLeAudioContentMetadata.Builder();
        meta_builder.setLanguage("eng");
        meta_builder.setLanguage("deu");
        meta_builder.setProgramInfo("Public broadcast info");

        verifyBroadcastStarted(broadcastId, code, meta_builder.build());
    }

    @Test
    public void testCreateBroadcastNativeFailed() {
        int broadcastId = 243;
        byte[] code = {0x00, 0x01, 0x00};

        mService.mBroadcastCallbacks.register(mCallbacks);

        BluetoothLeAudioContentMetadata.Builder meta_builder =
                new BluetoothLeAudioContentMetadata.Builder();
        meta_builder.setLanguage("deu");
        meta_builder.setProgramInfo("Public broadcast info");
        BluetoothLeAudioContentMetadata meta = meta_builder.build();
        mService.createBroadcast(meta, code);

        int instance_id = 243;
        mService.startBroadcast(instance_id);
        verify(mNativeInterface, times(1)).startBroadcast(eq(instance_id));
        verify(mNativeInterface, times(1)).createBroadcast(eq(meta.getRawMetadata()), eq(1),
                eq(code));

        LeAudioStackEvent create_event =
                new LeAudioStackEvent(LeAudioStackEvent.EVENT_TYPE_BROADCAST_CREATED);
        create_event.valueInt1 = broadcastId;
        create_event.valueBool1 = false;
        mService.messageFromNative(create_event);

        mService.stopBroadcast(instance_id);
        verify(mNativeInterface, times(1)).stopBroadcast(eq(instance_id));
        Assert.assertFalse(mOnBroadcastStartedCalled);
        Assert.assertTrue(mOnBroadcastStartFailedCalled);
    }

    @Test
    public void testDestroyBroadcastNative() {
    public void testStartStopBroadcastNative() {
        int broadcastId = 243;
        int broadcast_profile = 0;
        byte[] code = {0x00, 0x01, 0x00};

        mService.mBroadcastCallbacks.register(mCallbacks);

        BluetoothLeAudioContentMetadata.Builder meta_builder =
        new BluetoothLeAudioContentMetadata.Builder();
        meta_builder.setLanguage("ENG");
        meta_builder.setLanguage("eng");
        meta_builder.setProgramInfo("Public broadcast info");
        BluetoothLeAudioContentMetadata meta = meta_builder.build();
        mService.createBroadcast(meta, code);

        int broadcast_id = 243;
        mService.destroyBroadcast(broadcast_id);
        verify(mNativeInterface, times(1)).destroyBroadcast(eq(broadcast_id));
        verifyBroadcastStarted(broadcastId, code, meta_builder.build());
        verifyBroadcastStopped(broadcastId);
    }

    private BluetoothLeBroadcastSubgroup createBroadcastSubgroup() {