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

Commit 9d97d08b authored by Treehugger Robot's avatar Treehugger Robot Committed by Automerger Merge Worker
Browse files

Merge "leaudio: Notify AF about configuration change on codec and freq change"...

Merge "leaudio: Notify AF about configuration change on codec and freq change" into main am: 581e3e26

Original change: https://android-review.googlesource.com/c/platform/packages/modules/Bluetooth/+/3158956



Change-Id: I23945f77b76dbafba7b3c25b07dd56a380cfc6c5
Signed-off-by: default avatarAutomerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>
parents cee948c1 581e3e26
Loading
Loading
Loading
Loading
+125 −14
Original line number Diff line number Diff line
@@ -3019,7 +3019,11 @@ public class LeAudioService extends ProfileService {
        mDialingOutTimeoutEvent = null;
    }

    void notifyAudioFrameworkForCodecConfigUpdate(int groupId, LeAudioGroupDescriptor descriptor) {
    void notifyAudioFrameworkForCodecConfigUpdate(
            int groupId,
            LeAudioGroupDescriptor descriptor,
            boolean outputCodecOrFreqChanged,
            boolean inputCodecOrFreqChanged) {
        Log.i(TAG, "notifyAudioFrameworkForCodecConfigUpdate groupId: " + groupId);

        if (!Flags.leaudioCodecConfigCallbackOrderFix()) {
@@ -3027,7 +3031,7 @@ public class LeAudioService extends ProfileService {
            return;
        }

        if (mActiveAudioOutDevice != null) {
        if (mActiveAudioOutDevice != null && outputCodecOrFreqChanged) {
            int volume = getAudioDeviceGroupVolume(groupId);

            final BluetoothProfileConnectionInfo connectionInfo;
@@ -3042,14 +3046,115 @@ public class LeAudioService extends ProfileService {
                    mActiveAudioOutDevice, mActiveAudioOutDevice, connectionInfo);
        }

        if (mActiveAudioInDevice != null) {
        if (mActiveAudioInDevice != null && inputCodecOrFreqChanged) {
            mAudioManager.handleBluetoothActiveDeviceChanged(
                    mActiveAudioOutDevice,
                    mActiveAudioOutDevice,
                    mActiveAudioInDevice,
                    mActiveAudioInDevice,
                    BluetoothProfileConnectionInfo.createLeAudioInfo(false, false));
        }
    }

    boolean isOutputCodecOfSampleFrequencyChanged(
            BluetoothLeAudioCodecStatus previous, BluetoothLeAudioCodecStatus next) {
        if ((previous == null) && (next == null)) {
            return false;
        }

        if ((previous == null) || (next == null)) {
            Log.d(TAG, previous + " != " + next);
            return true;
        }

        if ((previous.getOutputCodecConfig() == null) && (next.getOutputCodecConfig() == null)) {
            /* Nothing changed here.*/
            return false;
        }

        if ((previous.getOutputCodecConfig() == null || next.getOutputCodecConfig() == null)) {
            Log.d(
                    TAG,
                    "New output codec: "
                            + (previous.getOutputCodecConfig()
                                    + " != "
                                    + next.getOutputCodecConfig()));
            return true;
        }

        if (previous.getOutputCodecConfig().getCodecType()
                != next.getOutputCodecConfig().getCodecType()) {
            Log.d(
                    TAG,
                    "Different output codec type: "
                            + (previous.getOutputCodecConfig().getCodecType()
                                    + " != "
                                    + next.getOutputCodecConfig().getCodecType()));
            return true;
        }
        if (previous.getOutputCodecConfig().getSampleRate()
                != next.getOutputCodecConfig().getSampleRate()) {
            Log.d(
                    TAG,
                    "Different output samplerate: "
                            + (previous.getOutputCodecConfig().getSampleRate()
                                    + " != "
                                    + next.getOutputCodecConfig().getSampleRate()));
            return true;
        }

        return false;
    }

    boolean isInputCodecOfSampleFrequencyChanged(
            BluetoothLeAudioCodecStatus previous, BluetoothLeAudioCodecStatus next) {
        if ((previous == null) && (next == null)) {
            return false;
        }

        if ((previous == null) || (next == null)) {
            Log.d(TAG, previous + " != " + next);
            return true;
        }

        if ((previous.getInputCodecConfig() == null) && (next.getInputCodecConfig() == null)) {
            /* Nothing changed here.*/
            return false;
        }

        if ((previous.getInputCodecConfig() == null) || (next.getInputCodecConfig() == null)) {
            Log.d(
                    TAG,
                    "New input codec: "
                            + (previous.getInputCodecConfig()
                                    + " != "
                                    + next.getInputCodecConfig()));
            return true;
        }

        if (previous.getInputCodecConfig().getCodecType()
                != next.getInputCodecConfig().getCodecType()) {
            Log.d(
                    TAG,
                    "Different input codec type: "
                            + (previous.getInputCodecConfig().getCodecType()
                                    + " != "
                                    + next.getInputCodecConfig().getCodecType()));
            return true;
        }

        if (previous.getInputCodecConfig().getSampleRate()
                != next.getInputCodecConfig().getSampleRate()) {
            Log.d(
                    TAG,
                    "Different input samplerate: "
                            + (previous.getInputCodecConfig().getSampleRate()
                                    + " != "
                                    + next.getInputCodecConfig().getSampleRate()));
            return true;
        }

        return false;
    }

    // Suppressed since this is part of a local process
    @SuppressLint("AndroidFrameworkRequiresPermission")
    void messageFromNative(LeAudioStackEvent stackEvent) {
@@ -3199,18 +3304,24 @@ public class LeAudioService extends ProfileService {
                            descriptor.mInputSelectableConfig,
                            descriptor.mOutputSelectableConfig);

            if (descriptor.mCodecStatus != null) {
                Log.d(TAG, " Replacing codec status for group: " + groupId);
            } else {
                Log.d(TAG, " New codec status for group: " + groupId);
            }
            boolean outputCodecOrFreqChanged =
                    isOutputCodecOfSampleFrequencyChanged(descriptor.mCodecStatus, status);
            boolean inputCodecOrFreqChanged =
                    isInputCodecOfSampleFrequencyChanged(descriptor.mCodecStatus, status);

            Log.d(
                    TAG,
                    ("Codec update for group:" + groupId)
                            + (", outputCodecOrFreqChanged: " + outputCodecOrFreqChanged)
                            + (", inputCodecOrFreqChanged: " + inputCodecOrFreqChanged));

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

            if (descriptor.isActive()) {
            if (descriptor.isActive() && (outputCodecOrFreqChanged || inputCodecOrFreqChanged)) {
                // Audio framework needs to be notified so it get new codec config
                notifyAudioFrameworkForCodecConfigUpdate(groupId, descriptor);
                notifyAudioFrameworkForCodecConfigUpdate(
                        groupId, descriptor, outputCodecOrFreqChanged, inputCodecOrFreqChanged);
            }
        } else if (stackEvent.type == LeAudioStackEvent.EVENT_TYPE_AUDIO_CONF_CHANGED) {
            int direction = stackEvent.valueInt1;
+123 −2
Original line number Diff line number Diff line
@@ -52,8 +52,8 @@ import android.media.BluetoothProfileConnectionInfo;
import android.os.Handler;
import android.os.Looper;
import android.os.ParcelUuid;
import android.sysprop.BluetoothProperties;
import android.platform.test.flag.junit.SetFlagsRule;
import android.sysprop.BluetoothProperties;

import androidx.test.filters.MediumTest;
import androidx.test.platform.app.InstrumentationRegistry;
@@ -2171,7 +2171,8 @@ public class LeAudioServiceTest {

    /** Test native interface group status message handling */
    @Test
    public void testMessageFromNativeGroupCodecConfigChanged() {
    public void testMessageFromNativeGroupCodecConfigChangedNonActiveDevice() {
        mSetFlagsRule.enableFlags(Flags.FLAG_LEAUDIO_CODEC_CONFIG_CALLBACK_ORDER_FIX);
        onGroupCodecConfChangedCallbackCalled = false;

        injectLocalCodecConfigCapaChanged(INPUT_CAPABILITIES_CONFIG, OUTPUT_CAPABILITIES_CONFIG);
@@ -2213,15 +2214,135 @@ public class LeAudioServiceTest {

        injectGroupSelectableCodecConfigChanged(
                testGroupId, INPUT_SELECTABLE_CONFIG, OUTPUT_SELECTABLE_CONFIG);
        // Inject configuration and check that AF is NOT notified.
        injectGroupCurrentCodecConfigChanged(testGroupId, LC3_16KHZ_CONFIG, LC3_48KHZ_CONFIG);

        TestUtils.waitForLooperToFinishScheduledTask(mService.getMainLooper());
        assertThat(onGroupCodecConfChangedCallbackCalled).isTrue();

        verify(mAudioManager, times(0))
                .handleBluetoothActiveDeviceChanged(
                        any(), any(), any(BluetoothProfileConnectionInfo.class));

        onGroupCodecConfChangedCallbackCalled = false;

        // Now inject again new configuration and check that AF is not notified.
        testCodecStatus =
                new BluetoothLeAudioCodecStatus(
                        LC3_16KHZ_CONFIG,
                        LC3_16KHZ_CONFIG,
                        INPUT_CAPABILITIES_CONFIG,
                        OUTPUT_CAPABILITIES_CONFIG,
                        INPUT_SELECTABLE_CONFIG,
                        OUTPUT_SELECTABLE_CONFIG);

        injectGroupCurrentCodecConfigChanged(testGroupId, LC3_16KHZ_CONFIG, LC3_16KHZ_CONFIG);

        TestUtils.waitForLooperToFinishScheduledTask(mService.getMainLooper());
        assertThat(onGroupCodecConfChangedCallbackCalled).isTrue();

        verify(mAudioManager, times(0))
                .handleBluetoothActiveDeviceChanged(
                        any(), any(), any(BluetoothProfileConnectionInfo.class));

        onGroupCodecConfChangedCallbackCalled = false;
        mService.mLeAudioCallbacks.unregister(leAudioCallbacks);
    }

    /** Test native interface group status message handling */
    @Test
    public void testMessageFromNativeGroupCodecConfigChangedActiveDevice_DifferentConfiguration() {
        mSetFlagsRule.enableFlags(Flags.FLAG_LEAUDIO_CODEC_CONFIG_CALLBACK_ORDER_FIX);
        onGroupCodecConfChangedCallbackCalled = false;

        injectLocalCodecConfigCapaChanged(INPUT_CAPABILITIES_CONFIG, OUTPUT_CAPABILITIES_CONFIG);

        doReturn(true).when(mNativeInterface).connectLeAudio(any(BluetoothDevice.class));
        connectTestDevice(mSingleDevice, testGroupId);

        testCodecStatus =
                new BluetoothLeAudioCodecStatus(
                        LC3_16KHZ_CONFIG,
                        LC3_48KHZ_CONFIG,
                        INPUT_CAPABILITIES_CONFIG,
                        OUTPUT_CAPABILITIES_CONFIG,
                        INPUT_SELECTABLE_CONFIG,
                        OUTPUT_SELECTABLE_CONFIG);

        IBluetoothLeAudioCallback leAudioCallbacks =
                new IBluetoothLeAudioCallback.Stub() {
                    @Override
                    public void onCodecConfigChanged(int gid, BluetoothLeAudioCodecStatus status) {
                        onGroupCodecConfChangedCallbackCalled = true;
                        assertThat(status.equals(testCodecStatus)).isTrue();
                    }

                    @Override
                    public void onGroupStatusChanged(int gid, int gStatus) {}

                    @Override
                    public void onGroupNodeAdded(BluetoothDevice device, int gid) {}

                    @Override
                    public void onGroupNodeRemoved(BluetoothDevice device, int gid) {}

                    @Override
                    public void onGroupStreamStatusChanged(int groupId, int groupStreamStatus) {}
                };

        synchronized (this.mService.mLeAudioCallbacks) {
            mService.mLeAudioCallbacks.register(leAudioCallbacks);
        }

        injectGroupSelectableCodecConfigChanged(
                testGroupId, INPUT_SELECTABLE_CONFIG, OUTPUT_SELECTABLE_CONFIG);

        injectGroupCurrentCodecConfigChanged(testGroupId, LC3_16KHZ_CONFIG, LC3_48KHZ_CONFIG);

        injectAudioConfChanged(
                testGroupId,
                BluetoothLeAudio.CONTEXT_TYPE_MEDIA | BluetoothLeAudio.CONTEXT_TYPE_CONVERSATIONAL,
                3);

        injectGroupStatusChange(testGroupId, LeAudioStackEvent.GROUP_STATUS_ACTIVE);

        TestUtils.waitForLooperToFinishScheduledTask(mService.getMainLooper());
        assertThat(onGroupCodecConfChangedCallbackCalled).isTrue();

        verify(mAudioManager, times(2))
                .handleBluetoothActiveDeviceChanged(
                        any(), any(), any(BluetoothProfileConnectionInfo.class));

        onGroupCodecConfChangedCallbackCalled = false;
        reset(mAudioManager);

        // Now inject configuration different sample rate on one direction
        testCodecStatus =
                new BluetoothLeAudioCodecStatus(
                        LC3_16KHZ_CONFIG,
                        LC3_16KHZ_CONFIG,
                        INPUT_CAPABILITIES_CONFIG,
                        OUTPUT_CAPABILITIES_CONFIG,
                        INPUT_SELECTABLE_CONFIG,
                        OUTPUT_SELECTABLE_CONFIG);

        injectGroupCurrentCodecConfigChanged(testGroupId, LC3_16KHZ_CONFIG, LC3_16KHZ_CONFIG);

        TestUtils.waitForLooperToFinishScheduledTask(mService.getMainLooper());
        assertThat(onGroupCodecConfChangedCallbackCalled).isTrue();

        verify(mAudioManager, times(1))
                .handleBluetoothActiveDeviceChanged(
                        any(), any(), any(BluetoothProfileConnectionInfo.class));

        synchronized (this.mService.mLeAudioCallbacks) {
            mService.mLeAudioCallbacks.unregister(leAudioCallbacks);
        }

        onGroupCodecConfChangedCallbackCalled = false;
        reset(mAudioManager);
    }

    /** Test native interface group status message handling */
    @Test
    public void testMessageFromNativeGroupCodecConfigChanged_OneDirectionOnly() {
+12 −12
Original line number Diff line number Diff line
@@ -856,13 +856,15 @@ public:
      ccid_contexts.source.unset(LeAudioContextType::CONVERSATIONAL);
    }

    bool group_is_streaming = group->IsStreaming();

    BidirectionalPair<std::vector<uint8_t>> ccids = {
            .sink = ContentControlIdKeeper::GetInstance()->GetAllCcids(ccid_contexts.sink),
            .source = ContentControlIdKeeper::GetInstance()->GetAllCcids(ccid_contexts.source)};
    if (group->IsPendingConfiguration()) {
      return groupStateMachine_->ConfigureStream(group, configuration_context_type_,
                                                 remote_contexts, ccids);
    } else if (group->GetState() != AseState::BTA_LE_AUDIO_ASE_STATE_STREAMING) {
    } else if (!group_is_streaming) {
      stream_setup_start_timestamp_ = bluetooth::common::time_get_os_boottime_us();
    }

@@ -870,7 +872,7 @@ public:
     * when there would be request to stream unicast.
     */
    if (com::android::bluetooth::flags::leaudio_broadcast_audio_handover_policies() &&
        !sink_monitor_mode_ && source_monitor_mode_ && !group->IsStreaming()) {
        !sink_monitor_mode_ && source_monitor_mode_ && !group_is_streaming) {
      callbacks_->OnUnicastMonitorModeStatus(bluetooth::le_audio::types::kLeAudioDirectionSource,
                                             UnicastMonitorModeStatus::STREAMING_REQUESTED);
    }
@@ -878,6 +880,13 @@ public:
    bool result = groupStateMachine_->StartStream(group, configuration_context_type,
                                                  remote_contexts, ccids);

    if (result && !group_is_streaming) {
      /* Notify Java about new configuration when start stream has been accepted and
       * it is not metadata update
       */
      SendAudioGroupCurrentCodecConfigChanged(group);
    }

    return result;
  }

@@ -4374,6 +4383,7 @@ public:
    /* Need to reconfigure stream */
    group->SetPendingConfiguration();
    groupStateMachine_->StopStream(group);
    SendAudioGroupCurrentCodecConfigChanged(group);
    return true;
  }

@@ -5280,22 +5290,12 @@ public:
                std::bind(&LeAudioClientImpl::UpdateAudioConfigToHal, weak_factory_.GetWeakPtr(),
                          std::placeholders::_1, std::placeholders::_2));

        /* When at least one direction is started we can assume new
         * configuration here */
        bool new_configuration = false;
        if (audio_sender_state_ == AudioState::READY_TO_START) {
          StartSendingAudio(group_id);
          new_configuration = true;
        }

        if (audio_receiver_state_ == AudioState::READY_TO_START) {
          StartReceivingAudio(group_id);
          new_configuration = true;
        }

        if (new_configuration) {
          /* Notify Java about new configuration */
          SendAudioGroupCurrentCodecConfigChanged(group);
        }
        break;
      }