mirror of
https://github.com/samsonjs/media.git
synced 2026-04-27 15:07:40 +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
|
every media item. Previously it was not called for the first one. Use
|
||||||
`MediaCodecRenderer.experimentalEnableProcessedStreamChangedAtStart()`
|
`MediaCodecRenderer.experimentalEnableProcessedStreamChangedAtStart()`
|
||||||
to enable this.
|
to enable this.
|
||||||
|
* Add `PreloadMediaSource.PreloadControl.onPreloadError` to allow
|
||||||
|
`PreloadMediaSource.PreloadControl` implementations to take actions when
|
||||||
|
error occurs.
|
||||||
* Transformer:
|
* Transformer:
|
||||||
* Track Selection:
|
* Track Selection:
|
||||||
* Extractors:
|
* Extractors:
|
||||||
|
|
|
||||||
|
|
@ -249,6 +249,11 @@ public final class DefaultPreloadManager extends BasePreloadManager<Integer> {
|
||||||
onPreloadCompleted(mediaSource);
|
onPreloadCompleted(mediaSource);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onPreloadError(PreloadException error, PreloadMediaSource mediaSource) {
|
||||||
|
onPreloadCompleted(mediaSource);
|
||||||
|
}
|
||||||
|
|
||||||
private boolean continueOrCompletePreloading(
|
private boolean continueOrCompletePreloading(
|
||||||
PreloadMediaSource mediaSource,
|
PreloadMediaSource mediaSource,
|
||||||
Predicate<Status> continueLoadingPredicate,
|
Predicate<Status> continueLoadingPredicate,
|
||||||
|
|
|
||||||
|
|
@ -16,6 +16,7 @@
|
||||||
package androidx.media3.exoplayer.source.preload;
|
package androidx.media3.exoplayer.source.preload;
|
||||||
|
|
||||||
import static androidx.media3.common.util.Assertions.checkNotNull;
|
import static androidx.media3.common.util.Assertions.checkNotNull;
|
||||||
|
import static androidx.media3.common.util.Util.postOrRun;
|
||||||
|
|
||||||
import android.os.Handler;
|
import android.os.Handler;
|
||||||
import android.os.Looper;
|
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.BandwidthMeter;
|
||||||
import androidx.media3.exoplayer.upstream.CmcdConfiguration;
|
import androidx.media3.exoplayer.upstream.CmcdConfiguration;
|
||||||
import androidx.media3.exoplayer.upstream.LoadErrorHandlingPolicy;
|
import androidx.media3.exoplayer.upstream.LoadErrorHandlingPolicy;
|
||||||
|
import java.io.IOException;
|
||||||
import java.util.Arrays;
|
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.
|
* @param mediaSource The {@link PreloadMediaSource} that has loaded to the end of source.
|
||||||
*/
|
*/
|
||||||
default void onLoadedToTheEndOfSource(PreloadMediaSource mediaSource) {}
|
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}. */
|
/** Factory for {@link PreloadMediaSource}. */
|
||||||
|
|
@ -203,6 +213,7 @@ public final class PreloadMediaSource extends WrappingMediaSource {
|
||||||
}
|
}
|
||||||
|
|
||||||
private static final String TAG = "PreloadMediaSource";
|
private static final String TAG = "PreloadMediaSource";
|
||||||
|
private static final long CHECK_FOR_PRELOAD_ERROR_INTERVAL_MS = 100;
|
||||||
|
|
||||||
private final PreloadControl preloadControl;
|
private final PreloadControl preloadControl;
|
||||||
private final TrackSelector trackSelector;
|
private final TrackSelector trackSelector;
|
||||||
|
|
@ -253,10 +264,11 @@ public final class PreloadMediaSource extends WrappingMediaSource {
|
||||||
this.startPositionUs = startPositionUs;
|
this.startPositionUs = startPositionUs;
|
||||||
onSourcePreparedNotified = false;
|
onSourcePreparedNotified = false;
|
||||||
if (isUsedByPlayer()) {
|
if (isUsedByPlayer()) {
|
||||||
notifyOnUsedByPlayer();
|
onUsedByPlayer();
|
||||||
} else {
|
} else {
|
||||||
setPlayerId(PlayerId.UNSET); // Set to PlayerId.UNSET as there is no ongoing playback.
|
setPlayerId(PlayerId.UNSET); // Set to PlayerId.UNSET as there is no ongoing playback.
|
||||||
prepareSourceInternal(bandwidthMeter.getTransferListener());
|
prepareSourceInternal(bandwidthMeter.getTransferListener());
|
||||||
|
checkForPreloadError();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
@ -267,7 +279,8 @@ public final class PreloadMediaSource extends WrappingMediaSource {
|
||||||
* <p>Can be called from any thread.
|
* <p>Can be called from any thread.
|
||||||
*/
|
*/
|
||||||
public void clear() {
|
public void clear() {
|
||||||
preloadHandler.post(
|
postOrRun(
|
||||||
|
preloadHandler,
|
||||||
() -> {
|
() -> {
|
||||||
if (preloadingMediaPeriodAndKey != null) {
|
if (preloadingMediaPeriodAndKey != null) {
|
||||||
mediaSource.releasePeriod(preloadingMediaPeriodAndKey.first.mediaPeriod);
|
mediaSource.releasePeriod(preloadingMediaPeriodAndKey.first.mediaPeriod);
|
||||||
|
|
@ -279,7 +292,7 @@ public final class PreloadMediaSource extends WrappingMediaSource {
|
||||||
@Override
|
@Override
|
||||||
protected void prepareSourceInternal() {
|
protected void prepareSourceInternal() {
|
||||||
if (isUsedByPlayer() && !onUsedByPlayerNotified) {
|
if (isUsedByPlayer() && !onUsedByPlayerNotified) {
|
||||||
notifyOnUsedByPlayer();
|
onUsedByPlayer();
|
||||||
}
|
}
|
||||||
if (timeline != null) {
|
if (timeline != null) {
|
||||||
onChildSourceInfoRefreshed(timeline);
|
onChildSourceInfoRefreshed(timeline);
|
||||||
|
|
@ -298,6 +311,7 @@ public final class PreloadMediaSource extends WrappingMediaSource {
|
||||||
}
|
}
|
||||||
onSourcePreparedNotified = true;
|
onSourcePreparedNotified = true;
|
||||||
if (!preloadControl.onSourcePrepared(this)) {
|
if (!preloadControl.onSourcePrepared(this)) {
|
||||||
|
stopPreloading();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
Pair<Object, Long> periodPosition =
|
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 class PreloadMediaPeriodCallback implements MediaPeriod.Callback {
|
||||||
|
|
||||||
private final long periodStartPositionUs;
|
private final long periodStartPositionUs;
|
||||||
|
|
@ -419,14 +469,18 @@ public final class PreloadMediaSource extends WrappingMediaSource {
|
||||||
} catch (ExoPlaybackException e) {
|
} catch (ExoPlaybackException e) {
|
||||||
Log.e(TAG, "Failed to select tracks", e);
|
Log.e(TAG, "Failed to select tracks", e);
|
||||||
}
|
}
|
||||||
if (trackSelectorResult != null) {
|
if (trackSelectorResult == null) {
|
||||||
preloadMediaPeriod.selectTracksForPreloading(
|
stopPreloading();
|
||||||
trackSelectorResult.selections, periodStartPositionUs);
|
return;
|
||||||
if (preloadControl.onTracksSelected(PreloadMediaSource.this)) {
|
|
||||||
preloadMediaPeriod.continueLoading(
|
|
||||||
new LoadingInfo.Builder().setPlaybackPositionUs(periodStartPositionUs).build());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
preloadMediaPeriod.selectTracksForPreloading(
|
||||||
|
trackSelectorResult.selections, periodStartPositionUs);
|
||||||
|
if (!preloadControl.onTracksSelected(PreloadMediaSource.this)) {
|
||||||
|
stopPreloading();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
preloadMediaPeriod.continueLoading(
|
||||||
|
new LoadingInfo.Builder().setPlaybackPositionUs(periodStartPositionUs).build());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
@ -437,32 +491,20 @@ public final class PreloadMediaSource extends WrappingMediaSource {
|
||||||
PreloadMediaPeriod preloadMediaPeriod = (PreloadMediaPeriod) mediaPeriod;
|
PreloadMediaPeriod preloadMediaPeriod = (PreloadMediaPeriod) mediaPeriod;
|
||||||
if (prepared && mediaPeriod.getBufferedPositionUs() == C.TIME_END_OF_SOURCE) {
|
if (prepared && mediaPeriod.getBufferedPositionUs() == C.TIME_END_OF_SOURCE) {
|
||||||
preloadControl.onLoadedToTheEndOfSource(PreloadMediaSource.this);
|
preloadControl.onLoadedToTheEndOfSource(PreloadMediaSource.this);
|
||||||
} else if (!prepared
|
stopPreloading();
|
||||||
|| preloadControl.onContinueLoadingRequested(
|
return;
|
||||||
PreloadMediaSource.this, preloadMediaPeriod.getBufferedPositionUs())) {
|
|
||||||
preloadMediaPeriod.continueLoading(
|
|
||||||
new LoadingInfo.Builder().setPlaybackPositionUs(periodStartPositionUs).build());
|
|
||||||
}
|
}
|
||||||
|
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 {
|
private static class MediaPeriodKey {
|
||||||
|
|
||||||
public final MediaSource.MediaPeriodId mediaPeriodId;
|
public final MediaSource.MediaPeriodId mediaPeriodId;
|
||||||
|
|
|
||||||
|
|
@ -124,6 +124,9 @@ public class PreloadAndPlaybackCoordinationTest {
|
||||||
public void onUsedByPlayer(PreloadMediaSource mediaSource) {
|
public void onUsedByPlayer(PreloadMediaSource mediaSource) {
|
||||||
preloadControlOnUsedByPlayerCounter.addAndGet(1);
|
preloadControlOnUsedByPlayerCounter.addAndGet(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onPreloadError(PreloadException error, PreloadMediaSource mediaSource) {}
|
||||||
};
|
};
|
||||||
PreloadMediaSource.Factory preloadMediaSourceFactory =
|
PreloadMediaSource.Factory preloadMediaSourceFactory =
|
||||||
new PreloadMediaSource.Factory(
|
new PreloadMediaSource.Factory(
|
||||||
|
|
|
||||||
|
|
@ -46,6 +46,7 @@ import androidx.media3.exoplayer.analytics.PlayerId;
|
||||||
import androidx.media3.exoplayer.audio.AudioRendererEventListener;
|
import androidx.media3.exoplayer.audio.AudioRendererEventListener;
|
||||||
import androidx.media3.exoplayer.drm.DrmSessionEventListener;
|
import androidx.media3.exoplayer.drm.DrmSessionEventListener;
|
||||||
import androidx.media3.exoplayer.drm.DrmSessionManager;
|
import androidx.media3.exoplayer.drm.DrmSessionManager;
|
||||||
|
import androidx.media3.exoplayer.drm.DrmSessionManagerProvider;
|
||||||
import androidx.media3.exoplayer.metadata.MetadataOutput;
|
import androidx.media3.exoplayer.metadata.MetadataOutput;
|
||||||
import androidx.media3.exoplayer.source.MediaPeriod;
|
import androidx.media3.exoplayer.source.MediaPeriod;
|
||||||
import androidx.media3.exoplayer.source.MediaSource;
|
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.BandwidthMeter;
|
||||||
import androidx.media3.exoplayer.upstream.DefaultAllocator;
|
import androidx.media3.exoplayer.upstream.DefaultAllocator;
|
||||||
import androidx.media3.exoplayer.upstream.DefaultBandwidthMeter;
|
import androidx.media3.exoplayer.upstream.DefaultBandwidthMeter;
|
||||||
|
import androidx.media3.exoplayer.upstream.LoadErrorHandlingPolicy;
|
||||||
import androidx.media3.exoplayer.video.VideoRendererEventListener;
|
import androidx.media3.exoplayer.video.VideoRendererEventListener;
|
||||||
import androidx.media3.test.utils.FakeAudioRenderer;
|
import androidx.media3.test.utils.FakeAudioRenderer;
|
||||||
import androidx.media3.test.utils.FakeMediaPeriod;
|
import androidx.media3.test.utils.FakeMediaPeriod;
|
||||||
|
|
@ -71,8 +73,9 @@ import androidx.media3.test.utils.FakeTrackSelector;
|
||||||
import androidx.media3.test.utils.FakeVideoRenderer;
|
import androidx.media3.test.utils.FakeVideoRenderer;
|
||||||
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.io.IOException;
|
||||||
|
import java.util.concurrent.TimeoutException;
|
||||||
import java.util.concurrent.atomic.AtomicBoolean;
|
import java.util.concurrent.atomic.AtomicBoolean;
|
||||||
import java.util.concurrent.atomic.AtomicInteger;
|
|
||||||
import java.util.concurrent.atomic.AtomicReference;
|
import java.util.concurrent.atomic.AtomicReference;
|
||||||
import org.junit.Before;
|
import org.junit.Before;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
|
|
@ -108,40 +111,19 @@ public final class PreloadMediaSourceTest {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void preload_loadPeriodToTargetPreloadPosition() throws Exception {
|
public void preload_loadPeriodToTargetPreloadPosition() throws Exception {
|
||||||
AtomicInteger onSourcePreparedCounter = new AtomicInteger();
|
|
||||||
AtomicBoolean onTracksSelectedCalled = new AtomicBoolean();
|
|
||||||
AtomicBoolean onContinueLoadingStopped = new AtomicBoolean();
|
|
||||||
AtomicReference<PreloadMediaSource> preloadMediaSourceReference = new AtomicReference<>();
|
AtomicReference<PreloadMediaSource> preloadMediaSourceReference = new AtomicReference<>();
|
||||||
AtomicBoolean onUsedByPlayerCalled = new AtomicBoolean();
|
TestPreloadControl preloadControl =
|
||||||
PreloadMediaSource.PreloadControl preloadControl =
|
new TestPreloadControl() {
|
||||||
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
|
@Override
|
||||||
public boolean onContinueLoadingRequested(
|
public boolean onContinueLoadingRequested(
|
||||||
PreloadMediaSource mediaSource, long bufferedPositionUs) {
|
PreloadMediaSource mediaSource, long bufferedPositionUs) {
|
||||||
preloadMediaSourceReference.set(mediaSource);
|
onContinueLoadingRequestedCalled = true;
|
||||||
if (bufferedPositionUs >= TARGET_PRELOAD_POSITION_US) {
|
if (bufferedPositionUs >= TARGET_PRELOAD_POSITION_US) {
|
||||||
onContinueLoadingStopped.set(true);
|
preloadMediaSourceReference.set(mediaSource);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onUsedByPlayer(PreloadMediaSource mediaSource) {
|
|
||||||
onUsedByPlayerCalled.set(true);
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
ProgressiveMediaSource.Factory mediaSourceFactory =
|
ProgressiveMediaSource.Factory mediaSourceFactory =
|
||||||
new ProgressiveMediaSource.Factory(
|
new ProgressiveMediaSource.Factory(
|
||||||
|
|
@ -166,47 +148,27 @@ public final class PreloadMediaSourceTest {
|
||||||
.build());
|
.build());
|
||||||
|
|
||||||
preloadMediaSource.preload(/* startPositionUs= */ 0L);
|
preloadMediaSource.preload(/* startPositionUs= */ 0L);
|
||||||
runMainLooperUntil(onContinueLoadingStopped::get);
|
runMainLooperUntil(() -> preloadMediaSourceReference.get() != null);
|
||||||
|
|
||||||
assertThat(onSourcePreparedCounter.get()).isEqualTo(1);
|
assertThat(preloadControl.onSourcePreparedCalledCount).isEqualTo(1);
|
||||||
assertThat(onTracksSelectedCalled.get()).isTrue();
|
assertThat(preloadControl.onTrackSelectedCalled).isTrue();
|
||||||
assertThat(onUsedByPlayerCalled.get()).isFalse();
|
assertThat(preloadControl.onContinueLoadingRequestedCalled).isTrue();
|
||||||
|
assertThat(preloadControl.onUsedByPlayerCalled).isFalse();
|
||||||
|
assertThat(preloadControl.onPreloadErrorCalled).isFalse();
|
||||||
assertThat(preloadMediaSourceReference.get()).isSameInstanceAs(preloadMediaSource);
|
assertThat(preloadMediaSourceReference.get()).isSameInstanceAs(preloadMediaSource);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void preload_stopWhenTracksSelectedByPreloadControl() throws Exception {
|
public void preload_stopWhenTracksSelectedByPreloadControl() throws Exception {
|
||||||
AtomicInteger onSourcePreparedCounter = new AtomicInteger();
|
|
||||||
AtomicBoolean onTracksSelectedCalled = new AtomicBoolean();
|
|
||||||
AtomicReference<PreloadMediaSource> preloadMediaSourceReference = new AtomicReference<>();
|
AtomicReference<PreloadMediaSource> preloadMediaSourceReference = new AtomicReference<>();
|
||||||
AtomicBoolean onContinueLoadingRequestedCalled = new AtomicBoolean();
|
TestPreloadControl preloadControl =
|
||||||
AtomicBoolean onUsedByPlayerCalled = new AtomicBoolean();
|
new TestPreloadControl() {
|
||||||
PreloadMediaSource.PreloadControl preloadControl =
|
|
||||||
new PreloadMediaSource.PreloadControl() {
|
|
||||||
@Override
|
|
||||||
public boolean onSourcePrepared(PreloadMediaSource mediaSource) {
|
|
||||||
onSourcePreparedCounter.addAndGet(1);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean onTracksSelected(PreloadMediaSource mediaSource) {
|
public boolean onTracksSelected(PreloadMediaSource mediaSource) {
|
||||||
|
onTrackSelectedCalled = true;
|
||||||
preloadMediaSourceReference.set(mediaSource);
|
preloadMediaSourceReference.set(mediaSource);
|
||||||
onTracksSelectedCalled.set(true);
|
|
||||||
return false;
|
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 =
|
ProgressiveMediaSource.Factory mediaSourceFactory =
|
||||||
new ProgressiveMediaSource.Factory(
|
new ProgressiveMediaSource.Factory(
|
||||||
|
|
@ -231,47 +193,27 @@ public final class PreloadMediaSourceTest {
|
||||||
.build());
|
.build());
|
||||||
|
|
||||||
preloadMediaSource.preload(/* startPositionUs= */ 0L);
|
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(preloadMediaSourceReference.get()).isSameInstanceAs(preloadMediaSource);
|
||||||
assertThat(onContinueLoadingRequestedCalled.get()).isFalse();
|
assertThat(preloadControl.onContinueLoadingRequestedCalled).isFalse();
|
||||||
assertThat(onUsedByPlayerCalled.get()).isFalse();
|
assertThat(preloadControl.onPreloadErrorCalled).isFalse();
|
||||||
|
assertThat(preloadControl.onUsedByPlayerCalled).isFalse();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void preload_stopWhenSourcePreparedByPreloadControl() throws Exception {
|
public void preload_stopWhenSourcePreparedByPreloadControl() {
|
||||||
AtomicInteger onSourcePreparedCounter = new AtomicInteger();
|
|
||||||
AtomicReference<PreloadMediaSource> preloadMediaSourceReference = new AtomicReference<>();
|
AtomicReference<PreloadMediaSource> preloadMediaSourceReference = new AtomicReference<>();
|
||||||
AtomicBoolean onTracksSelectedCalled = new AtomicBoolean();
|
TestPreloadControl preloadControl =
|
||||||
AtomicBoolean onContinueLoadingRequestedCalled = new AtomicBoolean();
|
new TestPreloadControl() {
|
||||||
AtomicBoolean onUsedByPlayerCalled = new AtomicBoolean();
|
|
||||||
PreloadMediaSource.PreloadControl preloadControl =
|
|
||||||
new PreloadMediaSource.PreloadControl() {
|
|
||||||
@Override
|
@Override
|
||||||
public boolean onSourcePrepared(PreloadMediaSource mediaSource) {
|
public boolean onSourcePrepared(PreloadMediaSource mediaSource) {
|
||||||
|
onSourcePreparedCalledCount++;
|
||||||
preloadMediaSourceReference.set(mediaSource);
|
preloadMediaSourceReference.set(mediaSource);
|
||||||
onSourcePreparedCounter.addAndGet(1);
|
|
||||||
return false;
|
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 =
|
ProgressiveMediaSource.Factory mediaSourceFactory =
|
||||||
new ProgressiveMediaSource.Factory(
|
new ProgressiveMediaSource.Factory(
|
||||||
|
|
@ -298,42 +240,16 @@ public final class PreloadMediaSourceTest {
|
||||||
shadowOf(Looper.getMainLooper()).idle();
|
shadowOf(Looper.getMainLooper()).idle();
|
||||||
|
|
||||||
assertThat(preloadMediaSourceReference.get()).isSameInstanceAs(preloadMediaSource);
|
assertThat(preloadMediaSourceReference.get()).isSameInstanceAs(preloadMediaSource);
|
||||||
assertThat(onSourcePreparedCounter.get()).isEqualTo(1);
|
assertThat(preloadControl.onSourcePreparedCalledCount).isEqualTo(1);
|
||||||
assertThat(onTracksSelectedCalled.get()).isFalse();
|
assertThat(preloadControl.onTrackSelectedCalled).isFalse();
|
||||||
assertThat(onContinueLoadingRequestedCalled.get()).isFalse();
|
assertThat(preloadControl.onContinueLoadingRequestedCalled).isFalse();
|
||||||
assertThat(onUsedByPlayerCalled.get()).isFalse();
|
assertThat(preloadControl.onUsedByPlayerCalled).isFalse();
|
||||||
|
assertThat(preloadControl.onPreloadErrorCalled).isFalse();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void preload_whileSourceIsAccessedByExternalCaller_notProceedWithPreloading() {
|
public void preload_whileSourceIsAccessedByExternalCaller_notProceedWithPreloading() {
|
||||||
AtomicBoolean onSourcePreparedCalled = new AtomicBoolean(false);
|
TestPreloadControl preloadControl = new TestPreloadControl();
|
||||||
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);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
TrackSelector trackSelector = new FakeTrackSelector();
|
TrackSelector trackSelector = new FakeTrackSelector();
|
||||||
trackSelector.init(() -> {}, bandwidthMeter);
|
trackSelector.init(() -> {}, bandwidthMeter);
|
||||||
PreloadMediaSource.Factory preloadMediaSourceFactory =
|
PreloadMediaSource.Factory preloadMediaSourceFactory =
|
||||||
|
|
@ -361,52 +277,21 @@ public final class PreloadMediaSourceTest {
|
||||||
shadowOf(Looper.getMainLooper()).idle();
|
shadowOf(Looper.getMainLooper()).idle();
|
||||||
|
|
||||||
assertThat(externalCallerMediaSourceReference.get()).isSameInstanceAs(preloadMediaSource);
|
assertThat(externalCallerMediaSourceReference.get()).isSameInstanceAs(preloadMediaSource);
|
||||||
assertThat(onSourcePreparedCalled.get()).isFalse();
|
assertThat(preloadControl.onSourcePreparedCalledCount).isEqualTo(0);
|
||||||
assertThat(onTracksSelectedCalled.get()).isFalse();
|
assertThat(preloadControl.onTrackSelectedCalled).isFalse();
|
||||||
assertThat(onUsedByPlayerCalled.get()).isTrue();
|
assertThat(preloadControl.onUsedByPlayerCalled).isTrue();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void preload_loadToTheEndOfSource() throws Exception {
|
public void preload_loadToTheEndOfSource() throws Exception {
|
||||||
AtomicInteger onSourcePreparedCounter = new AtomicInteger();
|
AtomicReference<PreloadMediaSource> preloadMediaSourceReference = new AtomicReference<>();
|
||||||
AtomicBoolean onTracksSelectedCalled = new AtomicBoolean();
|
TestPreloadControl preloadControl =
|
||||||
AtomicBoolean onContinueLoadingRequestedCalled = new AtomicBoolean();
|
new TestPreloadControl() {
|
||||||
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);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onLoadedToTheEndOfSource(PreloadMediaSource mediaSource) {
|
public void onLoadedToTheEndOfSource(PreloadMediaSource mediaSource) {
|
||||||
onLoadedToTheEndOfSourceCalled.set(true);
|
super.onLoadedToTheEndOfSource(mediaSource);
|
||||||
|
onLoadedToTheEndOfSourceCalled = true;
|
||||||
|
preloadMediaSourceReference.set(mediaSource);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
ProgressiveMediaSource.Factory mediaSourceFactory =
|
ProgressiveMediaSource.Factory mediaSourceFactory =
|
||||||
|
|
@ -432,45 +317,184 @@ public final class PreloadMediaSourceTest {
|
||||||
.build());
|
.build());
|
||||||
|
|
||||||
preloadMediaSource.preload(/* startPositionUs= */ 0L);
|
preloadMediaSource.preload(/* startPositionUs= */ 0L);
|
||||||
runMainLooperUntil(onLoadedToTheEndOfSourceCalled::get);
|
runMainLooperUntil(() -> preloadMediaSourceReference.get() != null);
|
||||||
|
|
||||||
assertThat(onSourcePreparedCounter.get()).isEqualTo(1);
|
assertThat(preloadControl.onSourcePreparedCalledCount).isEqualTo(1);
|
||||||
assertThat(onTracksSelectedCalled.get()).isTrue();
|
assertThat(preloadControl.onTrackSelectedCalled).isTrue();
|
||||||
assertThat(onContinueLoadingRequestedCalled.get()).isTrue();
|
// In fact, PreloadControl.onContinueLoadingRequested is not necessarily to be called if the
|
||||||
assertThat(onUsedByPlayerCalled.get()).isFalse();
|
// 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
|
@Test
|
||||||
public void
|
public void
|
||||||
prepareSource_beforeSourceInfoRefreshedForPreloading_onlyInvokeExternalCallerOnSourceInfoRefreshed() {
|
prepareSource_beforeSourceInfoRefreshedForPreloading_onlyInvokeExternalCallerOnSourceInfoRefreshed() {
|
||||||
AtomicBoolean onSourcePreparedCalled = new AtomicBoolean(false);
|
TestPreloadControl preloadControl = new TestPreloadControl();
|
||||||
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);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
FakeMediaSourceFactory mediaSourceFactory = new FakeMediaSourceFactory();
|
FakeMediaSourceFactory mediaSourceFactory = new FakeMediaSourceFactory();
|
||||||
TrackSelector trackSelector = new FakeTrackSelector();
|
TrackSelector trackSelector = new FakeTrackSelector();
|
||||||
trackSelector.init(() -> {}, bandwidthMeter);
|
trackSelector.init(() -> {}, bandwidthMeter);
|
||||||
|
|
@ -501,41 +525,14 @@ public final class PreloadMediaSourceTest {
|
||||||
shadowOf(Looper.getMainLooper()).idle();
|
shadowOf(Looper.getMainLooper()).idle();
|
||||||
|
|
||||||
assertThat(externalCallerMediaSourceReference.get()).isSameInstanceAs(preloadMediaSource);
|
assertThat(externalCallerMediaSourceReference.get()).isSameInstanceAs(preloadMediaSource);
|
||||||
assertThat(onSourcePreparedCalled.get()).isFalse();
|
assertThat(preloadControl.onSourcePreparedCalledCount).isEqualTo(0);
|
||||||
assertThat(onTracksSelectedCalled.get()).isFalse();
|
assertThat(preloadControl.onTrackSelectedCalled).isFalse();
|
||||||
assertThat(onUsedByPlayerCalled.get()).isTrue();
|
assertThat(preloadControl.onUsedByPlayerCalled).isTrue();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void prepareSource_afterPreload_immediatelyInvokeExternalCallerOnSourceInfoRefreshed() {
|
public void prepareSource_afterPreload_immediatelyInvokeExternalCallerOnSourceInfoRefreshed() {
|
||||||
AtomicBoolean onSourcePreparedCalled = new AtomicBoolean(false);
|
TestPreloadControl preloadControl = new TestPreloadControl();
|
||||||
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);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
FakeMediaSourceFactory mediaSourceFactory = new FakeMediaSourceFactory();
|
FakeMediaSourceFactory mediaSourceFactory = new FakeMediaSourceFactory();
|
||||||
TrackSelector trackSelector = new FakeTrackSelector();
|
TrackSelector trackSelector = new FakeTrackSelector();
|
||||||
trackSelector.init(() -> {}, bandwidthMeter);
|
trackSelector.init(() -> {}, bandwidthMeter);
|
||||||
|
|
@ -562,38 +559,15 @@ public final class PreloadMediaSourceTest {
|
||||||
preloadMediaSource.prepareSource(
|
preloadMediaSource.prepareSource(
|
||||||
externalCaller, bandwidthMeter.getTransferListener(), PlayerId.UNSET);
|
externalCaller, bandwidthMeter.getTransferListener(), PlayerId.UNSET);
|
||||||
|
|
||||||
assertThat(onSourcePreparedCalled.get()).isTrue();
|
assertThat(preloadControl.onSourcePreparedCalledCount).isGreaterThan(0);
|
||||||
assertThat(onTracksSelectedCalled.get()).isTrue();
|
assertThat(preloadControl.onTrackSelectedCalled).isTrue();
|
||||||
assertThat(externalCallerMediaSourceReference.get()).isSameInstanceAs(preloadMediaSource);
|
assertThat(externalCallerMediaSourceReference.get()).isSameInstanceAs(preloadMediaSource);
|
||||||
assertThat(onUsedByPlayerCalled.get()).isTrue();
|
assertThat(preloadControl.onUsedByPlayerCalled).isTrue();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void createPeriodWithSameMediaPeriodIdAndStartPosition_returnExistingPeriod()
|
public void createPeriodWithSameMediaPeriodIdAndStartPosition_returnExistingPeriod()
|
||||||
throws Exception {
|
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<>();
|
AtomicReference<MediaSource> internalSourceReference = new AtomicReference<>();
|
||||||
MediaSource.Factory mockMediaSourceFactory = mock(MediaSource.Factory.class);
|
MediaSource.Factory mockMediaSourceFactory = mock(MediaSource.Factory.class);
|
||||||
when(mockMediaSourceFactory.createMediaSource(any()))
|
when(mockMediaSourceFactory.createMediaSource(any()))
|
||||||
|
|
@ -639,7 +613,7 @@ public final class PreloadMediaSourceTest {
|
||||||
PreloadMediaSource.Factory preloadMediaSourceFactory =
|
PreloadMediaSource.Factory preloadMediaSourceFactory =
|
||||||
new PreloadMediaSource.Factory(
|
new PreloadMediaSource.Factory(
|
||||||
mockMediaSourceFactory,
|
mockMediaSourceFactory,
|
||||||
preloadControl,
|
new TestPreloadControl(),
|
||||||
mockTrackSelector,
|
mockTrackSelector,
|
||||||
bandwidthMeter,
|
bandwidthMeter,
|
||||||
getRendererCapabilities(renderersFactory),
|
getRendererCapabilities(renderersFactory),
|
||||||
|
|
@ -669,36 +643,12 @@ public final class PreloadMediaSourceTest {
|
||||||
MediaSource.MediaPeriodId mediaPeriodId = new MediaSource.MediaPeriodId(periodPosition.first);
|
MediaSource.MediaPeriodId mediaPeriodId = new MediaSource.MediaPeriodId(periodPosition.first);
|
||||||
preloadMediaSource.createPeriod(mediaPeriodId, allocator, periodPosition.second);
|
preloadMediaSource.createPeriod(mediaPeriodId, allocator, periodPosition.second);
|
||||||
|
|
||||||
assertThat(onTracksSelectedCalled.get()).isTrue();
|
|
||||||
verify(internalSourceReference.get()).createPeriod(any(), any(), anyLong());
|
verify(internalSourceReference.get()).createPeriod(any(), any(), anyLong());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void createPeriodWithSameMediaPeriodIdAndDifferentStartPosition_returnNewPeriod()
|
public void createPeriodWithSameMediaPeriodIdAndDifferentStartPosition_returnNewPeriod()
|
||||||
throws Exception {
|
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<>();
|
AtomicReference<MediaSource> internalSourceReference = new AtomicReference<>();
|
||||||
MediaSource.Factory mockMediaSourceFactory = mock(MediaSource.Factory.class);
|
MediaSource.Factory mockMediaSourceFactory = mock(MediaSource.Factory.class);
|
||||||
when(mockMediaSourceFactory.createMediaSource(any()))
|
when(mockMediaSourceFactory.createMediaSource(any()))
|
||||||
|
|
@ -744,7 +694,7 @@ public final class PreloadMediaSourceTest {
|
||||||
PreloadMediaSource.Factory preloadMediaSourceFactory =
|
PreloadMediaSource.Factory preloadMediaSourceFactory =
|
||||||
new PreloadMediaSource.Factory(
|
new PreloadMediaSource.Factory(
|
||||||
mockMediaSourceFactory,
|
mockMediaSourceFactory,
|
||||||
preloadControl,
|
new TestPreloadControl(),
|
||||||
mockTrackSelector,
|
mockTrackSelector,
|
||||||
bandwidthMeter,
|
bandwidthMeter,
|
||||||
getRendererCapabilities(renderersFactory),
|
getRendererCapabilities(renderersFactory),
|
||||||
|
|
@ -775,35 +725,11 @@ public final class PreloadMediaSourceTest {
|
||||||
MediaSource.MediaPeriodId mediaPeriodId = new MediaSource.MediaPeriodId(periodPosition.first);
|
MediaSource.MediaPeriodId mediaPeriodId = new MediaSource.MediaPeriodId(periodPosition.first);
|
||||||
preloadMediaSource.createPeriod(mediaPeriodId, allocator, periodPosition.second);
|
preloadMediaSource.createPeriod(mediaPeriodId, allocator, periodPosition.second);
|
||||||
|
|
||||||
assertThat(onTracksSelectedCalled.get()).isTrue();
|
|
||||||
verify(internalSourceReference.get(), times(2)).createPeriod(any(), any(), anyLong());
|
verify(internalSourceReference.get(), times(2)).createPeriod(any(), any(), anyLong());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void clear_preloadingPeriodReleased() throws Exception {
|
public void clear_preloadingPeriodReleased() {
|
||||||
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) {}
|
|
||||||
};
|
|
||||||
MediaSource.Factory mockMediaSourceFactory = mock(MediaSource.Factory.class);
|
MediaSource.Factory mockMediaSourceFactory = mock(MediaSource.Factory.class);
|
||||||
AtomicBoolean preloadingMediaPeriodReleased = new AtomicBoolean();
|
AtomicBoolean preloadingMediaPeriodReleased = new AtomicBoolean();
|
||||||
when(mockMediaSourceFactory.createMediaSource(any()))
|
when(mockMediaSourceFactory.createMediaSource(any()))
|
||||||
|
|
@ -836,7 +762,7 @@ public final class PreloadMediaSourceTest {
|
||||||
PreloadMediaSource.Factory preloadMediaSourceFactory =
|
PreloadMediaSource.Factory preloadMediaSourceFactory =
|
||||||
new PreloadMediaSource.Factory(
|
new PreloadMediaSource.Factory(
|
||||||
mockMediaSourceFactory,
|
mockMediaSourceFactory,
|
||||||
preloadControl,
|
new TestPreloadControl(),
|
||||||
trackSelector,
|
trackSelector,
|
||||||
bandwidthMeter,
|
bandwidthMeter,
|
||||||
getRendererCapabilities(renderersFactory),
|
getRendererCapabilities(renderersFactory),
|
||||||
|
|
@ -848,7 +774,7 @@ public final class PreloadMediaSourceTest {
|
||||||
.setUri(Uri.parse("asset://android_asset/media/mp4/sample.mp4"))
|
.setUri(Uri.parse("asset://android_asset/media/mp4/sample.mp4"))
|
||||||
.build());
|
.build());
|
||||||
preloadMediaSource.preload(/* startPositionUs= */ 0L);
|
preloadMediaSource.preload(/* startPositionUs= */ 0L);
|
||||||
runMainLooperUntil(onTracksSelectedCalled::get);
|
shadowOf(Looper.getMainLooper()).idle();
|
||||||
|
|
||||||
preloadMediaSource.clear();
|
preloadMediaSource.clear();
|
||||||
shadowOf(Looper.getMainLooper()).idle();
|
shadowOf(Looper.getMainLooper()).idle();
|
||||||
|
|
@ -858,27 +784,6 @@ public final class PreloadMediaSourceTest {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void releaseSourceByAllExternalCallers_preloadNotCalledBefore_releaseInternalSource() {
|
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<>();
|
AtomicReference<MediaSource> internalSourceReference = new AtomicReference<>();
|
||||||
MediaSource.Factory mockMediaSourceFactory = mock(MediaSource.Factory.class);
|
MediaSource.Factory mockMediaSourceFactory = mock(MediaSource.Factory.class);
|
||||||
when(mockMediaSourceFactory.createMediaSource(any()))
|
when(mockMediaSourceFactory.createMediaSource(any()))
|
||||||
|
|
@ -904,7 +809,7 @@ public final class PreloadMediaSourceTest {
|
||||||
PreloadMediaSource.Factory preloadMediaSourceFactory =
|
PreloadMediaSource.Factory preloadMediaSourceFactory =
|
||||||
new PreloadMediaSource.Factory(
|
new PreloadMediaSource.Factory(
|
||||||
mockMediaSourceFactory,
|
mockMediaSourceFactory,
|
||||||
preloadControl,
|
new TestPreloadControl(),
|
||||||
trackSelector,
|
trackSelector,
|
||||||
bandwidthMeter,
|
bandwidthMeter,
|
||||||
getRendererCapabilities(renderersFactory),
|
getRendererCapabilities(renderersFactory),
|
||||||
|
|
@ -931,29 +836,7 @@ public final class PreloadMediaSourceTest {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void releaseSourceByAllExternalCallers_stillPreloading_notReleaseInternalSource() {
|
public void releaseSourceByAllExternalCallers_stillPreloading_notReleaseInternalSource() {
|
||||||
AtomicBoolean onSourcePreparedCalled = new AtomicBoolean(false);
|
TestPreloadControl preloadControl = new TestPreloadControl();
|
||||||
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) {}
|
|
||||||
};
|
|
||||||
AtomicReference<MediaSource> internalSourceReference = new AtomicReference<>();
|
AtomicReference<MediaSource> internalSourceReference = new AtomicReference<>();
|
||||||
MediaSource.Factory mockMediaSourceFactory = mock(MediaSource.Factory.class);
|
MediaSource.Factory mockMediaSourceFactory = mock(MediaSource.Factory.class);
|
||||||
when(mockMediaSourceFactory.createMediaSource(any()))
|
when(mockMediaSourceFactory.createMediaSource(any()))
|
||||||
|
|
@ -999,7 +882,7 @@ public final class PreloadMediaSourceTest {
|
||||||
externalCaller, bandwidthMeter.getTransferListener(), PlayerId.UNSET);
|
externalCaller, bandwidthMeter.getTransferListener(), PlayerId.UNSET);
|
||||||
preloadMediaSource.releaseSource(externalCaller);
|
preloadMediaSource.releaseSource(externalCaller);
|
||||||
|
|
||||||
assertThat(onSourcePreparedCalled.get()).isTrue();
|
assertThat(preloadControl.onSourcePreparedCalledCount).isGreaterThan(0);
|
||||||
assertThat(externalCallerSourceInfoRefreshedCalled.get()).isTrue();
|
assertThat(externalCallerSourceInfoRefreshedCalled.get()).isTrue();
|
||||||
MediaSource internalSource = internalSourceReference.get();
|
MediaSource internalSource = internalSourceReference.get();
|
||||||
assertThat(internalSource).isNotNull();
|
assertThat(internalSource).isNotNull();
|
||||||
|
|
@ -1009,27 +892,6 @@ public final class PreloadMediaSourceTest {
|
||||||
@Test
|
@Test
|
||||||
public void
|
public void
|
||||||
releaseSourceNotByAllExternalCallers_preloadNotCalledBefore_notReleaseInternalSource() {
|
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<>();
|
AtomicReference<MediaSource> internalSourceReference = new AtomicReference<>();
|
||||||
MediaSource.Factory mockMediaSourceFactory = mock(MediaSource.Factory.class);
|
MediaSource.Factory mockMediaSourceFactory = mock(MediaSource.Factory.class);
|
||||||
when(mockMediaSourceFactory.createMediaSource(any()))
|
when(mockMediaSourceFactory.createMediaSource(any()))
|
||||||
|
|
@ -1055,7 +917,7 @@ public final class PreloadMediaSourceTest {
|
||||||
PreloadMediaSource.Factory preloadMediaSourceFactory =
|
PreloadMediaSource.Factory preloadMediaSourceFactory =
|
||||||
new PreloadMediaSource.Factory(
|
new PreloadMediaSource.Factory(
|
||||||
mockMediaSourceFactory,
|
mockMediaSourceFactory,
|
||||||
preloadControl,
|
new TestPreloadControl(),
|
||||||
trackSelector,
|
trackSelector,
|
||||||
bandwidthMeter,
|
bandwidthMeter,
|
||||||
getRendererCapabilities(renderersFactory),
|
getRendererCapabilities(renderersFactory),
|
||||||
|
|
@ -1088,29 +950,7 @@ public final class PreloadMediaSourceTest {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void releasePreloadMediaSource_notUsedByExternalCallers_releaseInternalSource() {
|
public void releasePreloadMediaSource_notUsedByExternalCallers_releaseInternalSource() {
|
||||||
AtomicBoolean onSourcePreparedCalled = new AtomicBoolean(false);
|
TestPreloadControl preloadControl = new TestPreloadControl();
|
||||||
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) {}
|
|
||||||
};
|
|
||||||
AtomicReference<MediaSource> internalSourceReference = new AtomicReference<>();
|
AtomicReference<MediaSource> internalSourceReference = new AtomicReference<>();
|
||||||
MediaSource.Factory mockMediaSourceFactory = mock(MediaSource.Factory.class);
|
MediaSource.Factory mockMediaSourceFactory = mock(MediaSource.Factory.class);
|
||||||
when(mockMediaSourceFactory.createMediaSource(any()))
|
when(mockMediaSourceFactory.createMediaSource(any()))
|
||||||
|
|
@ -1152,7 +992,7 @@ public final class PreloadMediaSourceTest {
|
||||||
preloadMediaSource.releasePreloadMediaSource();
|
preloadMediaSource.releasePreloadMediaSource();
|
||||||
shadowOf(Looper.getMainLooper()).idle();
|
shadowOf(Looper.getMainLooper()).idle();
|
||||||
|
|
||||||
assertThat(onSourcePreparedCalled.get()).isTrue();
|
assertThat(preloadControl.onSourcePreparedCalledCount).isGreaterThan(0);
|
||||||
MediaSource internalSource = internalSourceReference.get();
|
MediaSource internalSource = internalSourceReference.get();
|
||||||
assertThat(internalSource).isNotNull();
|
assertThat(internalSource).isNotNull();
|
||||||
verify(internalSource).releaseSource(any());
|
verify(internalSource).releaseSource(any());
|
||||||
|
|
@ -1160,29 +1000,7 @@ public final class PreloadMediaSourceTest {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void releasePreloadMediaSource_stillUsedByExternalCallers_releaseInternalSource() {
|
public void releasePreloadMediaSource_stillUsedByExternalCallers_releaseInternalSource() {
|
||||||
AtomicBoolean onSourcePreparedCalled = new AtomicBoolean(false);
|
TestPreloadControl preloadControl = new TestPreloadControl();
|
||||||
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) {}
|
|
||||||
};
|
|
||||||
AtomicReference<MediaSource> internalSourceReference = new AtomicReference<>();
|
AtomicReference<MediaSource> internalSourceReference = new AtomicReference<>();
|
||||||
MediaSource.Factory mockMediaSourceFactory = mock(MediaSource.Factory.class);
|
MediaSource.Factory mockMediaSourceFactory = mock(MediaSource.Factory.class);
|
||||||
when(mockMediaSourceFactory.createMediaSource(any()))
|
when(mockMediaSourceFactory.createMediaSource(any()))
|
||||||
|
|
@ -1230,13 +1048,57 @@ public final class PreloadMediaSourceTest {
|
||||||
preloadMediaSource.releasePreloadMediaSource();
|
preloadMediaSource.releasePreloadMediaSource();
|
||||||
shadowOf(Looper.getMainLooper()).idle();
|
shadowOf(Looper.getMainLooper()).idle();
|
||||||
|
|
||||||
assertThat(onSourcePreparedCalled.get()).isTrue();
|
assertThat(preloadControl.onSourcePreparedCalledCount).isGreaterThan(0);
|
||||||
assertThat(externalCallerSourceInfoRefreshedCalled.get()).isTrue();
|
assertThat(externalCallerSourceInfoRefreshedCalled.get()).isTrue();
|
||||||
MediaSource internalSource = internalSourceReference.get();
|
MediaSource internalSource = internalSourceReference.get();
|
||||||
assertThat(internalSource).isNotNull();
|
assertThat(internalSource).isNotNull();
|
||||||
verify(internalSource, times(0)).releaseSource(any());
|
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) {
|
private static RendererCapabilities[] getRendererCapabilities(RenderersFactory renderersFactory) {
|
||||||
Renderer[] renderers =
|
Renderer[] renderers =
|
||||||
renderersFactory.createRenderers(
|
renderersFactory.createRenderers(
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue