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

Commit 9bb69005 authored by Grzegorz Kołodziejczyk's avatar Grzegorz Kołodziejczyk Committed by Grzegorz Kolodziejczyk (xWF)
Browse files

le_audio: Implement default setter for fallback to unicast group

This CL add mechanism that sets earliest connectedi and assigned to
group LE Audio device as default group.

Bug: 375421718
Bug: 375422795
Flag: com.android.bluetooth.flags.leaudio_broadcast_primary_group_selection
Test: atest LeAudioServiceTest
Test: atest LeAudioBroadcastServiceTest
Change-Id: Ic38a97bdcd1cd57f3597526cf8798c5d6aaabce6
parent 646c6475
Loading
Loading
Loading
Loading
+66 −7
Original line number Diff line number Diff line
@@ -26,7 +26,6 @@ import static com.android.bluetooth.flags.Flags.leaudioAllowedContextMask;
import static com.android.bluetooth.flags.Flags.leaudioBigDependsOnAudioState;
import static com.android.bluetooth.flags.Flags.leaudioBroadcastApiManagePrimaryGroup;
import static com.android.bluetooth.flags.Flags.leaudioBroadcastAssistantPeripheralEntrustment;
import static com.android.bluetooth.flags.Flags.leaudioBroadcastApiManagePrimaryGroup;
import static com.android.bluetooth.flags.Flags.leaudioUseAudioModeListener;
import static com.android.modules.utils.build.SdkLevel.isAtLeastU;

