Add a builder to DefaultAudioSink

`DefaultAudioSink` already has 3 telescoping
constructors and an other one would be have been
needed to add a buffer size tuning option.

PiperOrigin-RevId: 414703366
This commit is contained in:
krocard 2021-12-07 14:06:05 +00:00 committed by Ian Baker
parent dcc69056bf
commit 341bb57498
10 changed files with 217 additions and 105 deletions

View File

@ -66,7 +66,7 @@ public final class FfmpegAudioRenderer extends DecoderAudioRenderer<FfmpegAudioD
this( this(
eventHandler, eventHandler,
eventListener, eventListener,
new DefaultAudioSink(/* audioCapabilities= */ null, audioProcessors)); new DefaultAudioSink.Builder().setAudioProcessors(audioProcessors).build());
} }
/** /**

View File

@ -28,7 +28,6 @@ import androidx.media3.datasource.DefaultDataSource;
import androidx.media3.exoplayer.ExoPlayer; import androidx.media3.exoplayer.ExoPlayer;
import androidx.media3.exoplayer.Renderer; import androidx.media3.exoplayer.Renderer;
import androidx.media3.exoplayer.RenderersFactory; import androidx.media3.exoplayer.RenderersFactory;
import androidx.media3.exoplayer.audio.AudioProcessor;
import androidx.media3.exoplayer.audio.AudioSink; import androidx.media3.exoplayer.audio.AudioSink;
import androidx.media3.exoplayer.audio.DefaultAudioSink; import androidx.media3.exoplayer.audio.DefaultAudioSink;
import androidx.media3.exoplayer.source.MediaSource; import androidx.media3.exoplayer.source.MediaSource;
@ -67,9 +66,7 @@ public class FlacPlaybackTest {
} }
private static void playAndAssertAudioSinkInput(String fileName) throws Exception { private static void playAndAssertAudioSinkInput(String fileName) throws Exception {
CapturingAudioSink audioSink = CapturingAudioSink audioSink = new CapturingAudioSink(new DefaultAudioSink.Builder().build());
new CapturingAudioSink(
new DefaultAudioSink(/* audioCapabilities= */ null, new AudioProcessor[0]));
TestPlaybackRunnable testPlaybackRunnable = TestPlaybackRunnable testPlaybackRunnable =
new TestPlaybackRunnable( new TestPlaybackRunnable(

View File

@ -47,6 +47,7 @@ dependencies {
compileOnly 'org.checkerframework:checker-qual:' + checkerframeworkVersion compileOnly 'org.checkerframework:checker-qual:' + checkerframeworkVersion
compileOnly 'org.checkerframework:checker-compat-qual:' + checkerframeworkCompatVersion compileOnly 'org.checkerframework:checker-compat-qual:' + checkerframeworkCompatVersion
compileOnly 'org.jetbrains.kotlin:kotlin-annotations-jvm:' + kotlinAnnotationsVersion compileOnly 'org.jetbrains.kotlin:kotlin-annotations-jvm:' + kotlinAnnotationsVersion
compileOnly 'com.google.errorprone:error_prone_annotations:' + errorProneVersion
androidTestImplementation 'androidx.test:runner:' + androidxTestRunnerVersion androidTestImplementation 'androidx.test:runner:' + androidxTestRunnerVersion
androidTestImplementation 'com.linkedin.dexmaker:dexmaker:' + dexmakerVersion androidTestImplementation 'com.linkedin.dexmaker:dexmaker:' + dexmakerVersion
androidTestImplementation 'com.linkedin.dexmaker:dexmaker-mockito:' + dexmakerVersion androidTestImplementation 'com.linkedin.dexmaker:dexmaker-mockito:' + dexmakerVersion

View File

@ -28,7 +28,6 @@ import androidx.media3.exoplayer.audio.AudioCapabilities;
import androidx.media3.exoplayer.audio.AudioRendererEventListener; import androidx.media3.exoplayer.audio.AudioRendererEventListener;
import androidx.media3.exoplayer.audio.AudioSink; import androidx.media3.exoplayer.audio.AudioSink;
import androidx.media3.exoplayer.audio.DefaultAudioSink; import androidx.media3.exoplayer.audio.DefaultAudioSink;
import androidx.media3.exoplayer.audio.DefaultAudioSink.DefaultAudioProcessorChain;
import androidx.media3.exoplayer.audio.MediaCodecAudioRenderer; import androidx.media3.exoplayer.audio.MediaCodecAudioRenderer;
import androidx.media3.exoplayer.mediacodec.DefaultMediaCodecAdapterFactory; import androidx.media3.exoplayer.mediacodec.DefaultMediaCodecAdapterFactory;
import androidx.media3.exoplayer.mediacodec.MediaCodecAdapter; import androidx.media3.exoplayer.mediacodec.MediaCodecAdapter;
@ -666,14 +665,15 @@ public class DefaultRenderersFactory implements RenderersFactory {
boolean enableFloatOutput, boolean enableFloatOutput,
boolean enableAudioTrackPlaybackParams, boolean enableAudioTrackPlaybackParams,
boolean enableOffload) { boolean enableOffload) {
return new DefaultAudioSink( return new DefaultAudioSink.Builder()
AudioCapabilities.getCapabilities(context), .setAudioCapabilities(AudioCapabilities.getCapabilities(context))
new DefaultAudioProcessorChain(), .setEnableFloatOutput(enableFloatOutput)
enableFloatOutput, .setEnableAudioTrackPlaybackParams(enableAudioTrackPlaybackParams)
enableAudioTrackPlaybackParams, .setOffloadMode(
enableOffload enableOffload
? DefaultAudioSink.OFFLOAD_MODE_ENABLED_GAPLESS_REQUIRED ? DefaultAudioSink.OFFLOAD_MODE_ENABLED_GAPLESS_REQUIRED
: DefaultAudioSink.OFFLOAD_MODE_DISABLED); : DefaultAudioSink.OFFLOAD_MODE_DISABLED)
.build();
} }
/** /**

View File

@ -47,7 +47,6 @@ import androidx.media3.common.util.Util;
import androidx.media3.datasource.DataSource; import androidx.media3.datasource.DataSource;
import androidx.media3.exoplayer.analytics.AnalyticsCollector; import androidx.media3.exoplayer.analytics.AnalyticsCollector;
import androidx.media3.exoplayer.analytics.AnalyticsListener; import androidx.media3.exoplayer.analytics.AnalyticsListener;
import androidx.media3.exoplayer.audio.AudioCapabilities;
import androidx.media3.exoplayer.audio.AudioSink; import androidx.media3.exoplayer.audio.AudioSink;
import androidx.media3.exoplayer.audio.DefaultAudioSink; import androidx.media3.exoplayer.audio.DefaultAudioSink;
import androidx.media3.exoplayer.audio.MediaCodecAudioRenderer; import androidx.media3.exoplayer.audio.MediaCodecAudioRenderer;
@ -1585,8 +1584,7 @@ public interface ExoPlayer extends Player {
* <ul> * <ul>
* <li>Audio offload rendering is enabled in {@link * <li>Audio offload rendering is enabled in {@link
* DefaultRenderersFactory#setEnableAudioOffload} or the equivalent option passed to {@link * DefaultRenderersFactory#setEnableAudioOffload} or the equivalent option passed to {@link
* DefaultAudioSink#DefaultAudioSink(AudioCapabilities, * DefaultAudioSink.Builder#setOffloadMode}.
* DefaultAudioSink.AudioProcessorChain, boolean, boolean, int)}.
* <li>An audio track is playing in a format that the device supports offloading (for example, * <li>An audio track is playing in a format that the device supports offloading (for example,
* MP3 or AAC). * MP3 or AAC).
* <li>The {@link AudioSink} is playing with an offload {@link AudioTrack}. * <li>The {@link AudioSink} is playing with an offload {@link AudioTrack}.

View File

@ -57,6 +57,7 @@ import androidx.media3.exoplayer.audio.AudioSink.SinkFormatSupport;
import androidx.media3.exoplayer.drm.DrmSession; import androidx.media3.exoplayer.drm.DrmSession;
import androidx.media3.exoplayer.drm.DrmSession.DrmSessionException; import androidx.media3.exoplayer.drm.DrmSession.DrmSessionException;
import androidx.media3.exoplayer.source.SampleStream.ReadDataResult; import androidx.media3.exoplayer.source.SampleStream.ReadDataResult;
import com.google.common.base.MoreObjects;
import java.lang.annotation.Documented; import java.lang.annotation.Documented;
import java.lang.annotation.Retention; import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy; import java.lang.annotation.RetentionPolicy;
@ -175,7 +176,15 @@ public abstract class DecoderAudioRenderer<
@Nullable AudioRendererEventListener eventListener, @Nullable AudioRendererEventListener eventListener,
@Nullable AudioCapabilities audioCapabilities, @Nullable AudioCapabilities audioCapabilities,
AudioProcessor... audioProcessors) { AudioProcessor... audioProcessors) {
this(eventHandler, eventListener, new DefaultAudioSink(audioCapabilities, audioProcessors)); this(
eventHandler,
eventListener,
new DefaultAudioSink.Builder()
.setAudioCapabilities(
MoreObjects.firstNonNull(
audioCapabilities, AudioCapabilities.DEFAULT_AUDIO_CAPABILITIES))
.setAudioProcessors(audioProcessors)
.build());
} }
/** /**

View File

@ -15,6 +15,7 @@
*/ */
package androidx.media3.exoplayer.audio; package androidx.media3.exoplayer.audio;
import static androidx.media3.common.util.Assertions.checkNotNull;
import static java.lang.Math.max; import static java.lang.Math.max;
import static java.lang.Math.min; import static java.lang.Math.min;
@ -49,6 +50,8 @@ import androidx.media3.extractor.Ac3Util;
import androidx.media3.extractor.Ac4Util; import androidx.media3.extractor.Ac4Util;
import androidx.media3.extractor.DtsUtil; import androidx.media3.extractor.DtsUtil;
import androidx.media3.extractor.MpegAudioUtil; import androidx.media3.extractor.MpegAudioUtil;
import com.google.errorprone.annotations.InlineMe;
import com.google.errorprone.annotations.InlineMeValidationDisabled;
import java.lang.annotation.Documented; import java.lang.annotation.Documented;
import java.lang.annotation.Retention; import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy; import java.lang.annotation.RetentionPolicy;
@ -58,6 +61,7 @@ import java.util.ArrayDeque;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collections; import java.util.Collections;
import org.checkerframework.checker.nullness.qual.MonotonicNonNull; import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
import org.checkerframework.checker.nullness.qual.RequiresNonNull;
/** /**
* Plays audio data. The implementation delegates to an {@link AudioTrack} and handles playback * Plays audio data. The implementation delegates to an {@link AudioTrack} and handles playback
@ -212,6 +216,106 @@ public final class DefaultAudioSink implements AudioSink {
} }
} }
/** A builder to create {@link DefaultAudioSink} instances. */
public static final class Builder {
@Nullable private AudioCapabilities audioCapabilities;
@Nullable private AudioProcessorChain audioProcessorChain;
private boolean enableFloatOutput;
private boolean enableAudioTrackPlaybackParams;
private int offloadMode;
/** Creates a new builder. */
public Builder() {
offloadMode = OFFLOAD_MODE_DISABLED;
}
/**
* Sets audio capabilities for playback on this device. May be {@code null} if the default
* capabilities (no encoded audio passthrough support) should be assumed.
*
* <p>The default value is {@code null}.
*/
public Builder setAudioCapabilities(@Nullable AudioCapabilities audioCapabilities) {
this.audioCapabilities = audioCapabilities;
return this;
}
/**
* Sets an array of {@link AudioProcessor AudioProcessors}s that will process PCM audio before
* output. May be empty. Equivalent of {@code setAudioProcessorChain(new
* DefaultAudioProcessorChain(audioProcessors)}.
*
* <p>The default value is an empty array.
*/
public Builder setAudioProcessors(AudioProcessor[] audioProcessors) {
checkNotNull(audioProcessors);
return setAudioProcessorChain(new DefaultAudioProcessorChain(audioProcessors));
}
/**
* Sets the {@link AudioProcessorChain} to process audio before playback. The instance passed in
* must not be reused in other sinks. Processing chains are only supported for PCM playback (not
* passthrough or offload).
*
* <p>By default, no processing will be applied.
*/
public Builder setAudioProcessorChain(AudioProcessorChain audioProcessorChain) {
checkNotNull(audioProcessorChain);
this.audioProcessorChain = audioProcessorChain;
return this;
}
/**
* Sets whether to enable 32-bit float output or integer output. Where possible, 32-bit float
* output will be used if the input is 32-bit float, and also if the input is high resolution
* (24-bit or 32-bit) integer PCM. Float output is supported from API level 21. Audio processing
* (for example, speed adjustment) will not be available when float output is in use.
*
* <p>The default value is {@code false}.
*/
public Builder setEnableFloatOutput(boolean enableFloatOutput) {
this.enableFloatOutput = enableFloatOutput;
return this;
}
/**
* Sets whether to control the playback speed using the platform implementation (see {@link
* AudioTrack#setPlaybackParams(PlaybackParams)}), if supported. If set to {@code false}, speed
* up/down of the audio will be done by ExoPlayer (see {@link SonicAudioProcessor}). Platform
* speed adjustment is lower latency, but less reliable.
*
* <p>The default value is {@code false}.
*/
public Builder setEnableAudioTrackPlaybackParams(boolean enableAudioTrackPlaybackParams) {
this.enableAudioTrackPlaybackParams = enableAudioTrackPlaybackParams;
return this;
}
/**
* Sets the offload mode. If an audio format can be both played with offload and encoded audio
* passthrough, it will be played in offload. Audio offload is supported from API level 29. Most
* Android devices can only support one offload {@link AudioTrack} at a time and can invalidate
* it at any time. Thus an app can never be guaranteed that it will be able to play in offload.
* Audio processing (for example, speed adjustment) will not be available when offload is in
* use.
*
* <p>The default value is {@link #OFFLOAD_MODE_DISABLED}.
*/
public Builder setOffloadMode(@OffloadMode int offloadMode) {
this.offloadMode = offloadMode;
return this;
}
/** Builds the {@link DefaultAudioSink}. Must only be called once per Builder instance. */
public DefaultAudioSink build() {
if (audioProcessorChain == null) {
audioProcessorChain = new DefaultAudioProcessorChain();
}
return new DefaultAudioSink(this);
}
}
/** The default playback speed. */ /** The default playback speed. */
public static final float DEFAULT_PLAYBACK_SPEED = 1f; public static final float DEFAULT_PLAYBACK_SPEED = 1f;
/** The minimum allowed playback speed. Lower values will be constrained to fall in range. */ /** The minimum allowed playback speed. Lower values will be constrained to fall in range. */
@ -379,76 +483,78 @@ public final class DefaultAudioSink implements AudioSink {
private boolean offloadDisabledUntilNextConfiguration; private boolean offloadDisabledUntilNextConfiguration;
private boolean isWaitingForOffloadEndOfStreamHandled; private boolean isWaitingForOffloadEndOfStreamHandled;
/** /** @deprecated Use {@link Builder}. */
* Creates a new default audio sink. @Deprecated
* @InlineMeValidationDisabled("Migrate constructor to Builder")
* @param audioCapabilities The audio capabilities for playback on this device. May be null if the @InlineMe(
* default capabilities (no encoded audio passthrough support) should be assumed. replacement =
* @param audioProcessors An array of {@link AudioProcessor}s that will process PCM audio before "new DefaultAudioSink.Builder()"
* output. May be empty. + ".setAudioCapabilities(audioCapabilities)"
*/ + ".setAudioProcessors(audioProcessors)"
+ ".build()",
imports = "androidx.media3.exoplayer.audio.DefaultAudioSink")
public DefaultAudioSink( public DefaultAudioSink(
@Nullable AudioCapabilities audioCapabilities, AudioProcessor[] audioProcessors) { @Nullable AudioCapabilities audioCapabilities, AudioProcessor[] audioProcessors) {
this(audioCapabilities, audioProcessors, /* enableFloatOutput= */ false); this(new Builder().setAudioCapabilities(audioCapabilities).setAudioProcessors(audioProcessors));
} }
/** /** @deprecated Use {@link Builder}. */
* Creates a new default audio sink, optionally using float output for high resolution PCM. @Deprecated
* @InlineMeValidationDisabled("Migrate constructor to Builder")
* @param audioCapabilities The audio capabilities for playback on this device. May be null if the @InlineMe(
* default capabilities (no encoded audio passthrough support) should be assumed. replacement =
* @param audioProcessors An array of {@link AudioProcessor}s that will process PCM audio before "new DefaultAudioSink.Builder()"
* output. May be empty. + ".setAudioCapabilities(audioCapabilities)"
* @param enableFloatOutput Whether to enable 32-bit float output. Where possible, 32-bit float + ".setAudioProcessors(audioProcessors)"
* output will be used if the input is 32-bit float, and also if the input is high resolution + ".setEnableFloatOutput(enableFloatOutput)"
* (24-bit or 32-bit) integer PCM. Audio processing (for example, speed adjustment) will not + ".build()",
* be available when float output is in use. imports = "androidx.media3.exoplayer.audio.DefaultAudioSink")
*/
public DefaultAudioSink( public DefaultAudioSink(
@Nullable AudioCapabilities audioCapabilities, @Nullable AudioCapabilities audioCapabilities,
AudioProcessor[] audioProcessors, AudioProcessor[] audioProcessors,
boolean enableFloatOutput) { boolean enableFloatOutput) {
this( this(
audioCapabilities, new Builder()
new DefaultAudioProcessorChain(audioProcessors), .setAudioCapabilities(audioCapabilities)
enableFloatOutput, .setAudioProcessors(audioProcessors)
/* enableAudioTrackPlaybackParams= */ false, .setEnableFloatOutput(enableFloatOutput));
OFFLOAD_MODE_DISABLED);
} }
/** /** @deprecated Use {@link Builder}. */
* Creates a new default audio sink, optionally using float output for high resolution PCM and @Deprecated
* with the specified {@code audioProcessorChain}. @InlineMeValidationDisabled("Migrate constructor to Builder")
* @InlineMe(
* @param audioCapabilities The audio capabilities for playback on this device. May be null if the replacement =
* default capabilities (no encoded audio passthrough support) should be assumed. "new DefaultAudioSink.Builder()"
* @param audioProcessorChain An {@link AudioProcessorChain} which is used to apply playback + ".setAudioCapabilities(audioCapabilities)"
* parameters adjustments. The instance passed in must not be reused in other sinks. + ".setAudioProcessorChain(audioProcessorChain)"
* @param enableFloatOutput Whether to enable 32-bit float output. Where possible, 32-bit float + ".setEnableFloatOutput(enableFloatOutput)"
* output will be used if the input is 32-bit float, and also if the input is high resolution + ".setEnableAudioTrackPlaybackParams(enableAudioTrackPlaybackParams)"
* (24-bit or 32-bit) integer PCM. Float output is supported from API level 21. Audio + ".setOffloadMode(offloadMode)"
* processing (for example, speed adjustment) will not be available when float output is in + ".build()",
* use. imports = "androidx.media3.exoplayer.audio.DefaultAudioSink")
* @param enableAudioTrackPlaybackParams Whether to enable setting playback speed using {@link
* android.media.AudioTrack#setPlaybackParams(PlaybackParams)}, if supported.
* @param offloadMode Audio offload configuration. If an audio format can be both played with
* offload and encoded audio passthrough, it will be played in offload. Audio offload is
* supported from API level 29. Most Android devices can only support one offload {@link
* android.media.AudioTrack} at a time and can invalidate it at any time. Thus an app can
* never be guaranteed that it will be able to play in offload. Audio processing (for example,
* speed adjustment) will not be available when offload is in use.
*/
public DefaultAudioSink( public DefaultAudioSink(
@Nullable AudioCapabilities audioCapabilities, @Nullable AudioCapabilities audioCapabilities,
AudioProcessorChain audioProcessorChain, AudioProcessorChain audioProcessorChain,
boolean enableFloatOutput, boolean enableFloatOutput,
boolean enableAudioTrackPlaybackParams, boolean enableAudioTrackPlaybackParams,
@OffloadMode int offloadMode) { @OffloadMode int offloadMode) {
this.audioCapabilities = audioCapabilities; this(
this.audioProcessorChain = Assertions.checkNotNull(audioProcessorChain); new Builder()
this.enableFloatOutput = Util.SDK_INT >= 21 && enableFloatOutput; .setAudioCapabilities(audioCapabilities)
this.enableAudioTrackPlaybackParams = Util.SDK_INT >= 23 && enableAudioTrackPlaybackParams; .setAudioProcessorChain(audioProcessorChain)
this.offloadMode = Util.SDK_INT >= 29 ? offloadMode : OFFLOAD_MODE_DISABLED; .setEnableFloatOutput(enableFloatOutput)
.setEnableAudioTrackPlaybackParams(enableAudioTrackPlaybackParams)
.setOffloadMode(offloadMode));
}
@RequiresNonNull("#1.audioProcessorChain")
private DefaultAudioSink(Builder builder) {
audioCapabilities = builder.audioCapabilities;
audioProcessorChain = builder.audioProcessorChain;
enableFloatOutput = Util.SDK_INT >= 21 && builder.enableFloatOutput;
enableAudioTrackPlaybackParams = Util.SDK_INT >= 23 && builder.enableAudioTrackPlaybackParams;
offloadMode = Util.SDK_INT >= 29 ? builder.offloadMode : OFFLOAD_MODE_DISABLED;
releasingConditionVariable = new ConditionVariable(true); releasingConditionVariable = new ConditionVariable(true);
audioTrackPositionTracker = new AudioTrackPositionTracker(new PositionTrackerListener()); audioTrackPositionTracker = new AudioTrackPositionTracker(new PositionTrackerListener());
channelMappingAudioProcessor = new ChannelMappingAudioProcessor(); channelMappingAudioProcessor = new ChannelMappingAudioProcessor();
@ -596,8 +702,7 @@ public final class DefaultAudioSink implements AudioSink {
if (useOffloadedPlayback(inputFormat, audioAttributes)) { if (useOffloadedPlayback(inputFormat, audioAttributes)) {
outputMode = OUTPUT_MODE_OFFLOAD; outputMode = OUTPUT_MODE_OFFLOAD;
outputEncoding = outputEncoding =
MimeTypes.getEncoding( MimeTypes.getEncoding(checkNotNull(inputFormat.sampleMimeType), inputFormat.codecs);
Assertions.checkNotNull(inputFormat.sampleMimeType), inputFormat.codecs);
outputChannelConfig = Util.getAudioTrackChannelConfig(inputFormat.channelCount); outputChannelConfig = Util.getAudioTrackChannelConfig(inputFormat.channelCount);
} else { } else {
outputMode = OUTPUT_MODE_PASSTHROUGH; outputMode = OUTPUT_MODE_PASSTHROUGH;
@ -871,7 +976,7 @@ public final class DefaultAudioSink implements AudioSink {
private AudioTrack buildAudioTrack() throws InitializationException { private AudioTrack buildAudioTrack() throws InitializationException {
try { try {
return Assertions.checkNotNull(configuration) return checkNotNull(configuration)
.buildAudioTrack(tunneling, audioAttributes, audioSessionId); .buildAudioTrack(tunneling, audioAttributes, audioSessionId);
} catch (InitializationException e) { } catch (InitializationException e) {
maybeDisableOffload(); maybeDisableOffload();
@ -1216,7 +1321,7 @@ public final class DefaultAudioSink implements AudioSink {
audioTrack.pause(); audioTrack.pause();
} }
if (isOffloadedPlayback(audioTrack)) { if (isOffloadedPlayback(audioTrack)) {
Assertions.checkNotNull(offloadStreamEventCallbackV29).unregister(audioTrack); checkNotNull(offloadStreamEventCallbackV29).unregister(audioTrack);
} }
// AudioTrack.release can take some time, so we call it on a background thread. // AudioTrack.release can take some time, so we call it on a background thread.
final AudioTrack toRelease = audioTrack; final AudioTrack toRelease = audioTrack;
@ -1518,8 +1623,7 @@ public final class DefaultAudioSink implements AudioSink {
} }
@C.Encoding @C.Encoding
int encoding = int encoding = MimeTypes.getEncoding(checkNotNull(format.sampleMimeType), format.codecs);
MimeTypes.getEncoding(Assertions.checkNotNull(format.sampleMimeType), format.codecs);
// Check for encodings that are known to work for passthrough with the implementation in this // Check for encodings that are known to work for passthrough with the implementation in this
// class. This avoids trying to use passthrough with an encoding where the device/app reports // class. This avoids trying to use passthrough with an encoding where the device/app reports
// it's capable but it is untested or known to be broken (for example AAC-LC). // it's capable but it is untested or known to be broken (for example AAC-LC).
@ -1630,8 +1734,7 @@ public final class DefaultAudioSink implements AudioSink {
return false; return false;
} }
@C.Encoding @C.Encoding
int encoding = int encoding = MimeTypes.getEncoding(checkNotNull(format.sampleMimeType), format.codecs);
MimeTypes.getEncoding(Assertions.checkNotNull(format.sampleMimeType), format.codecs);
if (encoding == C.ENCODING_INVALID) { if (encoding == C.ENCODING_INVALID) {
return false; return false;
} }

View File

@ -159,7 +159,10 @@ public class MediaCodecAudioRenderer extends MediaCodecRenderer implements Media
mediaCodecSelector, mediaCodecSelector,
eventHandler, eventHandler,
eventListener, eventListener,
new DefaultAudioSink(audioCapabilities, audioProcessors)); new DefaultAudioSink.Builder()
.setAudioCapabilities(audioCapabilities)
.setAudioProcessors(audioProcessors)
.build());
} }
/** /**

View File

@ -15,6 +15,7 @@
*/ */
package androidx.media3.exoplayer.audio; package androidx.media3.exoplayer.audio;
import static androidx.media3.exoplayer.audio.AudioCapabilities.DEFAULT_AUDIO_CAPABILITIES;
import static androidx.media3.exoplayer.audio.AudioSink.CURRENT_POSITION_NOT_SET; import static androidx.media3.exoplayer.audio.AudioSink.CURRENT_POSITION_NOT_SET;
import static androidx.media3.exoplayer.audio.AudioSink.SINK_FORMAT_SUPPORTED_DIRECTLY; import static androidx.media3.exoplayer.audio.AudioSink.SINK_FORMAT_SUPPORTED_DIRECTLY;
import static androidx.media3.exoplayer.audio.AudioSink.SINK_FORMAT_SUPPORTED_WITH_TRANSCODING; import static androidx.media3.exoplayer.audio.AudioSink.SINK_FORMAT_SUPPORTED_WITH_TRANSCODING;
@ -24,6 +25,7 @@ import androidx.media3.common.C;
import androidx.media3.common.Format; import androidx.media3.common.Format;
import androidx.media3.common.MimeTypes; import androidx.media3.common.MimeTypes;
import androidx.media3.common.PlaybackParameters; import androidx.media3.common.PlaybackParameters;
import androidx.media3.exoplayer.audio.DefaultAudioSink.DefaultAudioProcessorChain;
import androidx.test.ext.junit.runners.AndroidJUnit4; import androidx.test.ext.junit.runners.AndroidJUnit4;
import java.nio.ByteBuffer; import java.nio.ByteBuffer;
import java.nio.ByteOrder; import java.nio.ByteOrder;
@ -37,7 +39,6 @@ import org.robolectric.annotation.Config;
/** Unit tests for {@link DefaultAudioSink}. */ /** Unit tests for {@link DefaultAudioSink}. */
@RunWith(AndroidJUnit4.class) @RunWith(AndroidJUnit4.class)
public final class DefaultAudioSinkTest { public final class DefaultAudioSinkTest {
private static final int CHANNEL_COUNT_MONO = 1; private static final int CHANNEL_COUNT_MONO = 1;
private static final int CHANNEL_COUNT_STEREO = 2; private static final int CHANNEL_COUNT_STEREO = 2;
private static final int BYTES_PER_FRAME_16_BIT = 2; private static final int BYTES_PER_FRAME_16_BIT = 2;
@ -59,19 +60,20 @@ public final class DefaultAudioSinkTest {
arrayAudioBufferSink = new ArrayAudioBufferSink(); arrayAudioBufferSink = new ArrayAudioBufferSink();
TeeAudioProcessor teeAudioProcessor = new TeeAudioProcessor(arrayAudioBufferSink); TeeAudioProcessor teeAudioProcessor = new TeeAudioProcessor(arrayAudioBufferSink);
defaultAudioSink = defaultAudioSink =
new DefaultAudioSink( new DefaultAudioSink.Builder()
AudioCapabilities.DEFAULT_AUDIO_CAPABILITIES, .setAudioCapabilities(DEFAULT_AUDIO_CAPABILITIES)
new DefaultAudioSink.DefaultAudioProcessorChain(teeAudioProcessor), .setAudioProcessorChain(new DefaultAudioProcessorChain(teeAudioProcessor))
/* enableFloatOutput= */ false, .setOffloadMode(DefaultAudioSink.OFFLOAD_MODE_DISABLED)
/* enableAudioTrackPlaybackParams= */ false, .build();
DefaultAudioSink.OFFLOAD_MODE_DISABLED);
} }
@Test @Test
public void handlesSpecializedAudioProcessorArray() { public void handlesSpecializedAudioProcessorArray() {
defaultAudioSink = defaultAudioSink =
new DefaultAudioSink( new DefaultAudioSink.Builder()
AudioCapabilities.DEFAULT_AUDIO_CAPABILITIES, new TeeAudioProcessor[0]); .setAudioCapabilities(DEFAULT_AUDIO_CAPABILITIES)
.setAudioProcessors(new TeeAudioProcessor[0])
.build();
} }
@Test @Test
@ -203,10 +205,7 @@ public final class DefaultAudioSinkTest {
@Test @Test
public void floatPcmNeedsTranscodingIfFloatOutputDisabled() { public void floatPcmNeedsTranscodingIfFloatOutputDisabled() {
defaultAudioSink = defaultAudioSink =
new DefaultAudioSink( new DefaultAudioSink.Builder().setAudioCapabilities(DEFAULT_AUDIO_CAPABILITIES).build();
AudioCapabilities.DEFAULT_AUDIO_CAPABILITIES,
new AudioProcessor[0],
/* enableFloatOutput= */ false);
Format floatFormat = Format floatFormat =
STEREO_44_1_FORMAT STEREO_44_1_FORMAT
.buildUpon() .buildUpon()
@ -221,10 +220,10 @@ public final class DefaultAudioSinkTest {
@Test @Test
public void floatPcmNeedsTranscodingIfFloatOutputEnabledBeforeApi21() { public void floatPcmNeedsTranscodingIfFloatOutputEnabledBeforeApi21() {
defaultAudioSink = defaultAudioSink =
new DefaultAudioSink( new DefaultAudioSink.Builder()
AudioCapabilities.DEFAULT_AUDIO_CAPABILITIES, .setAudioCapabilities(DEFAULT_AUDIO_CAPABILITIES)
new AudioProcessor[0], .setEnableFloatOutput(true)
/* enableFloatOutput= */ true); .build();
Format floatFormat = Format floatFormat =
STEREO_44_1_FORMAT STEREO_44_1_FORMAT
.buildUpon() .buildUpon()
@ -239,10 +238,10 @@ public final class DefaultAudioSinkTest {
@Test @Test
public void floatOutputSupportedIfFloatOutputEnabledFromApi21() { public void floatOutputSupportedIfFloatOutputEnabledFromApi21() {
defaultAudioSink = defaultAudioSink =
new DefaultAudioSink( new DefaultAudioSink.Builder()
AudioCapabilities.DEFAULT_AUDIO_CAPABILITIES, .setAudioCapabilities(DEFAULT_AUDIO_CAPABILITIES)
new AudioProcessor[0], .setEnableFloatOutput(true)
/* enableFloatOutput= */ true); .build();
Format floatFormat = Format floatFormat =
STEREO_44_1_FORMAT STEREO_44_1_FORMAT
.buildUpon() .buildUpon()
@ -267,8 +266,9 @@ public final class DefaultAudioSinkTest {
@Test @Test
public void audioSinkWithAacAudioCapabilitiesWithoutOffload_doesNotSupportAac() { public void audioSinkWithAacAudioCapabilitiesWithoutOffload_doesNotSupportAac() {
DefaultAudioSink defaultAudioSink = DefaultAudioSink defaultAudioSink =
new DefaultAudioSink( new DefaultAudioSink.Builder()
new AudioCapabilities(new int[] {C.ENCODING_AAC_LC}, 2), new AudioProcessor[0]); .setAudioCapabilities(new AudioCapabilities(new int[] {C.ENCODING_AAC_LC}, 2))
.build();
Format aacLcFormat = Format aacLcFormat =
STEREO_44_1_FORMAT STEREO_44_1_FORMAT
.buildUpon() .buildUpon()

View File

@ -33,7 +33,6 @@ import androidx.media3.exoplayer.DefaultRenderersFactory;
import androidx.media3.exoplayer.Renderer; import androidx.media3.exoplayer.Renderer;
import androidx.media3.exoplayer.RenderersFactory; import androidx.media3.exoplayer.RenderersFactory;
import androidx.media3.exoplayer.audio.AudioCapabilities; import androidx.media3.exoplayer.audio.AudioCapabilities;
import androidx.media3.exoplayer.audio.AudioProcessor;
import androidx.media3.exoplayer.audio.AudioRendererEventListener; import androidx.media3.exoplayer.audio.AudioRendererEventListener;
import androidx.media3.exoplayer.audio.DefaultAudioSink; import androidx.media3.exoplayer.audio.DefaultAudioSink;
import androidx.media3.exoplayer.audio.MediaCodecAudioRenderer; import androidx.media3.exoplayer.audio.MediaCodecAudioRenderer;
@ -96,7 +95,9 @@ public class CapturingRenderersFactory implements RenderersFactory, Dumper.Dumpa
/* enableDecoderFallback= */ false, /* enableDecoderFallback= */ false,
eventHandler, eventHandler,
audioRendererEventListener, audioRendererEventListener,
new DefaultAudioSink(AudioCapabilities.getCapabilities(context), new AudioProcessor[0])), new DefaultAudioSink.Builder()
.setAudioCapabilities(AudioCapabilities.getCapabilities(context))
.build()),
new TextRenderer(textRendererOutput, eventHandler.getLooper()), new TextRenderer(textRendererOutput, eventHandler.getLooper()),
new MetadataRenderer(metadataRendererOutput, eventHandler.getLooper()) new MetadataRenderer(metadataRendererOutput, eventHandler.getLooper())
}; };