diff --git a/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/source/SingleSampleMediaPeriod.java b/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/source/SingleSampleMediaPeriod.java index 1098a35a3e..cc1e03ad2f 100644 --- a/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/source/SingleSampleMediaPeriod.java +++ b/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/source/SingleSampleMediaPeriod.java @@ -40,6 +40,7 @@ import androidx.media3.exoplayer.upstream.LoadErrorHandlingPolicy.LoadErrorInfo; import androidx.media3.exoplayer.upstream.Loader; import androidx.media3.exoplayer.upstream.Loader.LoadErrorAction; import androidx.media3.exoplayer.upstream.Loader.Loadable; +import androidx.media3.exoplayer.util.ReleasableExecutor; import java.io.IOException; import java.util.ArrayList; import java.util.Arrays; @@ -80,7 +81,8 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull; long durationUs, LoadErrorHandlingPolicy loadErrorHandlingPolicy, EventDispatcher eventDispatcher, - boolean treatLoadErrorsAsEndOfStream) { + boolean treatLoadErrorsAsEndOfStream, + @Nullable ReleasableExecutor downloadExecutor) { this.dataSpec = dataSpec; this.dataSourceFactory = dataSourceFactory; this.transferListener = transferListener; @@ -91,7 +93,10 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull; this.treatLoadErrorsAsEndOfStream = treatLoadErrorsAsEndOfStream; tracks = new TrackGroupArray(new TrackGroup(format)); sampleStreams = new ArrayList<>(); - loader = new Loader("SingleSampleMediaPeriod"); + loader = + downloadExecutor != null + ? new Loader(downloadExecutor) + : new Loader("SingleSampleMediaPeriod"); } public void release() { diff --git a/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/source/SingleSampleMediaSource.java b/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/source/SingleSampleMediaSource.java index e31e1250be..900b60c0b2 100644 --- a/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/source/SingleSampleMediaSource.java +++ b/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/source/SingleSampleMediaSource.java @@ -24,6 +24,7 @@ import androidx.media3.common.Format; import androidx.media3.common.MediaItem; import androidx.media3.common.MimeTypes; import androidx.media3.common.Timeline; +import androidx.media3.common.util.Consumer; import androidx.media3.common.util.UnstableApi; import androidx.media3.datasource.DataSource; import androidx.media3.datasource.DataSpec; @@ -33,8 +34,11 @@ import androidx.media3.exoplayer.text.TextRenderer; import androidx.media3.exoplayer.upstream.Allocator; import androidx.media3.exoplayer.upstream.DefaultLoadErrorHandlingPolicy; import androidx.media3.exoplayer.upstream.LoadErrorHandlingPolicy; +import androidx.media3.exoplayer.util.ReleasableExecutor; +import com.google.common.base.Supplier; import com.google.common.collect.ImmutableList; import com.google.errorprone.annotations.CanIgnoreReturnValue; +import java.util.concurrent.Executor; /** * @deprecated The only use for this class is subtitle playback, but it is only compatible with @@ -56,6 +60,7 @@ public final class SingleSampleMediaSource extends BaseMediaSource { private boolean treatLoadErrorsAsEndOfStream; @Nullable private Object tag; @Nullable private String trackId; + @Nullable private Supplier downloadExecutorSupplier; /** * Creates a factory for {@link SingleSampleMediaSource}s. @@ -127,6 +132,23 @@ public final class SingleSampleMediaSource extends BaseMediaSource { return this; } + /** + * Sets a supplier for an {@link Executor} that is used for loading the media. + * + * @param downloadExecutor A {@link Supplier} that provides an externally managed {@link + * Executor} for downloading and extraction. + * @param downloadExecutorReleaser A callback triggered once a load task is finished and a + * supplied executor is no longer required. + * @return This factory, for convenience. + */ + @CanIgnoreReturnValue + public Factory setDownloadExecutor( + Supplier downloadExecutor, Consumer downloadExecutorReleaser) { + this.downloadExecutorSupplier = + () -> ReleasableExecutor.from(downloadExecutor.get(), downloadExecutorReleaser); + return this; + } + /** * Returns a new {@link SingleSampleMediaSource} using the current parameters. * @@ -143,7 +165,8 @@ public final class SingleSampleMediaSource extends BaseMediaSource { durationUs, loadErrorHandlingPolicy, treatLoadErrorsAsEndOfStream, - tag); + tag, + downloadExecutorSupplier); } } @@ -155,6 +178,7 @@ public final class SingleSampleMediaSource extends BaseMediaSource { private final boolean treatLoadErrorsAsEndOfStream; private final Timeline timeline; private final MediaItem mediaItem; + @Nullable private final Supplier downloadExecutorSupplier; @Nullable private TransferListener transferListener; @@ -165,7 +189,8 @@ public final class SingleSampleMediaSource extends BaseMediaSource { long durationUs, LoadErrorHandlingPolicy loadErrorHandlingPolicy, boolean treatLoadErrorsAsEndOfStream, - @Nullable Object tag) { + @Nullable Object tag, + @Nullable Supplier downloadExecutorSupplier) { this.dataSourceFactory = dataSourceFactory; this.durationUs = durationUs; this.loadErrorHandlingPolicy = loadErrorHandlingPolicy; @@ -199,6 +224,7 @@ public final class SingleSampleMediaSource extends BaseMediaSource { /* useLiveConfiguration= */ false, /* manifest= */ null, mediaItem); + this.downloadExecutorSupplier = downloadExecutorSupplier; } // MediaSource implementation. @@ -229,7 +255,8 @@ public final class SingleSampleMediaSource extends BaseMediaSource { durationUs, loadErrorHandlingPolicy, createEventDispatcher(id), - treatLoadErrorsAsEndOfStream); + treatLoadErrorsAsEndOfStream, + downloadExecutorSupplier != null ? downloadExecutorSupplier.get() : null); } @Override