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

Commit 25ee8699 authored by Grzegorz Kolodziejczyk's avatar Grzegorz Kolodziejczyk Committed by Gerrit Code Review
Browse files

Merge "le_audio: Introduce Audio Mode listener" into main

parents f6a7881f 296e7901
Loading
Loading
Loading
Loading
+82 −20
Original line number Diff line number Diff line
@@ -23,6 +23,7 @@ import static android.bluetooth.IBluetoothLeAudio.LE_AUDIO_GROUP_ID_INVALID;
import static com.android.bluetooth.flags.Flags.leaudioBroadcastFeatureSupport;
import static com.android.bluetooth.flags.Flags.leaudioApiSynchronizedBlockFix;
import static com.android.bluetooth.flags.Flags.leaudioAllowedContextMask;
import static com.android.bluetooth.flags.Flags.leaudioUseAudioModeListener;
import static com.android.bluetooth.Utils.enforceBluetoothPrivilegedPermission;
import static com.android.modules.utils.build.SdkLevel.isAtLeastU;

@@ -175,6 +176,7 @@ public class LeAudioService extends ProfileService {
            leaudioApiSynchronizedBlockFix() ? mGroupReadWriteLock.readLock() : mGroupLock;
    private final Lock mGroupWriteLock =
            leaudioApiSynchronizedBlockFix() ? mGroupReadWriteLock.writeLock() : mGroupLock;
    private final Context mContext;
    ServiceFactory mServiceFactory = new ServiceFactory();

    LeAudioNativeInterface mLeAudioNativeInterface;
@@ -198,6 +200,7 @@ public class LeAudioService extends ProfileService {
    LeAudioTmapGattServer mTmapGattServer;
    int mTmapRoleMask;
    int mUnicastGroupIdDeactivatedForBroadcastTransition = LE_AUDIO_GROUP_ID_INVALID;
    int mCurrentAudioMode = AudioManager.MODE_INVALID;
    Optional<Integer> mBroadcastIdDeactivatedForUnicastTransition = Optional.empty();
    Optional<Boolean> mQueuedInCallValue = Optional.empty();
    boolean mTmapStarted = false;
@@ -235,12 +238,14 @@ public class LeAudioService extends ProfileService {

    public LeAudioService(Context ctx) {
        super(ctx);
        mContext = ctx;
    }

    @VisibleForTesting
    LeAudioService(Context ctx, LeAudioNativeInterface nativeInterface) {
        super(ctx);
        mLeAudioNativeInterface = nativeInterface;
        mContext = ctx;
    }

    private class LeAudioGroupDescriptor {
@@ -393,6 +398,7 @@ public class LeAudioService extends ProfileService {
    private Handler mHandler = new Handler(Looper.getMainLooper());
    private final AudioManagerAudioDeviceCallback mAudioManagerAudioDeviceCallback =
            new AudioManagerAudioDeviceCallback();
    private final AudioModeChangeListener mAudioModeChangeListener = new AudioModeChangeListener();

    @Override
    protected IProfileServiceBinder initBinder() {
@@ -516,6 +522,11 @@ public class LeAudioService extends ProfileService {
            return;
        }
        nativeInterface.init(mLeAudioCodecConfig.getCodecConfigOffloading());

        if (leaudioUseAudioModeListener()) {
            mAudioManager.addOnModeChangedListener(
                    mContext.getMainExecutor(), mAudioModeChangeListener);
        }
    }

    @Override
@@ -527,6 +538,10 @@ public class LeAudioService extends ProfileService {
        }

        mQueuedInCallValue = Optional.empty();
        if (leaudioUseAudioModeListener()) {
            mAudioManager.removeOnModeChangedListener(mAudioModeChangeListener);
        }

        mCreateBroadcastQueue.clear();
        mAwaitingBroadcastCreateResponse = false;
        mIsSourceStreamMonitorModeEnabled = false;
@@ -2776,10 +2791,12 @@ public class LeAudioService extends ProfileService {
            return;
        }

        if (!leaudioUseAudioModeListener()) {
            if (mQueuedInCallValue.isPresent()) {
                mLeAudioNativeInterface.setInCall(mQueuedInCallValue.get());
                mQueuedInCallValue = Optional.empty();
            }
        }

        BluetoothDevice unicastDevice =
                getLeadDeviceForTheGroup(mUnicastGroupIdDeactivatedForBroadcastTransition);
@@ -3165,7 +3182,9 @@ public class LeAudioService extends ProfileService {
                    /* Check if broadcast was deactivated due to unicast */
                    if (mBroadcastIdDeactivatedForUnicastTransition.isPresent()) {
                        updateFallbackUnicastGroupIdForBroadcast(groupId);
                        if (!leaudioUseAudioModeListener()) {
                            mQueuedInCallValue = Optional.empty();
                        }
                        startBroadcast(mBroadcastIdDeactivatedForUnicastTransition.get());
                        mBroadcastIdDeactivatedForUnicastTransition = Optional.empty();
                    }
@@ -3805,8 +3824,11 @@ public class LeAudioService extends ProfileService {
            return;
        }

        if (!leaudioUseAudioModeListener()) {
            /* For setting inCall mode */
        if (Flags.leaudioBroadcastAudioHandoverPolicies() && inCall && !areBroadcastsAllStopped()) {
            if (Flags.leaudioBroadcastAudioHandoverPolicies()
                    && inCall
                    && !areBroadcastsAllStopped()) {
                mQueuedInCallValue = Optional.of(true);

                /* Request activation of unicast group */
@@ -3815,9 +3837,11 @@ public class LeAudioService extends ProfileService {
                        LeAudioStackEvent.STATUS_LOCAL_STREAM_REQUESTED);
                return;
            }
        }

        mLeAudioNativeInterface.setInCall(inCall);

        if (!leaudioUseAudioModeListener()) {
            /* For clearing inCall mode */
            if (Flags.leaudioBroadcastAudioHandoverPolicies()
                    && !inCall
@@ -3827,6 +3851,7 @@ public class LeAudioService extends ProfileService {
                        LeAudioStackEvent.STATUS_LOCAL_STREAM_SUSPENDED);
            }
        }
    }

    /**
     * Sends the preferred audio profiles for a dual mode audio device to the native stack.
@@ -4185,6 +4210,36 @@ public class LeAudioService extends ProfileService {
        startAudioServersBackgroundScan(/* retry = */ false);
    }

    @VisibleForTesting
    void handleAudioModeChange(int mode) {
        Log.d(TAG, "Audio mode changed: " + mCurrentAudioMode + " -> " + mode);

        mCurrentAudioMode = mode;

        switch (mode) {
            case AudioManager.MODE_RINGTONE:
            case AudioManager.MODE_IN_CALL:
            case AudioManager.MODE_IN_COMMUNICATION:
                if (!areBroadcastsAllStopped()) {
                    /* Request activation of unicast group */
                    handleUnicastStreamStatusChange(
                            LeAudioStackEvent.DIRECTION_SINK,
                            LeAudioStackEvent.STATUS_LOCAL_STREAM_REQUESTED);
                }
                break;
            case AudioManager.MODE_NORMAL:
                if (mBroadcastIdDeactivatedForUnicastTransition.isPresent()) {
                    handleUnicastStreamStatusChange(
                            LeAudioStackEvent.DIRECTION_SINK,
                            LeAudioStackEvent.STATUS_LOCAL_STREAM_SUSPENDED);
                }
                break;
            default:
                Log.d(TAG, "Not handled audio mode set: " + mode);
                break;
        }
    }

    private LeAudioGroupDescriptor getGroupDescriptor(int groupId) {
        mGroupReadLock.lock();
        try {
@@ -4717,6 +4772,13 @@ public class LeAudioService extends ProfileService {
        }
    }

    class AudioModeChangeListener implements AudioManager.OnModeChangedListener {
        @Override
        public void onModeChanged(int mode) {
            handleAudioModeChange(mode);
        }
    }

    /**
     * Binder object: must be a static class or memory leak may occur
     */
+62 −0
Original line number Diff line number Diff line
@@ -1033,6 +1033,68 @@ public class LeAudioBroadcastServiceTest {
        verify(mLeAudioBroadcasterNativeInterface, times(2)).startBroadcast(eq(broadcastId));
    }

    @Test
    public void testAudioModeDrivenBroadcastSwitch() {
        mSetFlagsRule.enableFlags(Flags.FLAG_LEAUDIO_USE_AUDIO_MODE_LISTENER);

        int groupId = 1;
        int broadcastId = 243;
        byte[] code = {0x00, 0x01, 0x00, 0x02};

        prepareHandoverStreamingBroadcast(groupId, broadcastId, code);

        /* Imitate setting device in call */
        mService.handleAudioModeChange(AudioManager.MODE_IN_CALL);

        /* Check if broadcast is paused by AudioMode handling */
        verify(mLeAudioBroadcasterNativeInterface, times(1)).pauseBroadcast(eq(broadcastId));

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

        LeAudioStackEvent create_event =
                new LeAudioStackEvent(LeAudioStackEvent.EVENT_TYPE_GROUP_STATUS_CHANGED);
        create_event.valueInt1 = groupId;
        create_event.valueInt2 = LeAudioStackEvent.GROUP_STATUS_ACTIVE;
        mService.messageFromNative(create_event);

        verify(mAudioManager, times(1))
                .handleBluetoothActiveDeviceChanged(
                        eq(mDevice), eq(null), any(BluetoothProfileConnectionInfo.class));
        verify(mAudioManager, times(1))
                .handleBluetoothActiveDeviceChanged(
                        eq(null), eq(mBroadcastDevice), any(BluetoothProfileConnectionInfo.class));

        /* Active group should become the one that was active before broadcasting */
        int activeGroup = mService.getActiveGroupId();
        Assert.assertEquals(activeGroup, groupId);

        /* Imitate setting device not in call */
        mService.handleAudioModeChange(AudioManager.MODE_NORMAL);

        verify(mLeAudioNativeInterface, times(2)).groupSetActive(eq(LE_AUDIO_GROUP_ID_INVALID));

        /* Imitate group inactivity to cause start broadcast */
        create_event = new LeAudioStackEvent(LeAudioStackEvent.EVENT_TYPE_GROUP_STATUS_CHANGED);
        create_event.valueInt1 = groupId;
        create_event.valueInt2 = LeAudioStackEvent.GROUP_STATUS_INACTIVE;
        mService.messageFromNative(create_event);

        /* Only one Unicast device should become inactive due to Sink monitor mode */
        verify(mAudioManager, times(1))
                .handleBluetoothActiveDeviceChanged(
                        eq(null), eq(mDevice), any(BluetoothProfileConnectionInfo.class));
        verify(mAudioManager, times(1))
                .handleBluetoothActiveDeviceChanged(
                        eq(mBroadcastDevice), eq(null), any(BluetoothProfileConnectionInfo.class));

        /* Verify if broadcast is auto-started on start */
        verify(mLeAudioBroadcasterNativeInterface, times(2)).startBroadcast(eq(broadcastId));
    }

    @Test
    public void testBroadcastResumeUnicastGroupChangeRequestDriven() {
        int groupId = 1;