CEC: Implement getSupportedShortAudioDescriptor method.

Construct the three byte short audio descriptor for the
audio format codecs when parsing of sadConfig.xml file is failed
in HdmiCecLocalDeviceAudioSystem class.

Bug: 231308055
Test: None

Change-Id: I8177409b9004ff6ff3f539372b636874208575db
This commit is contained in:
Aravind Angadi
2021-03-09 01:09:03 +05:30
committed by Venkatarama Avadhani
parent 565f2ab115
commit ef3c489eee

View File

@@ -71,6 +71,9 @@ public class HdmiCecLocalDeviceAudioSystem extends HdmiCecLocalDeviceSource {
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 @@ public class HdmiCecLocalDeviceAudioSystem extends HdmiCecLocalDeviceSource {
}
}
@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 @@ public class HdmiCecLocalDeviceAudioSystem extends HdmiCecLocalDeviceSource {
}
}
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 @@ public class HdmiCecLocalDeviceAudioSystem extends HdmiCecLocalDeviceSource {
} else {
HdmiLogger.warning(
"Dropping Short Audio Descriptor with length %d for requested codec %x",
sad.length, audioFormatCode);
sad.length, audioCodec);
}
}
}
@@ -528,7 +532,7 @@ public class HdmiCecLocalDeviceAudioSystem extends HdmiCecLocalDeviceSource {
}
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 @@ public class HdmiCecLocalDeviceAudioSystem extends HdmiCecLocalDeviceSource {
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 @@ public class HdmiCecLocalDeviceAudioSystem extends HdmiCecLocalDeviceSource {
/**
* 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 @@ public class HdmiCecLocalDeviceAudioSystem extends HdmiCecLocalDeviceSource {
}
@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