diff --git a/core/api/current.txt b/core/api/current.txt index 85ae6a149d311..4ddf67e7dc378 100644 --- a/core/api/current.txt +++ b/core/api/current.txt @@ -20371,6 +20371,8 @@ package android.media { field @NonNull public static final android.os.Parcelable.Creator CREATOR; field public static final int STANDARD_EDID = 1; // 0x1 field public static final int STANDARD_NONE = 0; // 0x0 + field public static final int STANDARD_SADB = 2; // 0x2 + field public static final int STANDARD_VSADB = 3; // 0x3 } public abstract class AudioDeviceCallback { diff --git a/core/jni/android_media_AudioDescriptor.h b/core/jni/android_media_AudioDescriptor.h index 680ac3f7519ea..bac761c48aaae 100644 --- a/core/jni/android_media_AudioDescriptor.h +++ b/core/jni/android_media_AudioDescriptor.h @@ -25,6 +25,8 @@ namespace android { // keep these values in sync with ExtraAudioDescriptor.java #define STANDARD_NONE 0 #define STANDARD_EDID 1 +#define STANDARD_SADB 2 +#define STANDARD_VSADB 3 static inline status_t audioStandardFromNative(audio_standard_t nStandard, int* standard) { status_t result = NO_ERROR; @@ -35,6 +37,12 @@ static inline status_t audioStandardFromNative(audio_standard_t nStandard, int* case AUDIO_STANDARD_EDID: *standard = STANDARD_EDID; break; + case AUDIO_STANDARD_SADB: + *standard = STANDARD_SADB; + break; + case AUDIO_STANDARD_VSADB: + *standard = STANDARD_VSADB; + break; default: result = BAD_VALUE; } diff --git a/media/java/android/media/AudioDescriptor.java b/media/java/android/media/AudioDescriptor.java index df648be4c157b..85a653c9d80c9 100644 --- a/media/java/android/media/AudioDescriptor.java +++ b/media/java/android/media/AudioDescriptor.java @@ -41,11 +41,21 @@ public class AudioDescriptor implements Parcelable { * The Extended Display Identification Data (EDID) standard for a short audio descriptor. */ public static final int STANDARD_EDID = 1; + /** + * The standard for a Speaker Allocation Data Block (SADB). + */ + public static final int STANDARD_SADB = 2; + /** + * The standard for a Vendor-Specific Audio Data Block (VSADB). + */ + public static final int STANDARD_VSADB = 3; /** @hide */ @IntDef({ STANDARD_NONE, STANDARD_EDID, + STANDARD_SADB, + STANDARD_VSADB, }) @Retention(RetentionPolicy.SOURCE) public @interface AudioDescriptorStandard {} diff --git a/media/java/android/media/audio/common/AidlConversion.java b/media/java/android/media/audio/common/AidlConversion.java index 490809c63e960..65fd51b9ece91 100644 --- a/media/java/android/media/audio/common/AidlConversion.java +++ b/media/java/android/media/audio/common/AidlConversion.java @@ -585,6 +585,10 @@ public class AidlConversion { switch (standard) { case AudioDescriptor.STANDARD_EDID: return AudioStandard.EDID; + case AudioDescriptor.STANDARD_SADB: + return AudioStandard.SADB; + case AudioDescriptor.STANDARD_VSADB: + return AudioStandard.VSADB; case AudioDescriptor.STANDARD_NONE: default: return AudioStandard.NONE; @@ -599,6 +603,10 @@ public class AidlConversion { switch (standard) { case AudioStandard.EDID: return AudioDescriptor.STANDARD_EDID; + case AudioStandard.SADB: + return AudioDescriptor.STANDARD_SADB; + case AudioStandard.VSADB: + return AudioDescriptor.STANDARD_VSADB; case AudioStandard.NONE: default: return AudioDescriptor.STANDARD_NONE; diff --git a/services/core/java/com/android/server/hdmi/HdmiControlService.java b/services/core/java/com/android/server/hdmi/HdmiControlService.java index de01f9383fa58..85bd16b2cb2f7 100644 --- a/services/core/java/com/android/server/hdmi/HdmiControlService.java +++ b/services/core/java/com/android/server/hdmi/HdmiControlService.java @@ -4527,7 +4527,7 @@ public class HdmiControlService extends SystemService { } @ServiceThreadOnly - void handleEarcCapabilitiesReported(List capabilities, int portId) { + void handleEarcCapabilitiesReported(byte[] rawCapabilities, int portId) { assertRunOnServiceThread(); if (!getPortInfo(portId).isEarcSupported()) { Slog.w(TAG, @@ -4537,7 +4537,7 @@ public class HdmiControlService extends SystemService { // If eARC is disabled, the local device is null. In this case, the HAL shouldn't have // reported eARC capabilities, but even if it did, it won't take effect. if (mEarcLocalDevice != null) { - mEarcLocalDevice.handleEarcCapabilitiesReported(capabilities); + mEarcLocalDevice.handleEarcCapabilitiesReported(rawCapabilities); } } } diff --git a/services/core/java/com/android/server/hdmi/HdmiEarcController.java b/services/core/java/com/android/server/hdmi/HdmiEarcController.java index ca623810131b3..85225097ba5a6 100644 --- a/services/core/java/com/android/server/hdmi/HdmiEarcController.java +++ b/services/core/java/com/android/server/hdmi/HdmiEarcController.java @@ -21,8 +21,6 @@ import android.os.Looper; import com.android.internal.annotations.VisibleForTesting; -import java.util.List; - final class HdmiEarcController { private static final String TAG = "HdmiEarcController"; @@ -109,9 +107,9 @@ final class HdmiEarcController { () -> mService.handleEarcStateChange(status, portId)); } - public void onCapabilitiesReported(List capabilities, int portId) { + public void onCapabilitiesReported(byte[] rawCapabilities, int portId) { runOnServiceThread( - () -> mService.handleEarcCapabilitiesReported(capabilities, portId)); + () -> mService.handleEarcCapabilitiesReported(rawCapabilities, portId)); } } diff --git a/services/core/java/com/android/server/hdmi/HdmiEarcLocalDevice.java b/services/core/java/com/android/server/hdmi/HdmiEarcLocalDevice.java index 6859bdbab7f09..e95ecd2bb6cdd 100644 --- a/services/core/java/com/android/server/hdmi/HdmiEarcLocalDevice.java +++ b/services/core/java/com/android/server/hdmi/HdmiEarcLocalDevice.java @@ -21,8 +21,6 @@ import android.util.IndentingPrintWriter; import com.android.internal.annotations.GuardedBy; -import java.util.List; - /** * Class that models a local eARC device hosted in this system. * The class contains methods that are common between eARC TX and eARC RX devices. @@ -51,7 +49,7 @@ abstract class HdmiEarcLocalDevice extends HdmiLocalDevice { protected abstract void handleEarcStateChange(@Constants.EarcStatus int status); - protected abstract void handleEarcCapabilitiesReported(List capabilities); + protected abstract void handleEarcCapabilitiesReported(byte[] rawCapabilities); protected void disableDevice() { } diff --git a/services/core/java/com/android/server/hdmi/HdmiEarcLocalDeviceTx.java b/services/core/java/com/android/server/hdmi/HdmiEarcLocalDeviceTx.java index 6e629059e6d2f..c7c7702b871a1 100644 --- a/services/core/java/com/android/server/hdmi/HdmiEarcLocalDeviceTx.java +++ b/services/core/java/com/android/server/hdmi/HdmiEarcLocalDeviceTx.java @@ -27,10 +27,11 @@ import android.media.AudioDeviceInfo; import android.media.AudioProfile; import android.os.Handler; import android.util.IndentingPrintWriter; +import android.util.Slog; import java.util.ArrayList; +import java.util.Arrays; import java.util.List; -import java.util.stream.Collectors; /** * Represents a local eARC device of type TX residing in the Android system. @@ -42,6 +43,24 @@ public class HdmiEarcLocalDeviceTx extends HdmiEarcLocalDevice { // How long to wait for the audio system to report its capabilities after eARC was connected static final long REPORT_CAPS_MAX_DELAY_MS = 2_000; + // eARC Capability Data Structure parameters + private static final int EARC_CAPS_PAYLOAD_LENGTH = 0x02; + private static final int EARC_CAPS_DATA_START = 0x03; + + // Table 55 CTA Data Block Tag Codes + private static final int TAGCODE_AUDIO_DATA_BLOCK = 0x01; // Includes one or more Short Audio + // Descriptors + private static final int TAGCODE_SADB_DATA_BLOCK = 0x04; // Speaker Allocation Data Block + private static final int TAGCODE_USE_EXTENDED_TAG = 0x07; // Use Extended Tag + + // Table 56 Extended Tag Format (2nd byte of Data Block) + private static final int EXTENDED_TAGCODE_VSADB = 0x11; // Vendor-Specific Audio Data Block + + // eARC capability mask and shift + private static final int EARC_CAPS_TAGCODE_MASK = 0xE0; + private static final int EARC_CAPS_TAGCODE_SHIFT = 0x05; + private static final int EARC_CAPS_LENGTH_MASK = 0x1F; + // Handler and runnable for waiting for the audio system to report its capabilities after eARC // was connected private Handler mReportCapsHandler; @@ -71,23 +90,22 @@ public class HdmiEarcLocalDeviceTx extends HdmiEarcLocalDevice { } } - protected void handleEarcCapabilitiesReported(List capabilities) { + protected void handleEarcCapabilitiesReported(byte[] rawCapabilities) { synchronized (mLock) { if (mEarcStatus == HDMI_EARC_STATUS_EARC_CONNECTED && mReportCapsHandler.hasCallbacks(mReportCapsRunnable)) { mReportCapsHandler.removeCallbacksAndMessages(null); - notifyEarcStatusToAudioService(true, capabilities); + List audioDescriptors = parseCapabilities(rawCapabilities); + notifyEarcStatusToAudioService(true, audioDescriptors); } } } - private void notifyEarcStatusToAudioService(boolean enabled, List capabilities) { + private void notifyEarcStatusToAudioService( + boolean enabled, List audioDescriptors) { AudioDeviceAttributes attributes = new AudioDeviceAttributes( AudioDeviceAttributes.ROLE_OUTPUT, AudioDeviceInfo.TYPE_HDMI_EARC, "", "", - new ArrayList(), capabilities.stream() - .map(cap -> new AudioDescriptor(AudioDescriptor.STANDARD_EDID, - AudioProfile.AUDIO_ENCAPSULATION_TYPE_NONE, cap)) - .collect(Collectors.toList())); + new ArrayList(), audioDescriptors); mService.getAudioManager().setWiredDeviceConnectionState(attributes, enabled ? 1 : 0); } @@ -108,6 +126,81 @@ public class HdmiEarcLocalDeviceTx extends HdmiEarcLocalDevice { } } + private List parseCapabilities(byte[] rawCapabilities) { + List audioDescriptors = new ArrayList<>(); + if (rawCapabilities.length < EARC_CAPS_DATA_START + 1) { + Slog.i(TAG, "Raw eARC capabilities array doesn´t contain any blocks."); + return audioDescriptors; + } + int earcCapsSize = rawCapabilities[EARC_CAPS_PAYLOAD_LENGTH]; + if (rawCapabilities.length < earcCapsSize) { + Slog.i(TAG, "Raw eARC capabilities array is shorter than the reported payload length."); + return audioDescriptors; + } + int firstByteOfBlock = EARC_CAPS_DATA_START; + while (firstByteOfBlock < earcCapsSize) { + // Tag Code: Bit 5-7 + int tagCode = + (rawCapabilities[firstByteOfBlock] & EARC_CAPS_TAGCODE_MASK) + >> EARC_CAPS_TAGCODE_SHIFT; + // Length: Bit 0-4 + int length = rawCapabilities[firstByteOfBlock] & EARC_CAPS_LENGTH_MASK; + if (length == 0) { + // End Marker of eARC capability. + break; + } + AudioDescriptor descriptor; + switch (tagCode) { + case TAGCODE_AUDIO_DATA_BLOCK: + int earcSadLen = length; + if (length % 3 != 0) { + Slog.e(TAG, "Invalid length of SAD block: expected a factor of 3 but got " + + length % 3); + break; + } + byte[] earcSad = new byte[earcSadLen]; + System.arraycopy(rawCapabilities, firstByteOfBlock + 1, earcSad, 0, earcSadLen); + for (int i = 0; i < earcSadLen; i += 3) { + descriptor = new AudioDescriptor( + AudioDescriptor.STANDARD_EDID, + AudioProfile.AUDIO_ENCAPSULATION_TYPE_NONE, + Arrays.copyOfRange(earcSad, i, i + 3)); + audioDescriptors.add(descriptor); + } + break; + case TAGCODE_SADB_DATA_BLOCK: + //Include Tag code size + int earcSadbLen = length + 1; + byte[] earcSadb = new byte[earcSadbLen]; + System.arraycopy(rawCapabilities, firstByteOfBlock, earcSadb, 0, earcSadbLen); + descriptor = new AudioDescriptor( + AudioDescriptor.STANDARD_SADB, + AudioProfile.AUDIO_ENCAPSULATION_TYPE_NONE, + earcSadb); + audioDescriptors.add(descriptor); + break; + case TAGCODE_USE_EXTENDED_TAG: + if (rawCapabilities[firstByteOfBlock + 1] == EXTENDED_TAGCODE_VSADB) { + int earcVsadbLen = length + 1; //Include Tag code size + byte[] earcVsadb = new byte[earcVsadbLen]; + System.arraycopy(rawCapabilities, firstByteOfBlock, earcVsadb, 0, + earcVsadbLen); + descriptor = new AudioDescriptor( + AudioDescriptor.STANDARD_VSADB, + AudioProfile.AUDIO_ENCAPSULATION_TYPE_NONE, + earcVsadb); + audioDescriptors.add(descriptor); + } + break; + default: + Slog.w(TAG, "This tagcode was not handled: " + tagCode); + break; + } + firstByteOfBlock += (length + 1); + } + return audioDescriptors; + } + /** Dump internal status of HdmiEarcLocalDeviceTx object */ protected void dump(final IndentingPrintWriter pw) { synchronized (mLock) { diff --git a/services/tests/servicestests/src/com/android/server/hdmi/HdmiEarcLocalDeviceTxTest.java b/services/tests/servicestests/src/com/android/server/hdmi/HdmiEarcLocalDeviceTxTest.java index bf78a659a26ba..bf44e0944bf07 100644 --- a/services/tests/servicestests/src/com/android/server/hdmi/HdmiEarcLocalDeviceTxTest.java +++ b/services/tests/servicestests/src/com/android/server/hdmi/HdmiEarcLocalDeviceTxTest.java @@ -16,11 +16,15 @@ package com.android.server.hdmi; +import static android.media.AudioProfile.AUDIO_ENCAPSULATION_TYPE_NONE; + import static com.android.server.SystemService.PHASE_SYSTEM_SERVICES_READY; import static com.android.server.hdmi.Constants.HDMI_EARC_STATUS_ARC_PENDING; import static com.android.server.hdmi.Constants.HDMI_EARC_STATUS_EARC_CONNECTED; import static com.android.server.hdmi.Constants.HDMI_EARC_STATUS_EARC_PENDING; +import static com.google.common.truth.Truth.assertThat; + import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyInt; import static org.mockito.ArgumentMatchers.eq; @@ -29,6 +33,8 @@ import static org.mockito.Mockito.verify; import android.content.Context; import android.hardware.hdmi.HdmiDeviceInfo; +import android.media.AudioDescriptor; +import android.media.AudioDeviceAttributes; import android.media.AudioManager; import android.os.Looper; import android.os.test.TestLooper; @@ -41,12 +47,16 @@ import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.junit.runners.JUnit4; +import org.mockito.ArgumentCaptor; +import org.mockito.Captor; import org.mockito.Mock; import org.mockito.Mockito; import org.mockito.MockitoAnnotations; import java.util.ArrayList; +import java.util.Arrays; import java.util.Collections; +import java.util.List; @SmallTest @Presubmit @@ -59,12 +69,19 @@ public class HdmiEarcLocalDeviceTxTest { private HdmiEarcLocalDevice mHdmiEarcLocalDeviceTx; private FakeNativeWrapper mNativeWrapper; private FakePowerManagerWrapper mPowerManager; + private byte[] mEarcCapabilities = new byte[]{ + 0x01, 0x01, 0x1a, 0x35, 0x0f, 0x7f, 0x07, 0x15, 0x07, 0x50, 0x3d, 0x1f, (byte) 0xc0, + 0x57, 0x06, 0x03, 0x67, 0x7e, 0x03, 0x5f, 0x7e, 0x03, 0x5f, 0x7e, 0x01, (byte) 0x83, + 0x5f, 0x00, 0x00, 0x00, 0x00, 0x00}; private Looper mMyLooper; private TestLooper mTestLooper = new TestLooper(); @Mock private AudioManager mAudioManager; + @Captor + ArgumentCaptor mAudioAttributesCaptor; + @Before public void setUp() { MockitoAnnotations.initMocks(this); @@ -119,15 +136,131 @@ public class HdmiEarcLocalDeviceTxTest { } @Test - public void earcGetsConnected_capsReportedInTime() { + public void earcGetsConnected_capsReportedInTime_sad() { mHdmiEarcLocalDeviceTx.handleEarcStateChange(HDMI_EARC_STATUS_EARC_CONNECTED); mTestLooper.moveTimeForward(HdmiEarcLocalDeviceTx.REPORT_CAPS_MAX_DELAY_MS - 200); mTestLooper.dispatchAll(); - // TO DO: add meaningful capabilities and test that they get forwarded to AudioManager - // correctly. - mHdmiEarcLocalDeviceTx.handleEarcCapabilitiesReported(new ArrayList<>()); + mHdmiEarcLocalDeviceTx.handleEarcCapabilitiesReported(new byte[]{ + 0x01, 0x01, 0x1a, 0x35, 0x0f, 0x7f, 0x07, 0x15, 0x07, 0x50, 0x3d, 0x1f, (byte) 0xc0, + 0x57, 0x06, 0x03, 0x67, 0x7e, 0x03, 0x5f, 0x7e, 0x03, 0x5f, 0x7e, 0x01, 0x00, 0x5f, + 0x00, 0x00, 0x00, 0x00, 0x00 + }); mTestLooper.dispatchAll(); - verify(mAudioManager, times(1)).setWiredDeviceConnectionState(any(), eq(1)); + verify(mAudioManager, times(1)).setWiredDeviceConnectionState( + mAudioAttributesCaptor.capture(), eq(1)); + AudioDeviceAttributes attributes = mAudioAttributesCaptor.getValue(); + List descriptors = attributes.getAudioDescriptors(); + List expectedDescriptors = new ArrayList(Arrays.asList( + new AudioDescriptor(AudioDescriptor.STANDARD_EDID, AUDIO_ENCAPSULATION_TYPE_NONE, + new byte[] {15, 127, 7}), + new AudioDescriptor(AudioDescriptor.STANDARD_EDID, AUDIO_ENCAPSULATION_TYPE_NONE, + new byte[] {21, 7, 80}), + new AudioDescriptor(AudioDescriptor.STANDARD_EDID, AUDIO_ENCAPSULATION_TYPE_NONE, + new byte[] {61, 31, -64}), + new AudioDescriptor(AudioDescriptor.STANDARD_EDID, AUDIO_ENCAPSULATION_TYPE_NONE, + new byte[] {87, 6, 3}), + new AudioDescriptor(AudioDescriptor.STANDARD_EDID, AUDIO_ENCAPSULATION_TYPE_NONE, + new byte[] {103, 126, 3}), + new AudioDescriptor(AudioDescriptor.STANDARD_EDID, AUDIO_ENCAPSULATION_TYPE_NONE, + new byte[] {95, 126, 3}), + new AudioDescriptor(AudioDescriptor.STANDARD_EDID, AUDIO_ENCAPSULATION_TYPE_NONE, + new byte[] {95, 126, 1}))); + assertThat(descriptors).isEqualTo(expectedDescriptors); + } + + @Test + public void earcGetsConnected_capsReportedInTime_sad_sadb() { + mHdmiEarcLocalDeviceTx.handleEarcStateChange(HDMI_EARC_STATUS_EARC_CONNECTED); + mTestLooper.moveTimeForward(HdmiEarcLocalDeviceTx.REPORT_CAPS_MAX_DELAY_MS - 200); + mTestLooper.dispatchAll(); + mHdmiEarcLocalDeviceTx.handleEarcCapabilitiesReported(new byte[]{ + 0x01, 0x01, 0x1a, 0x35, 0x0f, 0x7f, 0x07, 0x15, 0x07, 0x50, 0x3d, 0x1f, (byte) 0xc0, + 0x57, 0x06, 0x03, 0x67, 0x7e, 0x03, 0x5f, 0x7e, 0x03, 0x5f, 0x7e, 0x01, (byte) 0x83, + 0x5f, 0x00, 0x00, 0x00, 0x00, 0x00}); + mTestLooper.dispatchAll(); + verify(mAudioManager, times(1)).setWiredDeviceConnectionState( + mAudioAttributesCaptor.capture(), eq(1)); + AudioDeviceAttributes attributes = mAudioAttributesCaptor.getValue(); + List descriptors = attributes.getAudioDescriptors(); + List expectedDescriptors = new ArrayList(Arrays.asList( + new AudioDescriptor(AudioDescriptor.STANDARD_EDID, AUDIO_ENCAPSULATION_TYPE_NONE, + new byte[] {15, 127, 7}), + new AudioDescriptor(AudioDescriptor.STANDARD_EDID, AUDIO_ENCAPSULATION_TYPE_NONE, + new byte[] {21, 7, 80}), + new AudioDescriptor(AudioDescriptor.STANDARD_EDID, AUDIO_ENCAPSULATION_TYPE_NONE, + new byte[] {61, 31, -64}), + new AudioDescriptor(AudioDescriptor.STANDARD_EDID, AUDIO_ENCAPSULATION_TYPE_NONE, + new byte[] {87, 6, 3}), + new AudioDescriptor(AudioDescriptor.STANDARD_EDID, AUDIO_ENCAPSULATION_TYPE_NONE, + new byte[] {103, 126, 3}), + new AudioDescriptor(AudioDescriptor.STANDARD_EDID, AUDIO_ENCAPSULATION_TYPE_NONE, + new byte[] {95, 126, 3}), + new AudioDescriptor(AudioDescriptor.STANDARD_EDID, AUDIO_ENCAPSULATION_TYPE_NONE, + new byte[] {95, 126, 1}), + new AudioDescriptor(AudioDescriptor.STANDARD_SADB, AUDIO_ENCAPSULATION_TYPE_NONE, + new byte[] {-125, 95, 0, 0}))); + assertThat(descriptors).isEqualTo(expectedDescriptors); + } + + @Test + public void earcGetsConnected_capsReportedInTime_sad_sadb_vsadb() { + mHdmiEarcLocalDeviceTx.handleEarcStateChange(HDMI_EARC_STATUS_EARC_CONNECTED); + mTestLooper.moveTimeForward(HdmiEarcLocalDeviceTx.REPORT_CAPS_MAX_DELAY_MS - 200); + mTestLooper.dispatchAll(); + mHdmiEarcLocalDeviceTx.handleEarcCapabilitiesReported(new byte[]{ + 0x01, 0x01, 0x21, 0x35, 0x5F, 0x7E, 0x03, 0x5F, 0x7E, 0x01, 0x67, 0x7E, 0x03, 0x57, + 0x06, 0x03, 0x3D, 0x1E, (byte) 0xC0, 0x15, 0x07, 0x50, 0x0F, 0x7F, 0x07, + (byte) 0x83, 0x5F, 0x00, 0x00, (byte) 0xE6, 0x11, 0x46, (byte) 0xD0, 0x00, 0x70, + 0x00, 0x03, 0x01, (byte) 0x80, 0x00, (byte) 0x9D, (byte) 0xAD, (byte) 0x9E, 0x7B, + 0x08, (byte) 0xC1, (byte) 0xA8, 0x23, (byte) 0x9B, 0x49, 0x5C, (byte) 0xF5, 0x6B, + (byte) 0xAC, 0x22, (byte) 0xC2, (byte) 0x80, 0x48, 0x67, 0x7F, 0x59, 0x1C, 0x20, + 0x71, 0x35, 0x25, (byte) 0x9F, 0x43, 0x70, 0x1E, 0x32, 0x15, 0x60, (byte) 0xED, + (byte) 0xC8, 0x77, (byte) 0xA3, 0x24, 0x2E, (byte) 0xDA, (byte) 0x94, 0x6D, 0x35, + 0x34, 0x0F, 0x30, 0x62, 0x1A, 0x3B, (byte) 0xC9, 0x5A, (byte) 0xE6, (byte) 0xD8, + 0x22, 0x11, 0x56, (byte) 0xA6, (byte) 0x99, (byte) 0xCF, (byte) 0xE3, 0x1B, + (byte) 0x88, (byte) 0xA0, 0x2A, 0x5B, 0x6C, 0x5E, 0x53, 0x01, 0x47, 0x69, 0x51, + 0x61, (byte) 0xC7, (byte) 0xCB, 0x1B, 0x28, 0x14, 0x23, 0x10, (byte) 0xB1, 0x34, + 0x5E, 0x57, (byte) 0x97, (byte) 0xB3, 0x78, 0x03, 0x79, (byte) 0x8A, (byte) 0xFE, + 0x1E, (byte) 0xC8, (byte) 0xAB, 0x14, 0x74, 0x73, (byte) 0xFA, (byte) 0xBB, + (byte) 0xF7, 0x4E, 0x00, (byte) 0xFC, 0x5C, (byte) 0xDC, (byte) 0x8B, (byte) 0xC9, + 0x1E, 0x16, 0x35, (byte) 0xB1, (byte) 0x98, (byte) 0xEB, 0x2B, (byte) 0xE6, + (byte) 0xFC, (byte) 0xCC, 0x3C, 0x30, 0x19, 0x40, (byte) 0xC0, 0x50, (byte) 0xF2, + 0x58, 0x30, 0x4B, 0x0C, 0x7A, (byte) 0xE0, (byte) 0xFF, 0x7A, 0x64, 0x78, + (byte) 0xF8, 0x56, (byte) 0xF8, 0x6E, 0x72, 0x42, 0x49, 0x4E, (byte) 0xA6, + (byte) 0x95, (byte) 0xF5, 0x4C, 0x4F, (byte) 0xFF, 0x7F, 0x21, (byte) 0xA2, + (byte) 0x98, 0x33, (byte) 0x90, (byte) 0xFD, 0x17, 0x08, 0x13, (byte) 0xB2, 0x00, + (byte) 0xA9, (byte) 0xB5, (byte) 0xBD, (byte) 0xB5, (byte) 0xC1, (byte) 0xC7, 0x45, + (byte) 0xD9, (byte) 0xDC, (byte) 0x8B, 0x58, (byte) 0xB3, 0x5D, 0x5E, 0x72, + (byte) 0xE6, (byte) 0x8D, (byte) 0xDD, 0x0B, 0x21, (byte) 0xF3, (byte) 0x9A, + (byte) 0x8E, 0x1B, 0x79, 0x59, (byte) 0xE1, 0x3F, (byte) 0xAC, 0x24, (byte) 0xA0, + (byte) 0xC8, 0x56, (byte) 0xFD, (byte) 0x85, (byte) 0x8F, 0x6A, (byte) 0x80, 0x41, + (byte) 0xA8, 0x5D, 0x2C, (byte) 0xC2, 0x69, (byte) 0xA1, 0x0D, (byte) 0x82, 0x04, + 0x5D, (byte) 0xCA, (byte) 0xB4, (byte) 0x9F, 0x3A, 0x2D, (byte) 0xBF, 0x24}); + mTestLooper.dispatchAll(); + verify(mAudioManager, times(1)).setWiredDeviceConnectionState( + mAudioAttributesCaptor.capture(), eq(1)); + AudioDeviceAttributes attributes = mAudioAttributesCaptor.getValue(); + List descriptors = attributes.getAudioDescriptors(); + List expectedDescriptors = new ArrayList(Arrays.asList( + new AudioDescriptor(AudioDescriptor.STANDARD_EDID, AUDIO_ENCAPSULATION_TYPE_NONE, + new byte[] {95, 126, 3}), + new AudioDescriptor(AudioDescriptor.STANDARD_EDID, AUDIO_ENCAPSULATION_TYPE_NONE, + new byte[] {95, 126, 1}), + new AudioDescriptor(AudioDescriptor.STANDARD_EDID, AUDIO_ENCAPSULATION_TYPE_NONE, + new byte[] {103, 126, 3}), + new AudioDescriptor(AudioDescriptor.STANDARD_EDID, AUDIO_ENCAPSULATION_TYPE_NONE, + new byte[] {87, 6, 3}), + new AudioDescriptor(AudioDescriptor.STANDARD_EDID, AUDIO_ENCAPSULATION_TYPE_NONE, + new byte[] {61, 30, -64}), + new AudioDescriptor(AudioDescriptor.STANDARD_EDID, AUDIO_ENCAPSULATION_TYPE_NONE, + new byte[] {21, 7, 80}), + new AudioDescriptor(AudioDescriptor.STANDARD_EDID, AUDIO_ENCAPSULATION_TYPE_NONE, + new byte[] {15, 127, 7}), + new AudioDescriptor(AudioDescriptor.STANDARD_SADB, AUDIO_ENCAPSULATION_TYPE_NONE, + new byte[] {-125, 95, 0, 0}), + new AudioDescriptor(AudioDescriptor.STANDARD_VSADB, AUDIO_ENCAPSULATION_TYPE_NONE, + new byte[] {-26, 17, 70, -48, 0, 112, 0}))); + assertThat(descriptors).isEqualTo(expectedDescriptors); } @Test @@ -135,11 +268,14 @@ public class HdmiEarcLocalDeviceTxTest { mHdmiEarcLocalDeviceTx.handleEarcStateChange(HDMI_EARC_STATUS_EARC_CONNECTED); mTestLooper.moveTimeForward(HdmiEarcLocalDeviceTx.REPORT_CAPS_MAX_DELAY_MS + 1); mTestLooper.dispatchAll(); - // TO DO: verify that empty capabilities are forwarded to AudioManager. - verify(mAudioManager, times(1)).setWiredDeviceConnectionState(any(), eq(1)); + verify(mAudioManager, times(1)).setWiredDeviceConnectionState( + mAudioAttributesCaptor.capture(), eq(1)); + AudioDeviceAttributes attributes = mAudioAttributesCaptor.getValue(); + List descriptors = attributes.getAudioDescriptors(); + assertThat(descriptors).hasSize(0); Mockito.clearInvocations(mAudioManager); - mHdmiEarcLocalDeviceTx.handleEarcCapabilitiesReported(new ArrayList<>()); + mHdmiEarcLocalDeviceTx.handleEarcCapabilitiesReported(mEarcCapabilities); mTestLooper.dispatchAll(); verify(mAudioManager, times(0)).setWiredDeviceConnectionState(any(), anyInt()); } @@ -151,10 +287,14 @@ public class HdmiEarcLocalDeviceTxTest { mHdmiEarcLocalDeviceTx.handleEarcStateChange(HDMI_EARC_STATUS_ARC_PENDING); mTestLooper.dispatchAll(); verify(mAudioManager, times(0)).setWiredDeviceConnectionState(any(), eq(1)); - verify(mAudioManager, times(1)).setWiredDeviceConnectionState(any(), eq(0)); + verify(mAudioManager, times(1)).setWiredDeviceConnectionState( + mAudioAttributesCaptor.capture(), eq(0)); + AudioDeviceAttributes attributes = mAudioAttributesCaptor.getValue(); + List descriptors = attributes.getAudioDescriptors(); + assertThat(descriptors).hasSize(0); Mockito.clearInvocations(mAudioManager); - mHdmiEarcLocalDeviceTx.handleEarcCapabilitiesReported(new ArrayList<>()); + mHdmiEarcLocalDeviceTx.handleEarcCapabilitiesReported(mEarcCapabilities); mTestLooper.dispatchAll(); verify(mAudioManager, times(0)).setWiredDeviceConnectionState(any(), anyInt()); } @@ -168,7 +308,7 @@ public class HdmiEarcLocalDeviceTxTest { verify(mAudioManager, times(0)).setWiredDeviceConnectionState(any(), anyInt()); Mockito.clearInvocations(mAudioManager); - mHdmiEarcLocalDeviceTx.handleEarcCapabilitiesReported(new ArrayList<>()); + mHdmiEarcLocalDeviceTx.handleEarcCapabilitiesReported(mEarcCapabilities); mTestLooper.dispatchAll(); verify(mAudioManager, times(0)).setWiredDeviceConnectionState(any(), anyInt()); }