From b73d2cc736486cbb9bcf0c7abc008f878a5e1216 Mon Sep 17 00:00:00 2001 From: Cedric T Date: Tue, 18 Apr 2023 20:53:45 +0800 Subject: [PATCH 01/33] Add direct passthrough support for DTS audio. --- .../java/androidx/media3/common/MimeTypes.java | 4 ++++ .../java/androidx/media3/common/util/Util.java | 8 ++++++++ .../exoplayer/audio/AudioCapabilities.java | 13 ++++++++++--- .../java/androidx/media3/extractor/DtsUtil.java | 16 ++++++++++++++++ 4 files changed, 38 insertions(+), 3 deletions(-) diff --git a/libraries/common/src/main/java/androidx/media3/common/MimeTypes.java b/libraries/common/src/main/java/androidx/media3/common/MimeTypes.java index 5c9742e79d..27db8c9305 100644 --- a/libraries/common/src/main/java/androidx/media3/common/MimeTypes.java +++ b/libraries/common/src/main/java/androidx/media3/common/MimeTypes.java @@ -595,6 +595,10 @@ public final class MimeTypes { return C.ENCODING_DTS; case MimeTypes.AUDIO_DTS_HD: return C.ENCODING_DTS_HD; + case MimeTypes.AUDIO_DTS_EXPRESS: + return C.ENCODING_DTS; // This should be ENCODING_DTS_HD when IC platforms support it. + case MimeTypes.AUDIO_DTS_X: + return C.ENCODING_DTS; // This should be ENCODING_DTS_UHD_P2 when IC platforms support it. case MimeTypes.AUDIO_TRUEHD: return C.ENCODING_DOLBY_TRUEHD; case MimeTypes.AUDIO_OPUS: diff --git a/libraries/common/src/main/java/androidx/media3/common/util/Util.java b/libraries/common/src/main/java/androidx/media3/common/util/Util.java index 377b8bf6d8..ac87584747 100644 --- a/libraries/common/src/main/java/androidx/media3/common/util/Util.java +++ b/libraries/common/src/main/java/androidx/media3/common/util/Util.java @@ -1884,6 +1884,14 @@ public final class Util { return AudioFormat.CHANNEL_OUT_5POINT1 | AudioFormat.CHANNEL_OUT_BACK_CENTER; case 8: return AudioFormat.CHANNEL_OUT_7POINT1_SURROUND; + case 10: + if (Util.SDK_INT > 31) { + return AudioFormat.CHANNEL_OUT_5POINT1POINT4; + } else { + // This is used by DTS:X P2 with Direct Passthrough Playback. + // Specifying the audio format as 7.1 for 10 channels does not affect the playback. + return AudioFormat.CHANNEL_OUT_7POINT1_SURROUND; + } case 12: return AudioFormat.CHANNEL_OUT_7POINT1POINT4; default: diff --git a/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/audio/AudioCapabilities.java b/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/audio/AudioCapabilities.java index 499a2ae51c..57dc24e650 100644 --- a/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/audio/AudioCapabilities.java +++ b/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/audio/AudioCapabilities.java @@ -59,8 +59,9 @@ public final class AudioCapabilities { @SuppressWarnings("InlinedApi") private static final AudioCapabilities EXTERNAL_SURROUND_SOUND_CAPABILITIES = new AudioCapabilities( - new int[] { - AudioFormat.ENCODING_PCM_16BIT, AudioFormat.ENCODING_AC3, AudioFormat.ENCODING_E_AC3 + new int[]{ + AudioFormat.ENCODING_PCM_16BIT, AudioFormat.ENCODING_AC3, AudioFormat.ENCODING_E_AC3, + AudioFormat.ENCODING_DTS, AudioFormat.ENCODING_DTS_HD }, DEFAULT_MAX_CHANNEL_COUNT); @@ -220,7 +221,13 @@ public final class AudioCapabilities { channelCount = getMaxSupportedChannelCountForPassthrough(encoding, sampleRate); } else { channelCount = format.channelCount; - if (channelCount > maxChannelCount) { + if (format.sampleMimeType == MimeTypes.AUDIO_DTS_X) { + if (channelCount > 10) { + // To fix wrong reporting from device. ChannelCount is reported as 8 for DTS:X P2 + // on some devices. + return null; + } + } else if (channelCount > maxChannelCount) { return null; } } diff --git a/libraries/extractor/src/main/java/androidx/media3/extractor/DtsUtil.java b/libraries/extractor/src/main/java/androidx/media3/extractor/DtsUtil.java index 75e4004125..b835b231af 100644 --- a/libraries/extractor/src/main/java/androidx/media3/extractor/DtsUtil.java +++ b/libraries/extractor/src/main/java/androidx/media3/extractor/DtsUtil.java @@ -41,6 +41,9 @@ public final class DtsUtil { private static final int SYNC_VALUE_14B_BE = 0x1FFFE800; private static final int SYNC_VALUE_LE = 0xFE7F0180; private static final int SYNC_VALUE_14B_LE = 0xFF1F00E8; + private static final int SYNC_EXT_SUB_LE = 0x25205864; + private static final int SYNC_FTOC_LE = 0xF21B4140; + private static final int SYNC_FTOC_NON_SYNC_LE = 0xE842C471; private static final byte FIRST_BYTE_BE = (byte) (SYNC_VALUE_BE >>> 24); private static final byte FIRST_BYTE_14B_BE = (byte) (SYNC_VALUE_14B_BE >>> 24); private static final byte FIRST_BYTE_LE = (byte) (SYNC_VALUE_LE >>> 24); @@ -149,6 +152,19 @@ public final class DtsUtil { * @return The number of audio samples represented by the syncframe. */ public static int parseDtsAudioSampleCount(ByteBuffer buffer) { + + // Check for sync or non sync word for DTS:X Profile 2. + // DTS:X Profile 2's FrameSize = 1024. + if ((buffer.getInt(0) == SYNC_FTOC_LE) || + (buffer.getInt(0) == SYNC_FTOC_NON_SYNC_LE)) { + return 1024; + } + // Check for sync word for DTS Express. + // DTS Express's FrameSize = 4096. + else if (buffer.getInt(0) == SYNC_EXT_SUB_LE) { + return 4096; + } + // See ETSI TS 102 114 subsection 5.4.1. int position = buffer.position(); int nblks; From 22b45b75f7f3d877ef5ba140c68a6775f9c5fced Mon Sep 17 00:00:00 2001 From: Cedric T Date: Wed, 3 May 2023 14:03:15 +0800 Subject: [PATCH 02/33] Use getMaxSupportedChannelCountForPassthrough to assign channel Count --- .../media3/exoplayer/audio/AudioCapabilities.java | 13 ++++--------- 1 file changed, 4 insertions(+), 9 deletions(-) diff --git a/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/audio/AudioCapabilities.java b/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/audio/AudioCapabilities.java index 57dc24e650..7de74fe2be 100644 --- a/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/audio/AudioCapabilities.java +++ b/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/audio/AudioCapabilities.java @@ -73,7 +73,7 @@ public final class AudioCapabilities { new ImmutableMap.Builder() .put(C.ENCODING_AC3, 6) .put(C.ENCODING_AC4, 6) - .put(C.ENCODING_DTS, 6) + .put(C.ENCODING_DTS, 10) .put(C.ENCODING_E_AC3_JOC, 6) .put(C.ENCODING_E_AC3, 8) .put(C.ENCODING_DTS_HD, 8) @@ -212,7 +212,8 @@ public final class AudioCapabilities { return null; } int channelCount; - if (format.channelCount == Format.NO_VALUE || encoding == C.ENCODING_E_AC3_JOC) { + if (format.channelCount == Format.NO_VALUE || encoding == C.ENCODING_E_AC3_JOC + || encoding == C.ENCODING_DTS) { // In HLS chunkless preparation, the format channel count and sample rate may be unset. See // https://github.com/google/ExoPlayer/issues/10204 and b/222127949 for more details. // For E-AC3 JOC, the format is object based so the format channel count is arbitrary. @@ -221,13 +222,7 @@ public final class AudioCapabilities { channelCount = getMaxSupportedChannelCountForPassthrough(encoding, sampleRate); } else { channelCount = format.channelCount; - if (format.sampleMimeType == MimeTypes.AUDIO_DTS_X) { - if (channelCount > 10) { - // To fix wrong reporting from device. ChannelCount is reported as 8 for DTS:X P2 - // on some devices. - return null; - } - } else if (channelCount > maxChannelCount) { + if (channelCount > maxChannelCount) { return null; } } From 6823a2916aaf2cb14348a68f74e135f925fab63a Mon Sep 17 00:00:00 2001 From: Cedric T Date: Thu, 4 May 2023 14:42:02 +0800 Subject: [PATCH 03/33] Add C.ENCODING_DTS_UHD_P2 --- .../src/main/java/androidx/media3/common/C.java | 4 ++++ .../java/androidx/media3/common/MimeTypes.java | 4 ++-- .../exoplayer/audio/AudioCapabilities.java | 17 ++++++++++++++--- 3 files changed, 20 insertions(+), 5 deletions(-) diff --git a/libraries/common/src/main/java/androidx/media3/common/C.java b/libraries/common/src/main/java/androidx/media3/common/C.java index 5f243a3b93..6879ce2ab1 100644 --- a/libraries/common/src/main/java/androidx/media3/common/C.java +++ b/libraries/common/src/main/java/androidx/media3/common/C.java @@ -256,6 +256,10 @@ public final class C { @UnstableApi public static final int ENCODING_DTS = AudioFormat.ENCODING_DTS; /** See {@link AudioFormat#ENCODING_DTS_HD}. */ @UnstableApi public static final int ENCODING_DTS_HD = AudioFormat.ENCODING_DTS_HD; + /** + * TODO: To replace with AudioFormat.ENCODING_DTS_UHD_P2 when Android 14.0 is released. + */ + @UnstableApi public static final int ENCODING_DTS_UHD_P2 = 0x0000001e; /** See {@link AudioFormat#ENCODING_DOLBY_TRUEHD}. */ @UnstableApi public static final int ENCODING_DOLBY_TRUEHD = AudioFormat.ENCODING_DOLBY_TRUEHD; /** See {@link AudioFormat#ENCODING_OPUS}. */ diff --git a/libraries/common/src/main/java/androidx/media3/common/MimeTypes.java b/libraries/common/src/main/java/androidx/media3/common/MimeTypes.java index 27db8c9305..a42e52966b 100644 --- a/libraries/common/src/main/java/androidx/media3/common/MimeTypes.java +++ b/libraries/common/src/main/java/androidx/media3/common/MimeTypes.java @@ -596,9 +596,9 @@ public final class MimeTypes { case MimeTypes.AUDIO_DTS_HD: return C.ENCODING_DTS_HD; case MimeTypes.AUDIO_DTS_EXPRESS: - return C.ENCODING_DTS; // This should be ENCODING_DTS_HD when IC platforms support it. + return C.ENCODING_DTS_HD; case MimeTypes.AUDIO_DTS_X: - return C.ENCODING_DTS; // This should be ENCODING_DTS_UHD_P2 when IC platforms support it. + return C.ENCODING_DTS_UHD_P2; case MimeTypes.AUDIO_TRUEHD: return C.ENCODING_DOLBY_TRUEHD; case MimeTypes.AUDIO_OPUS: diff --git a/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/audio/AudioCapabilities.java b/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/audio/AudioCapabilities.java index 7de74fe2be..ef5de3664e 100644 --- a/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/audio/AudioCapabilities.java +++ b/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/audio/AudioCapabilities.java @@ -73,7 +73,8 @@ public final class AudioCapabilities { new ImmutableMap.Builder() .put(C.ENCODING_AC3, 6) .put(C.ENCODING_AC4, 6) - .put(C.ENCODING_DTS, 10) + .put(C.ENCODING_DTS, 6) + .put(C.ENCODING_DTS_UHD_P2, 10) .put(C.ENCODING_E_AC3_JOC, 6) .put(C.ENCODING_E_AC3, 8) .put(C.ENCODING_DTS_HD, 8) @@ -204,7 +205,8 @@ public final class AudioCapabilities { if (encoding == C.ENCODING_E_AC3_JOC && !supportsEncoding(C.ENCODING_E_AC3_JOC)) { // E-AC3 receivers support E-AC3 JOC streams (but decode only the base layer). encoding = C.ENCODING_E_AC3; - } else if (encoding == C.ENCODING_DTS_HD && !supportsEncoding(C.ENCODING_DTS_HD)) { + } else if ((encoding == C.ENCODING_DTS_HD && !supportsEncoding(C.ENCODING_DTS_HD)) || + (encoding == C.ENCODING_DTS_UHD_P2 && !supportsEncoding(C.ENCODING_DTS_UHD_P2))) { // DTS receivers support DTS-HD streams (but decode only the core layer). encoding = C.ENCODING_DTS; } @@ -222,7 +224,12 @@ public final class AudioCapabilities { channelCount = getMaxSupportedChannelCountForPassthrough(encoding, sampleRate); } else { channelCount = format.channelCount; - if (channelCount > maxChannelCount) { + if (format.sampleMimeType == MimeTypes.AUDIO_DTS_X) { + if (channelCount > 10) { + // To fix wrong reporting from device. ChannelCount is reported as 8 for DTS:X P2 on some devices + return null; + } + } else if (channelCount > maxChannelCount) { return null; } } @@ -360,6 +367,10 @@ public final class AudioCapabilities { public static int[] getDirectPlaybackSupportedEncodings() { ImmutableList.Builder supportedEncodingsListBuilder = ImmutableList.builder(); for (int encoding : ALL_SURROUND_ENCODINGS_AND_MAX_CHANNELS.keySet()) { + // Skip ENCODING_DTS_UHD_P2 if API < 34. Otherwise setEncoding will crash. + if ((Util.SDK_INT < 34) && (encoding == C.ENCODING_DTS_UHD_P2)) { + continue; + } if (AudioTrack.isDirectPlaybackSupported( new AudioFormat.Builder() .setChannelMask(AudioFormat.CHANNEL_OUT_STEREO) From c0e03f14a8d7b9a20ec474f9565711e297cf80a8 Mon Sep 17 00:00:00 2001 From: Cedric T Date: Thu, 4 May 2023 15:57:20 +0800 Subject: [PATCH 04/33] Remove skip channelCount check for ENCODING_DTS --- .../androidx/media3/exoplayer/audio/AudioCapabilities.java | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/audio/AudioCapabilities.java b/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/audio/AudioCapabilities.java index ef5de3664e..bbe0a3aae7 100644 --- a/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/audio/AudioCapabilities.java +++ b/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/audio/AudioCapabilities.java @@ -214,8 +214,7 @@ public final class AudioCapabilities { return null; } int channelCount; - if (format.channelCount == Format.NO_VALUE || encoding == C.ENCODING_E_AC3_JOC - || encoding == C.ENCODING_DTS) { + if (format.channelCount == Format.NO_VALUE || encoding == C.ENCODING_E_AC3_JOC) { // In HLS chunkless preparation, the format channel count and sample rate may be unset. See // https://github.com/google/ExoPlayer/issues/10204 and b/222127949 for more details. // For E-AC3 JOC, the format is object based so the format channel count is arbitrary. From 3b9d68091453a212f1cfa9ad1387027ed693e177 Mon Sep 17 00:00:00 2001 From: Cedric T Date: Fri, 5 May 2023 13:44:21 +0800 Subject: [PATCH 05/33] Add comments for DTSUtil.java --- .../java/androidx/media3/extractor/DtsUtil.java | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/libraries/extractor/src/main/java/androidx/media3/extractor/DtsUtil.java b/libraries/extractor/src/main/java/androidx/media3/extractor/DtsUtil.java index b835b231af..146df18c5c 100644 --- a/libraries/extractor/src/main/java/androidx/media3/extractor/DtsUtil.java +++ b/libraries/extractor/src/main/java/androidx/media3/extractor/DtsUtil.java @@ -41,7 +41,15 @@ public final class DtsUtil { private static final int SYNC_VALUE_14B_BE = 0x1FFFE800; private static final int SYNC_VALUE_LE = 0xFE7F0180; private static final int SYNC_VALUE_14B_LE = 0xFF1F00E8; + /** + * DTS Extension Substream Syncword (in different Endianness) is defined in Section 7.4.1 of: + * https://www.etsi.org/deliver/etsi_ts/102100_102199/102114/01.06.01_60/ts_102114v010601p.pdf + */ private static final int SYNC_EXT_SUB_LE = 0x25205864; + /** + * The two DTS FTOC Sync words below (in different Endianness) is defined in Section 6.4.4.1 of + * https://www.etsi.org/deliver/etsi_ts/103400_103499/103491/01.02.01_60/ts_103491v010201p.pdf + */ private static final int SYNC_FTOC_LE = 0xF21B4140; private static final int SYNC_FTOC_NON_SYNC_LE = 0xE842C471; private static final byte FIRST_BYTE_BE = (byte) (SYNC_VALUE_BE >>> 24); @@ -153,14 +161,15 @@ public final class DtsUtil { */ public static int parseDtsAudioSampleCount(ByteBuffer buffer) { - // Check for sync or non sync word for DTS:X Profile 2. - // DTS:X Profile 2's FrameSize = 1024. + // Check for DTS:X Profile 2 sync or non sync word and return + // 1024 if found. This is the only audio sample count that is used by DTS:X Streaming Encoder. if ((buffer.getInt(0) == SYNC_FTOC_LE) || (buffer.getInt(0) == SYNC_FTOC_NON_SYNC_LE)) { return 1024; } - // Check for sync word for DTS Express. - // DTS Express's FrameSize = 4096. + + // Check for DTS Express sync word and return 4096 if found. This is the only audio + // sample count that is used by DTS Streaming Encoder. else if (buffer.getInt(0) == SYNC_EXT_SUB_LE) { return 4096; } From d01a93b94e28d4b457d4e54d3078cc439ee7139c Mon Sep 17 00:00:00 2001 From: Cedric T Date: Fri, 5 May 2023 14:27:07 +0800 Subject: [PATCH 06/33] Add getAllSurroundEncodingsMaybeSupported() --- .../exoplayer/audio/AudioCapabilities.java | 22 ++++++++++++++----- 1 file changed, 17 insertions(+), 5 deletions(-) diff --git a/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/audio/AudioCapabilities.java b/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/audio/AudioCapabilities.java index bbe0a3aae7..1a48062ca4 100644 --- a/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/audio/AudioCapabilities.java +++ b/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/audio/AudioCapabilities.java @@ -42,6 +42,7 @@ import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableMap; import com.google.common.collect.ImmutableSet; import com.google.common.primitives.Ints; +import java.util.ArrayList; import java.util.Arrays; /** Represents the set of audio formats that a device is capable of playing. */ @@ -365,11 +366,7 @@ public final class AudioCapabilities { @DoNotInline public static int[] getDirectPlaybackSupportedEncodings() { ImmutableList.Builder supportedEncodingsListBuilder = ImmutableList.builder(); - for (int encoding : ALL_SURROUND_ENCODINGS_AND_MAX_CHANNELS.keySet()) { - // Skip ENCODING_DTS_UHD_P2 if API < 34. Otherwise setEncoding will crash. - if ((Util.SDK_INT < 34) && (encoding == C.ENCODING_DTS_UHD_P2)) { - continue; - } + for (int encoding : getAllSurroundEncodingsMaybeSupported()) { if (AudioTrack.isDirectPlaybackSupported( new AudioFormat.Builder() .setChannelMask(AudioFormat.CHANNEL_OUT_STEREO) @@ -406,5 +403,20 @@ public final class AudioCapabilities { } return 0; } + + /** + * Returns an array list of surround encodings that maybe supported. + */ + private static ArrayList getAllSurroundEncodingsMaybeSupported() { + ArrayList encodings = new ArrayList<>(); + for (int encoding : ALL_SURROUND_ENCODINGS_AND_MAX_CHANNELS.keySet()) { + // AudioFormat.ENCODING_DTS_UHD_P2 is supported from API 34. + if (Util.SDK_INT < 34 && encoding == C.ENCODING_DTS_UHD_P2) { + continue; + } + encodings.add(encoding); + } + return encodings; + } } } From 689451b0c658279ba33dc29ea0c8c85749263233 Mon Sep 17 00:00:00 2001 From: Cedric T Date: Fri, 5 May 2023 15:54:43 +0800 Subject: [PATCH 07/33] Set AudioCapabilities.DEFAULT_MAX_CHANNEL_COUNT to 10 --- .../media3/exoplayer/audio/AudioCapabilities.java | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/audio/AudioCapabilities.java b/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/audio/AudioCapabilities.java index 1a48062ca4..739a5d61b2 100644 --- a/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/audio/AudioCapabilities.java +++ b/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/audio/AudioCapabilities.java @@ -49,7 +49,7 @@ import java.util.Arrays; @UnstableApi public final class AudioCapabilities { - private static final int DEFAULT_MAX_CHANNEL_COUNT = 8; + private static final int DEFAULT_MAX_CHANNEL_COUNT = 10; @VisibleForTesting /* package */ static final int DEFAULT_SAMPLE_RATE_HZ = 48_000; /** The minimum audio capabilities supported by all devices. */ @@ -224,12 +224,7 @@ public final class AudioCapabilities { channelCount = getMaxSupportedChannelCountForPassthrough(encoding, sampleRate); } else { channelCount = format.channelCount; - if (format.sampleMimeType == MimeTypes.AUDIO_DTS_X) { - if (channelCount > 10) { - // To fix wrong reporting from device. ChannelCount is reported as 8 for DTS:X P2 on some devices - return null; - } - } else if (channelCount > maxChannelCount) { + if (channelCount > maxChannelCount) { return null; } } From b069fb1283bde4a27b1b4ec5a33dbab152bd6dfd Mon Sep 17 00:00:00 2001 From: Cedric T Date: Mon, 8 May 2023 10:02:09 +0800 Subject: [PATCH 08/33] Return Immutable List for getAllSurroundEncodingsMaybeSupported() --- .../androidx/media3/exoplayer/audio/AudioCapabilities.java | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/audio/AudioCapabilities.java b/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/audio/AudioCapabilities.java index 739a5d61b2..be24cc2e79 100644 --- a/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/audio/AudioCapabilities.java +++ b/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/audio/AudioCapabilities.java @@ -44,6 +44,8 @@ import com.google.common.collect.ImmutableSet; import com.google.common.primitives.Ints; import java.util.ArrayList; import java.util.Arrays; +import java.util.Collections; +import java.util.List; /** Represents the set of audio formats that a device is capable of playing. */ @UnstableApi @@ -402,7 +404,7 @@ public final class AudioCapabilities { /** * Returns an array list of surround encodings that maybe supported. */ - private static ArrayList getAllSurroundEncodingsMaybeSupported() { + private static List getAllSurroundEncodingsMaybeSupported() { ArrayList encodings = new ArrayList<>(); for (int encoding : ALL_SURROUND_ENCODINGS_AND_MAX_CHANNELS.keySet()) { // AudioFormat.ENCODING_DTS_UHD_P2 is supported from API 34. @@ -411,7 +413,7 @@ public final class AudioCapabilities { } encodings.add(encoding); } - return encodings; + return Collections.unmodifiableList(encodings); } } } From c984387248c8746378c89f135ca81b9c056a42b2 Mon Sep 17 00:00:00 2001 From: Cedric T Date: Mon, 8 May 2023 10:11:43 +0800 Subject: [PATCH 09/33] Re-word comments for new DTS Sync words in DtsUtil.java. --- .../src/main/java/androidx/media3/extractor/DtsUtil.java | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/libraries/extractor/src/main/java/androidx/media3/extractor/DtsUtil.java b/libraries/extractor/src/main/java/androidx/media3/extractor/DtsUtil.java index 146df18c5c..2721b6c153 100644 --- a/libraries/extractor/src/main/java/androidx/media3/extractor/DtsUtil.java +++ b/libraries/extractor/src/main/java/androidx/media3/extractor/DtsUtil.java @@ -42,13 +42,13 @@ public final class DtsUtil { private static final int SYNC_VALUE_LE = 0xFE7F0180; private static final int SYNC_VALUE_14B_LE = 0xFF1F00E8; /** - * DTS Extension Substream Syncword (in different Endianness) is defined in Section 7.4.1 of: - * https://www.etsi.org/deliver/etsi_ts/102100_102199/102114/01.06.01_60/ts_102114v010601p.pdf + * DTS Extension Substream Syncword (in different Endianness). See ETSI TS 102 114 (V1.6.1) + * Section 7.4.1. */ private static final int SYNC_EXT_SUB_LE = 0x25205864; /** - * The two DTS FTOC Sync words below (in different Endianness) is defined in Section 6.4.4.1 of - * https://www.etsi.org/deliver/etsi_ts/103400_103499/103491/01.02.01_60/ts_103491v010201p.pdf + * DTS FTOC Sync words (in different Endianness). See ETSI TS 103 491 (V1.2.1) + * Section 6.4.4.1. */ private static final int SYNC_FTOC_LE = 0xF21B4140; private static final int SYNC_FTOC_NON_SYNC_LE = 0xE842C471; From f47930e587478136028ad4e8da089d54ff99a755 Mon Sep 17 00:00:00 2001 From: Cedric T Date: Mon, 8 May 2023 15:35:39 +0800 Subject: [PATCH 10/33] Refactor getDirectPlaybackSupportedEncodings() --- .../androidx/media3/common/util/Util.java | 20 ++++++++++ .../exoplayer/audio/AudioCapabilities.java | 37 ++++++++++++------- 2 files changed, 44 insertions(+), 13 deletions(-) diff --git a/libraries/common/src/main/java/androidx/media3/common/util/Util.java b/libraries/common/src/main/java/androidx/media3/common/util/Util.java index ac87584747..1fb3f18c29 100644 --- a/libraries/common/src/main/java/androidx/media3/common/util/Util.java +++ b/libraries/common/src/main/java/androidx/media3/common/util/Util.java @@ -516,6 +516,26 @@ public final class Util { return concatenation; } + /** + * Creates a new Integer array containing the concatenation of two non-null Integer arrays. + * + * @param first The first array. + * @param second The second array. + * @return The concatenated result. + */ + @UnstableApi + @SuppressWarnings("nullness:assignment") + public static int[] nullSafeIntegerArrayConcatenation(int[] first, int[] second) { + int[] concatenation = Arrays.copyOf(first, first.length + second.length); + System.arraycopy( + /* src= */ second, + + /* srcPos= */ 0, + /* dest= */ concatenation, + /* destPos= */ first.length, + /* length= */ second.length); + return concatenation; + } + /** * Copies the contents of {@code list} into {@code array}. * diff --git a/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/audio/AudioCapabilities.java b/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/audio/AudioCapabilities.java index be24cc2e79..b81ccf3007 100644 --- a/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/audio/AudioCapabilities.java +++ b/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/audio/AudioCapabilities.java @@ -58,15 +58,11 @@ public final class AudioCapabilities { public static final AudioCapabilities DEFAULT_AUDIO_CAPABILITIES = new AudioCapabilities(new int[] {AudioFormat.ENCODING_PCM_16BIT}, DEFAULT_MAX_CHANNEL_COUNT); - /** Audio capabilities when the device specifies external surround sound. */ - @SuppressWarnings("InlinedApi") - private static final AudioCapabilities EXTERNAL_SURROUND_SOUND_CAPABILITIES = - new AudioCapabilities( - new int[]{ - AudioFormat.ENCODING_PCM_16BIT, AudioFormat.ENCODING_AC3, AudioFormat.ENCODING_E_AC3, - AudioFormat.ENCODING_DTS, AudioFormat.ENCODING_DTS_HD - }, - DEFAULT_MAX_CHANNEL_COUNT); + /** Encodings supported when the device specifies external surround sound. */ + private static final int[] EXTERNAL_SURROUND_SOUND_CAPABILITIES = + new int[]{ + AudioFormat.ENCODING_PCM_16BIT, AudioFormat.ENCODING_AC3, AudioFormat.ENCODING_E_AC3 + }; /** * All surround sound encodings that a device may be capable of playing mapped to a maximum @@ -101,6 +97,19 @@ public final class AudioCapabilities { return getCapabilities(context, intent); } + private static AudioCapabilities getExternalSurroundCapabilities(@Nullable Intent intent) { + int[] supportedEncodings = EXTERNAL_SURROUND_SOUND_CAPABILITIES; + + if (Util.SDK_INT >= 29) { + // Check if DTS Encodings are supported via Direct Playback. + int[] dtsTypes = {AudioFormat.ENCODING_DTS, AudioFormat.ENCODING_DTS_HD}; + supportedEncodings = Util.nullSafeIntegerArrayConcatenation(supportedEncodings, + Api29.getDirectPlaybackSupportedEncodings(dtsTypes)); + } + supportedEncodings = Arrays.stream(supportedEncodings).distinct().toArray(); + return new AudioCapabilities(supportedEncodings,/* defaultValue= */ DEFAULT_MAX_CHANNEL_COUNT); + } + @SuppressLint("InlinedApi") /* package */ static AudioCapabilities getCapabilities(Context context, @Nullable Intent intent) { // If a connection to Bluetooth device is detected, we only return the minimum capabilities that @@ -110,7 +119,7 @@ public final class AudioCapabilities { } if (deviceMaySetExternalSurroundSoundGlobalSetting() && Global.getInt(context.getContentResolver(), EXTERNAL_SURROUND_SOUND_KEY, 0) == 1) { - return EXTERNAL_SURROUND_SOUND_CAPABILITIES; + return getExternalSurroundCapabilities(intent); } // AudioTrack.isDirectPlaybackSupported returns true for encodings that are supported for audio // offload, as well as for encodings we want to list for passthrough mode. Therefore we only use @@ -118,7 +127,9 @@ public final class AudioCapabilities { // encodings. if (Util.SDK_INT >= 29 && (Util.isTv(context) || Util.isAutomotive(context))) { return new AudioCapabilities( - Api29.getDirectPlaybackSupportedEncodings(), DEFAULT_MAX_CHANNEL_COUNT); + Api29.getDirectPlaybackSupportedEncodings( + Api29.getAllSurroundEncodingsMaybeSupported().stream().mapToInt(Integer::intValue) + .toArray()), DEFAULT_MAX_CHANNEL_COUNT); } if (intent == null || intent.getIntExtra(AudioManager.EXTRA_AUDIO_PLUG_STATE, 0) == 0) { return DEFAULT_AUDIO_CAPABILITIES; @@ -361,9 +372,9 @@ public final class AudioCapabilities { private Api29() {} @DoNotInline - public static int[] getDirectPlaybackSupportedEncodings() { + public static int[] getDirectPlaybackSupportedEncodings(int[] encodings) { ImmutableList.Builder supportedEncodingsListBuilder = ImmutableList.builder(); - for (int encoding : getAllSurroundEncodingsMaybeSupported()) { + for (int encoding : encodings) { if (AudioTrack.isDirectPlaybackSupported( new AudioFormat.Builder() .setChannelMask(AudioFormat.CHANNEL_OUT_STEREO) From abc46d4319e6d9f6815da9d807fc51a032ea4815 Mon Sep 17 00:00:00 2001 From: Cedric T Date: Wed, 10 May 2023 09:40:15 +0800 Subject: [PATCH 11/33] Rename some variables and change to use ImmutableList.Builder. --- .../exoplayer/audio/AudioCapabilities.java | 17 +++++++---------- 1 file changed, 7 insertions(+), 10 deletions(-) diff --git a/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/audio/AudioCapabilities.java b/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/audio/AudioCapabilities.java index b81ccf3007..e16b372b45 100644 --- a/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/audio/AudioCapabilities.java +++ b/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/audio/AudioCapabilities.java @@ -42,10 +42,7 @@ import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableMap; import com.google.common.collect.ImmutableSet; import com.google.common.primitives.Ints; -import java.util.ArrayList; import java.util.Arrays; -import java.util.Collections; -import java.util.List; /** Represents the set of audio formats that a device is capable of playing. */ @UnstableApi @@ -59,7 +56,7 @@ public final class AudioCapabilities { new AudioCapabilities(new int[] {AudioFormat.ENCODING_PCM_16BIT}, DEFAULT_MAX_CHANNEL_COUNT); /** Encodings supported when the device specifies external surround sound. */ - private static final int[] EXTERNAL_SURROUND_SOUND_CAPABILITIES = + private static final int[] EXTERNAL_SURROUND_SOUND_ENCODINGS = new int[]{ AudioFormat.ENCODING_PCM_16BIT, AudioFormat.ENCODING_AC3, AudioFormat.ENCODING_E_AC3 }; @@ -98,13 +95,13 @@ public final class AudioCapabilities { } private static AudioCapabilities getExternalSurroundCapabilities(@Nullable Intent intent) { - int[] supportedEncodings = EXTERNAL_SURROUND_SOUND_CAPABILITIES; + int[] supportedEncodings = EXTERNAL_SURROUND_SOUND_ENCODINGS; if (Util.SDK_INT >= 29) { // Check if DTS Encodings are supported via Direct Playback. - int[] dtsTypes = {AudioFormat.ENCODING_DTS, AudioFormat.ENCODING_DTS_HD}; + int[] dtsEncodings = {AudioFormat.ENCODING_DTS, AudioFormat.ENCODING_DTS_HD}; supportedEncodings = Util.nullSafeIntegerArrayConcatenation(supportedEncodings, - Api29.getDirectPlaybackSupportedEncodings(dtsTypes)); + Api29.getDirectPlaybackSupportedEncodings(dtsEncodings)); } supportedEncodings = Arrays.stream(supportedEncodings).distinct().toArray(); return new AudioCapabilities(supportedEncodings,/* defaultValue= */ DEFAULT_MAX_CHANNEL_COUNT); @@ -415,8 +412,8 @@ public final class AudioCapabilities { /** * Returns an array list of surround encodings that maybe supported. */ - private static List getAllSurroundEncodingsMaybeSupported() { - ArrayList encodings = new ArrayList<>(); + private static ImmutableList getAllSurroundEncodingsMaybeSupported() { + ImmutableList.Builder encodings = new ImmutableList.Builder<>(); for (int encoding : ALL_SURROUND_ENCODINGS_AND_MAX_CHANNELS.keySet()) { // AudioFormat.ENCODING_DTS_UHD_P2 is supported from API 34. if (Util.SDK_INT < 34 && encoding == C.ENCODING_DTS_UHD_P2) { @@ -424,7 +421,7 @@ public final class AudioCapabilities { } encodings.add(encoding); } - return Collections.unmodifiableList(encodings); + return encodings.build(); } } } From 753257e4545fa6e409df14ff1e70b812650040a6 Mon Sep 17 00:00:00 2001 From: Cedric T Date: Wed, 10 May 2023 16:18:07 +0800 Subject: [PATCH 12/33] Refactor Audio Capabilities --- .../androidx/media3/common/util/Util.java | 41 +++++++++++++++++++ .../exoplayer/audio/AudioCapabilities.java | 38 ++++++++--------- 2 files changed, 58 insertions(+), 21 deletions(-) diff --git a/libraries/common/src/main/java/androidx/media3/common/util/Util.java b/libraries/common/src/main/java/androidx/media3/common/util/Util.java index 1fb3f18c29..59927890fe 100644 --- a/libraries/common/src/main/java/androidx/media3/common/util/Util.java +++ b/libraries/common/src/main/java/androidx/media3/common/util/Util.java @@ -536,6 +536,30 @@ public final class Util { return concatenation; } + /** + * Remove duplicates from an Integer array. + * + * @param inputs The input integer array. + * @return The integer array without duplicates. + */ + @UnstableApi + @SuppressWarnings("nullness:assignment") + public static int[] nullSafeIntegerArrayDistinct(int[] inputs) { + int end = inputs.length; + for (int i = 0; i < end; i++) { + for (int j = i + 1; j < end; j++) { + if (inputs[i] == inputs[j]) { + inputs[j] = inputs[end - 1]; + end--; + j--; + } + } + } + int[] newlist = new int[end]; + System.arraycopy(inputs, 0, newlist, 0, end); + return newlist; + } + /** * Copies the contents of {@code list} into {@code array}. * @@ -552,6 +576,23 @@ public final class Util { list.toArray(array); } + /** + * Creates a new Integer array from a List of Integers. + * + * @param list The list of integers to convert. + * @return Created array of integers. + */ + @UnstableApi + @SuppressWarnings("nullness:assignment") + public static int[] nullSafeIntegerListToArray(List list) { + int[] intList = new int[list.size()]; + + for (int i = 0; i < list.size(); i++) { + intList[i] = list.get(i); + } + return intList; + } + /** * Creates a {@link Handler} on the current {@link Looper} thread. * diff --git a/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/audio/AudioCapabilities.java b/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/audio/AudioCapabilities.java index e16b372b45..cd58c56512 100644 --- a/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/audio/AudioCapabilities.java +++ b/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/audio/AudioCapabilities.java @@ -94,19 +94,6 @@ public final class AudioCapabilities { return getCapabilities(context, intent); } - private static AudioCapabilities getExternalSurroundCapabilities(@Nullable Intent intent) { - int[] supportedEncodings = EXTERNAL_SURROUND_SOUND_ENCODINGS; - - if (Util.SDK_INT >= 29) { - // Check if DTS Encodings are supported via Direct Playback. - int[] dtsEncodings = {AudioFormat.ENCODING_DTS, AudioFormat.ENCODING_DTS_HD}; - supportedEncodings = Util.nullSafeIntegerArrayConcatenation(supportedEncodings, - Api29.getDirectPlaybackSupportedEncodings(dtsEncodings)); - } - supportedEncodings = Arrays.stream(supportedEncodings).distinct().toArray(); - return new AudioCapabilities(supportedEncodings,/* defaultValue= */ DEFAULT_MAX_CHANNEL_COUNT); - } - @SuppressLint("InlinedApi") /* package */ static AudioCapabilities getCapabilities(Context context, @Nullable Intent intent) { // If a connection to Bluetooth device is detected, we only return the minimum capabilities that @@ -114,27 +101,36 @@ public final class AudioCapabilities { if (Util.SDK_INT >= 23 && Api23.isBluetoothConnected(context)) { return DEFAULT_AUDIO_CAPABILITIES; } + int[] supportedEncodings = {}; + if (deviceMaySetExternalSurroundSoundGlobalSetting() && Global.getInt(context.getContentResolver(), EXTERNAL_SURROUND_SOUND_KEY, 0) == 1) { - return getExternalSurroundCapabilities(intent); + supportedEncodings = EXTERNAL_SURROUND_SOUND_ENCODINGS; } // AudioTrack.isDirectPlaybackSupported returns true for encodings that are supported for audio // offload, as well as for encodings we want to list for passthrough mode. Therefore we only use // it on TV and automotive devices, which generally shouldn't support audio offload for surround // encodings. if (Util.SDK_INT >= 29 && (Util.isTv(context) || Util.isAutomotive(context))) { - return new AudioCapabilities( + supportedEncodings = Util.nullSafeIntegerArrayConcatenation(supportedEncodings, Api29.getDirectPlaybackSupportedEncodings( - Api29.getAllSurroundEncodingsMaybeSupported().stream().mapToInt(Integer::intValue) - .toArray()), DEFAULT_MAX_CHANNEL_COUNT); + Util.nullSafeIntegerListToArray(Api29.getAllSurroundEncodingsMaybeSupported()))); } + if (intent == null || intent.getIntExtra(AudioManager.EXTRA_AUDIO_PLUG_STATE, 0) == 0) { - return DEFAULT_AUDIO_CAPABILITIES; + if (supportedEncodings.length == 0) { + return DEFAULT_AUDIO_CAPABILITIES; + } else { + return new AudioCapabilities(supportedEncodings, /* defaultValue= */ + DEFAULT_MAX_CHANNEL_COUNT); + } } + + supportedEncodings = Util.nullSafeIntegerArrayConcatenation(supportedEncodings, + intent.getIntArrayExtra(AudioManager.EXTRA_ENCODINGS)); + supportedEncodings = Util.nullSafeIntegerArrayDistinct(supportedEncodings); return new AudioCapabilities( - intent.getIntArrayExtra(AudioManager.EXTRA_ENCODINGS), - intent.getIntExtra( - AudioManager.EXTRA_MAX_CHANNEL_COUNT, /* defaultValue= */ DEFAULT_MAX_CHANNEL_COUNT)); + supportedEncodings, /* defaultValue= */ DEFAULT_MAX_CHANNEL_COUNT); } /** From b1ac7685bdfe6ea9f95c8b44ff8f6936dc1abd65 Mon Sep 17 00:00:00 2001 From: Cedric T Date: Wed, 10 May 2023 16:33:44 +0800 Subject: [PATCH 13/33] Add distinct encodings check before returning AudioCapabilities. --- .../java/androidx/media3/exoplayer/audio/AudioCapabilities.java | 1 + 1 file changed, 1 insertion(+) diff --git a/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/audio/AudioCapabilities.java b/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/audio/AudioCapabilities.java index cd58c56512..ac8153e434 100644 --- a/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/audio/AudioCapabilities.java +++ b/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/audio/AudioCapabilities.java @@ -121,6 +121,7 @@ public final class AudioCapabilities { if (supportedEncodings.length == 0) { return DEFAULT_AUDIO_CAPABILITIES; } else { + supportedEncodings = Util.nullSafeIntegerArrayDistinct(supportedEncodings); return new AudioCapabilities(supportedEncodings, /* defaultValue= */ DEFAULT_MAX_CHANNEL_COUNT); } From 924723d6b3c4a763fae3f5f3ebb66dacb1bc82f5 Mon Sep 17 00:00:00 2001 From: Cedric T Date: Wed, 10 May 2023 18:09:09 +0800 Subject: [PATCH 14/33] Additional changes to AudioCapabilities.java and Util.java --- .../androidx/media3/common/util/Util.java | 37 ------------------- .../exoplayer/audio/AudioCapabilities.java | 11 +++--- 2 files changed, 5 insertions(+), 43 deletions(-) diff --git a/libraries/common/src/main/java/androidx/media3/common/util/Util.java b/libraries/common/src/main/java/androidx/media3/common/util/Util.java index 59927890fe..300d303f91 100644 --- a/libraries/common/src/main/java/androidx/media3/common/util/Util.java +++ b/libraries/common/src/main/java/androidx/media3/common/util/Util.java @@ -516,26 +516,6 @@ public final class Util { return concatenation; } - /** - * Creates a new Integer array containing the concatenation of two non-null Integer arrays. - * - * @param first The first array. - * @param second The second array. - * @return The concatenated result. - */ - @UnstableApi - @SuppressWarnings("nullness:assignment") - public static int[] nullSafeIntegerArrayConcatenation(int[] first, int[] second) { - int[] concatenation = Arrays.copyOf(first, first.length + second.length); - System.arraycopy( - /* src= */ second, - + /* srcPos= */ 0, - /* dest= */ concatenation, - /* destPos= */ first.length, - /* length= */ second.length); - return concatenation; - } - /** * Remove duplicates from an Integer array. * @@ -576,23 +556,6 @@ public final class Util { list.toArray(array); } - /** - * Creates a new Integer array from a List of Integers. - * - * @param list The list of integers to convert. - * @return Created array of integers. - */ - @UnstableApi - @SuppressWarnings("nullness:assignment") - public static int[] nullSafeIntegerListToArray(List list) { - int[] intList = new int[list.size()]; - - for (int i = 0; i < list.size(); i++) { - intList[i] = list.get(i); - } - return intList; - } - /** * Creates a {@link Handler} on the current {@link Looper} thread. * diff --git a/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/audio/AudioCapabilities.java b/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/audio/AudioCapabilities.java index ac8153e434..b805640239 100644 --- a/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/audio/AudioCapabilities.java +++ b/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/audio/AudioCapabilities.java @@ -112,9 +112,8 @@ public final class AudioCapabilities { // it on TV and automotive devices, which generally shouldn't support audio offload for surround // encodings. if (Util.SDK_INT >= 29 && (Util.isTv(context) || Util.isAutomotive(context))) { - supportedEncodings = Util.nullSafeIntegerArrayConcatenation(supportedEncodings, - Api29.getDirectPlaybackSupportedEncodings( - Util.nullSafeIntegerListToArray(Api29.getAllSurroundEncodingsMaybeSupported()))); + supportedEncodings = Ints.concat(supportedEncodings, + Api29.getDirectPlaybackSupportedEncodings(Api29.getAllSurroundEncodingsMaybeSupported())); } if (intent == null || intent.getIntExtra(AudioManager.EXTRA_AUDIO_PLUG_STATE, 0) == 0) { @@ -127,7 +126,7 @@ public final class AudioCapabilities { } } - supportedEncodings = Util.nullSafeIntegerArrayConcatenation(supportedEncodings, + supportedEncodings = Ints.concat(supportedEncodings, intent.getIntArrayExtra(AudioManager.EXTRA_ENCODINGS)); supportedEncodings = Util.nullSafeIntegerArrayDistinct(supportedEncodings); return new AudioCapabilities( @@ -409,7 +408,7 @@ public final class AudioCapabilities { /** * Returns an array list of surround encodings that maybe supported. */ - private static ImmutableList getAllSurroundEncodingsMaybeSupported() { + private static int[] getAllSurroundEncodingsMaybeSupported() { ImmutableList.Builder encodings = new ImmutableList.Builder<>(); for (int encoding : ALL_SURROUND_ENCODINGS_AND_MAX_CHANNELS.keySet()) { // AudioFormat.ENCODING_DTS_UHD_P2 is supported from API 34. @@ -418,7 +417,7 @@ public final class AudioCapabilities { } encodings.add(encoding); } - return encodings.build(); + return Ints.toArray(encodings.build()); } } } From 53f35f46f5b3a6506efdc9769e280bc43af903d9 Mon Sep 17 00:00:00 2001 From: Cedric T Date: Thu, 11 May 2023 09:24:13 +0800 Subject: [PATCH 15/33] Use ImmutableSet to store discovered encodings in AudioCapabilities.java --- .../androidx/media3/common/util/Util.java | 24 ------------------- .../exoplayer/audio/AudioCapabilities.java | 23 +++++++++--------- 2 files changed, 11 insertions(+), 36 deletions(-) diff --git a/libraries/common/src/main/java/androidx/media3/common/util/Util.java b/libraries/common/src/main/java/androidx/media3/common/util/Util.java index 300d303f91..ac87584747 100644 --- a/libraries/common/src/main/java/androidx/media3/common/util/Util.java +++ b/libraries/common/src/main/java/androidx/media3/common/util/Util.java @@ -516,30 +516,6 @@ public final class Util { return concatenation; } - /** - * Remove duplicates from an Integer array. - * - * @param inputs The input integer array. - * @return The integer array without duplicates. - */ - @UnstableApi - @SuppressWarnings("nullness:assignment") - public static int[] nullSafeIntegerArrayDistinct(int[] inputs) { - int end = inputs.length; - for (int i = 0; i < end; i++) { - for (int j = i + 1; j < end; j++) { - if (inputs[i] == inputs[j]) { - inputs[j] = inputs[end - 1]; - end--; - j--; - } - } - } - int[] newlist = new int[end]; - System.arraycopy(inputs, 0, newlist, 0, end); - return newlist; - } - /** * Copies the contents of {@code list} into {@code array}. * diff --git a/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/audio/AudioCapabilities.java b/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/audio/AudioCapabilities.java index b805640239..e18e00c58d 100644 --- a/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/audio/AudioCapabilities.java +++ b/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/audio/AudioCapabilities.java @@ -101,36 +101,33 @@ public final class AudioCapabilities { if (Util.SDK_INT >= 23 && Api23.isBluetoothConnected(context)) { return DEFAULT_AUDIO_CAPABILITIES; } - int[] supportedEncodings = {}; + ImmutableSet.Builder supportedEncodings = new ImmutableSet.Builder<>(); if (deviceMaySetExternalSurroundSoundGlobalSetting() && Global.getInt(context.getContentResolver(), EXTERNAL_SURROUND_SOUND_KEY, 0) == 1) { - supportedEncodings = EXTERNAL_SURROUND_SOUND_ENCODINGS; + supportedEncodings.addAll(Ints.asList(EXTERNAL_SURROUND_SOUND_ENCODINGS)); } // AudioTrack.isDirectPlaybackSupported returns true for encodings that are supported for audio // offload, as well as for encodings we want to list for passthrough mode. Therefore we only use // it on TV and automotive devices, which generally shouldn't support audio offload for surround // encodings. if (Util.SDK_INT >= 29 && (Util.isTv(context) || Util.isAutomotive(context))) { - supportedEncodings = Ints.concat(supportedEncodings, - Api29.getDirectPlaybackSupportedEncodings(Api29.getAllSurroundEncodingsMaybeSupported())); + supportedEncodings.addAll(Ints.asList(Api29.getDirectPlaybackSupportedEncodings())); } if (intent == null || intent.getIntExtra(AudioManager.EXTRA_AUDIO_PLUG_STATE, 0) == 0) { - if (supportedEncodings.length == 0) { + if (supportedEncodings.build().isEmpty()) { return DEFAULT_AUDIO_CAPABILITIES; } else { - supportedEncodings = Util.nullSafeIntegerArrayDistinct(supportedEncodings); - return new AudioCapabilities(supportedEncodings, /* defaultValue= */ + return new AudioCapabilities(Ints.toArray(supportedEncodings.build()), /* defaultValue= */ DEFAULT_MAX_CHANNEL_COUNT); } } - supportedEncodings = Ints.concat(supportedEncodings, - intent.getIntArrayExtra(AudioManager.EXTRA_ENCODINGS)); - supportedEncodings = Util.nullSafeIntegerArrayDistinct(supportedEncodings); + supportedEncodings.addAll(Ints.asList( + intent.getIntArrayExtra(AudioManager.EXTRA_ENCODINGS))); return new AudioCapabilities( - supportedEncodings, /* defaultValue= */ DEFAULT_MAX_CHANNEL_COUNT); + Ints.toArray(supportedEncodings.build()), /* defaultValue= */ DEFAULT_MAX_CHANNEL_COUNT); } /** @@ -365,7 +362,8 @@ public final class AudioCapabilities { private Api29() {} @DoNotInline - public static int[] getDirectPlaybackSupportedEncodings(int[] encodings) { + public static int[] getDirectPlaybackSupportedEncodings() { + int[] encodings = Api29.getAllSurroundEncodingsMaybeSupported(); ImmutableList.Builder supportedEncodingsListBuilder = ImmutableList.builder(); for (int encoding : encodings) { if (AudioTrack.isDirectPlaybackSupported( @@ -408,6 +406,7 @@ public final class AudioCapabilities { /** * Returns an array list of surround encodings that maybe supported. */ + @DoNotInline private static int[] getAllSurroundEncodingsMaybeSupported() { ImmutableList.Builder encodings = new ImmutableList.Builder<>(); for (int encoding : ALL_SURROUND_ENCODINGS_AND_MAX_CHANNELS.keySet()) { From 773d3c52f143c70a3fe72b4354495c993692deb8 Mon Sep 17 00:00:00 2001 From: Cedric T Date: Thu, 11 May 2023 18:50:21 +0800 Subject: [PATCH 16/33] Swap empty line in AudioCapabilities.java --- .../java/androidx/media3/exoplayer/audio/AudioCapabilities.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/audio/AudioCapabilities.java b/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/audio/AudioCapabilities.java index e18e00c58d..486c3581eb 100644 --- a/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/audio/AudioCapabilities.java +++ b/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/audio/AudioCapabilities.java @@ -101,8 +101,8 @@ public final class AudioCapabilities { if (Util.SDK_INT >= 23 && Api23.isBluetoothConnected(context)) { return DEFAULT_AUDIO_CAPABILITIES; } - ImmutableSet.Builder supportedEncodings = new ImmutableSet.Builder<>(); + ImmutableSet.Builder supportedEncodings = new ImmutableSet.Builder<>(); if (deviceMaySetExternalSurroundSoundGlobalSetting() && Global.getInt(context.getContentResolver(), EXTERNAL_SURROUND_SOUND_KEY, 0) == 1) { supportedEncodings.addAll(Ints.asList(EXTERNAL_SURROUND_SOUND_ENCODINGS)); From 6b4cf4d3624744710e65e2ede1216ea66f27370e Mon Sep 17 00:00:00 2001 From: Cedric T Date: Fri, 12 May 2023 09:44:07 +0800 Subject: [PATCH 17/33] Swap HDMI case and non-HDMI case in AudioCapabilities. --- .../exoplayer/audio/AudioCapabilities.java | 22 +++++++++---------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/audio/AudioCapabilities.java b/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/audio/AudioCapabilities.java index 486c3581eb..debb231397 100644 --- a/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/audio/AudioCapabilities.java +++ b/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/audio/AudioCapabilities.java @@ -115,19 +115,19 @@ public final class AudioCapabilities { supportedEncodings.addAll(Ints.asList(Api29.getDirectPlaybackSupportedEncodings())); } - if (intent == null || intent.getIntExtra(AudioManager.EXTRA_AUDIO_PLUG_STATE, 0) == 0) { - if (supportedEncodings.build().isEmpty()) { - return DEFAULT_AUDIO_CAPABILITIES; - } else { - return new AudioCapabilities(Ints.toArray(supportedEncodings.build()), /* defaultValue= */ - DEFAULT_MAX_CHANNEL_COUNT); - } + if (intent == null || intent.getIntExtra(AudioManager.EXTRA_AUDIO_PLUG_STATE, 0) == 1) { + supportedEncodings.addAll(Ints.asList( + intent.getIntArrayExtra(AudioManager.EXTRA_ENCODINGS))); + return new AudioCapabilities( + Ints.toArray(supportedEncodings.build()), /* defaultValue= */ DEFAULT_MAX_CHANNEL_COUNT); } - supportedEncodings.addAll(Ints.asList( - intent.getIntArrayExtra(AudioManager.EXTRA_ENCODINGS))); - return new AudioCapabilities( - Ints.toArray(supportedEncodings.build()), /* defaultValue= */ DEFAULT_MAX_CHANNEL_COUNT); + if (supportedEncodings.build().isEmpty()) { + return DEFAULT_AUDIO_CAPABILITIES; + } else { + return new AudioCapabilities(Ints.toArray(supportedEncodings.build()), /* defaultValue= */ + DEFAULT_MAX_CHANNEL_COUNT); + } } /** From 905ad1ce3347c163d5f96ed1099fbc19e3b7c8e6 Mon Sep 17 00:00:00 2001 From: Cedric T Date: Fri, 12 May 2023 19:13:32 +0800 Subject: [PATCH 18/33] Fixed bug in HDMI reporting logic. --- .../java/androidx/media3/exoplayer/audio/AudioCapabilities.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/audio/AudioCapabilities.java b/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/audio/AudioCapabilities.java index debb231397..5bdca16166 100644 --- a/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/audio/AudioCapabilities.java +++ b/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/audio/AudioCapabilities.java @@ -115,7 +115,7 @@ public final class AudioCapabilities { supportedEncodings.addAll(Ints.asList(Api29.getDirectPlaybackSupportedEncodings())); } - if (intent == null || intent.getIntExtra(AudioManager.EXTRA_AUDIO_PLUG_STATE, 0) == 1) { + if (intent != null && intent.getIntExtra(AudioManager.EXTRA_AUDIO_PLUG_STATE, 0) == 1) { supportedEncodings.addAll(Ints.asList( intent.getIntArrayExtra(AudioManager.EXTRA_ENCODINGS))); return new AudioCapabilities( From cb29e8fb3d3d333a01b537ad564741c63ca7a5c7 Mon Sep 17 00:00:00 2001 From: Cedric T Date: Mon, 15 May 2023 10:36:37 +0800 Subject: [PATCH 19/33] Construct AudioCapabilities with HDMI reported MaxChannelCount. --- .../media3/exoplayer/audio/AudioCapabilities.java | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/audio/AudioCapabilities.java b/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/audio/AudioCapabilities.java index 5bdca16166..b0215f4070 100644 --- a/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/audio/AudioCapabilities.java +++ b/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/audio/AudioCapabilities.java @@ -119,7 +119,9 @@ public final class AudioCapabilities { supportedEncodings.addAll(Ints.asList( intent.getIntArrayExtra(AudioManager.EXTRA_ENCODINGS))); return new AudioCapabilities( - Ints.toArray(supportedEncodings.build()), /* defaultValue= */ DEFAULT_MAX_CHANNEL_COUNT); + Ints.toArray(supportedEncodings.build()), + intent.getIntExtra(AudioManager.EXTRA_MAX_CHANNEL_COUNT, /* defaultValue= */ + DEFAULT_MAX_CHANNEL_COUNT)); } if (supportedEncodings.build().isEmpty()) { @@ -227,7 +229,13 @@ public final class AudioCapabilities { channelCount = getMaxSupportedChannelCountForPassthrough(encoding, sampleRate); } else { channelCount = format.channelCount; - if (channelCount > maxChannelCount) { + // To file a Bug: Some DTS:X TVs reports ACTION_HDMI_AUDIO_PLUG.EXTRA_MAX_CHANNEL_COUNT as 8 + // instead of 10. + if (format.sampleMimeType == MimeTypes.AUDIO_DTS_X) { + if (channelCount > 10) { + return null; + } + } else if (channelCount > maxChannelCount) { return null; } } From 424b5d8d0e618c3c9f10e17e340431554cb42ad3 Mon Sep 17 00:00:00 2001 From: Cedric T Date: Tue, 16 May 2023 13:45:25 +0800 Subject: [PATCH 20/33] Add issue link for AudioCapabilities --- .../androidx/media3/exoplayer/audio/AudioCapabilities.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/audio/AudioCapabilities.java b/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/audio/AudioCapabilities.java index b0215f4070..87e851498c 100644 --- a/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/audio/AudioCapabilities.java +++ b/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/audio/AudioCapabilities.java @@ -229,8 +229,8 @@ public final class AudioCapabilities { channelCount = getMaxSupportedChannelCountForPassthrough(encoding, sampleRate); } else { channelCount = format.channelCount; - // To file a Bug: Some DTS:X TVs reports ACTION_HDMI_AUDIO_PLUG.EXTRA_MAX_CHANNEL_COUNT as 8 - // instead of 10. + // Some DTS:X TVs reports ACTION_HDMI_AUDIO_PLUG.EXTRA_MAX_CHANNEL_COUNT as 8 + // instead of 10. See https://github.com/androidx/media/issues/396 if (format.sampleMimeType == MimeTypes.AUDIO_DTS_X) { if (channelCount > 10) { return null; From 47b0726ea9c23f575af3f97e543dcdc1a7236009 Mon Sep 17 00:00:00 2001 From: Tianyi Feng Date: Tue, 16 May 2023 10:49:00 +0000 Subject: [PATCH 21/33] Format with google-java-format --- .../main/java/androidx/media3/common/C.java | 4 +--- .../exoplayer/audio/AudioCapabilities.java | 23 ++++++++----------- .../androidx/media3/extractor/DtsUtil.java | 7 +++--- 3 files changed, 14 insertions(+), 20 deletions(-) diff --git a/libraries/common/src/main/java/androidx/media3/common/C.java b/libraries/common/src/main/java/androidx/media3/common/C.java index 6879ce2ab1..601bd95287 100644 --- a/libraries/common/src/main/java/androidx/media3/common/C.java +++ b/libraries/common/src/main/java/androidx/media3/common/C.java @@ -256,9 +256,7 @@ public final class C { @UnstableApi public static final int ENCODING_DTS = AudioFormat.ENCODING_DTS; /** See {@link AudioFormat#ENCODING_DTS_HD}. */ @UnstableApi public static final int ENCODING_DTS_HD = AudioFormat.ENCODING_DTS_HD; - /** - * TODO: To replace with AudioFormat.ENCODING_DTS_UHD_P2 when Android 14.0 is released. - */ + /** TODO: To replace with AudioFormat.ENCODING_DTS_UHD_P2 when Android 14.0 is released. */ @UnstableApi public static final int ENCODING_DTS_UHD_P2 = 0x0000001e; /** See {@link AudioFormat#ENCODING_DOLBY_TRUEHD}. */ @UnstableApi public static final int ENCODING_DOLBY_TRUEHD = AudioFormat.ENCODING_DOLBY_TRUEHD; diff --git a/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/audio/AudioCapabilities.java b/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/audio/AudioCapabilities.java index 87e851498c..051c5c694d 100644 --- a/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/audio/AudioCapabilities.java +++ b/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/audio/AudioCapabilities.java @@ -57,8 +57,8 @@ public final class AudioCapabilities { /** Encodings supported when the device specifies external surround sound. */ private static final int[] EXTERNAL_SURROUND_SOUND_ENCODINGS = - new int[]{ - AudioFormat.ENCODING_PCM_16BIT, AudioFormat.ENCODING_AC3, AudioFormat.ENCODING_E_AC3 + new int[] { + AudioFormat.ENCODING_PCM_16BIT, AudioFormat.ENCODING_AC3, AudioFormat.ENCODING_E_AC3 }; /** @@ -116,19 +116,18 @@ public final class AudioCapabilities { } if (intent != null && intent.getIntExtra(AudioManager.EXTRA_AUDIO_PLUG_STATE, 0) == 1) { - supportedEncodings.addAll(Ints.asList( - intent.getIntArrayExtra(AudioManager.EXTRA_ENCODINGS))); + supportedEncodings.addAll(Ints.asList(intent.getIntArrayExtra(AudioManager.EXTRA_ENCODINGS))); return new AudioCapabilities( Ints.toArray(supportedEncodings.build()), - intent.getIntExtra(AudioManager.EXTRA_MAX_CHANNEL_COUNT, /* defaultValue= */ - DEFAULT_MAX_CHANNEL_COUNT)); + intent.getIntExtra( + AudioManager.EXTRA_MAX_CHANNEL_COUNT, /* defaultValue= */ DEFAULT_MAX_CHANNEL_COUNT)); } if (supportedEncodings.build().isEmpty()) { return DEFAULT_AUDIO_CAPABILITIES; } else { - return new AudioCapabilities(Ints.toArray(supportedEncodings.build()), /* defaultValue= */ - DEFAULT_MAX_CHANNEL_COUNT); + return new AudioCapabilities( + Ints.toArray(supportedEncodings.build()), /* defaultValue= */ DEFAULT_MAX_CHANNEL_COUNT); } } @@ -211,8 +210,8 @@ public final class AudioCapabilities { if (encoding == C.ENCODING_E_AC3_JOC && !supportsEncoding(C.ENCODING_E_AC3_JOC)) { // E-AC3 receivers support E-AC3 JOC streams (but decode only the base layer). encoding = C.ENCODING_E_AC3; - } else if ((encoding == C.ENCODING_DTS_HD && !supportsEncoding(C.ENCODING_DTS_HD)) || - (encoding == C.ENCODING_DTS_UHD_P2 && !supportsEncoding(C.ENCODING_DTS_UHD_P2))) { + } else if ((encoding == C.ENCODING_DTS_HD && !supportsEncoding(C.ENCODING_DTS_HD)) + || (encoding == C.ENCODING_DTS_UHD_P2 && !supportsEncoding(C.ENCODING_DTS_UHD_P2))) { // DTS receivers support DTS-HD streams (but decode only the core layer). encoding = C.ENCODING_DTS; } @@ -411,9 +410,7 @@ public final class AudioCapabilities { return 0; } - /** - * Returns an array list of surround encodings that maybe supported. - */ + /** Returns an array list of surround encodings that maybe supported. */ @DoNotInline private static int[] getAllSurroundEncodingsMaybeSupported() { ImmutableList.Builder encodings = new ImmutableList.Builder<>(); diff --git a/libraries/extractor/src/main/java/androidx/media3/extractor/DtsUtil.java b/libraries/extractor/src/main/java/androidx/media3/extractor/DtsUtil.java index 2721b6c153..26f8cbaa9b 100644 --- a/libraries/extractor/src/main/java/androidx/media3/extractor/DtsUtil.java +++ b/libraries/extractor/src/main/java/androidx/media3/extractor/DtsUtil.java @@ -47,10 +47,10 @@ public final class DtsUtil { */ private static final int SYNC_EXT_SUB_LE = 0x25205864; /** - * DTS FTOC Sync words (in different Endianness). See ETSI TS 103 491 (V1.2.1) - * Section 6.4.4.1. + * DTS FTOC Sync words (in different Endianness). See ETSI TS 103 491 (V1.2.1) Section 6.4.4.1. */ private static final int SYNC_FTOC_LE = 0xF21B4140; + private static final int SYNC_FTOC_NON_SYNC_LE = 0xE842C471; private static final byte FIRST_BYTE_BE = (byte) (SYNC_VALUE_BE >>> 24); private static final byte FIRST_BYTE_14B_BE = (byte) (SYNC_VALUE_14B_BE >>> 24); @@ -163,8 +163,7 @@ public final class DtsUtil { // Check for DTS:X Profile 2 sync or non sync word and return // 1024 if found. This is the only audio sample count that is used by DTS:X Streaming Encoder. - if ((buffer.getInt(0) == SYNC_FTOC_LE) || - (buffer.getInt(0) == SYNC_FTOC_NON_SYNC_LE)) { + if ((buffer.getInt(0) == SYNC_FTOC_LE) || (buffer.getInt(0) == SYNC_FTOC_NON_SYNC_LE)) { return 1024; } From 5a6906a2b63e5d06390b2919b29775b7e066bd3c Mon Sep 17 00:00:00 2001 From: Tianyi Feng Date: Thu, 25 May 2023 09:57:48 +0000 Subject: [PATCH 22/33] Add release note --- RELEASENOTES.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/RELEASENOTES.md b/RELEASENOTES.md index 07e3504a4f..efa4f95f9d 100644 --- a/RELEASENOTES.md +++ b/RELEASENOTES.md @@ -17,6 +17,8 @@ * Ogg: Fix bug when seeking in files with a long duration ([#391](https://github.com/androidx/media/issues/391)). * Audio: + * Add direct playback supports for DTS Express and DTS:X + ([#335](https://github.com/androidx/media/pull/335)). * Audio Offload: * Add `AudioSink.getFormatOffloadSupport(Format)` that retrieves level of offload support the sink can provide for the format through a From d0cd2f5f2136f4c438936991e56885714264765b Mon Sep 17 00:00:00 2001 From: Tianyi Feng Date: Tue, 16 May 2023 11:03:14 +0000 Subject: [PATCH 23/33] Refactor AudioCapabilities.getCapabilities --- .../androidx/media3/exoplayer/audio/AudioCapabilities.java | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/audio/AudioCapabilities.java b/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/audio/AudioCapabilities.java index 051c5c694d..f15cc2a185 100644 --- a/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/audio/AudioCapabilities.java +++ b/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/audio/AudioCapabilities.java @@ -123,11 +123,12 @@ public final class AudioCapabilities { AudioManager.EXTRA_MAX_CHANNEL_COUNT, /* defaultValue= */ DEFAULT_MAX_CHANNEL_COUNT)); } - if (supportedEncodings.build().isEmpty()) { + ImmutableSet supportedEncodingsSet = supportedEncodings.build(); + if (supportedEncodingsSet.isEmpty()) { return DEFAULT_AUDIO_CAPABILITIES; } else { return new AudioCapabilities( - Ints.toArray(supportedEncodings.build()), /* defaultValue= */ DEFAULT_MAX_CHANNEL_COUNT); + Ints.toArray(supportedEncodingsSet), /* defaultValue= */ DEFAULT_MAX_CHANNEL_COUNT); } } From c61f8d317ad7788d941e17f64d80f4b60e47eda7 Mon Sep 17 00:00:00 2001 From: Tianyi Feng Date: Tue, 16 May 2023 11:04:07 +0000 Subject: [PATCH 24/33] Add C.ENCODING_DTS_UHD_P2 to C.Encoding --- libraries/common/src/main/java/androidx/media3/common/C.java | 1 + 1 file changed, 1 insertion(+) diff --git a/libraries/common/src/main/java/androidx/media3/common/C.java b/libraries/common/src/main/java/androidx/media3/common/C.java index 601bd95287..79e4d56a26 100644 --- a/libraries/common/src/main/java/androidx/media3/common/C.java +++ b/libraries/common/src/main/java/androidx/media3/common/C.java @@ -192,6 +192,7 @@ public final class C { ENCODING_DTS_HD, ENCODING_DOLBY_TRUEHD, ENCODING_OPUS, + ENCODING_DTS_UHD_P2, }) public @interface Encoding {} From b9a53da121442f5b939f95ef59673ebdefc13e9b Mon Sep 17 00:00:00 2001 From: Tianyi Feng Date: Tue, 16 May 2023 11:07:52 +0000 Subject: [PATCH 25/33] Refactor AudioCapabilities.getCapabilities --- .../androidx/media3/exoplayer/audio/AudioCapabilities.java | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/audio/AudioCapabilities.java b/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/audio/AudioCapabilities.java index f15cc2a185..48fc945015 100644 --- a/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/audio/AudioCapabilities.java +++ b/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/audio/AudioCapabilities.java @@ -124,12 +124,11 @@ public final class AudioCapabilities { } ImmutableSet supportedEncodingsSet = supportedEncodings.build(); - if (supportedEncodingsSet.isEmpty()) { - return DEFAULT_AUDIO_CAPABILITIES; - } else { + if (!supportedEncodingsSet.isEmpty()) { return new AudioCapabilities( Ints.toArray(supportedEncodingsSet), /* defaultValue= */ DEFAULT_MAX_CHANNEL_COUNT); } + return DEFAULT_AUDIO_CAPABILITIES; } /** From 162f5e827a83b1cebaac6b945c04eccd10dd5b65 Mon Sep 17 00:00:00 2001 From: Tianyi Feng Date: Wed, 17 May 2023 12:40:22 +0000 Subject: [PATCH 26/33] Add type argument when using ImmutableSet --- .../media3/exoplayer/audio/AudioCapabilities.java | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/audio/AudioCapabilities.java b/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/audio/AudioCapabilities.java index 48fc945015..99941084b8 100644 --- a/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/audio/AudioCapabilities.java +++ b/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/audio/AudioCapabilities.java @@ -102,7 +102,7 @@ public final class AudioCapabilities { return DEFAULT_AUDIO_CAPABILITIES; } - ImmutableSet.Builder supportedEncodings = new ImmutableSet.Builder<>(); + ImmutableSet.Builder supportedEncodings = new ImmutableSet.Builder<>(); if (deviceMaySetExternalSurroundSoundGlobalSetting() && Global.getInt(context.getContentResolver(), EXTERNAL_SURROUND_SOUND_KEY, 0) == 1) { supportedEncodings.addAll(Ints.asList(EXTERNAL_SURROUND_SOUND_ENCODINGS)); @@ -123,10 +123,10 @@ public final class AudioCapabilities { AudioManager.EXTRA_MAX_CHANNEL_COUNT, /* defaultValue= */ DEFAULT_MAX_CHANNEL_COUNT)); } - ImmutableSet supportedEncodingsSet = supportedEncodings.build(); + ImmutableSet supportedEncodingsSet = supportedEncodings.build(); if (!supportedEncodingsSet.isEmpty()) { return new AudioCapabilities( - Ints.toArray(supportedEncodingsSet), /* defaultValue= */ DEFAULT_MAX_CHANNEL_COUNT); + Ints.toArray(supportedEncodingsSet), /* maxChannelCount= */ DEFAULT_MAX_CHANNEL_COUNT); } return DEFAULT_AUDIO_CAPABILITIES; } @@ -230,7 +230,7 @@ public final class AudioCapabilities { channelCount = format.channelCount; // Some DTS:X TVs reports ACTION_HDMI_AUDIO_PLUG.EXTRA_MAX_CHANNEL_COUNT as 8 // instead of 10. See https://github.com/androidx/media/issues/396 - if (format.sampleMimeType == MimeTypes.AUDIO_DTS_X) { + if (format.sampleMimeType.equals(MimeTypes.AUDIO_DTS_X)) { if (channelCount > 10) { return null; } From f69718e5ad42fb30ac2021a9d4bbb60546d80444 Mon Sep 17 00:00:00 2001 From: Tianyi Feng Date: Wed, 17 May 2023 13:06:58 +0000 Subject: [PATCH 27/33] Fix the lint issues --- .../java/androidx/media3/extractor/DtsUtil.java | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/libraries/extractor/src/main/java/androidx/media3/extractor/DtsUtil.java b/libraries/extractor/src/main/java/androidx/media3/extractor/DtsUtil.java index 26f8cbaa9b..b02ba440e3 100644 --- a/libraries/extractor/src/main/java/androidx/media3/extractor/DtsUtil.java +++ b/libraries/extractor/src/main/java/androidx/media3/extractor/DtsUtil.java @@ -160,16 +160,13 @@ public final class DtsUtil { * @return The number of audio samples represented by the syncframe. */ public static int parseDtsAudioSampleCount(ByteBuffer buffer) { - - // Check for DTS:X Profile 2 sync or non sync word and return - // 1024 if found. This is the only audio sample count that is used by DTS:X Streaming Encoder. if ((buffer.getInt(0) == SYNC_FTOC_LE) || (buffer.getInt(0) == SYNC_FTOC_NON_SYNC_LE)) { + // Check for DTS:X Profile 2 sync or non sync word and return + // 1024 if found. This is the only audio sample count that is used by DTS:X Streaming Encoder. return 1024; - } - - // Check for DTS Express sync word and return 4096 if found. This is the only audio - // sample count that is used by DTS Streaming Encoder. - else if (buffer.getInt(0) == SYNC_EXT_SUB_LE) { + } else if (buffer.getInt(0) == SYNC_EXT_SUB_LE) { + // Check for DTS Express sync word and return 4096 if found. This is the only audio + // sample count that is used by DTS Streaming Encoder. return 4096; } From 9d147f22271b22b3d9bb6a5f8f1a132d6348694c Mon Sep 17 00:00:00 2001 From: Tianyi Feng Date: Wed, 17 May 2023 13:08:07 +0000 Subject: [PATCH 28/33] Adjust the comment lines --- .../src/main/java/androidx/media3/extractor/DtsUtil.java | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/libraries/extractor/src/main/java/androidx/media3/extractor/DtsUtil.java b/libraries/extractor/src/main/java/androidx/media3/extractor/DtsUtil.java index b02ba440e3..19f870d84f 100644 --- a/libraries/extractor/src/main/java/androidx/media3/extractor/DtsUtil.java +++ b/libraries/extractor/src/main/java/androidx/media3/extractor/DtsUtil.java @@ -161,12 +161,12 @@ public final class DtsUtil { */ public static int parseDtsAudioSampleCount(ByteBuffer buffer) { if ((buffer.getInt(0) == SYNC_FTOC_LE) || (buffer.getInt(0) == SYNC_FTOC_NON_SYNC_LE)) { - // Check for DTS:X Profile 2 sync or non sync word and return - // 1024 if found. This is the only audio sample count that is used by DTS:X Streaming Encoder. + // Check for DTS:X Profile 2 sync or non sync word and return 1024 if found. This is the only + // audio sample count that is used by DTS:X Streaming Encoder. return 1024; } else if (buffer.getInt(0) == SYNC_EXT_SUB_LE) { - // Check for DTS Express sync word and return 4096 if found. This is the only audio - // sample count that is used by DTS Streaming Encoder. + // Check for DTS Express sync word and return 4096 if found. This is the only audio sample + // count that is used by DTS Streaming Encoder. return 4096; } From ea32f1129238700e3a8e75043e2a4be810e63300 Mon Sep 17 00:00:00 2001 From: Tianyi Feng Date: Fri, 19 May 2023 21:56:07 +0000 Subject: [PATCH 29/33] Refactor the methods and reword the comments --- .../androidx/media3/common/util/Util.java | 7 +++--- .../exoplayer/audio/AudioCapabilities.java | 25 ++++++++++--------- 2 files changed, 17 insertions(+), 15 deletions(-) diff --git a/libraries/common/src/main/java/androidx/media3/common/util/Util.java b/libraries/common/src/main/java/androidx/media3/common/util/Util.java index ac87584747..389e2cd8a2 100644 --- a/libraries/common/src/main/java/androidx/media3/common/util/Util.java +++ b/libraries/common/src/main/java/androidx/media3/common/util/Util.java @@ -1885,11 +1885,12 @@ public final class Util { case 8: return AudioFormat.CHANNEL_OUT_7POINT1_SURROUND; case 10: - if (Util.SDK_INT > 31) { + if (Util.SDK_INT >= 32) { return AudioFormat.CHANNEL_OUT_5POINT1POINT4; } else { - // This is used by DTS:X P2 with Direct Passthrough Playback. - // Specifying the audio format as 7.1 for 10 channels does not affect the playback. + // Before API 32, height channel masks are not available. For those 10-channel streams + // supported on the audio output devices (e.g. DTS:X P2), we will use 7.1-surround + // instead. return AudioFormat.CHANNEL_OUT_7POINT1_SURROUND; } case 12: diff --git a/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/audio/AudioCapabilities.java b/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/audio/AudioCapabilities.java index 99941084b8..003d2a89ca 100644 --- a/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/audio/AudioCapabilities.java +++ b/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/audio/AudioCapabilities.java @@ -56,10 +56,11 @@ public final class AudioCapabilities { new AudioCapabilities(new int[] {AudioFormat.ENCODING_PCM_16BIT}, DEFAULT_MAX_CHANNEL_COUNT); /** Encodings supported when the device specifies external surround sound. */ - private static final int[] EXTERNAL_SURROUND_SOUND_ENCODINGS = - new int[] { - AudioFormat.ENCODING_PCM_16BIT, AudioFormat.ENCODING_AC3, AudioFormat.ENCODING_E_AC3 - }; + private static final ImmutableList EXTERNAL_SURROUND_SOUND_ENCODINGS = + ImmutableList.of( + AudioFormat.ENCODING_PCM_16BIT, + AudioFormat.ENCODING_AC3, + AudioFormat.ENCODING_E_AC3); /** * All surround sound encodings that a device may be capable of playing mapped to a maximum @@ -105,14 +106,14 @@ public final class AudioCapabilities { ImmutableSet.Builder supportedEncodings = new ImmutableSet.Builder<>(); if (deviceMaySetExternalSurroundSoundGlobalSetting() && Global.getInt(context.getContentResolver(), EXTERNAL_SURROUND_SOUND_KEY, 0) == 1) { - supportedEncodings.addAll(Ints.asList(EXTERNAL_SURROUND_SOUND_ENCODINGS)); + supportedEncodings.addAll(EXTERNAL_SURROUND_SOUND_ENCODINGS); } // AudioTrack.isDirectPlaybackSupported returns true for encodings that are supported for audio // offload, as well as for encodings we want to list for passthrough mode. Therefore we only use // it on TV and automotive devices, which generally shouldn't support audio offload for surround // encodings. if (Util.SDK_INT >= 29 && (Util.isTv(context) || Util.isAutomotive(context))) { - supportedEncodings.addAll(Ints.asList(Api29.getDirectPlaybackSupportedEncodings())); + supportedEncodings.addAll(Api29.getDirectPlaybackSupportedEncodings()); } if (intent != null && intent.getIntExtra(AudioManager.EXTRA_AUDIO_PLUG_STATE, 0) == 1) { @@ -369,8 +370,8 @@ public final class AudioCapabilities { private Api29() {} @DoNotInline - public static int[] getDirectPlaybackSupportedEncodings() { - int[] encodings = Api29.getAllSurroundEncodingsMaybeSupported(); + public static ImmutableList getDirectPlaybackSupportedEncodings() { + ImmutableList encodings = Api29.getAllSurroundEncodingsMaybeSupported(); ImmutableList.Builder supportedEncodingsListBuilder = ImmutableList.builder(); for (int encoding : encodings) { if (AudioTrack.isDirectPlaybackSupported( @@ -384,7 +385,7 @@ public final class AudioCapabilities { } } supportedEncodingsListBuilder.add(AudioFormat.ENCODING_PCM_16BIT); - return Ints.toArray(supportedEncodingsListBuilder.build()); + return supportedEncodingsListBuilder.build(); } /** @@ -410,9 +411,9 @@ public final class AudioCapabilities { return 0; } - /** Returns an array list of surround encodings that maybe supported. */ + /** Returns a list of surround encodings that maybe supported. */ @DoNotInline - private static int[] getAllSurroundEncodingsMaybeSupported() { + private static ImmutableList getAllSurroundEncodingsMaybeSupported() { ImmutableList.Builder encodings = new ImmutableList.Builder<>(); for (int encoding : ALL_SURROUND_ENCODINGS_AND_MAX_CHANNELS.keySet()) { // AudioFormat.ENCODING_DTS_UHD_P2 is supported from API 34. @@ -421,7 +422,7 @@ public final class AudioCapabilities { } encodings.add(encoding); } - return Ints.toArray(encodings.build()); + return encodings.build(); } } } From 48509df714bfa26b33bb99b8809004316d104059 Mon Sep 17 00:00:00 2001 From: Tianyi Feng Date: Fri, 19 May 2023 23:10:52 +0000 Subject: [PATCH 30/33] Quick return the capabilities for API29 TV case --- .../androidx/media3/exoplayer/audio/AudioCapabilities.java | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/audio/AudioCapabilities.java b/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/audio/AudioCapabilities.java index 003d2a89ca..fa9c12cf46 100644 --- a/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/audio/AudioCapabilities.java +++ b/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/audio/AudioCapabilities.java @@ -114,10 +114,15 @@ public final class AudioCapabilities { // encodings. if (Util.SDK_INT >= 29 && (Util.isTv(context) || Util.isAutomotive(context))) { supportedEncodings.addAll(Api29.getDirectPlaybackSupportedEncodings()); + return new AudioCapabilities( + Ints.toArray(supportedEncodings.build()), DEFAULT_MAX_CHANNEL_COUNT); } if (intent != null && intent.getIntExtra(AudioManager.EXTRA_AUDIO_PLUG_STATE, 0) == 1) { - supportedEncodings.addAll(Ints.asList(intent.getIntArrayExtra(AudioManager.EXTRA_ENCODINGS))); + @Nullable int[] encodingsFromExtra = intent.getIntArrayExtra(AudioManager.EXTRA_ENCODINGS); + if (encodingsFromExtra != null) { + supportedEncodings.addAll(Ints.asList(encodingsFromExtra)); + } return new AudioCapabilities( Ints.toArray(supportedEncodings.build()), intent.getIntExtra( From fb34983bb71a755445c4af91f3f31e977d0bcbf5 Mon Sep 17 00:00:00 2001 From: Tianyi Feng Date: Sat, 20 May 2023 10:43:37 +0000 Subject: [PATCH 31/33] Format with google-java-format --- .../androidx/media3/exoplayer/audio/AudioCapabilities.java | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/audio/AudioCapabilities.java b/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/audio/AudioCapabilities.java index fa9c12cf46..3c97b1b99e 100644 --- a/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/audio/AudioCapabilities.java +++ b/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/audio/AudioCapabilities.java @@ -58,9 +58,7 @@ public final class AudioCapabilities { /** Encodings supported when the device specifies external surround sound. */ private static final ImmutableList EXTERNAL_SURROUND_SOUND_ENCODINGS = ImmutableList.of( - AudioFormat.ENCODING_PCM_16BIT, - AudioFormat.ENCODING_AC3, - AudioFormat.ENCODING_E_AC3); + AudioFormat.ENCODING_PCM_16BIT, AudioFormat.ENCODING_AC3, AudioFormat.ENCODING_E_AC3); /** * All surround sound encodings that a device may be capable of playing mapped to a maximum From f301214a1e09bb698c972d3fc3d932668f97d768 Mon Sep 17 00:00:00 2001 From: Tianyi Feng Date: Mon, 22 May 2023 17:35:51 +0000 Subject: [PATCH 32/33] Refactor the comment --- .../common/src/main/java/androidx/media3/common/util/Util.java | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/libraries/common/src/main/java/androidx/media3/common/util/Util.java b/libraries/common/src/main/java/androidx/media3/common/util/Util.java index 389e2cd8a2..2d82e993bb 100644 --- a/libraries/common/src/main/java/androidx/media3/common/util/Util.java +++ b/libraries/common/src/main/java/androidx/media3/common/util/Util.java @@ -1889,8 +1889,7 @@ public final class Util { return AudioFormat.CHANNEL_OUT_5POINT1POINT4; } else { // Before API 32, height channel masks are not available. For those 10-channel streams - // supported on the audio output devices (e.g. DTS:X P2), we will use 7.1-surround - // instead. + // supported on the audio output devices (e.g. DTS:X P2), we use 7.1-surround instead. return AudioFormat.CHANNEL_OUT_7POINT1_SURROUND; } case 12: From 730cfecd5754d3db4ed0cc0725f9fbe5f19ec707 Mon Sep 17 00:00:00 2001 From: Tianyi Feng Date: Tue, 23 May 2023 13:02:26 +0000 Subject: [PATCH 33/33] Make the API 34 check inline and refactor the comment --- RELEASENOTES.md | 2 +- .../main/java/androidx/media3/common/C.java | 2 +- .../exoplayer/audio/AudioCapabilities.java | 23 ++++++------------- 3 files changed, 9 insertions(+), 18 deletions(-) diff --git a/RELEASENOTES.md b/RELEASENOTES.md index efa4f95f9d..7eaf2499b9 100644 --- a/RELEASENOTES.md +++ b/RELEASENOTES.md @@ -17,7 +17,7 @@ * Ogg: Fix bug when seeking in files with a long duration ([#391](https://github.com/androidx/media/issues/391)). * Audio: - * Add direct playback supports for DTS Express and DTS:X + * Add direct playback support for DTS Express and DTS:X ([#335](https://github.com/androidx/media/pull/335)). * Audio Offload: * Add `AudioSink.getFormatOffloadSupport(Format)` that retrieves level of diff --git a/libraries/common/src/main/java/androidx/media3/common/C.java b/libraries/common/src/main/java/androidx/media3/common/C.java index 79e4d56a26..ed3fb91c0a 100644 --- a/libraries/common/src/main/java/androidx/media3/common/C.java +++ b/libraries/common/src/main/java/androidx/media3/common/C.java @@ -257,7 +257,7 @@ public final class C { @UnstableApi public static final int ENCODING_DTS = AudioFormat.ENCODING_DTS; /** See {@link AudioFormat#ENCODING_DTS_HD}. */ @UnstableApi public static final int ENCODING_DTS_HD = AudioFormat.ENCODING_DTS_HD; - /** TODO: To replace with AudioFormat.ENCODING_DTS_UHD_P2 when Android 14.0 is released. */ + // TODO(internal b/283949283): Use AudioFormat.ENCODING_DTS_UHD_P2 when Android 14 is released. @UnstableApi public static final int ENCODING_DTS_UHD_P2 = 0x0000001e; /** See {@link AudioFormat#ENCODING_DOLBY_TRUEHD}. */ @UnstableApi public static final int ENCODING_DOLBY_TRUEHD = AudioFormat.ENCODING_DOLBY_TRUEHD; diff --git a/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/audio/AudioCapabilities.java b/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/audio/AudioCapabilities.java index 3c97b1b99e..2c26755157 100644 --- a/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/audio/AudioCapabilities.java +++ b/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/audio/AudioCapabilities.java @@ -48,6 +48,8 @@ import java.util.Arrays; @UnstableApi public final class AudioCapabilities { + // TODO(internal b/283945513): Have separate default max channel counts in `AudioCapabilities` + // for PCM and compressed audio. private static final int DEFAULT_MAX_CHANNEL_COUNT = 10; @VisibleForTesting /* package */ static final int DEFAULT_SAMPLE_RATE_HZ = 48_000; @@ -374,9 +376,12 @@ public final class AudioCapabilities { @DoNotInline public static ImmutableList getDirectPlaybackSupportedEncodings() { - ImmutableList encodings = Api29.getAllSurroundEncodingsMaybeSupported(); ImmutableList.Builder supportedEncodingsListBuilder = ImmutableList.builder(); - for (int encoding : encodings) { + for (int encoding : ALL_SURROUND_ENCODINGS_AND_MAX_CHANNELS.keySet()) { + // AudioFormat.ENCODING_DTS_UHD_P2 is supported from API 34. + if (Util.SDK_INT < 34 && encoding == C.ENCODING_DTS_UHD_P2) { + continue; + } if (AudioTrack.isDirectPlaybackSupported( new AudioFormat.Builder() .setChannelMask(AudioFormat.CHANNEL_OUT_STEREO) @@ -413,19 +418,5 @@ public final class AudioCapabilities { } return 0; } - - /** Returns a list of surround encodings that maybe supported. */ - @DoNotInline - private static ImmutableList getAllSurroundEncodingsMaybeSupported() { - ImmutableList.Builder encodings = new ImmutableList.Builder<>(); - for (int encoding : ALL_SURROUND_ENCODINGS_AND_MAX_CHANNELS.keySet()) { - // AudioFormat.ENCODING_DTS_UHD_P2 is supported from API 34. - if (Util.SDK_INT < 34 && encoding == C.ENCODING_DTS_UHD_P2) { - continue; - } - encodings.add(encoding); - } - return encodings.build(); - } } }