@@ -844,6 +843,35 @@ public class LeAudioService extends ProfileService {
        mNativeInterface.setEnableState(device, enabled);
    }

    private void setDefaultBroadcastToUnicastFallbackGroup() {
        DatabaseManager dbManager = mAdapterService.getDatabase();
        if (dbManager == null) {
            Log.i(
                    TAG,
                    "Can't get db manager to pick default Broadcast to Unicast fallback group"
                            + ", leaving: "
                            + mUnicastGroupIdDeactivatedForBroadcastTransition);
            return;
        }

        List<BluetoothDevice> devices = dbManager.getMostRecentlyConnectedDevices();

        int targetDeviceIdx = -1;
        int targetGroupId = LE_AUDIO_GROUP_ID_INVALID;
        for (BluetoothDevice device : getConnectedDevices()) {
            LeAudioDeviceDescriptor descriptor = getDeviceDescriptor(device);
            if (devices.contains(device)) {
                int idx = devices.indexOf(device);
                if (idx > targetDeviceIdx) {
                    targetDeviceIdx = idx;
                    targetGroupId = descriptor.mGroupId;
                }
            }
        }

        updateFallbackUnicastGroupIdForBroadcast(targetGroupId);
    }

    public boolean connect(BluetoothDevice device) {
        Log.d(TAG, "connect(): " + device);

@@ -2418,7 +2446,8 @@ public class LeAudioService extends ProfileService {
                        + ", mExposedActiveDevice: "
                        + mExposedActiveDevice);

        if (isBroadcastActive()
        if (!Flags.leaudioBroadcastPrimaryGroupSelection()
                && isBroadcastActive()
                && currentlyActiveGroupId == LE_AUDIO_GROUP_ID_INVALID
                && mUnicastGroupIdDeactivatedForBroadcastTransition != LE_AUDIO_GROUP_ID_INVALID) {

@@ -3206,7 +3235,9 @@ public class LeAudioService extends ProfileService {
                    TAG,
                    "transitionFromBroadcastToUnicast: No valid unicast device for group ID: "
                            + mUnicastGroupIdDeactivatedForBroadcastTransition);
            if (!Flags.leaudioBroadcastPrimaryGroupSelection()) {
                updateFallbackUnicastGroupIdForBroadcast(LE_AUDIO_GROUP_ID_INVALID);
            }
            updateBroadcastActiveDevice(null, mActiveBroadcastAudioDevice, false);
            return;
        }
@@ -3218,7 +3249,9 @@ public class LeAudioService extends ProfileService {
                        + ", with device: "
                        + unicastDevice);

        if (!Flags.leaudioBroadcastPrimaryGroupSelection()) {
            updateFallbackUnicastGroupIdForBroadcast(LE_AUDIO_GROUP_ID_INVALID);
        }
        setActiveDevice(unicastDevice);
    }

@@ -3706,7 +3739,9 @@ public class LeAudioService extends ProfileService {
                        if (isBroadcastAllowedToBeActivateInCurrentAudioMode()) {
                            /* Check if broadcast was deactivated due to unicast */
                            if (mBroadcastIdDeactivatedForUnicastTransition.isPresent()) {
                                if (!Flags.leaudioBroadcastPrimaryGroupSelection()) {
                                    updateFallbackUnicastGroupIdForBroadcast(groupId);
                                }
                                if (!leaudioUseAudioModeListener()) {
                                    mQueuedInCallValue = Optional.empty();
                                }
@@ -3723,7 +3758,9 @@ public class LeAudioService extends ProfileService {
                                }
                            } else {
                                if (!mCreateBroadcastQueue.isEmpty()) {
                                    if (!Flags.leaudioBroadcastPrimaryGroupSelection()) {
                                        updateFallbackUnicastGroupIdForBroadcast(groupId);
                                    }
                                    BluetoothLeBroadcastSettings settings =
                                            mCreateBroadcastQueue.remove();
                                    createBroadcast(settings);
@@ -4182,6 +4219,12 @@ public class LeAudioService extends ProfileService {
        if (!isScannerNeeded()) {
            stopAudioServersBackgroundScan();
        }

        /* Set by default earliest connected device */
        if (Flags.leaudioBroadcastPrimaryGroupSelection()
                && mUnicastGroupIdDeactivatedForBroadcastTransition == LE_AUDIO_GROUP_ID_INVALID) {
            setDefaultBroadcastToUnicastFallbackGroup();
        }
    }

    /** Process a change for disconnection of a device. */
@@ -4247,6 +4290,12 @@ public class LeAudioService extends ProfileService {
                            false);
                    return;
                }

                /* Set by default earliest connected device */
                if (Flags.leaudioBroadcastPrimaryGroupSelection()
                        && mUnicastGroupIdDeactivatedForBroadcastTransition == groupId) {
                    setDefaultBroadcastToUnicastFallbackGroup();
                }
            }

            if (descriptor.isActive()
@@ -4841,6 +4890,12 @@ public class LeAudioService extends ProfileService {
            mGroupWriteLock.unlock();
        }

        /* Set by default earliest connected device */
        if (Flags.leaudioBroadcastPrimaryGroupSelection()
                && mUnicastGroupIdDeactivatedForBroadcastTransition == LE_AUDIO_GROUP_ID_INVALID) {
            setDefaultBroadcastToUnicastFallbackGroup();
        }

        if (mBluetoothEnabled) {
            setAuthorizationForRelatedProfiles(device, true);
            startAudioServersBackgroundScan(/* retry= */ false);
@@ -4906,9 +4961,13 @@ public class LeAudioService extends ProfileService {
                }

                if (mUnicastGroupIdDeactivatedForBroadcastTransition == groupId) {
                    if (Flags.leaudioBroadcastPrimaryGroupSelection()) {
                        setDefaultBroadcastToUnicastFallbackGroup();
                    } else {
                        updateFallbackUnicastGroupIdForBroadcast(LE_AUDIO_GROUP_ID_INVALID);
                    }
                }
            }
            mHandler.post(() -> notifyGroupNodeRemoved(device, groupId));
        } finally {
            mGroupReadLock.unlock();
+46 −0
Original line number Diff line number Diff line
@@ -35,6 +35,7 @@ import android.os.IBinder;
import android.os.Looper;
import android.os.ParcelUuid;
import android.os.RemoteException;
import android.platform.test.annotations.DisableFlags;
import android.platform.test.annotations.EnableFlags;
import android.platform.test.flag.junit.SetFlagsRule;

@@ -66,6 +67,7 @@ import org.mockito.Spy;
import org.mockito.junit.MockitoJUnit;
import org.mockito.junit.MockitoRule;

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.TimeoutException;
@@ -1564,6 +1566,7 @@ public class LeAudioBroadcastServiceTest {
    }

    @Test
    @DisableFlags(Flags.FLAG_LEAUDIO_BROADCAST_PRIMARY_GROUP_SELECTION)
    public void testUpdateFallbackInputDevice() {
        mSetFlagsRule.disableFlags(Flags.FLAG_LEAUDIO_USE_AUDIO_MODE_LISTENER);
        int groupId = 1;
@@ -1658,6 +1661,49 @@ public class LeAudioBroadcastServiceTest {
        }
    }

    @Test
    @EnableFlags({
        Flags.FLAG_LEAUDIO_BROADCAST_PRIMARY_GROUP_SELECTION,
        Flags.FLAG_LEAUDIO_BROADCAST_API_MANAGE_PRIMARY_GROUP,
        Flags.FLAG_LEAUDIO_USE_AUDIO_MODE_LISTENER
    })
    public void testManageBroadcastToUnicastFallbackGroup() {
        int groupId = 1;
        int groupId2 = 2;
        int broadcastId = 243;
        byte[] code = {0x00, 0x01, 0x00, 0x02};
        List<BluetoothDevice> devices = new ArrayList<>();

        when(mDatabaseManager.getMostRecentlyConnectedDevices()).thenReturn(devices);

        initializeNative();
        devices.add(mDevice);
        prepareHandoverStreamingBroadcast(groupId, broadcastId, code);
        mService.deviceConnected(mDevice);
        devices.add(mDevice2);
        prepareConnectedUnicastDevice(groupId2, mDevice2);
        mService.deviceConnected(mDevice2);

        Assert.assertEquals(mService.mUnicastGroupIdDeactivatedForBroadcastTransition, groupId);

        reset(mAudioManager);

        /* Update fallback active device (only input is active) */
        ArgumentCaptor<BluetoothProfileConnectionInfo> connectionInfoArgumentCaptor =
                ArgumentCaptor.forClass(BluetoothProfileConnectionInfo.class);

        mService.setBroadcastToUnicastFallbackGroup(groupId2);

        verify(mAudioManager)
                .handleBluetoothActiveDeviceChanged(
                        eq(mDevice2), eq(mDevice), connectionInfoArgumentCaptor.capture());
        List<BluetoothProfileConnectionInfo> connInfos =
                connectionInfoArgumentCaptor.getAllValues();
        Assert.assertEquals(connInfos.size(), 1);
        Assert.assertFalse(connInfos.get(0).isLeOutput());
        Assert.assertEquals(mService.getBroadcastToUnicastFallbackGroup(), groupId2);
    }

    private BluetoothLeBroadcastSettings buildBroadcastSettingsFromMetadata(
            BluetoothLeAudioContentMetadata contentMetadata,
            @Nullable byte[] broadcastCode,
+80 −0
Original line number Diff line number Diff line
@@ -56,6 +56,7 @@ import android.media.BluetoothProfileConnectionInfo;
import android.os.Handler;
import android.os.Looper;
import android.os.ParcelUuid;
import android.platform.test.annotations.DisableFlags;
import android.platform.test.annotations.EnableFlags;
import android.platform.test.flag.junit.SetFlagsRule;
import android.sysprop.BluetoothProperties;
@@ -1826,6 +1827,7 @@ public class LeAudioServiceTest {

    /** Test update unicast fallback active group when broadcast is ongoing */
    @Test
    @DisableFlags(Flags.FLAG_LEAUDIO_BROADCAST_PRIMARY_GROUP_SELECTION)
    public void testUpdateUnicastFallbackActiveDeviceGroupDuringBroadcast() {
        int groupId = 1;
        int preGroupId = 2;
@@ -3639,4 +3641,82 @@ public class LeAudioServiceTest {
                .setGroupAllowedContextMask(
                        groupId, BluetoothLeAudio.CONTEXTS_ALL, BluetoothLeAudio.CONTEXTS_ALL);
    }

    /** Test managing broadcast to unicast fallback group */
    @Test
    @EnableFlags({
        Flags.FLAG_LEAUDIO_BROADCAST_PRIMARY_GROUP_SELECTION,
        Flags.FLAG_LEAUDIO_BROADCAST_API_MANAGE_PRIMARY_GROUP
    })
    public void testManageBroadcastToUnicastFallbackGroup() {
        int firstGroupId = 1;
        int secondGroupId = 2;
        /* AUDIO_DIRECTION_OUTPUT_BIT = 0x01 */
        int direction = 1;
        int snkAudioLocation = 3;
        int srcAudioLocation = 4;
        int availableContexts = 5 + BluetoothLeAudio.CONTEXT_TYPE_RINGTONE;
        List<BluetoothDevice> devices = new ArrayList<>();

        when(mDatabaseManager.getMostRecentlyConnectedDevices()).thenReturn(devices);

        // Not connected device
        assertThat(mService.setActiveDevice(mSingleDevice)).isFalse();
        assertThat(mService.getBroadcastToUnicastFallbackGroup())
                .isEqualTo(BluetoothLeAudio.GROUP_ID_INVALID);

        // Connected device
        doReturn(true).when(mNativeInterface).connectLeAudio(any(BluetoothDevice.class));
        devices.add(mSingleDevice);
        connectTestDevice(mSingleDevice, testGroupId);

        // Group should be updated to default (earliest connected)
        assertThat(mService.getBroadcastToUnicastFallbackGroup()).isEqualTo(firstGroupId);

        // Add location support
        LeAudioStackEvent audioConfChangedEvent =
                new LeAudioStackEvent(LeAudioStackEvent.EVENT_TYPE_AUDIO_CONF_CHANGED);
        audioConfChangedEvent.device = mSingleDevice;
        audioConfChangedEvent.valueInt1 = direction;
        audioConfChangedEvent.valueInt2 = firstGroupId;
        audioConfChangedEvent.valueInt3 = snkAudioLocation;
        audioConfChangedEvent.valueInt4 = srcAudioLocation;
        audioConfChangedEvent.valueInt5 = availableContexts;
        mService.messageFromNative(audioConfChangedEvent);

        assertThat(mService.setActiveDevice(mSingleDevice)).isTrue();
        verify(mNativeInterface).groupSetActive(firstGroupId);

        // Set group and device as active
        LeAudioStackEvent groupStatusChangedEvent =
                new LeAudioStackEvent(LeAudioStackEvent.EVENT_TYPE_GROUP_STATUS_CHANGED);
        groupStatusChangedEvent.valueInt1 = firstGroupId;
        groupStatusChangedEvent.valueInt2 = LeAudioStackEvent.GROUP_STATUS_ACTIVE;
        mService.messageFromNative(groupStatusChangedEvent);

        // Set fallback group to not valid (not connected)
        mService.setBroadcastToUnicastFallbackGroup(secondGroupId);

        // Connect second device
        devices.add(mLeftDevice);
        connectTestDevice(mLeftDevice, secondGroupId);
        mService.deviceConnected(mLeftDevice);

        // Fallback device should remain earliest connected
        assertThat(mService.getBroadcastToUnicastFallbackGroup()).isEqualTo(firstGroupId);

        // Set fallback group to valid second
        mService.setBroadcastToUnicastFallbackGroup(secondGroupId);

        // Fallback device should be changed to second
        assertThat(mService.getBroadcastToUnicastFallbackGroup()).isEqualTo(secondGroupId);

        // no active device
        assertThat(mService.removeActiveDevice(false)).isTrue();
        verify(mNativeInterface).groupSetActive(BluetoothLeAudio.GROUP_ID_INVALID);

        // Set group and device as inactive active
        groupStatusChangedEvent.valueInt2 = LeAudioStackEvent.GROUP_STATUS_INACTIVE;
        mService.messageFromNative(groupStatusChangedEvent);
    }
}