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

Commit 64e0b5a2 authored by Yan Han's avatar Yan Han
Browse files

Fix volume UI from setStreamVolume when using adjust-only AVB

When AudioService#setStreamVolume is called, it first sets its stream
volume to the requested volume, and then tells HdmiControlService to
execute the volume change on the System Audio device.

This is problematic when using adjust-only absolute volume behavior,
where the System Audio device does not support <Set Audio Volume Level>
and therefore HdmiControlService is unable to set the System Audio
device's volume to a percentage.

To fix this, this CL makes HdmiControlService query the System Audio
device's volume level after AudioService receives setStreamVolume
call. This makes it so that AudioService is updated with its actual
volume level, instead of persisting an incorrect volume level and
showing incorrect UI.

The better long-term solution would be to change the API for adopting
absolute volume behavior to allow AudioService to be "lazier" in
updating its volume when setStreamVolume is called. But the approach in
this CL simpler, and still a big improvement to the current behavior.

Bug: 328219479
Test: atest TvToAudioSystemEarcAvbTest TvToAudioSystemArcAvbTest

Change-Id: Ib8a9d8273adc4ae9cf6e725894395fa4bb6d824d
parent 2966eb20
Loading
Loading
Loading
Loading
+14 −2
Original line number Original line Diff line number Diff line
@@ -4665,15 +4665,27 @@ public class HdmiControlService extends SystemService {
        public void onAudioDeviceVolumeChanged(
        public void onAudioDeviceVolumeChanged(
                @NonNull AudioDeviceAttributes audioDevice,
                @NonNull AudioDeviceAttributes audioDevice,
                @NonNull VolumeInfo volumeInfo) {
                @NonNull VolumeInfo volumeInfo) {
            int localDeviceAddress = mLocalDevice.getDeviceInfo().getLogicalAddress();


            // Do nothing if the System Audio device does not support <Set Audio Volume Level>
            // We can't send <Set Audio Volume Level> if the System Audio device doesn't support it.
            // But AudioService has already updated its volume and expects us to set it.
            // So the best we can do is to send <Give Audio Status>, which triggers
            // <Report Audio Status>, which should update AudioService with its correct volume.
            if (mSystemAudioDevice.getDeviceFeatures().getSetAudioVolumeLevelSupport()
            if (mSystemAudioDevice.getDeviceFeatures().getSetAudioVolumeLevelSupport()
                    != DeviceFeatures.FEATURE_SUPPORTED) {
                    != DeviceFeatures.FEATURE_SUPPORTED) {
                // Update the volume tracked in AbsoluteVolumeAudioStatusAction
                // so it correctly processes the next <Report Audio Status>
                HdmiCecLocalDevice avbDevice = isTvDevice() ? tv() : playback();
                avbDevice.updateAvbVolume(volumeInfo.getVolumeIndex());
                // Send <Give Audio Status>
                sendCecCommand(HdmiCecMessageBuilder.buildGiveAudioStatus(
                        localDeviceAddress,
                        mSystemAudioDevice.getLogicalAddress()
                ));
                return;
                return;
            }
            }


            // Send <Set Audio Volume Level> to notify the System Audio device of the volume change
            // Send <Set Audio Volume Level> to notify the System Audio device of the volume change
            int localDeviceAddress = mLocalDevice.getDeviceInfo().getLogicalAddress();
            sendCecCommand(SetAudioVolumeLevelMessage.build(
            sendCecCommand(SetAudioVolumeLevelMessage.build(
                            localDeviceAddress,
                            localDeviceAddress,
                            mSystemAudioDevice.getLogicalAddress(),
                            mSystemAudioDevice.getLogicalAddress(),
+17 −2
Original line number Original line Diff line number Diff line
@@ -235,7 +235,7 @@ public abstract class BaseTvToAudioSystemAvbTest extends BaseAbsoluteVolumeBehav
    }
    }


    @Test
    @Test
    public void adjustOnlyAvbEnabled_audioDeviceVolumeChanged_doesNotSendSetAudioVolumeLevel() {
    public void adjustOnlyAvbEnabled_audioDeviceVolumeChanged_requestsAndUpdatesAudioStatus() {
        enableAdjustOnlyAbsoluteVolumeBehavior();
        enableAdjustOnlyAbsoluteVolumeBehavior();


        mNativeWrapper.clearResultMessages();
        mNativeWrapper.clearResultMessages();
@@ -250,7 +250,22 @@ public abstract class BaseTvToAudioSystemAvbTest extends BaseAbsoluteVolumeBehav
        );
        );
        mTestLooper.dispatchAll();
        mTestLooper.dispatchAll();


        assertThat(mNativeWrapper.getResultMessages()).isEmpty();
        // We can't sent <Set Audio Volume Level> when using adjust-only AVB.
        // Instead, we send <Give Audio Status>, to get the System Audio device's volume level.
        // This ensures that we end up with a correct audio status in AudioService, even if it
        // set it incorrectly because it assumed that we could send <Set Audio Volume Level>
        assertThat(mNativeWrapper.getResultMessages().size()).isEqualTo(1);
        assertThat(mNativeWrapper.getResultMessages()).contains(
                HdmiCecMessageBuilder.buildGiveAudioStatus(getLogicalAddress(),
                        getSystemAudioDeviceLogicalAddress())
        );

        // When we receive <Report Audio Status>, we notify AudioService of the volume level.
        receiveReportAudioStatus(50,
                true);
        verify(mAudioManager).setStreamVolume(eq(AudioManager.STREAM_MUSIC),
                eq(50 * STREAM_MUSIC_MAX_VOLUME / AudioStatus.MAX_VOLUME),
                anyInt());
    }
    }


    @Test
    @Test