blob: 0b217b8c66f31927aa3d31aa4b8852d006912aae [file] [log] [blame]
/*
* Copyright 2020 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package android.hdmicec.cts.audio;
import static com.google.common.truth.Truth.assertThat;
import static com.google.common.truth.Truth.assertWithMessage;
import com.google.common.collect.Range;
import android.hdmicec.cts.AudioManagerHelper;
import android.hdmicec.cts.BaseHdmiCecCtsTest;
import android.hdmicec.cts.CecMessage;
import android.hdmicec.cts.CecOperand;
import android.hdmicec.cts.HdmiCecConstants;
import android.hdmicec.cts.LogicalAddress;
import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
import org.junit.After;
import org.junit.Ignore;
import org.junit.Rule;
import org.junit.rules.RuleChain;
import org.junit.runner.RunWith;
import org.junit.Test;
import java.util.concurrent.TimeUnit;
/** HDMI CEC test to test system audio mode (Section 11.2.15) */
@Ignore("b/162820841")
@RunWith(DeviceJUnit4ClassRunner.class)
public final class HdmiCecSystemAudioModeTest extends BaseHdmiCecCtsTest {
private static final LogicalAddress AUDIO_DEVICE = LogicalAddress.AUDIO_SYSTEM;
private static final int ON = 0x1;
private static final int OFF = 0x0;
public HdmiCecSystemAudioModeTest() {
super(HdmiCecConstants.CEC_DEVICE_TYPE_AUDIO_SYSTEM, "-t", "t");
}
@Rule
public RuleChain ruleChain =
RuleChain.outerRule(CecRules.requiresCec(this))
.around(CecRules.requiresLeanback(this))
.around(
CecRules.requiresDeviceType(
this, HdmiCecConstants.CEC_DEVICE_TYPE_AUDIO_SYSTEM))
.around(hdmiCecClient);
public void sendSystemAudioModeTermination() throws Exception {
hdmiCecClient.sendCecMessage(LogicalAddress.TV, AUDIO_DEVICE,
CecOperand.SYSTEM_AUDIO_MODE_REQUEST);
}
public void sendSystemAudioModeInitiation() throws Exception {
hdmiCecClient.sendCecMessage(LogicalAddress.TV, AUDIO_DEVICE,
CecOperand.SYSTEM_AUDIO_MODE_REQUEST,
CecMessage.formatParams(HdmiCecConstants.TV_PHYSICAL_ADDRESS,
HdmiCecConstants.PHYSICAL_ADDRESS_LENGTH));
}
private int getDutAudioStatus() throws Exception {
// Give a couple of seconds for the HdmiCecAudioManager intent to complete.
TimeUnit.SECONDS.sleep(2);
hdmiCecClient.sendCecMessage(LogicalAddress.TV, AUDIO_DEVICE, CecOperand.GIVE_AUDIO_STATUS);
String message = hdmiCecClient.checkExpectedOutput(LogicalAddress.TV,
CecOperand.REPORT_AUDIO_STATUS);
return CecMessage.getParams(message);
}
private void initateSystemAudioModeFromTuner() throws Exception {
getDevice().reboot();
hdmiCecClient.sendCecMessage(LogicalAddress.TUNER_1, AUDIO_DEVICE,
CecOperand.SYSTEM_AUDIO_MODE_REQUEST,
CecMessage.formatParams(HdmiCecConstants.TV_PHYSICAL_ADDRESS,
HdmiCecConstants.PHYSICAL_ADDRESS_LENGTH));
handleSetSystemAudioModeOnToTv();
}
private void handleSetSystemAudioModeOnToTv() throws Exception {
hdmiCecClient.checkExpectedOutput(CecOperand.REQUEST_ACTIVE_SOURCE);
hdmiCecClient.sendCecMessage(LogicalAddress.TV, LogicalAddress.BROADCAST, CecOperand.ACTIVE_SOURCE,
CecMessage.formatParams("2000"));
String message = hdmiCecClient.checkExpectedOutput(LogicalAddress.TV,
CecOperand.SET_SYSTEM_AUDIO_MODE);
assertThat(CecMessage.getParams(message)).isEqualTo(ON);
}
private void initiateSystemAudioModeFromDut() throws Exception {
getDevice().reboot();
hdmiCecClient.checkExpectedOutput(CecOperand.REPORT_PHYSICAL_ADDRESS);
hdmiCecClient.sendCecMessage(LogicalAddress.TV, LogicalAddress.AUDIO_SYSTEM,
CecOperand.GIVE_SYSTEM_AUDIO_MODE_STATUS);
hdmiCecClient.checkExpectedOutput(LogicalAddress.TV, CecOperand.INITIATE_ARC);
hdmiCecClient.sendCecMessage(LogicalAddress.TV, LogicalAddress.AUDIO_SYSTEM,
CecOperand.ARC_INITIATED);
handleSetSystemAudioModeOnToTv();
}
@After
public void resetVolume() throws Exception {
AudioManagerHelper.setDeviceVolume(getDevice(), 20);
}
/**
* Test 11.2.15-1
* Tests that the device handles <System Audio Mode Request> messages from various logical
* addresses correctly as a follower.
*/
@Test
public void cect_11_2_15_1_SystemAudioModeRequestAsFollower() throws Exception {
hdmiCecClient.sendCecMessage(LogicalAddress.TV, AUDIO_DEVICE,
CecOperand.SYSTEM_AUDIO_MODE_REQUEST,
CecMessage.formatParams(HdmiCecConstants.TV_PHYSICAL_ADDRESS,
HdmiCecConstants.PHYSICAL_ADDRESS_LENGTH));
String message = hdmiCecClient.checkExpectedOutput(CecOperand.SET_SYSTEM_AUDIO_MODE);
assertThat(CecMessage.getParams(message)).isEqualTo(ON);
/* Repeat test for device 0x3 (TUNER_1) */
hdmiCecClient.sendCecMessage(LogicalAddress.TUNER_1, AUDIO_DEVICE,
CecOperand.SYSTEM_AUDIO_MODE_REQUEST,
CecMessage.formatParams(HdmiCecConstants.TV_PHYSICAL_ADDRESS,
HdmiCecConstants.PHYSICAL_ADDRESS_LENGTH));
message = hdmiCecClient.checkExpectedOutput(CecOperand.SET_SYSTEM_AUDIO_MODE);
assertThat(CecMessage.getParams(message)).isEqualTo(ON);
}
/**
* Test 11.2.15-2
* Tests that the device issues <Set System Audio Mode>
* message when the feature is initiated in the device .
*/
@Test
public void cect_11_2_15_2_SystemAudioModeWithFeatureInitiation() throws Exception {
initiateSystemAudioModeFromDut();
String message = hdmiCecClient.checkExpectedOutput(CecOperand.SET_SYSTEM_AUDIO_MODE);
assertThat(CecMessage.getParams(message)).isEqualTo(ON);
}
/**
* Test 11.2.15-3
* Tests that the device doesn't broadcast any <Set System Audio Mode>
* messages when TV responds with a <Feature Abort> to a directly addressed
* <Set System Audio Mode> message.
*/
@Test
public void cect_11_2_15_3_SystemAudioModeWithFeatureAbort() throws Exception {
initiateSystemAudioModeFromDut();
hdmiCecClient.sendCecMessage(LogicalAddress.TV, AUDIO_DEVICE, CecOperand.FEATURE_ABORT,
CecMessage.formatParams(CecOperand.SET_SYSTEM_AUDIO_MODE + "04"));
hdmiCecClient.checkOutputDoesNotContainMessage(LogicalAddress.BROADCAST,
CecOperand.SET_SYSTEM_AUDIO_MODE);
//The DUT will need a reboot here so it'll forget the feature abort from the previous
// message. Else it may not respond correctly with a SET_SYSTEM_AUDIO_MODE message
// in future tests.
getDevice().reboot();
}
/**
* Test 11.2.15-4
* Tests that the device responds correctly to a <Give System Audio Status>
* message when System Audio Mode is "On".
*/
@Test
public void cect_11_2_15_4_SystemAudioModeStatusOn() throws Exception {
sendSystemAudioModeInitiation();
String message = hdmiCecClient.checkExpectedOutput(CecOperand.SET_SYSTEM_AUDIO_MODE);
assertThat(CecMessage.getParams(message)).isEqualTo(ON);
hdmiCecClient.sendCecMessage(LogicalAddress.TV, AUDIO_DEVICE,
CecOperand.GIVE_SYSTEM_AUDIO_MODE_STATUS);
message = hdmiCecClient.checkExpectedOutput(LogicalAddress.TV,
CecOperand.SYSTEM_AUDIO_MODE_STATUS);
assertThat(CecMessage.getParams(message)).isEqualTo(ON);
}
/**
* Test 11.2.15-5
* Tests that the device sends a <Set System Audio Mode> ["Off"]
* message when a <System Audio Mode Request> is received with no operands
*/
@Test
public void cect_11_2_15_5_SetSystemAudioModeOff() throws Exception {
sendSystemAudioModeInitiation();
String message = hdmiCecClient.checkExpectedOutput(CecOperand.SET_SYSTEM_AUDIO_MODE);
assertThat(CecMessage.getParams(message)).isEqualTo(ON);
sendSystemAudioModeTermination();
message = hdmiCecClient.checkExpectedOutput(CecOperand.SET_SYSTEM_AUDIO_MODE);
assertThat(CecMessage.getParams(message)).isEqualTo(OFF);
}
/**
* Test 11.2.15-6
* Tests that the device sends a <Set System Audio Mode> ["Off"]
* message before going into standby when System Audio Mode is on.
*/
@Test
public void cect_11_2_15_6_SystemAudioModeOffBeforeStandby() throws Exception {
try {
wakeUpDevice();
sendSystemAudioModeInitiation();
String message = hdmiCecClient.checkExpectedOutput(CecOperand.SET_SYSTEM_AUDIO_MODE);
assertThat(CecMessage.getParams(message)).isEqualTo(ON);
sendDeviceToSleep();
message = hdmiCecClient.checkExpectedOutput(CecOperand.SET_SYSTEM_AUDIO_MODE);
assertThat(CecMessage.getParams(message)).isEqualTo(OFF);
} finally {
wakeUpDevice();
}
}
/**
* Test 11.2.15-7
* Tests that the device responds correctly to a <Give System Audio Mode Status>
* message when the System Audio Mode is "Off".
*/
@Test
public void cect_11_2_15_7_SystemAudioModeStatusOff() throws Exception {
hdmiCecClient.sendCecMessage(LogicalAddress.TV, AUDIO_DEVICE,
CecOperand.SET_SYSTEM_AUDIO_MODE, CecMessage.formatParams(OFF));
hdmiCecClient.sendCecMessage(LogicalAddress.TV, AUDIO_DEVICE,
CecOperand.GIVE_SYSTEM_AUDIO_MODE_STATUS);
String message = hdmiCecClient.checkExpectedOutput(LogicalAddress.TV,
CecOperand.SYSTEM_AUDIO_MODE_STATUS);
assertThat(CecMessage.getParams(message)).isEqualTo(OFF);
}
/**
* Test 11.2.15-8
* Tests that the device handles <User Controlled Pressed> ["Mute"]
* correctly when System Audio Mode is "On".
*/
@Test
public void cect_11_2_15_8_HandleUcpMute() throws Exception {
AudioManagerHelper.unmuteDevice(getDevice(), hdmiCecClient);
hdmiCecClient.sendCecMessage(LogicalAddress.TV, AUDIO_DEVICE,
CecOperand.SYSTEM_AUDIO_MODE_REQUEST,
CecMessage.formatParams(HdmiCecConstants.TV_PHYSICAL_ADDRESS,
HdmiCecConstants.PHYSICAL_ADDRESS_LENGTH));
hdmiCecClient.sendUserControlPressAndRelease(LogicalAddress.TV, AUDIO_DEVICE,
HdmiCecConstants.CEC_CONTROL_MUTE, false);
assertWithMessage("Device is not muted")
.that(AudioManagerHelper.isDeviceMuted(getDevice()))
.isTrue();
}
/**
* Test 11.2.15-9
* Tests that the DUT responds with a <Report Audio Status> message with correct parameters
* to a <Give Audio Status> message when volume is set to 0%.
*/
@Test
public void cect_11_2_15_9_ReportAudioStatus_0() throws Exception {
sendSystemAudioModeInitiation();
AudioManagerHelper.unmuteDevice(getDevice(), hdmiCecClient);
AudioManagerHelper.setDeviceVolume(getDevice(), 0);
int reportedVolume = getDutAudioStatus();
assertThat(reportedVolume).isAnyOf(0, 128);
}
/**
* Test 11.2.15-9
* Tests that the DUT responds with a <Report Audio Status> message with correct parameters
* to a <Give Audio Status> message when volume is set to 50% and not muted.
*/
@Test
public void cect_11_2_15_9_ReportAudioStatus_50_unmuted() throws Exception {
sendSystemAudioModeInitiation();
AudioManagerHelper.unmuteDevice(getDevice(), hdmiCecClient);
AudioManagerHelper.setDeviceVolume(getDevice(), 50);
int reportedVolume = getDutAudioStatus();
/* Allow for a range of volume, since the actual volume set will depend on the device's
volume resolution. */
assertThat(reportedVolume).isIn(Range.closed(46, 54));
}
/**
* Test 11.2.15-9
* Tests that the DUT responds with a <Report Audio Status> message with correct parameters
* to a <Give Audio Status> message when volume is set to 100% and not muted.
*/
@Test
public void cect_11_2_15_9_ReportAudioStatus_100_unmuted() throws Exception {
sendSystemAudioModeInitiation();
AudioManagerHelper.unmuteDevice(getDevice(), hdmiCecClient);
AudioManagerHelper.setDeviceVolume(getDevice(), 100);
int reportedVolume = getDutAudioStatus();
assertThat(reportedVolume).isEqualTo(100);
}
/**
* Test 11.2.15-9
* Tests that the DUT responds with a <Report Audio Status> message with correct parameters
* to a <Give Audio Status> message when volume is muted.
*/
@Test
public void cect_11_2_15_9_ReportAudioStatusMuted() throws Exception {
sendSystemAudioModeInitiation();
AudioManagerHelper.muteDevice(getDevice(), hdmiCecClient);
int reportedVolume = getDutAudioStatus();
/* If device is muted, the 8th bit of CEC message parameters is set and the volume will
be greater than 127. */
assertWithMessage("Device not muted").that(reportedVolume).isGreaterThan(127);
}
/**
* Test 11.2.15-13
* Tests that the device responds to a <Request Short Audio Descriptor> message with a
* <Report Short Audio Descriptor> message with only those audio descriptors that are supported.
*/
@Test
public void cect_11_2_15_13_ValidShortAudioDescriptor() throws Exception {
hdmiCecClient.sendCecMessage(
LogicalAddress.TV,
AUDIO_DEVICE,
CecOperand.REQUEST_SHORT_AUDIO_DESCRIPTOR,
AudioManagerHelper.getRequestSadFormatsParams(getDevice(), true));
String message = hdmiCecClient.checkExpectedOutput(LogicalAddress.TV,
CecOperand.REPORT_SHORT_AUDIO_DESCRIPTOR);
int numFormats =
Math.min(
AudioManagerHelper.mSupportedAudioFormats.size(),
AudioManagerHelper.MAX_VALID_AUDIO_FORMATS);
/* Each Short Audio Descriptor is 3 bytes long. In the first byte of the params, bits 3-6
* will have the audio format. Bit 7 will always 0 for audio format defined in CEA-861-D.
* Bits 0-2 represent (Max number of channels - 1). Discard bits 0-2 and check for the
* format.
* Iterate the params by 3 bytes(6 nibbles) and extract only the first byte(2 nibbles).
*/
for (int i = 0; i < numFormats; i++) {
int audioFormat =
CecMessage.getParams(message, 6 * i, 6 * i + 2) >>> 3;
assertWithMessage("Could not find audio format " + audioFormat)
.that(AudioManagerHelper.mSupportedAudioFormats)
.contains(audioFormat);
}
}
/**
* Test 11.2.15-14
* Tests that the device responds to a <Request Short Audio Descriptor> message with a
* <Feature Abort> [“Invalid Operand”] when a <Request Short Audio Descriptor> message is
* received with a single [Audio Format ID][Audio Format Code] pair that is not supported.
*/
@Test
public void cect_11_2_15_14_InvalidShortAudioDescriptor() throws Exception {
hdmiCecClient.sendCecMessage(
LogicalAddress.TV,
AUDIO_DEVICE,
CecOperand.REQUEST_SHORT_AUDIO_DESCRIPTOR,
AudioManagerHelper.getRequestSadFormatsParams(getDevice(), false));
String message = hdmiCecClient.checkExpectedOutput(LogicalAddress.TV, CecOperand.FEATURE_ABORT);
assertThat(CecOperand.getOperand(CecMessage.getParams(message, 2)))
.isEqualTo(CecOperand.REQUEST_SHORT_AUDIO_DESCRIPTOR);
assertThat(CecMessage.getParams(message, 2, 4))
.isEqualTo(HdmiCecConstants.ABORT_INVALID_OPERAND);
}
/**
* Test 11.2.15-16
* Tests that the device unmute its volume when it broadcasts a
* <Set System Audio Mode> ["On"] message
*/
@Test
public void cect_11_2_15_16_UnmuteForSystemAudioRequestOn() throws Exception {
AudioManagerHelper.muteDevice(getDevice(), hdmiCecClient);
sendSystemAudioModeTermination();
String message = hdmiCecClient.checkExpectedOutput(CecOperand.SET_SYSTEM_AUDIO_MODE);
assertThat(CecMessage.getParams(message)).isEqualTo(OFF);
hdmiCecClient.sendCecMessage(LogicalAddress.TV, AUDIO_DEVICE,
CecOperand.SYSTEM_AUDIO_MODE_REQUEST,
CecMessage.formatParams(HdmiCecConstants.TV_PHYSICAL_ADDRESS,
HdmiCecConstants.PHYSICAL_ADDRESS_LENGTH));
message = hdmiCecClient.checkExpectedOutput(CecOperand.SET_SYSTEM_AUDIO_MODE);
assertThat(CecMessage.getParams(message)).isEqualTo(ON);
assertWithMessage("Device muted")
.that(AudioManagerHelper.isDeviceMuted(getDevice()))
.isFalse();
}
/**
* Test 11.2.15-17
* Tests that the device mute its volume when it broadcasts a
* <Set System Audio Mode> ["Off"] message
*/
@Test
public void cect_11_2_15_17_MuteForSystemAudioRequestOff() throws Exception {
hdmiCecClient.sendCecMessage(LogicalAddress.TV, AUDIO_DEVICE,
CecOperand.SYSTEM_AUDIO_MODE_REQUEST,
CecMessage.formatParams(HdmiCecConstants.TV_PHYSICAL_ADDRESS,
HdmiCecConstants.PHYSICAL_ADDRESS_LENGTH));
String message = hdmiCecClient.checkExpectedOutput(CecOperand.SET_SYSTEM_AUDIO_MODE);
assertThat(CecMessage.getParams(message)).isEqualTo(ON);
sendSystemAudioModeTermination();
message = hdmiCecClient.checkExpectedOutput(CecOperand.SET_SYSTEM_AUDIO_MODE);
assertThat(CecMessage.getParams(message)).isEqualTo(OFF);
assertWithMessage("Device not muted")
.that(AudioManagerHelper.isDeviceMuted(getDevice()))
.isTrue();
}
/**
* Test 11.2.15-18
* Tests that the device doesn't broadcast <Set System Audio Mode>
* messages if TV responds with a <Feature Abort> message to directly addressed
* <Set System Audio Mode> message within the required maximum response time of 1 second.
*/
@Test
public void cect_11_2_15_18_SystemAudioModeWithFeatureAbortWithinTime() throws Exception {
initiateSystemAudioModeFromDut();
hdmiCecClient.sendCecMessage(LogicalAddress.TV, AUDIO_DEVICE, CecOperand.FEATURE_ABORT,
CecMessage.formatParams(CecOperand.SET_SYSTEM_AUDIO_MODE + "04"));
hdmiCecClient.checkOutputDoesNotContainMessage(LogicalAddress.BROADCAST,
CecOperand.SET_SYSTEM_AUDIO_MODE);
}
/**
* Test 11.2.15-19
* Tests that the device doesn't broadcast <Set System Audio Mode>
* messages if TV responds with a <Feature Abort> message to directly addressed
* <Set System Audio Mode> message within the required maximum response time of 1 second.
* The <Set System Audio Mode> message should be initiated from logical address 3.
*/
@Test
public void cect_11_2_15_19_SystemAudioModeWithFeatureAbortWithinTime() throws Exception {
initateSystemAudioModeFromTuner();
hdmiCecClient.sendCecMessage(LogicalAddress.TV, AUDIO_DEVICE, CecOperand.FEATURE_ABORT,
CecMessage.formatParams(CecOperand.SET_SYSTEM_AUDIO_MODE + "04"));
hdmiCecClient.checkOutputDoesNotContainMessage(LogicalAddress.BROADCAST,
CecOperand.SET_SYSTEM_AUDIO_MODE);
}
}