Merge pull request #335 from cedricxperi:dts-direct-passthrough-support

PiperOrigin-RevId: 535255453
(cherry picked from commit 6a9167097e78341b3bd3ad8309ee79ae35ecfd13)
parent 95fdd3f7
...@@ -189,6 +189,7 @@ public final class C { ...@@ -189,6 +189,7 @@ public final class C {
ENCODING_DTS_HD, ENCODING_DTS_HD,
ENCODING_DOLBY_TRUEHD, ENCODING_DOLBY_TRUEHD,
ENCODING_OPUS, ENCODING_OPUS,
ENCODING_DTS_UHD_P2,
}) })
public @interface Encoding {} public @interface Encoding {}
...@@ -252,6 +253,8 @@ public final class C { ...@@ -252,6 +253,8 @@ public final class C {
public static final int ENCODING_DTS = AudioFormat.ENCODING_DTS; public static final int ENCODING_DTS = AudioFormat.ENCODING_DTS;
/** See {@link AudioFormat#ENCODING_DTS_HD}. */ /** See {@link AudioFormat#ENCODING_DTS_HD}. */
public static final int ENCODING_DTS_HD = AudioFormat.ENCODING_DTS_HD; public static final int ENCODING_DTS_HD = AudioFormat.ENCODING_DTS_HD;
// TODO(internal b/283949283): Use AudioFormat.ENCODING_DTS_UHD_P2 when Android 14 is released.
public static final int ENCODING_DTS_UHD_P2 = 0x0000001e;
/** See {@link AudioFormat#ENCODING_DOLBY_TRUEHD}. */ /** See {@link AudioFormat#ENCODING_DOLBY_TRUEHD}. */
public static final int ENCODING_DOLBY_TRUEHD = AudioFormat.ENCODING_DOLBY_TRUEHD; public static final int ENCODING_DOLBY_TRUEHD = AudioFormat.ENCODING_DOLBY_TRUEHD;
/** See {@link AudioFormat#ENCODING_OPUS}. */ /** See {@link AudioFormat#ENCODING_OPUS}. */
......
...@@ -575,6 +575,10 @@ public final class MimeTypes { ...@@ -575,6 +575,10 @@ public final class MimeTypes {
return C.ENCODING_DTS; return C.ENCODING_DTS;
case MimeTypes.AUDIO_DTS_HD: case MimeTypes.AUDIO_DTS_HD:
return C.ENCODING_DTS_HD; return C.ENCODING_DTS_HD;
case MimeTypes.AUDIO_DTS_EXPRESS:
return C.ENCODING_DTS_HD;
case MimeTypes.AUDIO_DTS_X:
return C.ENCODING_DTS_UHD_P2;
case MimeTypes.AUDIO_TRUEHD: case MimeTypes.AUDIO_TRUEHD:
return C.ENCODING_DOLBY_TRUEHD; return C.ENCODING_DOLBY_TRUEHD;
case MimeTypes.AUDIO_OPUS: case MimeTypes.AUDIO_OPUS:
......
...@@ -1801,6 +1801,14 @@ public final class Util { ...@@ -1801,6 +1801,14 @@ public final class Util {
return AudioFormat.CHANNEL_OUT_5POINT1 | AudioFormat.CHANNEL_OUT_BACK_CENTER; return AudioFormat.CHANNEL_OUT_5POINT1 | AudioFormat.CHANNEL_OUT_BACK_CENTER;
case 8: case 8:
return AudioFormat.CHANNEL_OUT_7POINT1_SURROUND; return AudioFormat.CHANNEL_OUT_7POINT1_SURROUND;
case 10:
if (Util.SDK_INT >= 32) {
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 use 7.1-surround instead.
return AudioFormat.CHANNEL_OUT_7POINT1_SURROUND;
}
case 12: case 12:
return AudioFormat.CHANNEL_OUT_7POINT1POINT4; return AudioFormat.CHANNEL_OUT_7POINT1POINT4;
default: default:
......
...@@ -46,21 +46,19 @@ import java.util.Arrays; ...@@ -46,21 +46,19 @@ import java.util.Arrays;
/** Represents the set of audio formats that a device is capable of playing. */ /** Represents the set of audio formats that a device is capable of playing. */
public final class AudioCapabilities { public final class AudioCapabilities {
private static final int DEFAULT_MAX_CHANNEL_COUNT = 8; // 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; @VisibleForTesting /* package */ static final int DEFAULT_SAMPLE_RATE_HZ = 48_000;
/** The minimum audio capabilities supported by all devices. */ /** The minimum audio capabilities supported by all devices. */
public static final AudioCapabilities DEFAULT_AUDIO_CAPABILITIES = public static final AudioCapabilities DEFAULT_AUDIO_CAPABILITIES =
new AudioCapabilities(new int[] {AudioFormat.ENCODING_PCM_16BIT}, DEFAULT_MAX_CHANNEL_COUNT); new AudioCapabilities(new int[] {AudioFormat.ENCODING_PCM_16BIT}, DEFAULT_MAX_CHANNEL_COUNT);
/** Audio capabilities when the device specifies external surround sound. */ /** Encodings supported when the device specifies external surround sound. */
@SuppressWarnings("InlinedApi") private static final ImmutableList<Integer> EXTERNAL_SURROUND_SOUND_ENCODINGS =
private static final AudioCapabilities EXTERNAL_SURROUND_SOUND_CAPABILITIES = ImmutableList.of(
new AudioCapabilities( AudioFormat.ENCODING_PCM_16BIT, AudioFormat.ENCODING_AC3, AudioFormat.ENCODING_E_AC3);
new int[] {
AudioFormat.ENCODING_PCM_16BIT, AudioFormat.ENCODING_AC3, AudioFormat.ENCODING_E_AC3
},
DEFAULT_MAX_CHANNEL_COUNT);
/** /**
* All surround sound encodings that a device may be capable of playing mapped to a maximum * All surround sound encodings that a device may be capable of playing mapped to a maximum
...@@ -71,6 +69,7 @@ public final class AudioCapabilities { ...@@ -71,6 +69,7 @@ public final class AudioCapabilities {
.put(C.ENCODING_AC3, 6) .put(C.ENCODING_AC3, 6)
.put(C.ENCODING_AC4, 6) .put(C.ENCODING_AC4, 6)
.put(C.ENCODING_DTS, 6) .put(C.ENCODING_DTS, 6)
.put(C.ENCODING_DTS_UHD_P2, 10)
.put(C.ENCODING_E_AC3_JOC, 6) .put(C.ENCODING_E_AC3_JOC, 6)
.put(C.ENCODING_E_AC3, 8) .put(C.ENCODING_E_AC3, 8)
.put(C.ENCODING_DTS_HD, 8) .put(C.ENCODING_DTS_HD, 8)
...@@ -101,27 +100,41 @@ public final class AudioCapabilities { ...@@ -101,27 +100,41 @@ public final class AudioCapabilities {
if (Util.SDK_INT >= 23 && Api23.isBluetoothConnected(context)) { if (Util.SDK_INT >= 23 && Api23.isBluetoothConnected(context)) {
return DEFAULT_AUDIO_CAPABILITIES; return DEFAULT_AUDIO_CAPABILITIES;
} }
ImmutableSet.Builder<Integer> supportedEncodings = new ImmutableSet.Builder<>();
if (deviceMaySetExternalSurroundSoundGlobalSetting() if (deviceMaySetExternalSurroundSoundGlobalSetting()
&& Global.getInt(context.getContentResolver(), EXTERNAL_SURROUND_SOUND_KEY, 0) == 1) { && Global.getInt(context.getContentResolver(), EXTERNAL_SURROUND_SOUND_KEY, 0) == 1) {
return EXTERNAL_SURROUND_SOUND_CAPABILITIES; supportedEncodings.addAll(EXTERNAL_SURROUND_SOUND_ENCODINGS);
} }
// AudioTrack.isDirectPlaybackSupported returns true for encodings that are supported for audio // 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 // 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 // it on TV and automotive devices, which generally shouldn't support audio offload for surround
// encodings. // encodings.
if (Util.SDK_INT >= 29 && (Util.isTv(context) || Util.isAutomotive(context))) { if (Util.SDK_INT >= 29 && (Util.isTv(context) || Util.isAutomotive(context))) {
supportedEncodings.addAll(Api29.getDirectPlaybackSupportedEncodings());
return new AudioCapabilities( return new AudioCapabilities(
Api29.getDirectPlaybackSupportedEncodings(), DEFAULT_MAX_CHANNEL_COUNT); Ints.toArray(supportedEncodings.build()), DEFAULT_MAX_CHANNEL_COUNT);
} }
if (intent == null || intent.getIntExtra(AudioManager.EXTRA_AUDIO_PLUG_STATE, 0) == 0) {
return DEFAULT_AUDIO_CAPABILITIES; if (intent != null && intent.getIntExtra(AudioManager.EXTRA_AUDIO_PLUG_STATE, 0) == 1) {
@Nullable int[] encodingsFromExtra = intent.getIntArrayExtra(AudioManager.EXTRA_ENCODINGS);
if (encodingsFromExtra != null) {
supportedEncodings.addAll(Ints.asList(encodingsFromExtra));
} }
return new AudioCapabilities( return new AudioCapabilities(
intent.getIntArrayExtra(AudioManager.EXTRA_ENCODINGS), Ints.toArray(supportedEncodings.build()),
intent.getIntExtra( intent.getIntExtra(
AudioManager.EXTRA_MAX_CHANNEL_COUNT, /* defaultValue= */ DEFAULT_MAX_CHANNEL_COUNT)); AudioManager.EXTRA_MAX_CHANNEL_COUNT, /* defaultValue= */ DEFAULT_MAX_CHANNEL_COUNT));
} }
ImmutableSet<Integer> supportedEncodingsSet = supportedEncodings.build();
if (!supportedEncodingsSet.isEmpty()) {
return new AudioCapabilities(
Ints.toArray(supportedEncodingsSet), /* maxChannelCount= */ DEFAULT_MAX_CHANNEL_COUNT);
}
return DEFAULT_AUDIO_CAPABILITIES;
}
/** /**
* Returns the global settings {@link Uri} used by the device to specify external surround sound, * Returns the global settings {@link Uri} used by the device to specify external surround sound,
* or null if the device does not support this functionality. * or null if the device does not support this functionality.
...@@ -201,7 +214,8 @@ public final class AudioCapabilities { ...@@ -201,7 +214,8 @@ public final class AudioCapabilities {
if (encoding == C.ENCODING_E_AC3_JOC && !supportsEncoding(C.ENCODING_E_AC3_JOC)) { 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). // E-AC3 receivers support E-AC3 JOC streams (but decode only the base layer).
encoding = C.ENCODING_E_AC3; 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). // DTS receivers support DTS-HD streams (but decode only the core layer).
encoding = C.ENCODING_DTS; encoding = C.ENCODING_DTS;
} }
...@@ -218,7 +232,13 @@ public final class AudioCapabilities { ...@@ -218,7 +232,13 @@ public final class AudioCapabilities {
channelCount = getMaxSupportedChannelCountForPassthrough(encoding, sampleRate); channelCount = getMaxSupportedChannelCountForPassthrough(encoding, sampleRate);
} else { } else {
channelCount = format.channelCount; channelCount = format.channelCount;
if (channelCount > maxChannelCount) { // 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.equals(MimeTypes.AUDIO_DTS_X)) {
if (channelCount > 10) {
return null;
}
} else if (channelCount > maxChannelCount) {
return null; return null;
} }
} }
...@@ -353,9 +373,13 @@ public final class AudioCapabilities { ...@@ -353,9 +373,13 @@ public final class AudioCapabilities {
private Api29() {} private Api29() {}
@DoNotInline @DoNotInline
public static int[] getDirectPlaybackSupportedEncodings() { public static ImmutableList<Integer> getDirectPlaybackSupportedEncodings() {
ImmutableList.Builder<Integer> supportedEncodingsListBuilder = ImmutableList.builder(); ImmutableList.Builder<Integer> supportedEncodingsListBuilder = ImmutableList.builder();
for (int encoding : ALL_SURROUND_ENCODINGS_AND_MAX_CHANNELS.keySet()) { 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( if (AudioTrack.isDirectPlaybackSupported(
new AudioFormat.Builder() new AudioFormat.Builder()
.setChannelMask(AudioFormat.CHANNEL_OUT_STEREO) .setChannelMask(AudioFormat.CHANNEL_OUT_STEREO)
...@@ -367,7 +391,7 @@ public final class AudioCapabilities { ...@@ -367,7 +391,7 @@ public final class AudioCapabilities {
} }
} }
supportedEncodingsListBuilder.add(AudioFormat.ENCODING_PCM_16BIT); supportedEncodingsListBuilder.add(AudioFormat.ENCODING_PCM_16BIT);
return Ints.toArray(supportedEncodingsListBuilder.build()); return supportedEncodingsListBuilder.build();
} }
/** /**
......
...@@ -39,6 +39,17 @@ public final class DtsUtil { ...@@ -39,6 +39,17 @@ public final class DtsUtil {
private static final int SYNC_VALUE_14B_BE = 0x1FFFE800; private static final int SYNC_VALUE_14B_BE = 0x1FFFE800;
private static final int SYNC_VALUE_LE = 0xFE7F0180; private static final int SYNC_VALUE_LE = 0xFE7F0180;
private static final int SYNC_VALUE_14B_LE = 0xFF1F00E8; private static final int SYNC_VALUE_14B_LE = 0xFF1F00E8;
/**
* 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;
/**
* 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_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_14B_BE = (byte) (SYNC_VALUE_14B_BE >>> 24);
private static final byte FIRST_BYTE_LE = (byte) (SYNC_VALUE_LE >>> 24); private static final byte FIRST_BYTE_LE = (byte) (SYNC_VALUE_LE >>> 24);
...@@ -147,6 +158,16 @@ public final class DtsUtil { ...@@ -147,6 +158,16 @@ public final class DtsUtil {
* @return The number of audio samples represented by the syncframe. * @return The number of audio samples represented by the syncframe.
*/ */
public static int parseDtsAudioSampleCount(ByteBuffer buffer) { 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.
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.
return 4096;
}
// See ETSI TS 102 114 subsection 5.4.1. // See ETSI TS 102 114 subsection 5.4.1.
int position = buffer.position(); int position = buffer.position();
int nblks; int nblks;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or sign in to comment