diff options
| author | 2022-09-20 11:37:32 +0000 | |
|---|---|---|
| committer | 2022-09-20 11:37:32 +0000 | |
| commit | b65741930f85808ced26b99fea1f4544b5ec5cb6 (patch) | |
| tree | 6a8243ef51026880bb9127aeaf3faa966be51a66 | |
| parent | 773627cfd38fdb413cc4f63b98f4d867d072e8ee (diff) | |
| parent | ef3c489eee4503a38e3bf5bcace4618c416610f5 (diff) | |
Merge "CEC: Implement getSupportedShortAudioDescriptor method."
| -rw-r--r-- | services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceAudioSystem.java | 229 |
1 files changed, 181 insertions, 48 deletions
diff --git a/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceAudioSystem.java b/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceAudioSystem.java index 99bbc3f2d86b..32ff5e220825 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 @@ 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); + @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; + } + } } - // 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; + } + 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; } - @Nullable - private byte[] getLpcmShortAudioDescriptor(AudioDeviceInfo deviceInfo) { - // TODO(b/80297701): implement - return null; + /** + * 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 |