Merge pull request #1754 from colinkho:loader-plumbing

PiperOrigin-RevId: 684781854
This commit is contained in:
Copybara-Service 2024-10-11 04:03:09 -07:00
commit 019fe0589f
9 changed files with 173 additions and 22 deletions

View File

@ -54,6 +54,7 @@ import androidx.media3.exoplayer.upstream.LoadErrorHandlingPolicy.LoadErrorInfo;
import androidx.media3.exoplayer.upstream.Loader; import androidx.media3.exoplayer.upstream.Loader;
import androidx.media3.exoplayer.upstream.Loader.LoadErrorAction; import androidx.media3.exoplayer.upstream.Loader.LoadErrorAction;
import androidx.media3.exoplayer.upstream.Loader.Loadable; import androidx.media3.exoplayer.upstream.Loader.Loadable;
import androidx.media3.exoplayer.util.ReleasableExecutor;
import androidx.media3.extractor.DiscardingTrackOutput; import androidx.media3.extractor.DiscardingTrackOutput;
import androidx.media3.extractor.Extractor; import androidx.media3.extractor.Extractor;
import androidx.media3.extractor.ExtractorOutput; import androidx.media3.extractor.ExtractorOutput;
@ -172,6 +173,8 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
* @param continueLoadingCheckIntervalBytes The number of bytes that should be loaded between each * @param continueLoadingCheckIntervalBytes The number of bytes that should be loaded between each
* invocation of {@link Callback#onContinueLoadingRequested(SequenceableLoader)}. * invocation of {@link Callback#onContinueLoadingRequested(SequenceableLoader)}.
* @param singleSampleDurationUs The duration of media with a single sample in microseconds. * @param singleSampleDurationUs The duration of media with a single sample in microseconds.
* @param downloadExecutor An optional externally provided {@link ReleasableExecutor} for loading
* and extracting media.
*/ */
// maybeFinishPrepare is not posted to the handler until initialization completes. // maybeFinishPrepare is not posted to the handler until initialization completes.
@SuppressWarnings({"nullness:argument", "nullness:methodref.receiver.bound"}) @SuppressWarnings({"nullness:argument", "nullness:methodref.receiver.bound"})
@ -187,7 +190,8 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
Allocator allocator, Allocator allocator,
@Nullable String customCacheKey, @Nullable String customCacheKey,
int continueLoadingCheckIntervalBytes, int continueLoadingCheckIntervalBytes,
long singleSampleDurationUs) { long singleSampleDurationUs,
@Nullable ReleasableExecutor downloadExecutor) {
this.uri = uri; this.uri = uri;
this.dataSource = dataSource; this.dataSource = dataSource;
this.drmSessionManager = drmSessionManager; this.drmSessionManager = drmSessionManager;
@ -198,7 +202,10 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
this.allocator = allocator; this.allocator = allocator;
this.customCacheKey = customCacheKey; this.customCacheKey = customCacheKey;
this.continueLoadingCheckIntervalBytes = continueLoadingCheckIntervalBytes; this.continueLoadingCheckIntervalBytes = continueLoadingCheckIntervalBytes;
loader = new Loader("ProgressiveMediaPeriod"); loader =
downloadExecutor != null
? new Loader(downloadExecutor)
: new Loader("ProgressiveMediaPeriod");
this.progressiveMediaExtractor = progressiveMediaExtractor; this.progressiveMediaExtractor = progressiveMediaExtractor;
this.singleSampleDurationUs = singleSampleDurationUs; this.singleSampleDurationUs = singleSampleDurationUs;
loadCondition = new ConditionVariable(); loadCondition = new ConditionVariable();

View File

@ -24,6 +24,7 @@ import androidx.annotation.Nullable;
import androidx.media3.common.C; import androidx.media3.common.C;
import androidx.media3.common.MediaItem; import androidx.media3.common.MediaItem;
import androidx.media3.common.Timeline; import androidx.media3.common.Timeline;
import androidx.media3.common.util.Consumer;
import androidx.media3.common.util.UnstableApi; import androidx.media3.common.util.UnstableApi;
import androidx.media3.common.util.Util; import androidx.media3.common.util.Util;
import androidx.media3.datasource.DataSource; import androidx.media3.datasource.DataSource;
@ -34,10 +35,13 @@ import androidx.media3.exoplayer.drm.DrmSessionManagerProvider;
import androidx.media3.exoplayer.upstream.Allocator; import androidx.media3.exoplayer.upstream.Allocator;
import androidx.media3.exoplayer.upstream.DefaultLoadErrorHandlingPolicy; import androidx.media3.exoplayer.upstream.DefaultLoadErrorHandlingPolicy;
import androidx.media3.exoplayer.upstream.LoadErrorHandlingPolicy; import androidx.media3.exoplayer.upstream.LoadErrorHandlingPolicy;
import androidx.media3.exoplayer.util.ReleasableExecutor;
import androidx.media3.extractor.DefaultExtractorsFactory; import androidx.media3.extractor.DefaultExtractorsFactory;
import androidx.media3.extractor.Extractor; import androidx.media3.extractor.Extractor;
import androidx.media3.extractor.ExtractorsFactory; import androidx.media3.extractor.ExtractorsFactory;
import com.google.common.base.Supplier;
import com.google.errorprone.annotations.CanIgnoreReturnValue; import com.google.errorprone.annotations.CanIgnoreReturnValue;
import java.util.concurrent.Executor;
/** /**
* Provides one period that loads data from a {@link Uri} and extracted using an {@link Extractor}. * Provides one period that loads data from a {@link Uri} and extracted using an {@link Extractor}.
@ -64,6 +68,7 @@ public final class ProgressiveMediaSource extends BaseMediaSource
private DrmSessionManagerProvider drmSessionManagerProvider; private DrmSessionManagerProvider drmSessionManagerProvider;
private LoadErrorHandlingPolicy loadErrorHandlingPolicy; private LoadErrorHandlingPolicy loadErrorHandlingPolicy;
private int continueLoadingCheckIntervalBytes; private int continueLoadingCheckIntervalBytes;
@Nullable private Supplier<ReleasableExecutor> downloadExecutorSupplier;
/** /**
* Creates a new factory for {@link ProgressiveMediaSource}s. * Creates a new factory for {@link ProgressiveMediaSource}s.
@ -197,6 +202,23 @@ public final class ProgressiveMediaSource extends BaseMediaSource
return this; 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 <T extends Executor> Factory setDownloadExecutor(
Supplier<T> downloadExecutor, Consumer<T> downloadExecutorReleaser) {
this.downloadExecutorSupplier =
() -> ReleasableExecutor.from(downloadExecutor.get(), downloadExecutorReleaser);
return this;
}
/** /**
* Returns a new {@link ProgressiveMediaSource} using the current parameters. * Returns a new {@link ProgressiveMediaSource} using the current parameters.
* *
@ -213,7 +235,8 @@ public final class ProgressiveMediaSource extends BaseMediaSource
progressiveMediaExtractorFactory, progressiveMediaExtractorFactory,
drmSessionManagerProvider.get(mediaItem), drmSessionManagerProvider.get(mediaItem),
loadErrorHandlingPolicy, loadErrorHandlingPolicy,
continueLoadingCheckIntervalBytes); continueLoadingCheckIntervalBytes,
downloadExecutorSupplier);
} }
@Override @Override
@ -233,6 +256,9 @@ public final class ProgressiveMediaSource extends BaseMediaSource
private final DrmSessionManager drmSessionManager; private final DrmSessionManager drmSessionManager;
private final LoadErrorHandlingPolicy loadableLoadErrorHandlingPolicy; private final LoadErrorHandlingPolicy loadableLoadErrorHandlingPolicy;
private final int continueLoadingCheckIntervalBytes; private final int continueLoadingCheckIntervalBytes;
@Nullable private final Supplier<ReleasableExecutor> downloadExecutorSupplier;
private boolean timelineIsPlaceholder; private boolean timelineIsPlaceholder;
private long timelineDurationUs; private long timelineDurationUs;
private boolean timelineIsSeekable; private boolean timelineIsSeekable;
@ -248,7 +274,8 @@ public final class ProgressiveMediaSource extends BaseMediaSource
ProgressiveMediaExtractor.Factory progressiveMediaExtractorFactory, ProgressiveMediaExtractor.Factory progressiveMediaExtractorFactory,
DrmSessionManager drmSessionManager, DrmSessionManager drmSessionManager,
LoadErrorHandlingPolicy loadableLoadErrorHandlingPolicy, LoadErrorHandlingPolicy loadableLoadErrorHandlingPolicy,
int continueLoadingCheckIntervalBytes) { int continueLoadingCheckIntervalBytes,
@Nullable Supplier<ReleasableExecutor> downloadExecutorSupplier) {
this.mediaItem = mediaItem; this.mediaItem = mediaItem;
this.dataSourceFactory = dataSourceFactory; this.dataSourceFactory = dataSourceFactory;
this.progressiveMediaExtractorFactory = progressiveMediaExtractorFactory; this.progressiveMediaExtractorFactory = progressiveMediaExtractorFactory;
@ -257,6 +284,7 @@ public final class ProgressiveMediaSource extends BaseMediaSource
this.continueLoadingCheckIntervalBytes = continueLoadingCheckIntervalBytes; this.continueLoadingCheckIntervalBytes = continueLoadingCheckIntervalBytes;
this.timelineIsPlaceholder = true; this.timelineIsPlaceholder = true;
this.timelineDurationUs = C.TIME_UNSET; this.timelineDurationUs = C.TIME_UNSET;
this.downloadExecutorSupplier = downloadExecutorSupplier;
} }
@Override @Override
@ -312,7 +340,8 @@ public final class ProgressiveMediaSource extends BaseMediaSource
allocator, allocator,
localConfiguration.customCacheKey, localConfiguration.customCacheKey,
continueLoadingCheckIntervalBytes, continueLoadingCheckIntervalBytes,
Util.msToUs(localConfiguration.imageDurationMs)); Util.msToUs(localConfiguration.imageDurationMs),
downloadExecutorSupplier != null ? downloadExecutorSupplier.get() : null);
} }
@Override @Override

View File

@ -45,6 +45,7 @@ import androidx.media3.exoplayer.upstream.LoadErrorHandlingPolicy;
import androidx.media3.exoplayer.upstream.LoadErrorHandlingPolicy.LoadErrorInfo; import androidx.media3.exoplayer.upstream.LoadErrorHandlingPolicy.LoadErrorInfo;
import androidx.media3.exoplayer.upstream.Loader; import androidx.media3.exoplayer.upstream.Loader;
import androidx.media3.exoplayer.upstream.Loader.LoadErrorAction; import androidx.media3.exoplayer.upstream.Loader.LoadErrorAction;
import androidx.media3.exoplayer.util.ReleasableExecutor;
import java.io.IOException; import java.io.IOException;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collections; import java.util.Collections;
@ -119,6 +120,8 @@ public class ChunkSampleStream<T extends ChunkSource>
* events. * events.
* @param canReportInitialDiscontinuity Whether the stream can report an initial discontinuity if * @param canReportInitialDiscontinuity Whether the stream can report an initial discontinuity if
* the first chunk can't start at the beginning and needs to preroll data. * the first chunk can't start at the beginning and needs to preroll data.
* @param downloadExecutor An optional externally provided {@link ReleasableExecutor} for loading
* and extracting media.
*/ */
public ChunkSampleStream( public ChunkSampleStream(
@C.TrackType int primaryTrackType, @C.TrackType int primaryTrackType,
@ -132,7 +135,8 @@ public class ChunkSampleStream<T extends ChunkSource>
DrmSessionEventListener.EventDispatcher drmEventDispatcher, DrmSessionEventListener.EventDispatcher drmEventDispatcher,
LoadErrorHandlingPolicy loadErrorHandlingPolicy, LoadErrorHandlingPolicy loadErrorHandlingPolicy,
MediaSourceEventListener.EventDispatcher mediaSourceEventDispatcher, MediaSourceEventListener.EventDispatcher mediaSourceEventDispatcher,
boolean canReportInitialDiscontinuity) { boolean canReportInitialDiscontinuity,
@Nullable ReleasableExecutor downloadExecutor) {
this.primaryTrackType = primaryTrackType; this.primaryTrackType = primaryTrackType;
this.embeddedTrackTypes = embeddedTrackTypes == null ? new int[0] : embeddedTrackTypes; this.embeddedTrackTypes = embeddedTrackTypes == null ? new int[0] : embeddedTrackTypes;
this.embeddedTrackFormats = embeddedTrackFormats == null ? new Format[0] : embeddedTrackFormats; this.embeddedTrackFormats = embeddedTrackFormats == null ? new Format[0] : embeddedTrackFormats;
@ -141,7 +145,8 @@ public class ChunkSampleStream<T extends ChunkSource>
this.mediaSourceEventDispatcher = mediaSourceEventDispatcher; this.mediaSourceEventDispatcher = mediaSourceEventDispatcher;
this.loadErrorHandlingPolicy = loadErrorHandlingPolicy; this.loadErrorHandlingPolicy = loadErrorHandlingPolicy;
this.canReportInitialDiscontinuity = canReportInitialDiscontinuity; this.canReportInitialDiscontinuity = canReportInitialDiscontinuity;
loader = new Loader("ChunkSampleStream"); loader =
downloadExecutor != null ? new Loader(downloadExecutor) : new Loader("ChunkSampleStream");
nextChunkHolder = new ChunkHolder(); nextChunkHolder = new ChunkHolder();
mediaChunks = new ArrayList<>(); mediaChunks = new ArrayList<>();
readOnlyMediaChunks = Collections.unmodifiableList(mediaChunks); readOnlyMediaChunks = Collections.unmodifiableList(mediaChunks);

View File

@ -31,12 +31,12 @@ import androidx.media3.common.util.Log;
import androidx.media3.common.util.TraceUtil; import androidx.media3.common.util.TraceUtil;
import androidx.media3.common.util.UnstableApi; import androidx.media3.common.util.UnstableApi;
import androidx.media3.common.util.Util; import androidx.media3.common.util.Util;
import androidx.media3.exoplayer.util.ReleasableExecutor;
import java.io.IOException; import java.io.IOException;
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;
import java.lang.annotation.Target; import java.lang.annotation.Target;
import java.util.concurrent.Executor;
import java.util.concurrent.ExecutorService; import java.util.concurrent.ExecutorService;
import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicBoolean;
@ -218,8 +218,7 @@ public final class Loader implements LoaderErrorThrower {
} }
} }
private final Executor downloadExecutor; private final ReleasableExecutor downloadExecutor;
private final Runnable downloadExecutorReleaser;
@Nullable private LoadTask<? extends Loadable> currentTask; @Nullable private LoadTask<? extends Loadable> currentTask;
@Nullable private IOException fatalError; @Nullable private IOException fatalError;
@ -231,20 +230,21 @@ public final class Loader implements LoaderErrorThrower {
* component using the loader. * component using the loader.
*/ */
public Loader(String threadNameSuffix) { public Loader(String threadNameSuffix) {
ExecutorService executorService = this(
Util.newSingleThreadExecutor(THREAD_NAME_PREFIX + threadNameSuffix); /* downloadExecutor= */ ReleasableExecutor.from(
this.downloadExecutor = executorService; Util.newSingleThreadExecutor(THREAD_NAME_PREFIX + threadNameSuffix),
this.downloadExecutorReleaser = executorService::shutdown; ExecutorService::shutdown));
} }
/** /**
* Constructs an instance. * Constructs an instance.
* *
* @param downloadExecutor An {@link Executor} for supplying the loader's thread. * @param downloadExecutor A {@link ReleasableExecutor} to run the load task. The {@link
* ReleasableExecutor} will be {@linkplain ReleasableExecutor#release() released} once the
* loader no longer requires it for new load tasks.
*/ */
public Loader(Executor downloadExecutor) { public Loader(ReleasableExecutor downloadExecutor) {
this.downloadExecutor = downloadExecutor; this.downloadExecutor = downloadExecutor;
this.downloadExecutorReleaser = () -> {};
} }
/** /**
@ -328,7 +328,7 @@ public final class Loader implements LoaderErrorThrower {
if (callback != null) { if (callback != null) {
downloadExecutor.execute(new ReleaseTask(callback)); downloadExecutor.execute(new ReleaseTask(callback));
} }
downloadExecutorReleaser.run(); downloadExecutor.release();
} }
// LoaderErrorThrower implementation. // LoaderErrorThrower implementation.

View File

@ -0,0 +1,58 @@
/*
* Copyright 2024 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.util;
import androidx.media3.common.util.Consumer;
import androidx.media3.common.util.UnstableApi;
import java.util.concurrent.Executor;
/**
* An {@link Executor} with a dedicated {@link #release} method to signal when it is not longer
* needed.
*/
@UnstableApi
public interface ReleasableExecutor extends Executor {
/**
* Releases the {@link Executor}, indicating that the caller no longer requires it for executing
* new commands.
*
* <p>When calling this method, there may still be pending commands that are currently executed.
*/
void release();
/**
* Creates a {@link ReleasableExecutor} from an {@link Executor} and a release callback.
*
* @param executor The {@link Executor}
* @param releaseCallback The release callback, accepting the {@code executor} as an argument.
* @return The releasable executor.
* @param <T> The type of {@link Executor}.
*/
static <T extends Executor> ReleasableExecutor from(T executor, Consumer<T> releaseCallback) {
return new ReleasableExecutor() {
@Override
public void execute(Runnable command) {
executor.execute(command);
}
@Override
public void release() {
releaseCallback.accept(executor);
}
};
}
}

View File

@ -19,7 +19,9 @@ import static androidx.media3.test.utils.robolectric.RobolectricUtil.runMainLoop
import static com.google.common.truth.Truth.assertThat; import static com.google.common.truth.Truth.assertThat;
import android.net.Uri; import android.net.Uri;
import androidx.annotation.Nullable;
import androidx.media3.common.C; import androidx.media3.common.C;
import androidx.media3.common.util.Consumer;
import androidx.media3.datasource.AssetDataSource; import androidx.media3.datasource.AssetDataSource;
import androidx.media3.exoplayer.LoadingInfo; import androidx.media3.exoplayer.LoadingInfo;
import androidx.media3.exoplayer.analytics.PlayerId; import androidx.media3.exoplayer.analytics.PlayerId;
@ -28,12 +30,16 @@ import androidx.media3.exoplayer.drm.DrmSessionManager;
import androidx.media3.exoplayer.source.MediaSource.MediaPeriodId; import androidx.media3.exoplayer.source.MediaSource.MediaPeriodId;
import androidx.media3.exoplayer.upstream.DefaultAllocator; import androidx.media3.exoplayer.upstream.DefaultAllocator;
import androidx.media3.exoplayer.upstream.DefaultLoadErrorHandlingPolicy; import androidx.media3.exoplayer.upstream.DefaultLoadErrorHandlingPolicy;
import androidx.media3.exoplayer.util.ReleasableExecutor;
import androidx.media3.extractor.Extractor; import androidx.media3.extractor.Extractor;
import androidx.media3.extractor.ExtractorsFactory; import androidx.media3.extractor.ExtractorsFactory;
import androidx.media3.extractor.mp4.Mp4Extractor; import androidx.media3.extractor.mp4.Mp4Extractor;
import androidx.media3.extractor.png.PngExtractor; import androidx.media3.extractor.png.PngExtractor;
import androidx.media3.extractor.text.SubtitleParser;
import androidx.test.core.app.ApplicationProvider; import androidx.test.core.app.ApplicationProvider;
import androidx.test.ext.junit.runners.AndroidJUnit4; import androidx.test.ext.junit.runners.AndroidJUnit4;
import java.util.concurrent.Executor;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeoutException; import java.util.concurrent.TimeoutException;
import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicBoolean;
import org.junit.Test; import org.junit.Test;
@ -67,8 +73,35 @@ public final class ProgressiveMediaPeriodTest {
testExtractorsUpdatesSourceInfoBeforeOnPreparedCallback(extractor, C.TIME_UNSET); testExtractorsUpdatesSourceInfoBeforeOnPreparedCallback(extractor, C.TIME_UNSET);
} }
@Test
public void supplyingCustomDownloadExecutor_downloadsOnCustomThread() throws TimeoutException {
AtomicBoolean hasThreadRun = new AtomicBoolean(false);
AtomicBoolean hasReleaseCallbackRun = new AtomicBoolean(false);
Executor executor =
Executors.newSingleThreadExecutor(r -> new ExecutionTrackingThread(r, hasThreadRun));
testExtractorsUpdatesSourceInfoBeforeOnPreparedCallback(
new BundledExtractorsAdapter(Mp4Extractor.newFactory(SubtitleParser.Factory.UNSUPPORTED)),
C.TIME_UNSET,
executor,
e -> hasReleaseCallbackRun.set(true));
assertThat(hasThreadRun.get()).isTrue();
assertThat(hasReleaseCallbackRun.get()).isTrue();
}
private static void testExtractorsUpdatesSourceInfoBeforeOnPreparedCallback( private static void testExtractorsUpdatesSourceInfoBeforeOnPreparedCallback(
ProgressiveMediaExtractor extractor, long imageDurationUs) throws TimeoutException { ProgressiveMediaExtractor extractor, long imageDurationUs) throws TimeoutException {
testExtractorsUpdatesSourceInfoBeforeOnPreparedCallback(
extractor, imageDurationUs, /* executor= */ null, /* executorReleased= */ null);
}
private static void testExtractorsUpdatesSourceInfoBeforeOnPreparedCallback(
ProgressiveMediaExtractor extractor,
long imageDurationUs,
@Nullable Executor executor,
@Nullable Consumer<Executor> executorReleased)
throws TimeoutException {
AtomicBoolean sourceInfoRefreshCalled = new AtomicBoolean(false); AtomicBoolean sourceInfoRefreshCalled = new AtomicBoolean(false);
ProgressiveMediaPeriod.Listener sourceInfoRefreshListener = ProgressiveMediaPeriod.Listener sourceInfoRefreshListener =
(durationUs, isSeekable, isLive) -> sourceInfoRefreshCalled.set(true); (durationUs, isSeekable, isLive) -> sourceInfoRefreshCalled.set(true);
@ -88,7 +121,8 @@ public final class ProgressiveMediaPeriodTest {
new DefaultAllocator(/* trimOnReset= */ true, C.DEFAULT_BUFFER_SEGMENT_SIZE), new DefaultAllocator(/* trimOnReset= */ true, C.DEFAULT_BUFFER_SEGMENT_SIZE),
/* customCacheKey= */ null, /* customCacheKey= */ null,
ProgressiveMediaSource.DEFAULT_LOADING_CHECK_INTERVAL_BYTES, ProgressiveMediaSource.DEFAULT_LOADING_CHECK_INTERVAL_BYTES,
imageDurationUs); imageDurationUs,
executor != null ? ReleasableExecutor.from(executor, executorReleased) : null);
AtomicBoolean prepareCallbackCalled = new AtomicBoolean(false); AtomicBoolean prepareCallbackCalled = new AtomicBoolean(false);
AtomicBoolean sourceInfoRefreshCalledBeforeOnPrepared = new AtomicBoolean(false); AtomicBoolean sourceInfoRefreshCalledBeforeOnPrepared = new AtomicBoolean(false);
@ -111,4 +145,19 @@ public final class ProgressiveMediaPeriodTest {
assertThat(sourceInfoRefreshCalledBeforeOnPrepared.get()).isTrue(); assertThat(sourceInfoRefreshCalledBeforeOnPrepared.get()).isTrue();
} }
private static final class ExecutionTrackingThread extends Thread {
private final AtomicBoolean hasRun;
public ExecutionTrackingThread(Runnable runnable, AtomicBoolean hasRun) {
super(runnable, "TestExecutionTrackingThread");
this.hasRun = hasRun;
}
@Override
public void run() {
hasRun.set(true);
super.run();
}
}
} }

