mirror of
https://github.com/samsonjs/media.git
synced 2026-04-10 12:05:47 +00:00
Add onPreloadError method to PreloadMediaSource.PreloadControl
Upon the call of `PreloadMediaSource.preload`, the source will periodically check the source refresh or period loading error, and trigger `PreloadMediaSource.PreloadControl.onPreloadError`. For now, the `DefaultPreloadManager` will skip the problematic source and continue to preload the next source. The checking of the error will be terminated when the source stops preloading or releases. PiperOrigin-RevId: 650195817
This commit is contained in:
parent
b4722ef1ea
commit
58ff8fa3c2
5 changed files with 363 additions and 448 deletions
|
|
@ -16,6 +16,9 @@
|
|||
every media item. Previously it was not called for the first one. Use
|
||||
`MediaCodecRenderer.experimentalEnableProcessedStreamChangedAtStart()`
|
||||
to enable this.
|
||||
* Add `PreloadMediaSource.PreloadControl.onPreloadError` to allow
|
||||
`PreloadMediaSource.PreloadControl` implementations to take actions when
|
||||
error occurs.
|
||||
* Transformer:
|
||||
* Track Selection:
|
||||
* Extractors:
|
||||
|
|
|
|||
|
|
@ -249,6 +249,11 @@ public final class DefaultPreloadManager extends BasePreloadManager<Integer> {
|
|||
onPreloadCompleted(mediaSource);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPreloadError(PreloadException error, PreloadMediaSource mediaSource) {
|
||||
onPreloadCompleted(mediaSource);
|
||||
}
|
||||
|
||||
private boolean continueOrCompletePreloading(
|
||||
PreloadMediaSource mediaSource,
|
||||
Predicate<Status> continueLoadingPredicate,
|
||||
|
|
|
|||
|
|
@ -16,6 +16,7 @@
|
|||
package androidx.media3.exoplayer.source.preload;
|
||||
|
||||
import static androidx.media3.common.util.Assertions.checkNotNull;
|
||||
import static androidx.media3.common.util.Util.postOrRun;
|
||||
|
||||
import android.os.Handler;
|
||||
import android.os.Looper;
|
||||
|
|
@ -45,6 +46,7 @@ import androidx.media3.exoplayer.upstream.Allocator;
|
|||
import androidx.media3.exoplayer.upstream.BandwidthMeter;
|
||||
import androidx.media3.exoplayer.upstream.CmcdConfiguration;
|
||||
import androidx.media3.exoplayer.upstream.LoadErrorHandlingPolicy;
|
||||
import java.io.IOException;
|
||||
import java.util.Arrays;
|
||||
|
||||
/**
|
||||
|
|
@ -105,6 +107,14 @@ public final class PreloadMediaSource extends WrappingMediaSource {
|
|||
* @param mediaSource The {@link PreloadMediaSource} that has loaded to the end of source.
|
||||
*/
|
||||
default void onLoadedToTheEndOfSource(PreloadMediaSource mediaSource) {}
|
||||
|
||||
/**
|
||||
* Called from {@link PreloadMediaSource} when an error occurs.
|
||||
*
|
||||
* @param error The {@linkplain PreloadException error}.
|
||||
* @param mediaSource The {@link PreloadMediaSource} that has the error occur.
|
||||
*/
|
||||
void onPreloadError(PreloadException error, PreloadMediaSource mediaSource);
|
||||
}
|
||||
|
||||
/** Factory for {@link PreloadMediaSource}. */
|
||||
|
|
@ -203,6 +213,7 @@ public final class PreloadMediaSource extends WrappingMediaSource {
|
|||
}
|
||||
|
||||
private static final String TAG = "PreloadMediaSource";
|
||||
private static final long CHECK_FOR_PRELOAD_ERROR_INTERVAL_MS = 100;
|
||||
|
||||
private final PreloadControl preloadControl;
|
||||
private final TrackSelector trackSelector;
|
||||
|
|
@ -253,10 +264,11 @@ public final class PreloadMediaSource extends WrappingMediaSource {
|
|||
this.startPositionUs = startPositionUs;
|
||||
onSourcePreparedNotified = false;
|
||||
if (isUsedByPlayer()) {
|
||||
notifyOnUsedByPlayer();
|
||||
onUsedByPlayer();
|
||||
} else {
|
||||
setPlayerId(PlayerId.UNSET); // Set to PlayerId.UNSET as there is no ongoing playback.
|
||||
prepareSourceInternal(bandwidthMeter.getTransferListener());
|
||||
checkForPreloadError();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
|
@ -267,7 +279,8 @@ public final class PreloadMediaSource extends WrappingMediaSource {
|
|||
* <p>Can be called from any thread.
|
||||
*/
|
||||
public void clear() {
|
||||
preloadHandler.post(
|
||||
postOrRun(
|
||||
preloadHandler,
|
||||
() -> {
|
||||
if (preloadingMediaPeriodAndKey != null) {
|
||||
mediaSource.releasePeriod(preloadingMediaPeriodAndKey.first.mediaPeriod);
|
||||
|
|
@ -279,7 +292,7 @@ public final class PreloadMediaSource extends WrappingMediaSource {
|
|||
@Override
|
||||
protected void prepareSourceInternal() {
|
||||
if (isUsedByPlayer() && !onUsedByPlayerNotified) {
|
||||
notifyOnUsedByPlayer();
|
||||
onUsedByPlayer();
|
||||
}
|
||||
if (timeline != null) {
|
||||
onChildSourceInfoRefreshed(timeline);
|
||||
|
|
@ -298,6 +311,7 @@ public final class PreloadMediaSource extends WrappingMediaSource {
|
|||
}
|
||||
onSourcePreparedNotified = true;
|
||||
if (!preloadControl.onSourcePrepared(this)) {
|
||||
stopPreloading();
|
||||
return;
|
||||
}
|
||||
Pair<Object, Long> periodPosition =
|
||||
|
|
@ -393,6 +407,42 @@ public final class PreloadMediaSource extends WrappingMediaSource {
|
|||
});
|
||||
}
|
||||
|
||||
private boolean isUsedByPlayer() {
|
||||
return prepareSourceCalled();
|
||||
}
|
||||
|
||||
private void onUsedByPlayer() {
|
||||
preloadControl.onUsedByPlayer(this);
|
||||
stopPreloading();
|
||||
onUsedByPlayerNotified = true;
|
||||
}
|
||||
|
||||
private void checkForPreloadError() {
|
||||
try {
|
||||
maybeThrowSourceInfoRefreshError();
|
||||
if (preloadingMediaPeriodAndKey != null) {
|
||||
preloadingMediaPeriodAndKey.first.maybeThrowPrepareError();
|
||||
}
|
||||
preloadHandler.postDelayed(this::checkForPreloadError, CHECK_FOR_PRELOAD_ERROR_INTERVAL_MS);
|
||||
} catch (IOException e) {
|
||||
preloadControl.onPreloadError(
|
||||
new PreloadException(this.getMediaItem(), /* message= */ null, e), this);
|
||||
stopPreloading();
|
||||
}
|
||||
}
|
||||
|
||||
private void stopPreloading() {
|
||||
preloadHandler.removeCallbacksAndMessages(null);
|
||||
}
|
||||
|
||||
private static boolean mediaPeriodIdEqualsWithoutWindowSequenceNumber(
|
||||
MediaPeriodId firstPeriodId, MediaPeriodId secondPeriodId) {
|
||||
return firstPeriodId.periodUid.equals(secondPeriodId.periodUid)
|
||||
&& firstPeriodId.adGroupIndex == secondPeriodId.adGroupIndex
|
||||
&& firstPeriodId.adIndexInAdGroup == secondPeriodId.adIndexInAdGroup
|
||||
&& firstPeriodId.nextAdGroupIndex == secondPeriodId.nextAdGroupIndex;
|
||||
}
|
||||
|
||||
private class PreloadMediaPeriodCallback implements MediaPeriod.Callback {
|
||||
|
||||
private final long periodStartPositionUs;
|
||||
|
|
@ -419,14 +469,18 @@ public final class PreloadMediaSource extends WrappingMediaSource {
|
|||
} catch (ExoPlaybackException e) {
|
||||
Log.e(TAG, "Failed to select tracks", e);
|
||||
}
|
||||
if (trackSelectorResult != null) {
|
||||
preloadMediaPeriod.selectTracksForPreloading(
|
||||
trackSelectorResult.selections, periodStartPositionUs);
|
||||
if (preloadControl.onTracksSelected(PreloadMediaSource.this)) {
|
||||
preloadMediaPeriod.continueLoading(
|
||||
new LoadingInfo.Builder().setPlaybackPositionUs(periodStartPositionUs).build());
|
||||
}
|
||||
if (trackSelectorResult == null) {
|
||||
stopPreloading();
|
||||
return;
|
||||
}
|
||||
preloadMediaPeriod.selectTracksForPreloading(
|
||||
trackSelectorResult.selections, periodStartPositionUs);
|
||||
if (!preloadControl.onTracksSelected(PreloadMediaSource.this)) {
|
||||
stopPreloading();
|
||||
return;
|
||||
}
|
||||
preloadMediaPeriod.continueLoading(
|
||||
new LoadingInfo.Builder().setPlaybackPositionUs(periodStartPositionUs).build());
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
@ -437,32 +491,20 @@ public final class PreloadMediaSource extends WrappingMediaSource {
|
|||
PreloadMediaPeriod preloadMediaPeriod = (PreloadMediaPeriod) mediaPeriod;
|
||||
if (prepared && mediaPeriod.getBufferedPositionUs() == C.TIME_END_OF_SOURCE) {
|
||||
preloadControl.onLoadedToTheEndOfSource(PreloadMediaSource.this);
|
||||
} else if (!prepared
|
||||
|| preloadControl.onContinueLoadingRequested(
|
||||
PreloadMediaSource.this, preloadMediaPeriod.getBufferedPositionUs())) {
|
||||
preloadMediaPeriod.continueLoading(
|
||||
new LoadingInfo.Builder().setPlaybackPositionUs(periodStartPositionUs).build());
|
||||
stopPreloading();
|
||||
return;
|
||||
}
|
||||
if (prepared
|
||||
&& !preloadControl.onContinueLoadingRequested(
|
||||
PreloadMediaSource.this, preloadMediaPeriod.getBufferedPositionUs())) {
|
||||
stopPreloading();
|
||||
return;
|
||||
}
|
||||
preloadMediaPeriod.continueLoading(
|
||||
new LoadingInfo.Builder().setPlaybackPositionUs(periodStartPositionUs).build());
|
||||
}
|
||||
}
|
||||
|
||||
private boolean isUsedByPlayer() {
|
||||
return prepareSourceCalled();
|
||||
}
|
||||
|
||||
private void notifyOnUsedByPlayer() {
|
||||
preloadControl.onUsedByPlayer(this);
|
||||
onUsedByPlayerNotified = true;
|
||||
}
|
||||
|
||||
private static boolean mediaPeriodIdEqualsWithoutWindowSequenceNumber(
|
||||
MediaPeriodId firstPeriodId, MediaPeriodId secondPeriodId) {
|
||||
return firstPeriodId.periodUid.equals(secondPeriodId.periodUid)
|
||||
&& firstPeriodId.adGroupIndex == secondPeriodId.adGroupIndex
|
||||
&& firstPeriodId.adIndexInAdGroup == secondPeriodId.adIndexInAdGroup
|
||||
&& firstPeriodId.nextAdGroupIndex == secondPeriodId.nextAdGroupIndex;
|
||||
}
|
||||
|
||||
private static class MediaPeriodKey {
|
||||
|
||||
public final MediaSource.MediaPeriodId mediaPeriodId;
|
||||
|
|
|
|||
|
|
@ -124,6 +124,9 @@ public class PreloadAndPlaybackCoordinationTest {
|
|||
public void onUsedByPlayer(PreloadMediaSource mediaSource) {
|
||||
preloadControlOnUsedByPlayerCounter.addAndGet(1);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPreloadError(PreloadException error, PreloadMediaSource mediaSource) {}
|
||||
};
|
||||
PreloadMediaSource.Factory preloadMediaSourceFactory =
|
||||
new PreloadMediaSource.Factory(
|
||||
|
|
|
|||
|
|
@ -46,6 +46,7 @@ import androidx.media3.exoplayer.analytics.PlayerId;
|
|||
import androidx.media3.exoplayer.audio.AudioRendererEventListener;
|
||||
import androidx.media3.exoplayer.drm.DrmSessionEventListener;
|
||||
import androidx.media3.exoplayer.drm.DrmSessionManager;
|
||||
import androidx.media3.exoplayer.drm.DrmSessionManagerProvider;
|
||||
import androidx.media3.exoplayer.metadata.MetadataOutput;
|
||||
import androidx.media3.exoplayer.source.MediaPeriod;
|
||||
import androidx.media3.exoplayer.source.MediaSource;
|
||||
|
|
@ -61,6 +62,7 @@ import androidx.media3.exoplayer.upstream.Allocator;
|
|||
import androidx.media3.exoplayer.upstream.BandwidthMeter;
|
||||
import androidx.media3.exoplayer.upstream.DefaultAllocator;
|
||||
import androidx.media3.exoplayer.upstream.DefaultBandwidthMeter;
|
||||
import androidx.media3.exoplayer.upstream.LoadErrorHandlingPolicy;
|
||||
import androidx.media3.exoplayer.video.VideoRendererEventListener;
|
||||
import androidx.media3.test.utils.FakeAudioRenderer;
|
||||
import androidx.media3.test.utils.FakeMediaPeriod;
|
||||
|
|
@ -71,8 +73,9 @@ import androidx.media3.test.utils.FakeTrackSelector;
|
|||
import androidx.media3.test.utils.FakeVideoRenderer;
|
||||
import androidx.test.core.app.ApplicationProvider;
|
||||
import androidx.test.ext.junit.runners.AndroidJUnit4;
|
||||
import java.io.IOException;
|
||||
import java.util.concurrent.TimeoutException;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
import java.util.concurrent.atomic.AtomicReference;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
|
|
@ -108,40 +111,19 @@ public final class PreloadMediaSourceTest {
|
|||
|
||||
@Test
|
||||
public void preload_loadPeriodToTargetPreloadPosition() throws Exception {
|
||||
AtomicInteger onSourcePreparedCounter = new AtomicInteger();
|
||||
AtomicBoolean onTracksSelectedCalled = new AtomicBoolean();
|
||||
AtomicBoolean onContinueLoadingStopped = new AtomicBoolean();
|
||||
AtomicReference<PreloadMediaSource> preloadMediaSourceReference = new AtomicReference<>();
|
||||
AtomicBoolean onUsedByPlayerCalled = new AtomicBoolean();
|
||||
PreloadMediaSource.PreloadControl preloadControl =
|
||||
new PreloadMediaSource.PreloadControl() {
|
||||
@Override
|
||||
public boolean onSourcePrepared(PreloadMediaSource mediaSource) {
|
||||
onSourcePreparedCounter.addAndGet(1);
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onTracksSelected(PreloadMediaSource mediaSource) {
|
||||
onTracksSelectedCalled.set(true);
|
||||
return true;
|
||||
}
|
||||
|
||||
TestPreloadControl preloadControl =
|
||||
new TestPreloadControl() {
|
||||
@Override
|
||||
public boolean onContinueLoadingRequested(
|
||||
PreloadMediaSource mediaSource, long bufferedPositionUs) {
|
||||
preloadMediaSourceReference.set(mediaSource);
|
||||
onContinueLoadingRequestedCalled = true;
|
||||
if (bufferedPositionUs >= TARGET_PRELOAD_POSITION_US) {
|
||||
onContinueLoadingStopped.set(true);
|
||||
preloadMediaSourceReference.set(mediaSource);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onUsedByPlayer(PreloadMediaSource mediaSource) {
|
||||
onUsedByPlayerCalled.set(true);
|
||||
}
|
||||
};
|
||||
ProgressiveMediaSource.Factory mediaSourceFactory =
|
||||
new ProgressiveMediaSource.Factory(
|
||||
|
|
@ -166,47 +148,27 @@ public final class PreloadMediaSourceTest {
|
|||
.build());
|
||||
|
||||
preloadMediaSource.preload(/* startPositionUs= */ 0L);
|
||||
runMainLooperUntil(onContinueLoadingStopped::get);
|
||||
runMainLooperUntil(() -> preloadMediaSourceReference.get() != null);
|
||||
|
||||
assertThat(onSourcePreparedCounter.get()).isEqualTo(1);
|
||||
assertThat(onTracksSelectedCalled.get()).isTrue();
|
||||
assertThat(onUsedByPlayerCalled.get()).isFalse();
|
||||
assertThat(preloadControl.onSourcePreparedCalledCount).isEqualTo(1);
|
||||
assertThat(preloadControl.onTrackSelectedCalled).isTrue();
|
||||
assertThat(preloadControl.onContinueLoadingRequestedCalled).isTrue();
|
||||
assertThat(preloadControl.onUsedByPlayerCalled).isFalse();
|
||||
assertThat(preloadControl.onPreloadErrorCalled).isFalse();
|
||||
assertThat(preloadMediaSourceReference.get()).isSameInstanceAs(preloadMediaSource);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void preload_stopWhenTracksSelectedByPreloadControl() throws Exception {
|
||||
AtomicInteger onSourcePreparedCounter = new AtomicInteger();
|
||||
AtomicBoolean onTracksSelectedCalled = new AtomicBoolean();
|
||||
AtomicReference<PreloadMediaSource> preloadMediaSourceReference = new AtomicReference<>();
|
||||
AtomicBoolean onContinueLoadingRequestedCalled = new AtomicBoolean();
|
||||
AtomicBoolean onUsedByPlayerCalled = new AtomicBoolean();
|
||||
PreloadMediaSource.PreloadControl preloadControl =
|
||||
new PreloadMediaSource.PreloadControl() {
|
||||
@Override
|
||||
public boolean onSourcePrepared(PreloadMediaSource mediaSource) {
|
||||
onSourcePreparedCounter.addAndGet(1);
|
||||
return true;
|
||||
}
|
||||
|
||||
TestPreloadControl preloadControl =
|
||||
new TestPreloadControl() {
|
||||
@Override
|
||||
public boolean onTracksSelected(PreloadMediaSource mediaSource) {
|
||||
onTrackSelectedCalled = true;
|
||||
preloadMediaSourceReference.set(mediaSource);
|
||||
onTracksSelectedCalled.set(true);
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onContinueLoadingRequested(
|
||||
PreloadMediaSource mediaSource, long bufferedPositionUs) {
|
||||
onContinueLoadingRequestedCalled.set(true);
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onUsedByPlayer(PreloadMediaSource mediaSource) {
|
||||
onUsedByPlayerCalled.set(true);
|
||||
}
|
||||
};
|
||||
ProgressiveMediaSource.Factory mediaSourceFactory =
|
||||
new ProgressiveMediaSource.Factory(
|
||||
|
|
@ -231,47 +193,27 @@ public final class PreloadMediaSourceTest {
|
|||
.build());
|
||||
|
||||
preloadMediaSource.preload(/* startPositionUs= */ 0L);
|
||||
runMainLooperUntil(onTracksSelectedCalled::get);
|
||||
runMainLooperUntil(() -> preloadMediaSourceReference.get() != null);
|
||||
|
||||
assertThat(onSourcePreparedCounter.get()).isEqualTo(1);
|
||||
assertThat(preloadControl.onSourcePreparedCalledCount).isEqualTo(1);
|
||||
assertThat(preloadControl.onTrackSelectedCalled).isTrue();
|
||||
assertThat(preloadMediaSourceReference.get()).isSameInstanceAs(preloadMediaSource);
|
||||
assertThat(onContinueLoadingRequestedCalled.get()).isFalse();
|
||||
assertThat(onUsedByPlayerCalled.get()).isFalse();
|
||||
assertThat(preloadControl.onContinueLoadingRequestedCalled).isFalse();
|
||||
assertThat(preloadControl.onPreloadErrorCalled).isFalse();
|
||||
assertThat(preloadControl.onUsedByPlayerCalled).isFalse();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void preload_stopWhenSourcePreparedByPreloadControl() throws Exception {
|
||||
AtomicInteger onSourcePreparedCounter = new AtomicInteger();
|
||||
public void preload_stopWhenSourcePreparedByPreloadControl() {
|
||||
AtomicReference<PreloadMediaSource> preloadMediaSourceReference = new AtomicReference<>();
|
||||
AtomicBoolean onTracksSelectedCalled = new AtomicBoolean();
|
||||
AtomicBoolean onContinueLoadingRequestedCalled = new AtomicBoolean();
|
||||
AtomicBoolean onUsedByPlayerCalled = new AtomicBoolean();
|
||||
PreloadMediaSource.PreloadControl preloadControl =
|
||||
new PreloadMediaSource.PreloadControl() {
|
||||
TestPreloadControl preloadControl =
|
||||
new TestPreloadControl() {
|
||||
@Override
|
||||
public boolean onSourcePrepared(PreloadMediaSource mediaSource) {
|
||||
onSourcePreparedCalledCount++;
|
||||
preloadMediaSourceReference.set(mediaSource);
|
||||
onSourcePreparedCounter.addAndGet(1);
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onTracksSelected(PreloadMediaSource mediaSource) {
|
||||
onTracksSelectedCalled.set(true);
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onContinueLoadingRequested(
|
||||
PreloadMediaSource mediaSource, long bufferedPositionUs) {
|
||||
onContinueLoadingRequestedCalled.set(true);
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onUsedByPlayer(PreloadMediaSource mediaSource) {
|
||||
onUsedByPlayerCalled.set(true);
|
||||
}
|
||||
};
|
||||
ProgressiveMediaSource.Factory mediaSourceFactory =
|
||||
new ProgressiveMediaSource.Factory(
|
||||
|
|
@ -298,42 +240,16 @@ public final class PreloadMediaSourceTest {
|
|||
shadowOf(Looper.getMainLooper()).idle();
|
||||
|
||||
assertThat(preloadMediaSourceReference.get()).isSameInstanceAs(preloadMediaSource);
|
||||
assertThat(onSourcePreparedCounter.get()).isEqualTo(1);
|
||||
assertThat(onTracksSelectedCalled.get()).isFalse();
|
||||
assertThat(onContinueLoadingRequestedCalled.get()).isFalse();
|
||||
assertThat(onUsedByPlayerCalled.get()).isFalse();
|
||||
assertThat(preloadControl.onSourcePreparedCalledCount).isEqualTo(1);
|
||||
assertThat(preloadControl.onTrackSelectedCalled).isFalse();
|
||||
assertThat(preloadControl.onContinueLoadingRequestedCalled).isFalse();
|
||||
assertThat(preloadControl.onUsedByPlayerCalled).isFalse();
|
||||
assertThat(preloadControl.onPreloadErrorCalled).isFalse();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void preload_whileSourceIsAccessedByExternalCaller_notProceedWithPreloading() {
|
||||
AtomicBoolean onSourcePreparedCalled = new AtomicBoolean(false);
|
||||
AtomicBoolean onTracksSelectedCalled = new AtomicBoolean(false);
|
||||
AtomicBoolean onUsedByPlayerCalled = new AtomicBoolean();
|
||||
PreloadMediaSource.PreloadControl preloadControl =
|
||||
new PreloadMediaSource.PreloadControl() {
|
||||
@Override
|
||||
public boolean onSourcePrepared(PreloadMediaSource mediaSource) {
|
||||
onSourcePreparedCalled.set(true);
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onTracksSelected(PreloadMediaSource mediaSource) {
|
||||
onTracksSelectedCalled.set(true);
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onContinueLoadingRequested(
|
||||
PreloadMediaSource mediaSource, long bufferedPositionUs) {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onUsedByPlayer(PreloadMediaSource mediaSource) {
|
||||
onUsedByPlayerCalled.set(true);
|
||||
}
|
||||
};
|
||||
TestPreloadControl preloadControl = new TestPreloadControl();
|
||||
TrackSelector trackSelector = new FakeTrackSelector();
|
||||
trackSelector.init(() -> {}, bandwidthMeter);
|
||||
PreloadMediaSource.Factory preloadMediaSourceFactory =
|
||||
|
|
@ -361,52 +277,21 @@ public final class PreloadMediaSourceTest {
|
|||
shadowOf(Looper.getMainLooper()).idle();
|
||||
|
||||
assertThat(externalCallerMediaSourceReference.get()).isSameInstanceAs(preloadMediaSource);
|
||||
assertThat(onSourcePreparedCalled.get()).isFalse();
|
||||
assertThat(onTracksSelectedCalled.get()).isFalse();
|
||||
assertThat(onUsedByPlayerCalled.get()).isTrue();
|
||||
assertThat(preloadControl.onSourcePreparedCalledCount).isEqualTo(0);
|
||||
assertThat(preloadControl.onTrackSelectedCalled).isFalse();
|
||||
assertThat(preloadControl.onUsedByPlayerCalled).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void preload_loadToTheEndOfSource() throws Exception {
|
||||
AtomicInteger onSourcePreparedCounter = new AtomicInteger();
|
||||
AtomicBoolean onTracksSelectedCalled = new AtomicBoolean();
|
||||
AtomicBoolean onContinueLoadingRequestedCalled = new AtomicBoolean();
|
||||
AtomicBoolean onLoadedToTheEndOfSourceCalled = new AtomicBoolean();
|
||||
AtomicBoolean onUsedByPlayerCalled = new AtomicBoolean();
|
||||
PreloadMediaSource.PreloadControl preloadControl =
|
||||
new PreloadMediaSource.PreloadControl() {
|
||||
@Override
|
||||
public boolean onSourcePrepared(PreloadMediaSource mediaSource) {
|
||||
onSourcePreparedCounter.addAndGet(1);
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onTracksSelected(PreloadMediaSource mediaSource) {
|
||||
onTracksSelectedCalled.set(true);
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onContinueLoadingRequested(
|
||||
PreloadMediaSource mediaSource, long bufferedPositionUs) {
|
||||
// In fact, this method is not necessarily to be called if the
|
||||
// LOADING_CHECK_INTERVAL_BYTES set for the ProgressiveMediaSource.Factory is large
|
||||
// enough to have the media load to the end in one round. However, since we explicitly
|
||||
// set with a small value below, we will still expect this method to be called for at
|
||||
// least once.
|
||||
onContinueLoadingRequestedCalled.set(true);
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onUsedByPlayer(PreloadMediaSource mediaSource) {
|
||||
onUsedByPlayerCalled.set(true);
|
||||
}
|
||||
|
||||
AtomicReference<PreloadMediaSource> preloadMediaSourceReference = new AtomicReference<>();
|
||||
TestPreloadControl preloadControl =
|
||||
new TestPreloadControl() {
|
||||
@Override
|
||||
public void onLoadedToTheEndOfSource(PreloadMediaSource mediaSource) {
|
||||
onLoadedToTheEndOfSourceCalled.set(true);
|
||||
super.onLoadedToTheEndOfSource(mediaSource);
|
||||
onLoadedToTheEndOfSourceCalled = true;
|
||||
preloadMediaSourceReference.set(mediaSource);
|
||||
}
|
||||
};
|
||||
ProgressiveMediaSource.Factory mediaSourceFactory =
|
||||
|
|
@ -432,45 +317,184 @@ public final class PreloadMediaSourceTest {
|
|||
.build());
|
||||
|
||||
preloadMediaSource.preload(/* startPositionUs= */ 0L);
|
||||
runMainLooperUntil(onLoadedToTheEndOfSourceCalled::get);
|
||||
runMainLooperUntil(() -> preloadMediaSourceReference.get() != null);
|
||||
|
||||
assertThat(onSourcePreparedCounter.get()).isEqualTo(1);
|
||||
assertThat(onTracksSelectedCalled.get()).isTrue();
|
||||
assertThat(onContinueLoadingRequestedCalled.get()).isTrue();
|
||||
assertThat(onUsedByPlayerCalled.get()).isFalse();
|
||||
assertThat(preloadControl.onSourcePreparedCalledCount).isEqualTo(1);
|
||||
assertThat(preloadControl.onTrackSelectedCalled).isTrue();
|
||||
// In fact, PreloadControl.onContinueLoadingRequested is not necessarily to be called if the
|
||||
// LOADING_CHECK_INTERVAL_BYTES set for the ProgressiveMediaSource.Factory is large
|
||||
// enough to have the media load to the end in one round. However, since we explicitly
|
||||
// set with a small value below, we will still expect this method to be called for at
|
||||
// least once.
|
||||
assertThat(preloadControl.onContinueLoadingRequestedCalled).isTrue();
|
||||
assertThat(preloadControl.onLoadedToTheEndOfSourceCalled).isTrue();
|
||||
assertThat(preloadControl.onUsedByPlayerCalled).isFalse();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void preload_sourceInfoRefreshErrorThrows_onPreloadErrorCalled() throws TimeoutException {
|
||||
AtomicReference<PreloadException> preloadExceptionReference = new AtomicReference<>();
|
||||
AtomicReference<PreloadMediaSource> preloadMediaSourceReference = new AtomicReference<>();
|
||||
IOException causeException = new IOException("Failed to refresh source info");
|
||||
TestPreloadControl preloadControl =
|
||||
new TestPreloadControl() {
|
||||
@Override
|
||||
public void onPreloadError(PreloadException error, PreloadMediaSource mediaSource) {
|
||||
super.onPreloadError(error, mediaSource);
|
||||
preloadExceptionReference.set(error);
|
||||
preloadMediaSourceReference.set(mediaSource);
|
||||
}
|
||||
};
|
||||
MediaSource.Factory mediaSourceFactory =
|
||||
new MediaSource.Factory() {
|
||||
@Override
|
||||
public MediaSource.Factory setDrmSessionManagerProvider(
|
||||
DrmSessionManagerProvider drmSessionManagerProvider) {
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public MediaSource.Factory setLoadErrorHandlingPolicy(
|
||||
LoadErrorHandlingPolicy loadErrorHandlingPolicy) {
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public @C.ContentType int[] getSupportedTypes() {
|
||||
return new int[0];
|
||||
}
|
||||
|
||||
@Override
|
||||
public MediaSource createMediaSource(MediaItem mediaItem) {
|
||||
return new FakeMediaSource(/* timeline= */ null) {
|
||||
@Override
|
||||
public void maybeThrowSourceInfoRefreshError() throws IOException {
|
||||
throw causeException;
|
||||
}
|
||||
};
|
||||
}
|
||||
};
|
||||
TrackSelector trackSelector =
|
||||
new DefaultTrackSelector(ApplicationProvider.getApplicationContext());
|
||||
trackSelector.init(() -> {}, bandwidthMeter);
|
||||
PreloadMediaSource.Factory preloadMediaSourceFactory =
|
||||
new PreloadMediaSource.Factory(
|
||||
mediaSourceFactory,
|
||||
preloadControl,
|
||||
trackSelector,
|
||||
bandwidthMeter,
|
||||
getRendererCapabilities(renderersFactory),
|
||||
allocator,
|
||||
Util.getCurrentOrMainLooper());
|
||||
PreloadMediaSource preloadMediaSource =
|
||||
preloadMediaSourceFactory.createMediaSource(
|
||||
new MediaItem.Builder()
|
||||
.setUri(Uri.parse("asset://android_asset/media/mp4/sample.mp4"))
|
||||
.build());
|
||||
|
||||
preloadMediaSource.preload(/* startPositionUs= */ 0L);
|
||||
runMainLooperUntil(() -> preloadMediaSourceReference.get() != null);
|
||||
|
||||
assertThat(preloadControl.onPreloadErrorCalled).isTrue();
|
||||
assertThat(preloadExceptionReference.get()).hasCauseThat().isEqualTo(causeException);
|
||||
assertThat(preloadControl.onSourcePreparedCalledCount).isEqualTo(0);
|
||||
assertThat(preloadControl.onTrackSelectedCalled).isFalse();
|
||||
assertThat(preloadControl.onContinueLoadingRequestedCalled).isFalse();
|
||||
assertThat(preloadControl.onUsedByPlayerCalled).isFalse();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void preload_periodPrepareErrorThrows_onPreloadErrorCalled() throws TimeoutException {
|
||||
AtomicReference<PreloadException> preloadExceptionReference = new AtomicReference<>();
|
||||
AtomicReference<PreloadMediaSource> preloadMediaSourceReference = new AtomicReference<>();
|
||||
IOException causeException = new IOException("Failed to prepare the period");
|
||||
TestPreloadControl preloadControl =
|
||||
new TestPreloadControl() {
|
||||
@Override
|
||||
public void onPreloadError(PreloadException error, PreloadMediaSource mediaSource) {
|
||||
super.onPreloadError(error, mediaSource);
|
||||
preloadExceptionReference.set(error);
|
||||
preloadMediaSourceReference.set(mediaSource);
|
||||
}
|
||||
};
|
||||
MediaSource.Factory mediaSourceFactory =
|
||||
new MediaSource.Factory() {
|
||||
@Override
|
||||
public MediaSource.Factory setDrmSessionManagerProvider(
|
||||
DrmSessionManagerProvider drmSessionManagerProvider) {
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public MediaSource.Factory setLoadErrorHandlingPolicy(
|
||||
LoadErrorHandlingPolicy loadErrorHandlingPolicy) {
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public @C.ContentType int[] getSupportedTypes() {
|
||||
return new int[0];
|
||||
}
|
||||
|
||||
@Override
|
||||
public MediaSource createMediaSource(MediaItem mediaItem) {
|
||||
return new FakeMediaSource() {
|
||||
@Override
|
||||
public MediaPeriod createPeriod(
|
||||
MediaPeriodId id, Allocator allocator, long startPositionUs) {
|
||||
return new FakeMediaPeriod(
|
||||
TrackGroupArray.EMPTY,
|
||||
allocator,
|
||||
startPositionUs,
|
||||
new MediaSourceEventListener.EventDispatcher()) {
|
||||
@Override
|
||||
public void prepare(Callback callback, long positionUs) {
|
||||
// Do nothing to simulate that something wrong happens and onPrepared will not
|
||||
// be called.
|
||||
}
|
||||
|
||||
@Override
|
||||
public void maybeThrowPrepareError() throws IOException {
|
||||
throw causeException;
|
||||
}
|
||||
};
|
||||
}
|
||||
};
|
||||
}
|
||||
};
|
||||
TrackSelector trackSelector =
|
||||
new DefaultTrackSelector(ApplicationProvider.getApplicationContext());
|
||||
trackSelector.init(() -> {}, bandwidthMeter);
|
||||
PreloadMediaSource.Factory preloadMediaSourceFactory =
|
||||
new PreloadMediaSource.Factory(
|
||||
mediaSourceFactory,
|
||||
preloadControl,
|
||||
trackSelector,
|
||||
bandwidthMeter,
|
||||
getRendererCapabilities(renderersFactory),
|
||||
allocator,
|
||||
Util.getCurrentOrMainLooper());
|
||||
PreloadMediaSource preloadMediaSource =
|
||||
preloadMediaSourceFactory.createMediaSource(
|
||||
new MediaItem.Builder()
|
||||
.setUri(Uri.parse("asset://android_asset/media/mp4/sample.mp4"))
|
||||
.build());
|
||||
|
||||
preloadMediaSource.preload(/* startPositionUs= */ 0L);
|
||||
runMainLooperUntil(() -> preloadMediaSourceReference.get() != null);
|
||||
|
||||
assertThat(preloadControl.onPreloadErrorCalled).isTrue();
|
||||
assertThat(preloadExceptionReference.get()).hasCauseThat().isEqualTo(causeException);
|
||||
assertThat(preloadControl.onSourcePreparedCalledCount).isGreaterThan(0);
|
||||
assertThat(preloadControl.onTrackSelectedCalled).isFalse();
|
||||
assertThat(preloadControl.onContinueLoadingRequestedCalled).isFalse();
|
||||
assertThat(preloadControl.onUsedByPlayerCalled).isFalse();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void
|
||||
prepareSource_beforeSourceInfoRefreshedForPreloading_onlyInvokeExternalCallerOnSourceInfoRefreshed() {
|
||||
AtomicBoolean onSourcePreparedCalled = new AtomicBoolean(false);
|
||||
AtomicBoolean onTracksSelectedCalled = new AtomicBoolean(false);
|
||||
AtomicBoolean onUsedByPlayerCalled = new AtomicBoolean();
|
||||
PreloadMediaSource.PreloadControl preloadControl =
|
||||
new PreloadMediaSource.PreloadControl() {
|
||||
@Override
|
||||
public boolean onSourcePrepared(PreloadMediaSource mediaSource) {
|
||||
onSourcePreparedCalled.set(true);
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onTracksSelected(PreloadMediaSource mediaSource) {
|
||||
onTracksSelectedCalled.set(true);
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onContinueLoadingRequested(
|
||||
PreloadMediaSource mediaSource, long bufferedPositionUs) {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onUsedByPlayer(PreloadMediaSource mediaSource) {
|
||||
onUsedByPlayerCalled.set(true);
|
||||
}
|
||||
};
|
||||
TestPreloadControl preloadControl = new TestPreloadControl();
|
||||
FakeMediaSourceFactory mediaSourceFactory = new FakeMediaSourceFactory();
|
||||
TrackSelector trackSelector = new FakeTrackSelector();
|
||||
trackSelector.init(() -> {}, bandwidthMeter);
|
||||
|
|
@ -501,41 +525,14 @@ public final class PreloadMediaSourceTest {
|
|||
shadowOf(Looper.getMainLooper()).idle();
|
||||
|
||||
assertThat(externalCallerMediaSourceReference.get()).isSameInstanceAs(preloadMediaSource);
|
||||
assertThat(onSourcePreparedCalled.get()).isFalse();
|
||||
assertThat(onTracksSelectedCalled.get()).isFalse();
|
||||
assertThat(onUsedByPlayerCalled.get()).isTrue();
|
||||
assertThat(preloadControl.onSourcePreparedCalledCount).isEqualTo(0);
|
||||
assertThat(preloadControl.onTrackSelectedCalled).isFalse();
|
||||
assertThat(preloadControl.onUsedByPlayerCalled).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void prepareSource_afterPreload_immediatelyInvokeExternalCallerOnSourceInfoRefreshed() {
|
||||
AtomicBoolean onSourcePreparedCalled = new AtomicBoolean(false);
|
||||
AtomicBoolean onTracksSelectedCalled = new AtomicBoolean(false);
|
||||
AtomicBoolean onUsedByPlayerCalled = new AtomicBoolean();
|
||||
PreloadMediaSource.PreloadControl preloadControl =
|
||||
new PreloadMediaSource.PreloadControl() {
|
||||
@Override
|
||||
public boolean onSourcePrepared(PreloadMediaSource mediaSource) {
|
||||
onSourcePreparedCalled.set(true);
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onTracksSelected(PreloadMediaSource mediaSource) {
|
||||
onTracksSelectedCalled.set(true);
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onContinueLoadingRequested(
|
||||
PreloadMediaSource mediaSource, long bufferedPositionUs) {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onUsedByPlayer(PreloadMediaSource mediaSource) {
|
||||
onUsedByPlayerCalled.set(true);
|
||||
}
|
||||
};
|
||||
TestPreloadControl preloadControl = new TestPreloadControl();
|
||||
FakeMediaSourceFactory mediaSourceFactory = new FakeMediaSourceFactory();
|
||||
TrackSelector trackSelector = new FakeTrackSelector();
|
||||
trackSelector.init(() -> {}, bandwidthMeter);
|
||||
|
|
@ -562,38 +559,15 @@ public final class PreloadMediaSourceTest {
|
|||
preloadMediaSource.prepareSource(
|
||||
externalCaller, bandwidthMeter.getTransferListener(), PlayerId.UNSET);
|
||||
|
||||
assertThat(onSourcePreparedCalled.get()).isTrue();
|
||||
assertThat(onTracksSelectedCalled.get()).isTrue();
|
||||
assertThat(preloadControl.onSourcePreparedCalledCount).isGreaterThan(0);
|
||||
assertThat(preloadControl.onTrackSelectedCalled).isTrue();
|
||||
assertThat(externalCallerMediaSourceReference.get()).isSameInstanceAs(preloadMediaSource);
|
||||
assertThat(onUsedByPlayerCalled.get()).isTrue();
|
||||
assertThat(preloadControl.onUsedByPlayerCalled).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void createPeriodWithSameMediaPeriodIdAndStartPosition_returnExistingPeriod()
|
||||
throws Exception {
|
||||
AtomicBoolean onTracksSelectedCalled = new AtomicBoolean();
|
||||
PreloadMediaSource.PreloadControl preloadControl =
|
||||
new PreloadMediaSource.PreloadControl() {
|
||||
@Override
|
||||
public boolean onSourcePrepared(PreloadMediaSource mediaSource) {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onTracksSelected(PreloadMediaSource mediaSource) {
|
||||
onTracksSelectedCalled.set(true);
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onContinueLoadingRequested(
|
||||
PreloadMediaSource mediaSource, long bufferedPositionUs) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onUsedByPlayer(PreloadMediaSource mediaSource) {}
|
||||
};
|
||||
AtomicReference<MediaSource> internalSourceReference = new AtomicReference<>();
|
||||
MediaSource.Factory mockMediaSourceFactory = mock(MediaSource.Factory.class);
|
||||
when(mockMediaSourceFactory.createMediaSource(any()))
|
||||
|
|
@ -639,7 +613,7 @@ public final class PreloadMediaSourceTest {
|
|||
PreloadMediaSource.Factory preloadMediaSourceFactory =
|
||||
new PreloadMediaSource.Factory(
|
||||
mockMediaSourceFactory,
|
||||
preloadControl,
|
||||
new TestPreloadControl(),
|
||||
mockTrackSelector,
|
||||
bandwidthMeter,
|
||||
getRendererCapabilities(renderersFactory),
|
||||
|
|
@ -669,36 +643,12 @@ public final class PreloadMediaSourceTest {
|
|||
MediaSource.MediaPeriodId mediaPeriodId = new MediaSource.MediaPeriodId(periodPosition.first);
|
||||
preloadMediaSource.createPeriod(mediaPeriodId, allocator, periodPosition.second);
|
||||
|
||||
assertThat(onTracksSelectedCalled.get()).isTrue();
|
||||
verify(internalSourceReference.get()).createPeriod(any(), any(), anyLong());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void createPeriodWithSameMediaPeriodIdAndDifferentStartPosition_returnNewPeriod()
|
||||
throws Exception {
|
||||
AtomicBoolean onTracksSelectedCalled = new AtomicBoolean();
|
||||
PreloadMediaSource.PreloadControl preloadControl =
|
||||
new PreloadMediaSource.PreloadControl() {
|
||||
@Override
|
||||
public boolean onSourcePrepared(PreloadMediaSource mediaSource) {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onTracksSelected(PreloadMediaSource mediaSource) {
|
||||
onTracksSelectedCalled.set(true);
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onContinueLoadingRequested(
|
||||
PreloadMediaSource mediaSource, long bufferedPositionUs) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onUsedByPlayer(PreloadMediaSource mediaSource) {}
|
||||
};
|
||||
AtomicReference<MediaSource> internalSourceReference = new AtomicReference<>();
|
||||
MediaSource.Factory mockMediaSourceFactory = mock(MediaSource.Factory.class);
|
||||
when(mockMediaSourceFactory.createMediaSource(any()))
|
||||
|
|
@ -744,7 +694,7 @@ public final class PreloadMediaSourceTest {
|
|||
PreloadMediaSource.Factory preloadMediaSourceFactory =
|
||||
new PreloadMediaSource.Factory(
|
||||
mockMediaSourceFactory,
|
||||
preloadControl,
|
||||
new TestPreloadControl(),
|
||||
mockTrackSelector,
|
||||
bandwidthMeter,
|
||||
getRendererCapabilities(renderersFactory),
|
||||
|
|
@ -775,35 +725,11 @@ public final class PreloadMediaSourceTest {
|
|||
MediaSource.MediaPeriodId mediaPeriodId = new MediaSource.MediaPeriodId(periodPosition.first);
|
||||
preloadMediaSource.createPeriod(mediaPeriodId, allocator, periodPosition.second);
|
||||
|
||||
assertThat(onTracksSelectedCalled.get()).isTrue();
|
||||
verify(internalSourceReference.get(), times(2)).createPeriod(any(), any(), anyLong());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void clear_preloadingPeriodReleased() throws Exception {
|
||||
AtomicBoolean onTracksSelectedCalled = new AtomicBoolean();
|
||||
PreloadMediaSource.PreloadControl preloadControl =
|
||||
new PreloadMediaSource.PreloadControl() {
|
||||
@Override
|
||||
public boolean onSourcePrepared(PreloadMediaSource mediaSource) {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onTracksSelected(PreloadMediaSource mediaSource) {
|
||||
onTracksSelectedCalled.set(true);
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onContinueLoadingRequested(
|
||||
PreloadMediaSource mediaSource, long bufferedPositionUs) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onUsedByPlayer(PreloadMediaSource mediaSource) {}
|
||||
};
|
||||
public void clear_preloadingPeriodReleased() {
|
||||
MediaSource.Factory mockMediaSourceFactory = mock(MediaSource.Factory.class);
|
||||
AtomicBoolean preloadingMediaPeriodReleased = new AtomicBoolean();
|
||||
when(mockMediaSourceFactory.createMediaSource(any()))
|
||||
|
|
@ -836,7 +762,7 @@ public final class PreloadMediaSourceTest {
|
|||
PreloadMediaSource.Factory preloadMediaSourceFactory =
|
||||
new PreloadMediaSource.Factory(
|
||||
mockMediaSourceFactory,
|
||||
preloadControl,
|
||||
new TestPreloadControl(),
|
||||
trackSelector,
|
||||
bandwidthMeter,
|
||||
getRendererCapabilities(renderersFactory),
|
||||
|
|
@ -848,7 +774,7 @@ public final class PreloadMediaSourceTest {
|
|||
.setUri(Uri.parse("asset://android_asset/media/mp4/sample.mp4"))
|
||||
.build());
|
||||
preloadMediaSource.preload(/* startPositionUs= */ 0L);
|
||||
runMainLooperUntil(onTracksSelectedCalled::get);
|
||||
shadowOf(Looper.getMainLooper()).idle();
|
||||
|
||||
preloadMediaSource.clear();
|
||||
shadowOf(Looper.getMainLooper()).idle();
|
||||
|
|
@ -858,27 +784,6 @@ public final class PreloadMediaSourceTest {
|
|||
|
||||
@Test
|
||||
public void releaseSourceByAllExternalCallers_preloadNotCalledBefore_releaseInternalSource() {
|
||||
PreloadMediaSource.PreloadControl preloadControl =
|
||||
new PreloadMediaSource.PreloadControl() {
|
||||
@Override
|
||||
public boolean onSourcePrepared(PreloadMediaSource mediaSource) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onTracksSelected(PreloadMediaSource mediaSource) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onContinueLoadingRequested(
|
||||
PreloadMediaSource mediaSource, long bufferedPositionUs) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onUsedByPlayer(PreloadMediaSource mediaSource) {}
|
||||
};
|
||||
AtomicReference<MediaSource> internalSourceReference = new AtomicReference<>();
|
||||
MediaSource.Factory mockMediaSourceFactory = mock(MediaSource.Factory.class);
|
||||
when(mockMediaSourceFactory.createMediaSource(any()))
|
||||
|
|
@ -904,7 +809,7 @@ public final class PreloadMediaSourceTest {
|
|||
PreloadMediaSource.Factory preloadMediaSourceFactory =
|
||||
new PreloadMediaSource.Factory(
|
||||
mockMediaSourceFactory,
|
||||
preloadControl,
|
||||
new TestPreloadControl(),
|
||||
trackSelector,
|
||||
bandwidthMeter,
|
||||
getRendererCapabilities(renderersFactory),
|
||||
|
|
@ -931,29 +836,7 @@ public final class PreloadMediaSourceTest {
|
|||
|
||||
@Test
|
||||
public void releaseSourceByAllExternalCallers_stillPreloading_notReleaseInternalSource() {
|
||||
AtomicBoolean onSourcePreparedCalled = new AtomicBoolean(false);
|
||||
PreloadMediaSource.PreloadControl preloadControl =
|
||||
new PreloadMediaSource.PreloadControl() {
|
||||
@Override
|
||||
public boolean onSourcePrepared(PreloadMediaSource mediaSource) {
|
||||
onSourcePreparedCalled.set(true);
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onTracksSelected(PreloadMediaSource mediaSource) {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onContinueLoadingRequested(
|
||||
PreloadMediaSource mediaSource, long bufferedPositionUs) {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onUsedByPlayer(PreloadMediaSource mediaSource) {}
|
||||
};
|
||||
TestPreloadControl preloadControl = new TestPreloadControl();
|
||||
AtomicReference<MediaSource> internalSourceReference = new AtomicReference<>();
|
||||
MediaSource.Factory mockMediaSourceFactory = mock(MediaSource.Factory.class);
|
||||
when(mockMediaSourceFactory.createMediaSource(any()))
|
||||
|
|
@ -999,7 +882,7 @@ public final class PreloadMediaSourceTest {
|
|||
externalCaller, bandwidthMeter.getTransferListener(), PlayerId.UNSET);
|
||||
preloadMediaSource.releaseSource(externalCaller);
|
||||
|
||||
assertThat(onSourcePreparedCalled.get()).isTrue();
|
||||
assertThat(preloadControl.onSourcePreparedCalledCount).isGreaterThan(0);
|
||||
assertThat(externalCallerSourceInfoRefreshedCalled.get()).isTrue();
|
||||
MediaSource internalSource = internalSourceReference.get();
|
||||
assertThat(internalSource).isNotNull();
|
||||
|
|
@ -1009,27 +892,6 @@ public final class PreloadMediaSourceTest {
|
|||
@Test
|
||||
public void
|
||||
releaseSourceNotByAllExternalCallers_preloadNotCalledBefore_notReleaseInternalSource() {
|
||||
PreloadMediaSource.PreloadControl preloadControl =
|
||||
new PreloadMediaSource.PreloadControl() {
|
||||
@Override
|
||||
public boolean onSourcePrepared(PreloadMediaSource mediaSource) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onTracksSelected(PreloadMediaSource mediaSource) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onContinueLoadingRequested(
|
||||
PreloadMediaSource mediaSource, long bufferedPositionUs) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onUsedByPlayer(PreloadMediaSource mediaSource) {}
|
||||
};
|
||||
AtomicReference<MediaSource> internalSourceReference = new AtomicReference<>();
|
||||
MediaSource.Factory mockMediaSourceFactory = mock(MediaSource.Factory.class);
|
||||
when(mockMediaSourceFactory.createMediaSource(any()))
|
||||
|
|
@ -1055,7 +917,7 @@ public final class PreloadMediaSourceTest {
|
|||
PreloadMediaSource.Factory preloadMediaSourceFactory =
|
||||
new PreloadMediaSource.Factory(
|
||||
mockMediaSourceFactory,
|
||||
preloadControl,
|
||||
new TestPreloadControl(),
|
||||
trackSelector,
|
||||
bandwidthMeter,
|
||||
getRendererCapabilities(renderersFactory),
|
||||
|
|
@ -1088,29 +950,7 @@ public final class PreloadMediaSourceTest {
|
|||
|
||||
@Test
|
||||
public void releasePreloadMediaSource_notUsedByExternalCallers_releaseInternalSource() {
|
||||
AtomicBoolean onSourcePreparedCalled = new AtomicBoolean(false);
|
||||
PreloadMediaSource.PreloadControl preloadControl =
|
||||
new PreloadMediaSource.PreloadControl() {
|
||||
@Override
|
||||
public boolean onSourcePrepared(PreloadMediaSource mediaSource) {
|
||||
onSourcePreparedCalled.set(true);
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onTracksSelected(PreloadMediaSource mediaSource) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onContinueLoadingRequested(
|
||||
PreloadMediaSource mediaSource, long bufferedPositionUs) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onUsedByPlayer(PreloadMediaSource mediaSource) {}
|
||||
};
|
||||
TestPreloadControl preloadControl = new TestPreloadControl();
|
||||
AtomicReference<MediaSource> internalSourceReference = new AtomicReference<>();
|
||||
MediaSource.Factory mockMediaSourceFactory = mock(MediaSource.Factory.class);
|
||||
when(mockMediaSourceFactory.createMediaSource(any()))
|
||||
|
|
@ -1152,7 +992,7 @@ public final class PreloadMediaSourceTest {
|
|||
preloadMediaSource.releasePreloadMediaSource();
|
||||
shadowOf(Looper.getMainLooper()).idle();
|
||||
|
||||
assertThat(onSourcePreparedCalled.get()).isTrue();
|
||||
assertThat(preloadControl.onSourcePreparedCalledCount).isGreaterThan(0);
|
||||
MediaSource internalSource = internalSourceReference.get();
|
||||
assertThat(internalSource).isNotNull();
|
||||
verify(internalSource).releaseSource(any());
|
||||
|
|
@ -1160,29 +1000,7 @@ public final class PreloadMediaSourceTest {
|
|||
|
||||
@Test
|
||||
public void releasePreloadMediaSource_stillUsedByExternalCallers_releaseInternalSource() {
|
||||
AtomicBoolean onSourcePreparedCalled = new AtomicBoolean(false);
|
||||
PreloadMediaSource.PreloadControl preloadControl =
|
||||
new PreloadMediaSource.PreloadControl() {
|
||||
@Override
|
||||
public boolean onSourcePrepared(PreloadMediaSource mediaSource) {
|
||||
onSourcePreparedCalled.set(true);
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onTracksSelected(PreloadMediaSource mediaSource) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onContinueLoadingRequested(
|
||||
PreloadMediaSource mediaSource, long bufferedPositionUs) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onUsedByPlayer(PreloadMediaSource mediaSource) {}
|
||||
};
|
||||
TestPreloadControl preloadControl = new TestPreloadControl();
|
||||
AtomicReference<MediaSource> internalSourceReference = new AtomicReference<>();
|
||||
MediaSource.Factory mockMediaSourceFactory = mock(MediaSource.Factory.class);
|
||||
when(mockMediaSourceFactory.createMediaSource(any()))
|
||||
|
|
@ -1230,13 +1048,57 @@ public final class PreloadMediaSourceTest {
|
|||
preloadMediaSource.releasePreloadMediaSource();
|
||||
shadowOf(Looper.getMainLooper()).idle();
|
||||
|
||||
assertThat(onSourcePreparedCalled.get()).isTrue();
|
||||
assertThat(preloadControl.onSourcePreparedCalledCount).isGreaterThan(0);
|
||||
assertThat(externalCallerSourceInfoRefreshedCalled.get()).isTrue();
|
||||
MediaSource internalSource = internalSourceReference.get();
|
||||
assertThat(internalSource).isNotNull();
|
||||
verify(internalSource, times(0)).releaseSource(any());
|
||||
}
|
||||
|
||||
private static class TestPreloadControl implements PreloadMediaSource.PreloadControl {
|
||||
|
||||
public int onSourcePreparedCalledCount;
|
||||
public boolean onTrackSelectedCalled;
|
||||
public boolean onContinueLoadingRequestedCalled;
|
||||
public boolean onUsedByPlayerCalled;
|
||||
public boolean onLoadedToTheEndOfSourceCalled;
|
||||
public boolean onPreloadErrorCalled;
|
||||
|
||||
@Override
|
||||
public boolean onSourcePrepared(PreloadMediaSource mediaSource) {
|
||||
onSourcePreparedCalledCount++;
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onTracksSelected(PreloadMediaSource mediaSource) {
|
||||
onTrackSelectedCalled = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onContinueLoadingRequested(
|
||||
PreloadMediaSource mediaSource, long bufferedPositionUs) {
|
||||
onContinueLoadingRequestedCalled = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onUsedByPlayer(PreloadMediaSource mediaSource) {
|
||||
onUsedByPlayerCalled = true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onLoadedToTheEndOfSource(PreloadMediaSource mediaSource) {
|
||||
onLoadedToTheEndOfSourceCalled = true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPreloadError(PreloadException error, PreloadMediaSource mediaSource) {
|
||||
onPreloadErrorCalled = true;
|
||||
}
|
||||
}
|
||||
|
||||
private static RendererCapabilities[] getRendererCapabilities(RenderersFactory renderersFactory) {
|
||||
Renderer[] renderers =
|
||||
renderersFactory.createRenderers(
|
||||
|
|
|
|||
Loading…
Reference in a new issue