Fix DTS Express Audio Buffer Underflow Issue.

This commit is contained in:
Cedric T 2023-09-13 17:36:48 +08:00 committed by Tianyi Feng
parent a12bde4f57
commit 25acaa1c81
3 changed files with 55 additions and 3 deletions

View File

@ -653,6 +653,9 @@ public final class DefaultAudioSink implements AudioSink {
boolean enableAudioTrackPlaybackParams; boolean enableAudioTrackPlaybackParams;
boolean enableOffloadGapless = false; boolean enableOffloadGapless = false;
if (inputFormat.sampleMimeType.contains("audio/vnd.dts")) {
DtsUtil.setCurrentMimeType(inputFormat.sampleMimeType);
}
if (MimeTypes.AUDIO_RAW.equals(inputFormat.sampleMimeType)) { if (MimeTypes.AUDIO_RAW.equals(inputFormat.sampleMimeType)) {
Assertions.checkArgument(Util.isEncodingLinearPcm(inputFormat.pcmEncoding)); Assertions.checkArgument(Util.isEncodingLinearPcm(inputFormat.pcmEncoding));
@ -1459,6 +1462,7 @@ public final class DefaultAudioSink implements AudioSink {
} }
playing = false; playing = false;
offloadDisabledUntilNextConfiguration = false; offloadDisabledUntilNextConfiguration = false;
DtsUtil.clearCurrentMimeType();
} }
@Override @Override

View File

@ -26,6 +26,7 @@ import static java.lang.Math.max;
import android.media.AudioTrack; import android.media.AudioTrack;
import androidx.media3.common.C; import androidx.media3.common.C;
import androidx.media3.common.Format; import androidx.media3.common.Format;
import androidx.media3.common.MimeTypes;
import androidx.media3.common.util.UnstableApi; import androidx.media3.common.util.UnstableApi;
import androidx.media3.exoplayer.audio.DefaultAudioSink.OutputMode; import androidx.media3.exoplayer.audio.DefaultAudioSink.OutputMode;
import androidx.media3.extractor.AacUtil; import androidx.media3.extractor.AacUtil;
@ -62,7 +63,11 @@ public class DefaultAudioTrackBufferSizeProvider
* devices (e.g., Broadcom 7271). * devices (e.g., Broadcom 7271).
*/ */
private static final int AC3_BUFFER_MULTIPLICATION_FACTOR = 2; 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. */ /** A builder to create {@link DefaultAudioTrackBufferSizeProvider} instances. */
public static class Builder { public static class Builder {
@ -72,7 +77,7 @@ public class DefaultAudioTrackBufferSizeProvider
private int passthroughBufferDurationUs; private int passthroughBufferDurationUs;
private int offloadBufferDurationUs; private int offloadBufferDurationUs;
private int ac3BufferMultiplicationFactor; private int ac3BufferMultiplicationFactor;
private int dtseBufferMultiplicationFactor;
/** Creates a new builder. */ /** Creates a new builder. */
public Builder() { public Builder() {
minPcmBufferDurationUs = MIN_PCM_BUFFER_DURATION_US; minPcmBufferDurationUs = MIN_PCM_BUFFER_DURATION_US;
@ -81,6 +86,7 @@ public class DefaultAudioTrackBufferSizeProvider
passthroughBufferDurationUs = PASSTHROUGH_BUFFER_DURATION_US; passthroughBufferDurationUs = PASSTHROUGH_BUFFER_DURATION_US;
offloadBufferDurationUs = OFFLOAD_BUFFER_DURATION_US; offloadBufferDurationUs = OFFLOAD_BUFFER_DURATION_US;
ac3BufferMultiplicationFactor = AC3_BUFFER_MULTIPLICATION_FACTOR; ac3BufferMultiplicationFactor = AC3_BUFFER_MULTIPLICATION_FACTOR;
dtseBufferMultiplicationFactor = DTSE_BUFFER_MULTIPLICATION_FACTOR;
} }
/** /**
@ -143,6 +149,17 @@ public class DefaultAudioTrackBufferSizeProvider
return this; 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}. */ /** Build the {@link DefaultAudioTrackBufferSizeProvider}. */
public DefaultAudioTrackBufferSizeProvider build() { public DefaultAudioTrackBufferSizeProvider build() {
return new DefaultAudioTrackBufferSizeProvider(this); return new DefaultAudioTrackBufferSizeProvider(this);
@ -169,7 +186,11 @@ public class DefaultAudioTrackBufferSizeProvider
* (e.g., Broadcom 7271). * (e.g., Broadcom 7271).
*/ */
public final int ac3BufferMultiplicationFactor; 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) { protected DefaultAudioTrackBufferSizeProvider(Builder builder) {
minPcmBufferDurationUs = builder.minPcmBufferDurationUs; minPcmBufferDurationUs = builder.minPcmBufferDurationUs;
maxPcmBufferDurationUs = builder.maxPcmBufferDurationUs; maxPcmBufferDurationUs = builder.maxPcmBufferDurationUs;
@ -177,6 +198,7 @@ public class DefaultAudioTrackBufferSizeProvider
passthroughBufferDurationUs = builder.passthroughBufferDurationUs; passthroughBufferDurationUs = builder.passthroughBufferDurationUs;
offloadBufferDurationUs = builder.offloadBufferDurationUs; offloadBufferDurationUs = builder.offloadBufferDurationUs;
ac3BufferMultiplicationFactor = builder.ac3BufferMultiplicationFactor; ac3BufferMultiplicationFactor = builder.ac3BufferMultiplicationFactor;
dtseBufferMultiplicationFactor = builder.dtseBufferMultiplicationFactor;
} }
@Override @Override
@ -232,7 +254,20 @@ public class DefaultAudioTrackBufferSizeProvider
int bufferSizeUs = passthroughBufferDurationUs; int bufferSizeUs = passthroughBufferDurationUs;
if (encoding == C.ENCODING_AC3) { if (encoding == C.ENCODING_AC3) {
bufferSizeUs *= ac3BufferMultiplicationFactor; 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 = int byteRate =
bitrate != Format.NO_VALUE bitrate != Format.NO_VALUE
? divide(bitrate, 8, RoundingMode.CEILING) ? divide(bitrate, 8, RoundingMode.CEILING)

View File

@ -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, 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 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 * Returns whether a given integer matches a DTS sync word. Synchronization and storage modes are