From 25acaa1c817d32d6d053372cc76fa81b7c8a9d88 Mon Sep 17 00:00:00 2001 From: Cedric T Date: Wed, 13 Sep 2023 17:36:48 +0800 Subject: [PATCH 1/8] Fix DTS Express Audio Buffer Underflow Issue. --- .../exoplayer/audio/DefaultAudioSink.java | 4 ++ .../DefaultAudioTrackBufferSizeProvider.java | 41 +++++++++++++++++-- .../androidx/media3/extractor/DtsUtil.java | 13 ++++++ 3 files changed, 55 insertions(+), 3 deletions(-) diff --git a/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/audio/DefaultAudioSink.java b/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/audio/DefaultAudioSink.java index 19166aec9c4..b9775fa37f9 100644 --- a/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/audio/DefaultAudioSink.java +++ b/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/audio/DefaultAudioSink.java @@ -653,6 +653,9 @@ public void configure(Format inputFormat, int specifiedBufferSize, @Nullable int boolean enableAudioTrackPlaybackParams; boolean enableOffloadGapless = false; + if (inputFormat.sampleMimeType.contains("audio/vnd.dts")) { + DtsUtil.setCurrentMimeType(inputFormat.sampleMimeType); + } if (MimeTypes.AUDIO_RAW.equals(inputFormat.sampleMimeType)) { Assertions.checkArgument(Util.isEncodingLinearPcm(inputFormat.pcmEncoding)); @@ -1459,6 +1462,7 @@ public void reset() { } playing = false; offloadDisabledUntilNextConfiguration = false; + DtsUtil.clearCurrentMimeType(); } @Override diff --git a/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/audio/DefaultAudioTrackBufferSizeProvider.java b/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/audio/DefaultAudioTrackBufferSizeProvider.java index 5e178f0523d..951417cc0bc 100644 --- a/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/audio/DefaultAudioTrackBufferSizeProvider.java +++ b/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/audio/DefaultAudioTrackBufferSizeProvider.java @@ -26,6 +26,7 @@ import android.media.AudioTrack; import androidx.media3.common.C; import androidx.media3.common.Format; +import androidx.media3.common.MimeTypes; import androidx.media3.common.util.UnstableApi; import androidx.media3.exoplayer.audio.DefaultAudioSink.OutputMode; import androidx.media3.extractor.AacUtil; @@ -62,7 +63,11 @@ public class DefaultAudioTrackBufferSizeProvider * devices (e.g., Broadcom 7271). */ private static final int AC3_BUFFER_MULTIPLICATION_FACTOR = 2; - + /** + * Default multiplication factor to apply to DTS Express passthrough buffer to avoid underruns + * on some devices (e.g., Xiaomi A2 TV). + */ + private static final int DTSE_BUFFER_MULTIPLICATION_FACTOR = 4; /** A builder to create {@link DefaultAudioTrackBufferSizeProvider} instances. */ public static class Builder { @@ -72,7 +77,7 @@ public static class Builder { private int passthroughBufferDurationUs; private int offloadBufferDurationUs; private int ac3BufferMultiplicationFactor; - + private int dtseBufferMultiplicationFactor; /** Creates a new builder. */ public Builder() { minPcmBufferDurationUs = MIN_PCM_BUFFER_DURATION_US; @@ -81,6 +86,7 @@ public Builder() { passthroughBufferDurationUs = PASSTHROUGH_BUFFER_DURATION_US; offloadBufferDurationUs = OFFLOAD_BUFFER_DURATION_US; ac3BufferMultiplicationFactor = AC3_BUFFER_MULTIPLICATION_FACTOR; + dtseBufferMultiplicationFactor = DTSE_BUFFER_MULTIPLICATION_FACTOR; } /** @@ -143,6 +149,17 @@ public Builder setAc3BufferMultiplicationFactor(int ac3BufferMultiplicationFacto return this; } + /** + * Sets the multiplication factor to apply to the passthrough buffer for DTS Express to avoid + * underruns on some devices (e.g., Xiaomi A2 TV). Default is + * {@value #DTSE_BUFFER_MULTIPLICATION_FACTOR}. + */ + @CanIgnoreReturnValue + public Builder setDtseBufferMultiplicationFactor(int dtseBufferMultiplicationFactor) { + this.dtseBufferMultiplicationFactor = dtseBufferMultiplicationFactor; + return this; + } + /** Build the {@link DefaultAudioTrackBufferSizeProvider}. */ public DefaultAudioTrackBufferSizeProvider build() { return new DefaultAudioTrackBufferSizeProvider(this); @@ -169,7 +186,11 @@ public DefaultAudioTrackBufferSizeProvider build() { * (e.g., Broadcom 7271). */ public final int ac3BufferMultiplicationFactor; - + /** + * The multiplication factor to apply to DTS Express passthrough buffer to avoid underruns on some + * devices (e.g., Xiaomi A2 TV). + */ + public final int dtseBufferMultiplicationFactor; protected DefaultAudioTrackBufferSizeProvider(Builder builder) { minPcmBufferDurationUs = builder.minPcmBufferDurationUs; maxPcmBufferDurationUs = builder.maxPcmBufferDurationUs; @@ -177,6 +198,7 @@ protected DefaultAudioTrackBufferSizeProvider(Builder builder) { passthroughBufferDurationUs = builder.passthroughBufferDurationUs; offloadBufferDurationUs = builder.offloadBufferDurationUs; ac3BufferMultiplicationFactor = builder.ac3BufferMultiplicationFactor; + dtseBufferMultiplicationFactor = builder.dtseBufferMultiplicationFactor; } @Override @@ -232,7 +254,20 @@ protected int getPassthroughBufferSizeInBytes(@C.Encoding int encoding, int bitr int bufferSizeUs = passthroughBufferDurationUs; if (encoding == C.ENCODING_AC3) { bufferSizeUs *= ac3BufferMultiplicationFactor; + } else if ((DtsUtil.getCurrentMimeType().contentEquals(MimeTypes.AUDIO_DTS_EXPRESS) && (bitrate + != Format.NO_VALUE))) + // DTS Express for streaming uses a frame size (number of audio samples per channel per frame) + // of 4096. This requires a higher multiple for the buffersize computation. + // Need to use encoding DtsUtil.getCurrentMimeType(). ENCODING_DTS_HD cannot be used + // to represent DTS Express as some MTK firmware versions only recognises + // ENCODING_DTS for DTS Express passthrough playback. + // When bitrate is unknown (e.g. HLS-fMP4), the multiple below is not necessary as the buffer + // size is taken care of by getMaximumEncodedRateBytesPerSecond(). + { + // This is necessary to prevent buffer underflow during playback in DASH DTS Express. + bufferSizeUs *= dtseBufferMultiplicationFactor; } + int byteRate = bitrate != Format.NO_VALUE ? divide(bitrate, 8, RoundingMode.CEILING) 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 8e91119a591..add402f02b8 100644 --- a/libraries/extractor/src/main/java/androidx/media3/extractor/DtsUtil.java +++ b/libraries/extractor/src/main/java/androidx/media3/extractor/DtsUtil.java @@ -76,6 +76,19 @@ public final class DtsUtil { 64, 112, 128, 192, 224, 256, 384, 448, 512, 640, 768, 896, 1024, 1152, 1280, 1536, 1920, 2048, 2304, 2560, 2688, 2816, 2823, 2944, 3072, 3840, 4096, 6144, 7680 }; + private static String currentMimeType; + + public static void setCurrentMimeType(String currentMimeType) { + DtsUtil.currentMimeType = currentMimeType; + } + + public static String getCurrentMimeType() { + return currentMimeType; + } + + public static void clearCurrentMimeType() { + currentMimeType = ""; + } /** * Returns whether a given integer matches a DTS sync word. Synchronization and storage modes are From 7edfe58283b709d5c231a7dea9c3297e74b2dd06 Mon Sep 17 00:00:00 2001 From: Cedric T Date: Mon, 18 Sep 2023 14:13:16 +0800 Subject: [PATCH 2/8] Remove current mimetype state and add DTSHD test cases --- .../exoplayer/audio/DefaultAudioSink.java | 4 - .../DefaultAudioTrackBufferSizeProvider.java | 17 ++-- ...AudioTrackBufferSizeProviderDTSHDTest.java | 78 +++++++++++++++++++ .../androidx/media3/extractor/DtsUtil.java | 13 ---- 4 files changed, 84 insertions(+), 28 deletions(-) create mode 100644 libraries/exoplayer/src/test/java/androidx/media3/exoplayer/audio/DefaultAudioTrackBufferSizeProviderDTSHDTest.java diff --git a/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/audio/DefaultAudioSink.java b/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/audio/DefaultAudioSink.java index b9775fa37f9..19166aec9c4 100644 --- a/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/audio/DefaultAudioSink.java +++ b/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/audio/DefaultAudioSink.java @@ -653,9 +653,6 @@ public void configure(Format inputFormat, int specifiedBufferSize, @Nullable int boolean enableAudioTrackPlaybackParams; boolean enableOffloadGapless = false; - if (inputFormat.sampleMimeType.contains("audio/vnd.dts")) { - DtsUtil.setCurrentMimeType(inputFormat.sampleMimeType); - } if (MimeTypes.AUDIO_RAW.equals(inputFormat.sampleMimeType)) { Assertions.checkArgument(Util.isEncodingLinearPcm(inputFormat.pcmEncoding)); @@ -1462,7 +1459,6 @@ public void reset() { } playing = false; offloadDisabledUntilNextConfiguration = false; - DtsUtil.clearCurrentMimeType(); } @Override diff --git a/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/audio/DefaultAudioTrackBufferSizeProvider.java b/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/audio/DefaultAudioTrackBufferSizeProvider.java index 951417cc0bc..e3601f205e9 100644 --- a/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/audio/DefaultAudioTrackBufferSizeProvider.java +++ b/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/audio/DefaultAudioTrackBufferSizeProvider.java @@ -69,6 +69,7 @@ public class DefaultAudioTrackBufferSizeProvider */ private static final int DTSE_BUFFER_MULTIPLICATION_FACTOR = 4; /** A builder to create {@link DefaultAudioTrackBufferSizeProvider} instances. */ + public static class Builder { private int minPcmBufferDurationUs; @@ -78,6 +79,7 @@ public static class Builder { private int offloadBufferDurationUs; private int ac3BufferMultiplicationFactor; private int dtseBufferMultiplicationFactor; + /** Creates a new builder. */ public Builder() { minPcmBufferDurationUs = MIN_PCM_BUFFER_DURATION_US; @@ -254,17 +256,10 @@ protected int getPassthroughBufferSizeInBytes(@C.Encoding int encoding, int bitr int bufferSizeUs = passthroughBufferDurationUs; if (encoding == C.ENCODING_AC3) { bufferSizeUs *= ac3BufferMultiplicationFactor; - } else if ((DtsUtil.getCurrentMimeType().contentEquals(MimeTypes.AUDIO_DTS_EXPRESS) && (bitrate - != Format.NO_VALUE))) - // DTS Express for streaming uses a frame size (number of audio samples per channel per frame) - // of 4096. This requires a higher multiple for the buffersize computation. - // Need to use encoding DtsUtil.getCurrentMimeType(). ENCODING_DTS_HD cannot be used - // to represent DTS Express as some MTK firmware versions only recognises - // ENCODING_DTS for DTS Express passthrough playback. - // When bitrate is unknown (e.g. HLS-fMP4), the multiple below is not necessary as the buffer - // size is taken care of by getMaximumEncodedRateBytesPerSecond(). - { - // This is necessary to prevent buffer underflow during playback in DASH DTS Express. + } else if (encoding == C.ENCODING_DTS_HD) { + // DTS Express for streaming uses a frame size (number of audio samples per channel per frame) + // of 4096. This requires a higher multiple for the buffersize computation. Otherwise, there + // will be buffer underflow during DASH playback. bufferSizeUs *= dtseBufferMultiplicationFactor; } diff --git a/libraries/exoplayer/src/test/java/androidx/media3/exoplayer/audio/DefaultAudioTrackBufferSizeProviderDTSHDTest.java b/libraries/exoplayer/src/test/java/androidx/media3/exoplayer/audio/DefaultAudioTrackBufferSizeProviderDTSHDTest.java new file mode 100644 index 00000000000..18184f1e461 --- /dev/null +++ b/libraries/exoplayer/src/test/java/androidx/media3/exoplayer/audio/DefaultAudioTrackBufferSizeProviderDTSHDTest.java @@ -0,0 +1,78 @@ +/* + * Copyright (C) 2022 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package androidx.media3.exoplayer.audio; + +import static androidx.media3.common.C.MICROS_PER_SECOND; +import static androidx.media3.exoplayer.audio.DefaultAudioSink.OUTPUT_MODE_PASSTHROUGH; +import static androidx.media3.exoplayer.audio.DefaultAudioTrackBufferSizeProvider.getMaximumEncodedRateBytesPerSecond; +import static com.google.common.truth.Truth.assertThat; + +import androidx.media3.common.C; +import androidx.media3.common.Format; +import androidx.test.ext.junit.runners.AndroidJUnit4; +import org.junit.Test; +import org.junit.runner.RunWith; + +/** + * Tests for {@link DefaultAudioTrackBufferSizeProvider} DTS-HD (DTS Express) audio. + */ +@RunWith(AndroidJUnit4.class) +public class DefaultAudioTrackBufferSizeProviderDTSHDTest { + + private static final DefaultAudioTrackBufferSizeProvider DEFAULT = + new DefaultAudioTrackBufferSizeProvider.Builder().build(); + + @Test + public void + getBufferSizeInBytes_passthroughDtshdAndNoBitrate_assumesMaxByteRateTimesMultiplicationFactor() { + int bufferSize = + DEFAULT.getBufferSizeInBytes( + /* minBufferSizeInBytes= */ 0, + /* encoding= */ C.ENCODING_DTS_HD, + /* outputMode= */ OUTPUT_MODE_PASSTHROUGH, + /* pcmFrameSize= */ 1, + /* sampleRate= */ 0, + /* bitrate= */ Format.NO_VALUE, + /* maxAudioTrackPlaybackSpeed= */ 1); + + assertThat(bufferSize) + .isEqualTo( + durationUsToDtshdMaxBytes(DEFAULT.passthroughBufferDurationUs) + * DEFAULT.dtseBufferMultiplicationFactor); + } + + @Test + public void + getBufferSizeInBytes_passthroughDtshdAt384Kbits_isPassthroughBufferSizeTimesMultiplicationFactor() { + int bufferSize = + DEFAULT.getBufferSizeInBytes( + /* minBufferSizeInBytes= */ 0, + /* encoding= */ C.ENCODING_DTS_HD, + /* outputMode= */ OUTPUT_MODE_PASSTHROUGH, + /* pcmFrameSize= */ 1, + /* sampleRate= */ 0, + /* bitrate= */ 384_000, + /* maxAudioTrackPlaybackSpeed= */ 1); + + // Default buffer duration 0.25s => 0.25 * 384000 / 8 = 12000 + assertThat(bufferSize).isEqualTo(12000 * DEFAULT.dtseBufferMultiplicationFactor); + } + + private static int durationUsToDtshdMaxBytes(long durationUs) { + return (int) + (durationUs * getMaximumEncodedRateBytesPerSecond(C.ENCODING_DTS_HD) / MICROS_PER_SECOND); + } +} 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 add402f02b8..8e91119a591 100644 --- a/libraries/extractor/src/main/java/androidx/media3/extractor/DtsUtil.java +++ b/libraries/extractor/src/main/java/androidx/media3/extractor/DtsUtil.java @@ -76,19 +76,6 @@ public final class DtsUtil { 64, 112, 128, 192, 224, 256, 384, 448, 512, 640, 768, 896, 1024, 1152, 1280, 1536, 1920, 2048, 2304, 2560, 2688, 2816, 2823, 2944, 3072, 3840, 4096, 6144, 7680 }; - private static String currentMimeType; - - public static void setCurrentMimeType(String currentMimeType) { - DtsUtil.currentMimeType = currentMimeType; - } - - public static String getCurrentMimeType() { - return currentMimeType; - } - - public static void clearCurrentMimeType() { - currentMimeType = ""; - } /** * Returns whether a given integer matches a DTS sync word. Synchronization and storage modes are From 24d03b06254380384a643c609ccc4bbaed976e25 Mon Sep 17 00:00:00 2001 From: Cedric T Date: Mon, 18 Sep 2023 18:38:45 +0800 Subject: [PATCH 3/8] Rename DTSE to DTSHD --- .../DefaultAudioTrackBufferSizeProvider.java | 38 ++++++++++--------- ...AudioTrackBufferSizeProviderDTSHDTest.java | 4 +- 2 files changed, 22 insertions(+), 20 deletions(-) diff --git a/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/audio/DefaultAudioTrackBufferSizeProvider.java b/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/audio/DefaultAudioTrackBufferSizeProvider.java index e3601f205e9..8a729d8e8ae 100644 --- a/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/audio/DefaultAudioTrackBufferSizeProvider.java +++ b/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/audio/DefaultAudioTrackBufferSizeProvider.java @@ -26,7 +26,6 @@ import android.media.AudioTrack; import androidx.media3.common.C; import androidx.media3.common.Format; -import androidx.media3.common.MimeTypes; import androidx.media3.common.util.UnstableApi; import androidx.media3.exoplayer.audio.DefaultAudioSink.OutputMode; import androidx.media3.extractor.AacUtil; @@ -67,8 +66,11 @@ public class DefaultAudioTrackBufferSizeProvider * Default multiplication factor to apply to DTS Express passthrough buffer to avoid underruns * on some devices (e.g., Xiaomi A2 TV). */ - private static final int DTSE_BUFFER_MULTIPLICATION_FACTOR = 4; - /** A builder to create {@link DefaultAudioTrackBufferSizeProvider} instances. */ + private static final int DTSHD_BUFFER_MULTIPLICATION_FACTOR = 4; + + /** + * A builder to create {@link DefaultAudioTrackBufferSizeProvider} instances. + */ public static class Builder { @@ -78,7 +80,7 @@ public static class Builder { private int passthroughBufferDurationUs; private int offloadBufferDurationUs; private int ac3BufferMultiplicationFactor; - private int dtseBufferMultiplicationFactor; + private int dtshdBufferMultiplicationFactor; /** Creates a new builder. */ public Builder() { @@ -88,7 +90,7 @@ public Builder() { passthroughBufferDurationUs = PASSTHROUGH_BUFFER_DURATION_US; offloadBufferDurationUs = OFFLOAD_BUFFER_DURATION_US; ac3BufferMultiplicationFactor = AC3_BUFFER_MULTIPLICATION_FACTOR; - dtseBufferMultiplicationFactor = DTSE_BUFFER_MULTIPLICATION_FACTOR; + dtshdBufferMultiplicationFactor = DTSHD_BUFFER_MULTIPLICATION_FACTOR; } /** @@ -152,13 +154,13 @@ public Builder setAc3BufferMultiplicationFactor(int ac3BufferMultiplicationFacto } /** - * Sets the multiplication factor to apply to the passthrough buffer for DTS Express to avoid - * underruns on some devices (e.g., Xiaomi A2 TV). Default is - * {@value #DTSE_BUFFER_MULTIPLICATION_FACTOR}. + * Sets the multiplication factor to apply to the passthrough buffer for DTS-HD (DTS Express) + * to avoid underruns on some devices (e.g., Xiaomi A2 TV). Default is + * {@value #DTSHD_BUFFER_MULTIPLICATION_FACTOR}. */ @CanIgnoreReturnValue - public Builder setDtseBufferMultiplicationFactor(int dtseBufferMultiplicationFactor) { - this.dtseBufferMultiplicationFactor = dtseBufferMultiplicationFactor; + public Builder setDtshdBufferMultiplicationFactor(int dtshdBufferMultiplicationFactor) { + this.dtshdBufferMultiplicationFactor = dtshdBufferMultiplicationFactor; return this; } @@ -189,10 +191,10 @@ public DefaultAudioTrackBufferSizeProvider build() { */ public final int ac3BufferMultiplicationFactor; /** - * The multiplication factor to apply to DTS Express passthrough buffer to avoid underruns on some - * devices (e.g., Xiaomi A2 TV). + * The multiplication factor to apply to DTS-HD (DTS Express) passthrough buffer to avoid + * underruns on some devices (e.g., Xiaomi A2 TV). */ - public final int dtseBufferMultiplicationFactor; + public final int dtshdBufferMultiplicationFactor; protected DefaultAudioTrackBufferSizeProvider(Builder builder) { minPcmBufferDurationUs = builder.minPcmBufferDurationUs; maxPcmBufferDurationUs = builder.maxPcmBufferDurationUs; @@ -200,7 +202,7 @@ protected DefaultAudioTrackBufferSizeProvider(Builder builder) { passthroughBufferDurationUs = builder.passthroughBufferDurationUs; offloadBufferDurationUs = builder.offloadBufferDurationUs; ac3BufferMultiplicationFactor = builder.ac3BufferMultiplicationFactor; - dtseBufferMultiplicationFactor = builder.dtseBufferMultiplicationFactor; + dtshdBufferMultiplicationFactor = builder.dtshdBufferMultiplicationFactor; } @Override @@ -257,10 +259,10 @@ protected int getPassthroughBufferSizeInBytes(@C.Encoding int encoding, int bitr if (encoding == C.ENCODING_AC3) { bufferSizeUs *= ac3BufferMultiplicationFactor; } else if (encoding == C.ENCODING_DTS_HD) { - // DTS Express for streaming uses a frame size (number of audio samples per channel per frame) - // of 4096. This requires a higher multiple for the buffersize computation. Otherwise, there - // will be buffer underflow during DASH playback. - bufferSizeUs *= dtseBufferMultiplicationFactor; + // DTSHD (DTS Express) for streaming uses a frame size (number of audio samples per channel + // per frame of 4096. This requires a higher multiple for the buffersize computation. + // Otherwise, there will be buffer underflow during DASH playback. + bufferSizeUs *= dtshdBufferMultiplicationFactor; } int byteRate = diff --git a/libraries/exoplayer/src/test/java/androidx/media3/exoplayer/audio/DefaultAudioTrackBufferSizeProviderDTSHDTest.java b/libraries/exoplayer/src/test/java/androidx/media3/exoplayer/audio/DefaultAudioTrackBufferSizeProviderDTSHDTest.java index 18184f1e461..60f70413f2c 100644 --- a/libraries/exoplayer/src/test/java/androidx/media3/exoplayer/audio/DefaultAudioTrackBufferSizeProviderDTSHDTest.java +++ b/libraries/exoplayer/src/test/java/androidx/media3/exoplayer/audio/DefaultAudioTrackBufferSizeProviderDTSHDTest.java @@ -51,7 +51,7 @@ public class DefaultAudioTrackBufferSizeProviderDTSHDTest { assertThat(bufferSize) .isEqualTo( durationUsToDtshdMaxBytes(DEFAULT.passthroughBufferDurationUs) - * DEFAULT.dtseBufferMultiplicationFactor); + * DEFAULT.dtshdBufferMultiplicationFactor); } @Test @@ -68,7 +68,7 @@ public class DefaultAudioTrackBufferSizeProviderDTSHDTest { /* maxAudioTrackPlaybackSpeed= */ 1); // Default buffer duration 0.25s => 0.25 * 384000 / 8 = 12000 - assertThat(bufferSize).isEqualTo(12000 * DEFAULT.dtseBufferMultiplicationFactor); + assertThat(bufferSize).isEqualTo(12000 * DEFAULT.dtshdBufferMultiplicationFactor); } private static int durationUsToDtshdMaxBytes(long durationUs) { From 0f200ba5d190a184fd9c6f19b9488c770534c5d4 Mon Sep 17 00:00:00 2001 From: Cedric T Date: Mon, 18 Sep 2023 19:15:32 +0800 Subject: [PATCH 4/8] Update nits --- .../audio/DefaultAudioTrackBufferSizeProvider.java | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/audio/DefaultAudioTrackBufferSizeProvider.java b/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/audio/DefaultAudioTrackBufferSizeProvider.java index 8a729d8e8ae..f6870b3a2e3 100644 --- a/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/audio/DefaultAudioTrackBufferSizeProvider.java +++ b/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/audio/DefaultAudioTrackBufferSizeProvider.java @@ -68,9 +68,7 @@ public class DefaultAudioTrackBufferSizeProvider */ private static final int DTSHD_BUFFER_MULTIPLICATION_FACTOR = 4; - /** - * A builder to create {@link DefaultAudioTrackBufferSizeProvider} instances. - */ + /** A builder to create {@link DefaultAudioTrackBufferSizeProvider} instances. */ public static class Builder { @@ -156,7 +154,7 @@ public Builder setAc3BufferMultiplicationFactor(int ac3BufferMultiplicationFacto /** * Sets the multiplication factor to apply to the passthrough buffer for DTS-HD (DTS Express) * to avoid underruns on some devices (e.g., Xiaomi A2 TV). Default is - * {@value #DTSHD_BUFFER_MULTIPLICATION_FACTOR}. + * {@link #DTSHD_BUFFER_MULTIPLICATION_FACTOR}. */ @CanIgnoreReturnValue public Builder setDtshdBufferMultiplicationFactor(int dtshdBufferMultiplicationFactor) { @@ -259,8 +257,8 @@ protected int getPassthroughBufferSizeInBytes(@C.Encoding int encoding, int bitr if (encoding == C.ENCODING_AC3) { bufferSizeUs *= ac3BufferMultiplicationFactor; } else if (encoding == C.ENCODING_DTS_HD) { - // DTSHD (DTS Express) for streaming uses a frame size (number of audio samples per channel - // per frame of 4096. This requires a higher multiple for the buffersize computation. + // DTS-HD (DTS Express) for streaming uses a frame size (number of audio samples per channel + // per frame) of 4096. This requires a higher multiple for the buffersize computation. // Otherwise, there will be buffer underflow during DASH playback. bufferSizeUs *= dtshdBufferMultiplicationFactor; } From 215f663019213129427af987145b7dc51baf239a Mon Sep 17 00:00:00 2001 From: Tianyi Feng Date: Mon, 18 Sep 2023 12:01:49 +0000 Subject: [PATCH 5/8] Format with google-java-format --- .../audio/DefaultAudioTrackBufferSizeProvider.java | 13 ++++++++----- ...efaultAudioTrackBufferSizeProviderDTSHDTest.java | 8 +++----- 2 files changed, 11 insertions(+), 10 deletions(-) diff --git a/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/audio/DefaultAudioTrackBufferSizeProvider.java b/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/audio/DefaultAudioTrackBufferSizeProvider.java index f6870b3a2e3..717defa05a8 100644 --- a/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/audio/DefaultAudioTrackBufferSizeProvider.java +++ b/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/audio/DefaultAudioTrackBufferSizeProvider.java @@ -62,9 +62,10 @@ public class DefaultAudioTrackBufferSizeProvider * devices (e.g., Broadcom 7271). */ private static final int AC3_BUFFER_MULTIPLICATION_FACTOR = 2; + /** - * Default multiplication factor to apply to DTS Express passthrough buffer to avoid underruns - * on some devices (e.g., Xiaomi A2 TV). + * Default multiplication factor to apply to DTS Express passthrough buffer to avoid underruns on + * some devices (e.g., Xiaomi A2 TV). */ private static final int DTSHD_BUFFER_MULTIPLICATION_FACTOR = 4; @@ -152,9 +153,9 @@ public Builder setAc3BufferMultiplicationFactor(int ac3BufferMultiplicationFacto } /** - * Sets the multiplication factor to apply to the passthrough buffer for DTS-HD (DTS Express) - * to avoid underruns on some devices (e.g., Xiaomi A2 TV). Default is - * {@link #DTSHD_BUFFER_MULTIPLICATION_FACTOR}. + * Sets the multiplication factor to apply to the passthrough buffer for DTS-HD (DTS Express) to + * avoid underruns on some devices (e.g., Xiaomi A2 TV). Default is {@link + * #DTSHD_BUFFER_MULTIPLICATION_FACTOR}. */ @CanIgnoreReturnValue public Builder setDtshdBufferMultiplicationFactor(int dtshdBufferMultiplicationFactor) { @@ -188,11 +189,13 @@ public DefaultAudioTrackBufferSizeProvider build() { * (e.g., Broadcom 7271). */ public final int ac3BufferMultiplicationFactor; + /** * The multiplication factor to apply to DTS-HD (DTS Express) passthrough buffer to avoid * underruns on some devices (e.g., Xiaomi A2 TV). */ public final int dtshdBufferMultiplicationFactor; + protected DefaultAudioTrackBufferSizeProvider(Builder builder) { minPcmBufferDurationUs = builder.minPcmBufferDurationUs; maxPcmBufferDurationUs = builder.maxPcmBufferDurationUs; diff --git a/libraries/exoplayer/src/test/java/androidx/media3/exoplayer/audio/DefaultAudioTrackBufferSizeProviderDTSHDTest.java b/libraries/exoplayer/src/test/java/androidx/media3/exoplayer/audio/DefaultAudioTrackBufferSizeProviderDTSHDTest.java index 60f70413f2c..3c07c2fcb99 100644 --- a/libraries/exoplayer/src/test/java/androidx/media3/exoplayer/audio/DefaultAudioTrackBufferSizeProviderDTSHDTest.java +++ b/libraries/exoplayer/src/test/java/androidx/media3/exoplayer/audio/DefaultAudioTrackBufferSizeProviderDTSHDTest.java @@ -26,9 +26,7 @@ import org.junit.Test; import org.junit.runner.RunWith; -/** - * Tests for {@link DefaultAudioTrackBufferSizeProvider} DTS-HD (DTS Express) audio. - */ +/** Tests for {@link DefaultAudioTrackBufferSizeProvider} DTS-HD (DTS Express) audio. */ @RunWith(AndroidJUnit4.class) public class DefaultAudioTrackBufferSizeProviderDTSHDTest { @@ -37,7 +35,7 @@ public class DefaultAudioTrackBufferSizeProviderDTSHDTest { @Test public void - getBufferSizeInBytes_passthroughDtshdAndNoBitrate_assumesMaxByteRateTimesMultiplicationFactor() { + getBufferSizeInBytes_passthroughDtshdAndNoBitrate_assumesMaxByteRateTimesMultiplicationFactor() { int bufferSize = DEFAULT.getBufferSizeInBytes( /* minBufferSizeInBytes= */ 0, @@ -56,7 +54,7 @@ public class DefaultAudioTrackBufferSizeProviderDTSHDTest { @Test public void - getBufferSizeInBytes_passthroughDtshdAt384Kbits_isPassthroughBufferSizeTimesMultiplicationFactor() { + getBufferSizeInBytes_passthroughDtshdAt384Kbits_isPassthroughBufferSizeTimesMultiplicationFactor() { int bufferSize = DEFAULT.getBufferSizeInBytes( /* minBufferSizeInBytes= */ 0, From 49f45c45d18801fdb8ad4f6a6233acbc22f284a5 Mon Sep 17 00:00:00 2001 From: Tianyi Feng Date: Mon, 18 Sep 2023 12:12:47 +0000 Subject: [PATCH 6/8] Rebase and resolve conflict in the release notes --- RELEASENOTES.md | 2 ++ .../exoplayer/audio/DefaultAudioTrackBufferSizeProvider.java | 1 - 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/RELEASENOTES.md b/RELEASENOTES.md index 7ed4a03e29c..76d7982f5c8 100644 --- a/RELEASENOTES.md +++ b/RELEASENOTES.md @@ -11,6 +11,8 @@ stays at its current behavior of `true`. * Extractors: * Audio: + * Fix DTS Express audio buffer underflow issue + ([#650](https://github.com/androidx/media/pull/650)). * Video: * Text: * Remove `ExoplayerCuesDecoder`. Text tracks with `sampleMimeType = diff --git a/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/audio/DefaultAudioTrackBufferSizeProvider.java b/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/audio/DefaultAudioTrackBufferSizeProvider.java index 717defa05a8..1e5368dd729 100644 --- a/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/audio/DefaultAudioTrackBufferSizeProvider.java +++ b/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/audio/DefaultAudioTrackBufferSizeProvider.java @@ -70,7 +70,6 @@ public class DefaultAudioTrackBufferSizeProvider private static final int DTSHD_BUFFER_MULTIPLICATION_FACTOR = 4; /** A builder to create {@link DefaultAudioTrackBufferSizeProvider} instances. */ - public static class Builder { private int minPcmBufferDurationUs; From 834b61d1b7bee5322abcfab2f998de3c3ae966dc Mon Sep 17 00:00:00 2001 From: Tianyi Feng Date: Wed, 11 Oct 2023 16:36:49 +0000 Subject: [PATCH 7/8] Update the year in the copyright --- .../audio/DefaultAudioTrackBufferSizeProviderDTSHDTest.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/exoplayer/src/test/java/androidx/media3/exoplayer/audio/DefaultAudioTrackBufferSizeProviderDTSHDTest.java b/libraries/exoplayer/src/test/java/androidx/media3/exoplayer/audio/DefaultAudioTrackBufferSizeProviderDTSHDTest.java index 3c07c2fcb99..bd518167a40 100644 --- a/libraries/exoplayer/src/test/java/androidx/media3/exoplayer/audio/DefaultAudioTrackBufferSizeProviderDTSHDTest.java +++ b/libraries/exoplayer/src/test/java/androidx/media3/exoplayer/audio/DefaultAudioTrackBufferSizeProviderDTSHDTest.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2022 The Android Open Source Project + * Copyright (C) 2023 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. From 492048c00b331c01e6fcbd8efc672e4dc881bc18 Mon Sep 17 00:00:00 2001 From: Tianyi Feng Date: Thu, 12 Oct 2023 09:54:25 +0000 Subject: [PATCH 8/8] Modify the comment lines --- .../audio/DefaultAudioTrackBufferSizeProvider.java | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/audio/DefaultAudioTrackBufferSizeProvider.java b/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/audio/DefaultAudioTrackBufferSizeProvider.java index 1e5368dd729..d1a00a21a59 100644 --- a/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/audio/DefaultAudioTrackBufferSizeProvider.java +++ b/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/audio/DefaultAudioTrackBufferSizeProvider.java @@ -64,8 +64,7 @@ public class DefaultAudioTrackBufferSizeProvider private static final int AC3_BUFFER_MULTIPLICATION_FACTOR = 2; /** - * Default multiplication factor to apply to DTS Express passthrough buffer to avoid underruns on - * some devices (e.g., Xiaomi A2 TV). + * Default multiplication factor to apply to DTS Express passthrough buffer to avoid underruns. */ private static final int DTSHD_BUFFER_MULTIPLICATION_FACTOR = 4; @@ -153,8 +152,7 @@ public Builder setAc3BufferMultiplicationFactor(int ac3BufferMultiplicationFacto /** * Sets the multiplication factor to apply to the passthrough buffer for DTS-HD (DTS Express) to - * avoid underruns on some devices (e.g., Xiaomi A2 TV). Default is {@link - * #DTSHD_BUFFER_MULTIPLICATION_FACTOR}. + * avoid underruns. Default is {@link #DTSHD_BUFFER_MULTIPLICATION_FACTOR}. */ @CanIgnoreReturnValue public Builder setDtshdBufferMultiplicationFactor(int dtshdBufferMultiplicationFactor) { @@ -191,7 +189,7 @@ public DefaultAudioTrackBufferSizeProvider build() { /** * The multiplication factor to apply to DTS-HD (DTS Express) passthrough buffer to avoid - * underruns on some devices (e.g., Xiaomi A2 TV). + * underruns. */ public final int dtshdBufferMultiplicationFactor;