1 /* 2 * Copyright (C) 2022 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.android.server.hdmi; 18 19 import static com.android.server.hdmi.HdmiCecKeycode.CEC_KEYCODE_VOLUME_UP; 20 21 import static com.google.common.truth.Truth.assertThat; 22 23 import static org.mockito.ArgumentMatchers.any; 24 import static org.mockito.ArgumentMatchers.anyBoolean; 25 import static org.mockito.ArgumentMatchers.anyInt; 26 import static org.mockito.ArgumentMatchers.eq; 27 import static org.mockito.Mockito.clearInvocations; 28 import static org.mockito.Mockito.never; 29 import static org.mockito.Mockito.verify; 30 31 import android.hardware.hdmi.DeviceFeatures; 32 import android.hardware.hdmi.HdmiControlManager; 33 import android.hardware.hdmi.HdmiDeviceInfo; 34 import android.media.AudioDeviceAttributes; 35 import android.media.AudioDeviceVolumeManager; 36 import android.media.AudioManager; 37 import android.media.VolumeInfo; 38 import android.platform.test.annotations.Presubmit; 39 40 import androidx.test.filters.SmallTest; 41 42 import org.junit.Test; 43 import org.junit.runner.RunWith; 44 import org.junit.runners.JUnit4; 45 46 /** 47 * Tests for absolute volume behavior where the local device is a TV and the System Audio device 48 * is an Audio System. Assumes that the TV uses ARC (rather than eARC). 49 */ 50 @SmallTest 51 @Presubmit 52 @RunWith(JUnit4.class) 53 public class TvToAudioSystemAvbTest extends BaseAbsoluteVolumeBehaviorTest { 54 55 @Override createLocalDevice(HdmiControlService hdmiControlService)56 protected HdmiCecLocalDevice createLocalDevice(HdmiControlService hdmiControlService) { 57 return new HdmiCecLocalDeviceTv(hdmiControlService); 58 } 59 60 @Override getPhysicalAddress()61 protected int getPhysicalAddress() { 62 return 0x0000; 63 } 64 65 @Override getDeviceType()66 protected int getDeviceType() { 67 return HdmiDeviceInfo.DEVICE_TV; 68 } 69 70 @Override getAudioOutputDevice()71 protected AudioDeviceAttributes getAudioOutputDevice() { 72 return HdmiControlService.AUDIO_OUTPUT_DEVICE_HDMI_ARC; 73 } 74 75 @Override getSystemAudioDeviceLogicalAddress()76 protected int getSystemAudioDeviceLogicalAddress() { 77 return Constants.ADDR_AUDIO_SYSTEM; 78 } 79 80 @Override getSystemAudioDeviceType()81 protected int getSystemAudioDeviceType() { 82 return HdmiDeviceInfo.DEVICE_AUDIO_SYSTEM; 83 } 84 85 /** 86 * TVs start the process for adopting adjust-only AVB if the System Audio device doesn't 87 * support <Set Audio Volume Level> 88 */ 89 @Test savlNotSupported_allOtherConditionsMet_giveAudioStatusSent()90 public void savlNotSupported_allOtherConditionsMet_giveAudioStatusSent() { 91 mAudioManager.setDeviceVolumeBehavior(getAudioOutputDevice(), 92 AudioManager.DEVICE_VOLUME_BEHAVIOR_FULL); 93 setCecVolumeControlSetting(HdmiControlManager.VOLUME_CONTROL_ENABLED); 94 enableSystemAudioModeIfNeeded(); 95 verifyGiveAudioStatusNeverSent(); 96 97 receiveSetAudioVolumeLevelSupport(DeviceFeatures.FEATURE_NOT_SUPPORTED); 98 verifyGiveAudioStatusSent(); 99 } 100 101 @Test savlNotSupported_systemAudioDeviceSendsReportAudioStatus_adjustOnlyAvbEnabled()102 public void savlNotSupported_systemAudioDeviceSendsReportAudioStatus_adjustOnlyAvbEnabled() { 103 mAudioManager.setDeviceVolumeBehavior(getAudioOutputDevice(), 104 AudioManager.DEVICE_VOLUME_BEHAVIOR_FULL); 105 setCecVolumeControlSetting(HdmiControlManager.VOLUME_CONTROL_ENABLED); 106 enableSystemAudioModeIfNeeded(); 107 receiveSetAudioVolumeLevelSupport(DeviceFeatures.FEATURE_NOT_SUPPORTED); 108 109 // Adjust-only AVB should not be enabled before receiving <Report Audio Status> 110 assertThat(mAudioManager.getDeviceVolumeBehavior(getAudioOutputDevice())).isEqualTo( 111 AudioManager.DEVICE_VOLUME_BEHAVIOR_FULL); 112 113 receiveReportAudioStatus(20, false); 114 115 assertThat(mAudioManager.getDeviceVolumeBehavior(getAudioOutputDevice())).isEqualTo( 116 AudioManager.DEVICE_VOLUME_BEHAVIOR_ABSOLUTE_ADJUST_ONLY); 117 118 verify(mAudioDeviceVolumeManager).setDeviceAbsoluteVolumeAdjustOnlyBehavior( 119 eq(getAudioOutputDevice()), 120 eq(new VolumeInfo.Builder(AudioManager.STREAM_MUSIC) 121 .setVolumeIndex(20) 122 .setMuted(false) 123 .setMaxVolumeIndex(AudioStatus.MAX_VOLUME) 124 .setMinVolumeIndex(AudioStatus.MIN_VOLUME) 125 .build()), 126 any(), any(), anyBoolean()); 127 } 128 129 130 @Test avbEnabled_savlNotSupported_receiveReportAudioStatus_switchToAdjustOnlyAvb()131 public void avbEnabled_savlNotSupported_receiveReportAudioStatus_switchToAdjustOnlyAvb() { 132 enableAbsoluteVolumeBehavior(); 133 134 receiveSetAudioVolumeLevelSupport(DeviceFeatures.FEATURE_NOT_SUPPORTED); 135 136 receiveReportAudioStatus(40, true); 137 138 assertThat(mAudioManager.getDeviceVolumeBehavior(getAudioOutputDevice())).isEqualTo( 139 AudioManager.DEVICE_VOLUME_BEHAVIOR_ABSOLUTE_ADJUST_ONLY); 140 141 verify(mAudioDeviceVolumeManager).setDeviceAbsoluteVolumeAdjustOnlyBehavior( 142 eq(getAudioOutputDevice()), 143 eq(new VolumeInfo.Builder(AudioManager.STREAM_MUSIC) 144 .setVolumeIndex(40) 145 .setMuted(true) 146 .setMaxVolumeIndex(AudioStatus.MAX_VOLUME) 147 .setMinVolumeIndex(AudioStatus.MIN_VOLUME) 148 .build()), 149 any(), any(), anyBoolean()); 150 } 151 152 @Test avbEnabled_savlFeatureAborted_receiveReportAudioStatus_switchToAdjustOnlyAvb()153 public void avbEnabled_savlFeatureAborted_receiveReportAudioStatus_switchToAdjustOnlyAvb() { 154 enableAbsoluteVolumeBehavior(); 155 156 mNativeWrapper.onCecMessage(HdmiCecMessageBuilder.buildFeatureAbortCommand( 157 getSystemAudioDeviceLogicalAddress(), getLogicalAddress(), 158 Constants.MESSAGE_SET_AUDIO_VOLUME_LEVEL, Constants.ABORT_UNRECOGNIZED_OPCODE)); 159 mTestLooper.dispatchAll(); 160 161 receiveReportAudioStatus(40, true); 162 163 assertThat(mAudioManager.getDeviceVolumeBehavior(getAudioOutputDevice())).isEqualTo( 164 AudioManager.DEVICE_VOLUME_BEHAVIOR_ABSOLUTE_ADJUST_ONLY); 165 166 verify(mAudioDeviceVolumeManager).setDeviceAbsoluteVolumeAdjustOnlyBehavior( 167 eq(getAudioOutputDevice()), 168 eq(new VolumeInfo.Builder(AudioManager.STREAM_MUSIC) 169 .setVolumeIndex(40) 170 .setMuted(true) 171 .setMaxVolumeIndex(AudioStatus.MAX_VOLUME) 172 .setMinVolumeIndex(AudioStatus.MIN_VOLUME) 173 .build()), 174 any(), any(), anyBoolean()); 175 } 176 177 @Test adjustOnlyAvbEnabled_receiveReportAudioStatus_notifiesVolumeOrMuteChanges()178 public void adjustOnlyAvbEnabled_receiveReportAudioStatus_notifiesVolumeOrMuteChanges() { 179 enableAdjustOnlyAbsoluteVolumeBehavior(); 180 181 // New volume and mute status: sets both 182 receiveReportAudioStatus(20, true); 183 verify(mAudioManager).setStreamVolume(eq(AudioManager.STREAM_MUSIC), eq(5), 184 anyInt()); 185 verify(mAudioManager).adjustStreamVolume(eq(AudioManager.STREAM_MUSIC), 186 eq(AudioManager.ADJUST_MUTE), anyInt()); 187 clearInvocations(mAudioManager); 188 189 // New volume only: sets volume only 190 receiveReportAudioStatus(32, true); 191 verify(mAudioManager).setStreamVolume(eq(AudioManager.STREAM_MUSIC), eq(8), 192 anyInt()); 193 verify(mAudioManager, never()).adjustStreamVolume(eq(AudioManager.STREAM_MUSIC), 194 eq(AudioManager.ADJUST_MUTE), anyInt()); 195 clearInvocations(mAudioManager); 196 197 // New mute status only: sets mute only 198 receiveReportAudioStatus(32, false); 199 verify(mAudioManager, never()).setStreamVolume(eq(AudioManager.STREAM_MUSIC), eq(8), 200 anyInt()); 201 verify(mAudioManager).adjustStreamVolume(eq(AudioManager.STREAM_MUSIC), 202 eq(AudioManager.ADJUST_UNMUTE), anyInt()); 203 clearInvocations(mAudioManager); 204 205 // Repeat of earlier message: sets neither volume nor mute 206 receiveReportAudioStatus(32, false); 207 verify(mAudioManager, never()).setStreamVolume(eq(AudioManager.STREAM_MUSIC), eq(8), 208 anyInt()); 209 verify(mAudioManager, never()).adjustStreamVolume(eq(AudioManager.STREAM_MUSIC), 210 eq(AudioManager.ADJUST_UNMUTE), anyInt()); 211 212 // Volume not within range [0, 100]: sets neither volume nor mute 213 receiveReportAudioStatus(127, true); 214 verify(mAudioManager, never()).setStreamVolume(eq(AudioManager.STREAM_MUSIC), anyInt(), 215 anyInt()); 216 verify(mAudioManager, never()).adjustStreamVolume(eq(AudioManager.STREAM_MUSIC), anyInt(), 217 anyInt()); 218 } 219 220 @Test adjustOnlyAvbEnabled_audioDeviceVolumeAdjusted_sendsUcpAndGiveAudioStatus()221 public void adjustOnlyAvbEnabled_audioDeviceVolumeAdjusted_sendsUcpAndGiveAudioStatus() { 222 enableAdjustOnlyAbsoluteVolumeBehavior(); 223 mNativeWrapper.clearResultMessages(); 224 225 mHdmiControlService.getAbsoluteVolumeChangedListener().onAudioDeviceVolumeAdjusted( 226 getAudioOutputDevice(), 227 new VolumeInfo.Builder(AudioManager.STREAM_MUSIC) 228 .setMaxVolumeIndex(AudioStatus.MAX_VOLUME) 229 .setMinVolumeIndex(AudioStatus.MIN_VOLUME) 230 .build(), 231 AudioManager.ADJUST_RAISE, 232 AudioDeviceVolumeManager.ADJUST_MODE_NORMAL 233 ); 234 mTestLooper.dispatchAll(); 235 236 assertThat(mNativeWrapper.getResultMessages()).contains( 237 HdmiCecMessageBuilder.buildUserControlPressed(getLogicalAddress(), 238 getSystemAudioDeviceLogicalAddress(), CEC_KEYCODE_VOLUME_UP)); 239 assertThat(mNativeWrapper.getResultMessages()).contains( 240 HdmiCecMessageBuilder.buildUserControlReleased(getLogicalAddress(), 241 getSystemAudioDeviceLogicalAddress())); 242 assertThat(mNativeWrapper.getResultMessages()).contains( 243 HdmiCecMessageBuilder.buildGiveAudioStatus(getLogicalAddress(), 244 getSystemAudioDeviceLogicalAddress())); 245 } 246 247 @Test adjustOnlyAvbEnabled_audioDeviceVolumeChanged_doesNotSendSetAudioVolumeLevel()248 public void adjustOnlyAvbEnabled_audioDeviceVolumeChanged_doesNotSendSetAudioVolumeLevel() { 249 enableAdjustOnlyAbsoluteVolumeBehavior(); 250 251 mNativeWrapper.clearResultMessages(); 252 253 mHdmiControlService.getAbsoluteVolumeChangedListener().onAudioDeviceVolumeChanged( 254 getAudioOutputDevice(), 255 new VolumeInfo.Builder(AudioManager.STREAM_MUSIC) 256 .setVolumeIndex(20) 257 .setMaxVolumeIndex(AudioStatus.MAX_VOLUME) 258 .setMinVolumeIndex(AudioStatus.MIN_VOLUME) 259 .build() 260 ); 261 mTestLooper.dispatchAll(); 262 263 assertThat(mNativeWrapper.getResultMessages()).isEmpty(); 264 } 265 } 266