View File

@ -837,7 +837,8 @@ import java.util.regex.Pattern;
drmEventDispatcher, drmEventDispatcher,
loadErrorHandlingPolicy, loadErrorHandlingPolicy,
mediaSourceEventDispatcher, mediaSourceEventDispatcher,
canReportInitialDiscontinuity); canReportInitialDiscontinuity,
/* downloadExecutor= */ null);
synchronized (this) { synchronized (this) {
// The map is also accessed on the loading thread so synchronize access. // The map is also accessed on the loading thread so synchronize access.
trackEmsgHandlerBySampleStream.put(stream, trackPlayerEmsgHandler); trackEmsgHandlerBySampleStream.put(stream, trackPlayerEmsgHandler);

View File

@ -265,7 +265,8 @@ import java.util.List;
drmEventDispatcher, drmEventDispatcher,
loadErrorHandlingPolicy, loadErrorHandlingPolicy,
mediaSourceEventDispatcher, mediaSourceEventDispatcher,
/* canReportInitialDiscontinuity= */ false); /* canReportInitialDiscontinuity= */ false,
/* downloadExecutor= */ null);
} }
private static TrackGroupArray buildTrackGroups( private static TrackGroupArray buildTrackGroups(

View File

@ -188,7 +188,8 @@ public class FakeAdaptiveMediaPeriod
new DrmSessionEventListener.EventDispatcher(), new DrmSessionEventListener.EventDispatcher(),
new DefaultLoadErrorHandlingPolicy(/* minimumLoadableRetryCount= */ 3), new DefaultLoadErrorHandlingPolicy(/* minimumLoadableRetryCount= */ 3),
mediaSourceEventDispatcher, mediaSourceEventDispatcher,
/* canReportInitialDiscontinuity= */ false); /* canReportInitialDiscontinuity= */ false,
/* downloadExecutor= */ null);
streams[i] = sampleStream; streams[i] = sampleStream;
sampleStreams.add(sampleStream); sampleStreams.add(sampleStream);
streamResetFlags[i] = true; streamResetFlags[i] = true;