Merge "CEC: Implement getSupportedShortAudioDescriptor method."
diff --git a/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceAudioSystem.java b/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceAudioSystem.java
index 99bbc3f..32ff5e22 100644
--- a/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceAudioSystem.java
+++ b/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceAudioSystem.java
@@ -71,6 +71,9 @@
private static final String TAG = "HdmiCecLocalDeviceAudioSystem";
private static final boolean WAKE_ON_HOTPLUG = false;
+ private static final int MAX_CHANNELS = 8;
+ private static final HashMap<Integer, List<Integer>> AUDIO_CODECS_MAP =
+ mapAudioCodecWithAudioFormat();
// Whether the System Audio Control feature is enabled or not. True by default.
@GuardedBy("mLock")
@@ -485,17 +488,17 @@
}
}
- @AudioCodec int[] audioFormatCodes = parseAudioFormatCodes(message.getParams());
+ @AudioCodec int[] audioCodecs = parseAudioCodecs(message.getParams());
byte[] sadBytes;
if (config != null && config.size() > 0) {
- sadBytes = getSupportedShortAudioDescriptorsFromConfig(config, audioFormatCodes);
+ sadBytes = getSupportedShortAudioDescriptorsFromConfig(config, audioCodecs);
} else {
AudioDeviceInfo deviceInfo = getSystemAudioDeviceInfo();
if (deviceInfo == null) {
return Constants.ABORT_UNABLE_TO_DETERMINE;
}
- sadBytes = getSupportedShortAudioDescriptors(deviceInfo, audioFormatCodes);
+ sadBytes = getSupportedShortAudioDescriptors(deviceInfo, audioCodecs);
}
if (sadBytes.length == 0) {
@@ -508,11 +511,12 @@
}
}
- private byte[] getSupportedShortAudioDescriptors(
- AudioDeviceInfo deviceInfo, @AudioCodec int[] audioFormatCodes) {
- ArrayList<byte[]> sads = new ArrayList<>(audioFormatCodes.length);
- for (@AudioCodec int audioFormatCode : audioFormatCodes) {
- byte[] sad = getSupportedShortAudioDescriptor(deviceInfo, audioFormatCode);
+ @VisibleForTesting
+ byte[] getSupportedShortAudioDescriptors(
+ AudioDeviceInfo deviceInfo, @AudioCodec int[] audioCodecs) {
+ ArrayList<byte[]> sads = new ArrayList<>(audioCodecs.length);
+ for (@AudioCodec int audioCodec : audioCodecs) {
+ byte[] sad = getSupportedShortAudioDescriptor(deviceInfo, audioCodec);
if (sad != null) {
if (sad.length == 3) {
@@ -520,7 +524,7 @@
} else {
HdmiLogger.warning(
"Dropping Short Audio Descriptor with length %d for requested codec %x",
- sad.length, audioFormatCode);
+ sad.length, audioCodec);
}
}
}
@@ -528,7 +532,7 @@
}
private byte[] getSupportedShortAudioDescriptorsFromConfig(
- List<DeviceConfig> deviceConfig, @AudioCodec int[] audioFormatCodes) {
+ List<DeviceConfig> deviceConfig, @AudioCodec int[] audioCodecs) {
DeviceConfig deviceConfigToUse = null;
String audioDeviceName = SystemProperties.get(
Constants.PROPERTY_SYSTEM_AUDIO_MODE_AUDIO_PORT,
@@ -544,13 +548,13 @@
return new byte[0];
}
HashMap<Integer, byte[]> map = new HashMap<>();
- ArrayList<byte[]> sads = new ArrayList<>(audioFormatCodes.length);
+ ArrayList<byte[]> sads = new ArrayList<>(audioCodecs.length);
for (CodecSad codecSad : deviceConfigToUse.supportedCodecs) {
map.put(codecSad.audioCodec, codecSad.sad);
}
- for (int i = 0; i < audioFormatCodes.length; i++) {
- if (map.containsKey(audioFormatCodes[i])) {
- byte[] sad = map.get(audioFormatCodes[i]);
+ for (int i = 0; i < audioCodecs.length; i++) {
+ if (map.containsKey(audioCodecs[i])) {
+ byte[] sad = map.get(audioCodecs[i]);
if (sad != null && sad.length == 3) {
sads.add(sad);
}
@@ -572,42 +576,171 @@
/**
* Returns a 3 byte short audio descriptor as described in CEC 1.4 table 29 or null if the
- * audioFormatCode is not supported.
+ * audioCodec is not supported.
*/
@Nullable
- private byte[] getSupportedShortAudioDescriptor(
- AudioDeviceInfo deviceInfo, @AudioCodec int audioFormatCode) {
- switch (audioFormatCode) {
- case Constants.AUDIO_CODEC_NONE: {
- return null;
- }
- case Constants.AUDIO_CODEC_LPCM: {
- return getLpcmShortAudioDescriptor(deviceInfo);
- }
- // TODO(b/80297701): implement the rest of the codecs
- case Constants.AUDIO_CODEC_DD:
- case Constants.AUDIO_CODEC_MPEG1:
- case Constants.AUDIO_CODEC_MP3:
- case Constants.AUDIO_CODEC_MPEG2:
- case Constants.AUDIO_CODEC_AAC:
- case Constants.AUDIO_CODEC_DTS:
- case Constants.AUDIO_CODEC_ATRAC:
- case Constants.AUDIO_CODEC_ONEBITAUDIO:
- case Constants.AUDIO_CODEC_DDP:
- case Constants.AUDIO_CODEC_DTSHD:
- case Constants.AUDIO_CODEC_TRUEHD:
- case Constants.AUDIO_CODEC_DST:
- case Constants.AUDIO_CODEC_WMAPRO:
- default: {
- return null;
+ @VisibleForTesting
+ byte[] getSupportedShortAudioDescriptor(
+ AudioDeviceInfo deviceInfo, @AudioCodec int audioCodec) {
+ byte[] shortAudioDescriptor = new byte[3];
+
+ int[] deviceSupportedAudioFormats = deviceInfo.getEncodings();
+ // Return null when audioCodec or device does not support any audio formats.
+ if (!AUDIO_CODECS_MAP.containsKey(audioCodec) || deviceSupportedAudioFormats.length == 0) {
+ return null;
+ }
+ List<Integer> audioCodecSupportedAudioFormats = AUDIO_CODECS_MAP.get(audioCodec);
+
+ for (int supportedAudioFormat : deviceSupportedAudioFormats) {
+ if (audioCodecSupportedAudioFormats.contains(supportedAudioFormat)) {
+ // Initialise the first two bytes of short audio descriptor.
+ shortAudioDescriptor[0] = getFirstByteOfSAD(deviceInfo, audioCodec);
+ shortAudioDescriptor[1] = getSecondByteOfSAD(deviceInfo);
+ switch (audioCodec) {
+ case Constants.AUDIO_CODEC_NONE: {
+ return null;
+ }
+ case Constants.AUDIO_CODEC_LPCM: {
+ if (supportedAudioFormat == AudioFormat.ENCODING_PCM_16BIT) {
+ shortAudioDescriptor[2] = (byte) 0x01;
+ } else if (supportedAudioFormat
+ == AudioFormat.ENCODING_PCM_24BIT_PACKED) {
+ shortAudioDescriptor[2] = (byte) 0x04;
+ } else {
+ // Since no bit is reserved for these audio formats in LPCM codec.
+ shortAudioDescriptor[2] = (byte) 0x00;
+ }
+ return shortAudioDescriptor;
+ }
+ case Constants.AUDIO_CODEC_DD:
+ case Constants.AUDIO_CODEC_MPEG1:
+ case Constants.AUDIO_CODEC_MP3:
+ case Constants.AUDIO_CODEC_MPEG2:
+ case Constants.AUDIO_CODEC_AAC:
+ case Constants.AUDIO_CODEC_DTS: {
+ shortAudioDescriptor[2] = getThirdSadByteForCodecs2Through8(deviceInfo);
+ return shortAudioDescriptor;
+ }
+ case Constants.AUDIO_CODEC_DDP:
+ case Constants.AUDIO_CODEC_DTSHD:
+ case Constants.AUDIO_CODEC_TRUEHD: {
+ // Default value is 0x0 unless defined by Audio Codec Vendor.
+ shortAudioDescriptor[2] = (byte) 0x00;
+ return shortAudioDescriptor;
+ }
+ case Constants.AUDIO_CODEC_ATRAC:
+ case Constants.AUDIO_CODEC_ONEBITAUDIO:
+ case Constants.AUDIO_CODEC_DST:
+ case Constants.AUDIO_CODEC_WMAPRO:
+ // Not supported.
+ default: {
+ return null;
+ }
+ }
}
}
+ return null;
}
- @Nullable
- private byte[] getLpcmShortAudioDescriptor(AudioDeviceInfo deviceInfo) {
- // TODO(b/80297701): implement
- return null;
+ private static HashMap<Integer, List<Integer>> mapAudioCodecWithAudioFormat() {
+ // Mapping the values of @AudioCodec audio codecs with @AudioFormat audio formats.
+ HashMap<Integer, List<Integer>> audioCodecsMap = new HashMap<Integer, List<Integer>>();
+
+ audioCodecsMap.put(Constants.AUDIO_CODEC_NONE, List.of(AudioFormat.ENCODING_DEFAULT));
+ audioCodecsMap.put(
+ Constants.AUDIO_CODEC_LPCM,
+ List.of(
+ AudioFormat.ENCODING_PCM_8BIT,
+ AudioFormat.ENCODING_PCM_16BIT,
+ AudioFormat.ENCODING_PCM_FLOAT,
+ AudioFormat.ENCODING_PCM_24BIT_PACKED,
+ AudioFormat.ENCODING_PCM_32BIT));
+ audioCodecsMap.put(Constants.AUDIO_CODEC_DD, List.of(AudioFormat.ENCODING_AC3));
+ audioCodecsMap.put(Constants.AUDIO_CODEC_MPEG1, List.of(AudioFormat.ENCODING_AAC_HE_V1));
+ audioCodecsMap.put(Constants.AUDIO_CODEC_MPEG2, List.of(AudioFormat.ENCODING_AAC_HE_V2));
+ audioCodecsMap.put(Constants.AUDIO_CODEC_MP3, List.of(AudioFormat.ENCODING_MP3));
+ audioCodecsMap.put(Constants.AUDIO_CODEC_AAC, List.of(AudioFormat.ENCODING_AAC_LC));
+ audioCodecsMap.put(Constants.AUDIO_CODEC_DTS, List.of(AudioFormat.ENCODING_DTS));
+ audioCodecsMap.put(
+ Constants.AUDIO_CODEC_DDP,
+ List.of(AudioFormat.ENCODING_E_AC3, AudioFormat.ENCODING_E_AC3_JOC));
+ audioCodecsMap.put(Constants.AUDIO_CODEC_DTSHD, List.of(AudioFormat.ENCODING_DTS_HD));
+ audioCodecsMap.put(
+ Constants.AUDIO_CODEC_TRUEHD,
+ List.of(AudioFormat.ENCODING_DOLBY_TRUEHD, AudioFormat.ENCODING_DOLBY_MAT));
+
+ return audioCodecsMap;
+ }
+
+ private byte getFirstByteOfSAD(AudioDeviceInfo deviceInfo, @AudioCodec int audioCodec) {
+ byte firstByte = 0;
+ int maxNumberOfChannels = getMaxNumberOfChannels(deviceInfo);
+
+ // Fill bits 0-2 of the first byte.
+ firstByte |= (maxNumberOfChannels - 1);
+
+ // Fill bits 3-6 of the first byte.
+ firstByte |= (audioCodec << 3);
+
+ return firstByte;
+ }
+
+ private byte getSecondByteOfSAD(AudioDeviceInfo deviceInfo) {
+ ArrayList<Integer> samplingRates =
+ new ArrayList<Integer>(Arrays.asList(32, 44, 48, 88, 96, 176, 192));
+
+ // samplingRatesdevicesupports is guaranteed to be not null
+ int[] samplingRatesDeviceSupports = deviceInfo.getSampleRates();
+ if (samplingRatesDeviceSupports.length == 0) {
+ Slog.e(TAG, "Device supports arbitrary rates");
+ // Since device supports arbitrary rates, we will return 0x7f since bit 7 is reserved.
+ return (byte) 0x7f;
+ }
+ byte secondByte = 0;
+ for (int supportedSampleRate : samplingRatesDeviceSupports) {
+ if (samplingRates.contains(supportedSampleRate)) {
+ int index = samplingRates.indexOf(supportedSampleRate);
+ // Setting the bit of a sample rate which is being supported.
+ secondByte |= (1 << index);
+ }
+ }
+
+ return secondByte;
+ }
+
+ /**
+ * Empty array from deviceInfo.getChannelCounts() implies device supports arbitrary channel
+ * counts and hence we assume max channels are supported by the device.
+ */
+ private int getMaxNumberOfChannels(AudioDeviceInfo deviceInfo) {
+ int maxNumberOfChannels = MAX_CHANNELS;
+ int[] channelCounts = deviceInfo.getChannelCounts();
+ if (channelCounts.length != 0) {
+ maxNumberOfChannels = channelCounts[channelCounts.length - 1];
+ maxNumberOfChannels =
+ (maxNumberOfChannels > MAX_CHANNELS ? MAX_CHANNELS : maxNumberOfChannels);
+ }
+ return maxNumberOfChannels;
+ }
+
+ private byte getThirdSadByteForCodecs2Through8(AudioDeviceInfo deviceInfo) {
+ /*
+ * Here, we are assuming that max bit rate is closely equals to the max sampling rate the
+ * device supports.
+ */
+ int maxSamplingRate = 0;
+ int[] samplingRatesDeviceSupports = deviceInfo.getSampleRates();
+ if (samplingRatesDeviceSupports.length == 0) {
+ maxSamplingRate = 192;
+ } else {
+ for (int sampleRate : samplingRatesDeviceSupports) {
+ if (maxSamplingRate < sampleRate) {
+ maxSamplingRate = sampleRate;
+ }
+ }
+ }
+
+ return (byte) (maxSamplingRate / 8);
}
@Nullable
@@ -634,14 +767,14 @@
}
@AudioCodec
- private int[] parseAudioFormatCodes(byte[] params) {
- @AudioCodec int[] audioFormatCodes = new int[params.length];
+ private int[] parseAudioCodecs(byte[] params) {
+ @AudioCodec int[] audioCodecs = new int[params.length];
for (int i = 0; i < params.length; i++) {
byte val = params[i];
- audioFormatCodes[i] =
- val >= 1 && val <= Constants.AUDIO_CODEC_MAX ? val : Constants.AUDIO_CODEC_NONE;
+ audioCodecs[i] =
+ val >= 1 && val <= Constants.AUDIO_CODEC_MAX ? val : Constants.AUDIO_CODEC_NONE;
}
- return audioFormatCodes;
+ return audioCodecs;
}
@Override