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

Commit 0ee2596c authored by Yan Han's avatar Yan Han
Browse files

When using AVB, update mute state in AudioService after updating volume

When using absolute volume behavior (AVB), we track the volume and mute
state of the AVR independently, as they are treated this way in the CEC
protocol. A device can be muted but still remember its previous, nonzero
volume level, or be unmuted but with zero volume level.

However, volume and mute are not treated independently by AudioService:
setting the volume of a stream to zero mutes it, and setting it to a
nonzero value unmutes it. Because the current logic doesn't take this
into account, the mute state of STREAM_MUSIC can get set to an incorrect
value as the result of volume changes.

To ensure that STREAM_MUSIC has the correct mute state, this CL makes
it so we always set mute state after setting the volume level.

Since setting mute state doesn't have the unwanted side-effects of
setting volume, we will also set mute instead of volume in order to
show volume UI on TVs.

Test: atest TvToAudioSystemArcTest TvToAudioSystemEarcTest
Bug: 315734798

Change-Id: If9d991a7d9a8d383fab88b731be9d2a1b65d426e
parent 8356a5c5
Loading
Loading
Loading
Loading
+12 −9
Original line number Diff line number Diff line
@@ -98,18 +98,21 @@ final class AbsoluteVolumeAudioStatusAction extends HdmiCecFeatureAction {
            localDevice().getService().enableAbsoluteVolumeBehavior(audioStatus);
            mState = STATE_MONITOR_AUDIO_STATUS;
        } else if (mState == STATE_MONITOR_AUDIO_STATUS) {
            // On TV panels, we notify AudioService even if neither volume nor mute state changed.
            // This ensures that the user sees volume UI if they tried to adjust the AVR's volume,
            // even if the new volume level is the same as the previous one.
            boolean notifyAvbVolumeToShowUi = localDevice().getService().isTvDevice()
                    && audioStatus.equals(mLastAudioStatus);

            if (audioStatus.getVolume() != mLastAudioStatus.getVolume()
                    || notifyAvbVolumeToShowUi) {
            // Update volume in AudioService if it has changed since the last <Report Audio Status>
            boolean updateVolume = audioStatus.getVolume() != mLastAudioStatus.getVolume();
            if (updateVolume) {
                localDevice().getService().notifyAvbVolumeChange(audioStatus.getVolume());
            }

            if (audioStatus.getMute() != mLastAudioStatus.getMute()) {
            // Update mute in AudioService if any of the following conditions are met:
            // - The mute status changed
            // - The volume changed - we need to make sure mute is set correctly afterwards, since
            //   setting volume can affect mute status as well as a side effect.
            // - We're a TV panel - we want to trigger volume UI on TV panels, so that the user
            //   always gets visual feedback when they attempt to adjust the AVR's volume/mute.
            if ((audioStatus.getMute() != mLastAudioStatus.getMute())
                    || updateVolume
                    || localDevice().getService().isTvDevice()) {
                localDevice().getService().notifyAvbMuteChange(audioStatus.getMute());
            }
        }
+12 −10
Original line number Diff line number Diff line
@@ -519,11 +519,12 @@ public abstract class BaseAbsoluteVolumeBehaviorTest {
                eq(AudioManager.ADJUST_MUTE), anyInt());
        clearInvocations(mAudioManager);

        // New volume only: sets volume only
        // New volume only: sets both volume and mute.
        // Volume changes can affect mute status; we need to set mute afterwards to undo this.
        receiveReportAudioStatus(32, true);
        verify(mAudioManager).setStreamVolume(eq(AudioManager.STREAM_MUSIC), eq(8),
                anyInt());
        verify(mAudioManager, never()).adjustStreamVolume(eq(AudioManager.STREAM_MUSIC),
        verify(mAudioManager).adjustStreamVolume(eq(AudioManager.STREAM_MUSIC),
                eq(AudioManager.ADJUST_MUTE), anyInt());
        clearInvocations(mAudioManager);

@@ -536,17 +537,17 @@ public abstract class BaseAbsoluteVolumeBehaviorTest {
        clearInvocations(mAudioManager);

        // Repeat of earlier message: sets neither volume nor mute
        // Exception: On TV, volume is set to ensure that UI is shown
        // Exception: On TV, mute is set to ensure that UI is shown
        receiveReportAudioStatus(32, false);
        verify(mAudioManager, never()).setStreamVolume(eq(AudioManager.STREAM_MUSIC),
                eq(32), anyInt());
        if (getDeviceType() == HdmiDeviceInfo.DEVICE_TV) {
            verify(mAudioManager).setStreamVolume(eq(AudioManager.STREAM_MUSIC), eq(8),
                    anyInt());
            verify(mAudioManager).adjustStreamVolume(eq(AudioManager.STREAM_MUSIC),
                    eq(AudioManager.ADJUST_UNMUTE), anyInt());
        } else {
            verify(mAudioManager, never()).setStreamVolume(eq(AudioManager.STREAM_MUSIC), eq(8),
                    anyInt());
        }
            verify(mAudioManager, never()).adjustStreamVolume(eq(AudioManager.STREAM_MUSIC),
                    eq(AudioManager.ADJUST_UNMUTE), anyInt());
        }
        clearInvocations(mAudioManager);

        // Volume not within range [0, 100]: sets neither volume nor mute
@@ -570,7 +571,8 @@ public abstract class BaseAbsoluteVolumeBehaviorTest {
        receiveReportAudioStatus(32, false);
        verify(mAudioManager).setStreamVolume(eq(AudioManager.STREAM_MUSIC), eq(8),
                anyInt());
        verify(mAudioManager, never()).adjustStreamVolume(eq(AudioManager.STREAM_MUSIC),
        // Update mute status because we updated volume
        verify(mAudioManager).adjustStreamVolume(eq(AudioManager.STREAM_MUSIC),
                eq(AudioManager.ADJUST_UNMUTE), anyInt());
    }

+14 −13
Original line number Diff line number Diff line
@@ -174,11 +174,12 @@ public abstract class BaseTvToAudioSystemAvbTest extends BaseAbsoluteVolumeBehav
                eq(AudioManager.ADJUST_MUTE), anyInt());
        clearInvocations(mAudioManager);

        // New volume only: sets volume only
        // New volume only: sets both volume and mute.
        // Volume changes can affect mute status; we need to set mute afterwards to undo this.
        receiveReportAudioStatus(32, true);
        verify(mAudioManager).setStreamVolume(eq(AudioManager.STREAM_MUSIC), eq(8),
                anyInt());
        verify(mAudioManager, never()).adjustStreamVolume(eq(AudioManager.STREAM_MUSIC),
        verify(mAudioManager).adjustStreamVolume(eq(AudioManager.STREAM_MUSIC),
                eq(AudioManager.ADJUST_MUTE), anyInt());
        clearInvocations(mAudioManager);

@@ -190,11 +191,11 @@ public abstract class BaseTvToAudioSystemAvbTest extends BaseAbsoluteVolumeBehav
                eq(AudioManager.ADJUST_UNMUTE), anyInt());
        clearInvocations(mAudioManager);

        // Repeat of earlier message: sets volume only (to ensure volume UI is shown)
        // Repeat of earlier message: sets mute only (to ensure volume UI is shown)
        receiveReportAudioStatus(32, false);
        verify(mAudioManager).setStreamVolume(eq(AudioManager.STREAM_MUSIC), eq(8),
        verify(mAudioManager, never()).setStreamVolume(eq(AudioManager.STREAM_MUSIC), eq(8),
                anyInt());
        verify(mAudioManager, never()).adjustStreamVolume(eq(AudioManager.STREAM_MUSIC),
        verify(mAudioManager).adjustStreamVolume(eq(AudioManager.STREAM_MUSIC),
                eq(AudioManager.ADJUST_UNMUTE), anyInt());
        clearInvocations(mAudioManager);

@@ -392,18 +393,18 @@ public abstract class BaseTvToAudioSystemAvbTest extends BaseAbsoluteVolumeBehav
                INITIAL_SYSTEM_AUDIO_DEVICE_STATUS.getMute()));
        mTestLooper.dispatchAll();

        // HdmiControlService calls setStreamVolume to trigger volume UI
        verify(mAudioManager).setStreamVolume(
        // HdmiControlService calls adjustStreamVolume to trigger volume UI
        verify(mAudioManager).adjustStreamVolume(
                eq(AudioManager.STREAM_MUSIC),
                eq(AudioManager.ADJUST_UNMUTE),
                eq(AudioManager.FLAG_ABSOLUTE_VOLUME | AudioManager.FLAG_SHOW_UI));
        // setStreamVolume is not called because volume didn't change,
        // and adjustStreamVolume is sufficient to show volume UI
        verify(mAudioManager, never()).setStreamVolume(
                eq(AudioManager.STREAM_MUSIC),
                // Volume level is rescaled to the max volume of STREAM_MUSIC
                eq(INITIAL_SYSTEM_AUDIO_DEVICE_STATUS.getVolume()
                        * STREAM_MUSIC_MAX_VOLUME / AudioStatus.MAX_VOLUME),
                eq(AudioManager.FLAG_ABSOLUTE_VOLUME | AudioManager.FLAG_SHOW_UI));
        // adjustStreamVolume is not called because mute status didn't change,
        // and setStreamVolume is sufficient to show volume UI
        verify(mAudioManager, never()).adjustStreamVolume(
                eq(AudioManager.STREAM_MUSIC),
                eq(AudioManager.ADJUST_UNMUTE),
                eq(AudioManager.FLAG_ABSOLUTE_VOLUME | AudioManager.FLAG_SHOW_UI));
    }
}