mirror of
https://github.com/androidx/media.git
synced 2025-05-07 15:40:37 +08:00
Send media source events for fake media sources.
This allows to test sending events when using fake media sources. The FakeMediaSource now simulates a manifest load when being prepared. And the FakeMediaPeriod simulates a media load when being prepared. ------------- Created by MOE: https://github.com/google/moe MOE_MIGRATED_REVID=189205285
This commit is contained in:
parent
bb72d9eb6a
commit
c7c9a1e9e4
@ -295,33 +295,40 @@ public interface MediaSourceEventListener {
|
|||||||
|
|
||||||
/** Dispatches {@link #onLoadStarted(LoadEventInfo, MediaLoadData)}. */
|
/** Dispatches {@link #onLoadStarted(LoadEventInfo, MediaLoadData)}. */
|
||||||
public void loadStarted(
|
public void loadStarted(
|
||||||
final DataSpec dataSpec,
|
DataSpec dataSpec,
|
||||||
final int dataType,
|
int dataType,
|
||||||
final int trackType,
|
int trackType,
|
||||||
final @Nullable Format trackFormat,
|
@Nullable Format trackFormat,
|
||||||
final int trackSelectionReason,
|
int trackSelectionReason,
|
||||||
final @Nullable Object trackSelectionData,
|
@Nullable Object trackSelectionData,
|
||||||
final long mediaStartTimeUs,
|
long mediaStartTimeUs,
|
||||||
final long mediaEndTimeUs,
|
long mediaEndTimeUs,
|
||||||
final long elapsedRealtimeMs) {
|
long elapsedRealtimeMs) {
|
||||||
for (final ListenerAndHandler listenerAndHandler : listenerAndHandlers) {
|
loadStarted(
|
||||||
listenerAndHandler.handler.post(
|
new LoadEventInfo(
|
||||||
|
dataSpec, elapsedRealtimeMs, /* loadDurationMs= */ 0, /* bytesLoaded= */ 0),
|
||||||
|
new MediaLoadData(
|
||||||
|
windowIndex,
|
||||||
|
mediaPeriodId,
|
||||||
|
dataType,
|
||||||
|
trackType,
|
||||||
|
trackFormat,
|
||||||
|
trackSelectionReason,
|
||||||
|
trackSelectionData,
|
||||||
|
adjustMediaTime(mediaStartTimeUs),
|
||||||
|
adjustMediaTime(mediaEndTimeUs)));
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Dispatches {@link #onLoadStarted(LoadEventInfo, MediaLoadData)}. */
|
||||||
|
public void loadStarted(final LoadEventInfo loadEventInfo, final MediaLoadData mediaLoadData) {
|
||||||
|
for (ListenerAndHandler listenerAndHandler : listenerAndHandlers) {
|
||||||
|
Handler handler = listenerAndHandler.handler;
|
||||||
|
final MediaSourceEventListener listener = listenerAndHandler.listener;
|
||||||
|
handler.post(
|
||||||
new Runnable() {
|
new Runnable() {
|
||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
listenerAndHandler.listener.onLoadStarted(
|
listener.onLoadStarted(loadEventInfo, mediaLoadData);
|
||||||
new LoadEventInfo(
|
|
||||||
dataSpec, elapsedRealtimeMs, /* loadDurationMs= */ 0, /* bytesLoaded= */ 0),
|
|
||||||
new MediaLoadData(
|
|
||||||
windowIndex,
|
|
||||||
mediaPeriodId,
|
|
||||||
dataType,
|
|
||||||
trackType,
|
|
||||||
trackFormat,
|
|
||||||
trackSelectionReason,
|
|
||||||
trackSelectionData,
|
|
||||||
adjustMediaTime(mediaStartTimeUs),
|
|
||||||
adjustMediaTime(mediaEndTimeUs)));
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -350,34 +357,42 @@ public interface MediaSourceEventListener {
|
|||||||
|
|
||||||
/** Dispatches {@link #onLoadCompleted(LoadEventInfo, MediaLoadData)}. */
|
/** Dispatches {@link #onLoadCompleted(LoadEventInfo, MediaLoadData)}. */
|
||||||
public void loadCompleted(
|
public void loadCompleted(
|
||||||
final DataSpec dataSpec,
|
DataSpec dataSpec,
|
||||||
final int dataType,
|
int dataType,
|
||||||
final int trackType,
|
int trackType,
|
||||||
final @Nullable Format trackFormat,
|
@Nullable Format trackFormat,
|
||||||
final int trackSelectionReason,
|
int trackSelectionReason,
|
||||||
final @Nullable Object trackSelectionData,
|
@Nullable Object trackSelectionData,
|
||||||
final long mediaStartTimeUs,
|
long mediaStartTimeUs,
|
||||||
final long mediaEndTimeUs,
|
long mediaEndTimeUs,
|
||||||
final long elapsedRealtimeMs,
|
long elapsedRealtimeMs,
|
||||||
final long loadDurationMs,
|
long loadDurationMs,
|
||||||
final long bytesLoaded) {
|
long bytesLoaded) {
|
||||||
for (final ListenerAndHandler listenerAndHandler : listenerAndHandlers) {
|
loadCompleted(
|
||||||
listenerAndHandler.handler.post(
|
new LoadEventInfo(dataSpec, elapsedRealtimeMs, loadDurationMs, bytesLoaded),
|
||||||
|
new MediaLoadData(
|
||||||
|
windowIndex,
|
||||||
|
mediaPeriodId,
|
||||||
|
dataType,
|
||||||
|
trackType,
|
||||||
|
trackFormat,
|
||||||
|
trackSelectionReason,
|
||||||
|
trackSelectionData,
|
||||||
|
adjustMediaTime(mediaStartTimeUs),
|
||||||
|
adjustMediaTime(mediaEndTimeUs)));
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Dispatches {@link #onLoadCompleted(LoadEventInfo, MediaLoadData)}. */
|
||||||
|
public void loadCompleted(
|
||||||
|
final LoadEventInfo loadEventInfo, final MediaLoadData mediaLoadData) {
|
||||||
|
for (ListenerAndHandler listenerAndHandler : listenerAndHandlers) {
|
||||||
|
Handler handler = listenerAndHandler.handler;
|
||||||
|
final MediaSourceEventListener listener = listenerAndHandler.listener;
|
||||||
|
handler.post(
|
||||||
new Runnable() {
|
new Runnable() {
|
||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
listenerAndHandler.listener.onLoadCompleted(
|
listener.onLoadCompleted(loadEventInfo, mediaLoadData);
|
||||||
new LoadEventInfo(dataSpec, elapsedRealtimeMs, loadDurationMs, bytesLoaded),
|
|
||||||
new MediaLoadData(
|
|
||||||
windowIndex,
|
|
||||||
mediaPeriodId,
|
|
||||||
dataType,
|
|
||||||
trackType,
|
|
||||||
trackFormat,
|
|
||||||
trackSelectionReason,
|
|
||||||
trackSelectionData,
|
|
||||||
adjustMediaTime(mediaStartTimeUs),
|
|
||||||
adjustMediaTime(mediaEndTimeUs)));
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -406,34 +421,41 @@ public interface MediaSourceEventListener {
|
|||||||
|
|
||||||
/** Dispatches {@link #onLoadCanceled(LoadEventInfo, MediaLoadData)}. */
|
/** Dispatches {@link #onLoadCanceled(LoadEventInfo, MediaLoadData)}. */
|
||||||
public void loadCanceled(
|
public void loadCanceled(
|
||||||
final DataSpec dataSpec,
|
DataSpec dataSpec,
|
||||||
final int dataType,
|
int dataType,
|
||||||
final int trackType,
|
int trackType,
|
||||||
final @Nullable Format trackFormat,
|
@Nullable Format trackFormat,
|
||||||
final int trackSelectionReason,
|
int trackSelectionReason,
|
||||||
final @Nullable Object trackSelectionData,
|
@Nullable Object trackSelectionData,
|
||||||
final long mediaStartTimeUs,
|
long mediaStartTimeUs,
|
||||||
final long mediaEndTimeUs,
|
long mediaEndTimeUs,
|
||||||
final long elapsedRealtimeMs,
|
long elapsedRealtimeMs,
|
||||||
final long loadDurationMs,
|
long loadDurationMs,
|
||||||
final long bytesLoaded) {
|
long bytesLoaded) {
|
||||||
for (final ListenerAndHandler listenerAndHandler : listenerAndHandlers) {
|
loadCanceled(
|
||||||
listenerAndHandler.handler.post(
|
new LoadEventInfo(dataSpec, elapsedRealtimeMs, loadDurationMs, bytesLoaded),
|
||||||
|
new MediaLoadData(
|
||||||
|
windowIndex,
|
||||||
|
mediaPeriodId,
|
||||||
|
dataType,
|
||||||
|
trackType,
|
||||||
|
trackFormat,
|
||||||
|
trackSelectionReason,
|
||||||
|
trackSelectionData,
|
||||||
|
adjustMediaTime(mediaStartTimeUs),
|
||||||
|
adjustMediaTime(mediaEndTimeUs)));
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Dispatches {@link #onLoadCanceled(LoadEventInfo, MediaLoadData)}. */
|
||||||
|
public void loadCanceled(final LoadEventInfo loadEventInfo, final MediaLoadData mediaLoadData) {
|
||||||
|
for (ListenerAndHandler listenerAndHandler : listenerAndHandlers) {
|
||||||
|
Handler handler = listenerAndHandler.handler;
|
||||||
|
final MediaSourceEventListener listener = listenerAndHandler.listener;
|
||||||
|
handler.post(
|
||||||
new Runnable() {
|
new Runnable() {
|
||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
listenerAndHandler.listener.onLoadCanceled(
|
listener.onLoadCanceled(loadEventInfo, mediaLoadData);
|
||||||
new LoadEventInfo(dataSpec, elapsedRealtimeMs, loadDurationMs, bytesLoaded),
|
|
||||||
new MediaLoadData(
|
|
||||||
windowIndex,
|
|
||||||
mediaPeriodId,
|
|
||||||
dataType,
|
|
||||||
trackType,
|
|
||||||
trackFormat,
|
|
||||||
trackSelectionReason,
|
|
||||||
trackSelectionData,
|
|
||||||
adjustMediaTime(mediaStartTimeUs),
|
|
||||||
adjustMediaTime(mediaEndTimeUs)));
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -466,62 +488,79 @@ public interface MediaSourceEventListener {
|
|||||||
|
|
||||||
/** Dispatches {@link #onLoadError(LoadEventInfo, MediaLoadData, IOException, boolean)}. */
|
/** Dispatches {@link #onLoadError(LoadEventInfo, MediaLoadData, IOException, boolean)}. */
|
||||||
public void loadError(
|
public void loadError(
|
||||||
final DataSpec dataSpec,
|
DataSpec dataSpec,
|
||||||
final int dataType,
|
int dataType,
|
||||||
final int trackType,
|
int trackType,
|
||||||
final @Nullable Format trackFormat,
|
@Nullable Format trackFormat,
|
||||||
final int trackSelectionReason,
|
int trackSelectionReason,
|
||||||
final @Nullable Object trackSelectionData,
|
@Nullable Object trackSelectionData,
|
||||||
final long mediaStartTimeUs,
|
long mediaStartTimeUs,
|
||||||
final long mediaEndTimeUs,
|
long mediaEndTimeUs,
|
||||||
final long elapsedRealtimeMs,
|
long elapsedRealtimeMs,
|
||||||
final long loadDurationMs,
|
long loadDurationMs,
|
||||||
final long bytesLoaded,
|
long bytesLoaded,
|
||||||
|
IOException error,
|
||||||
|
boolean wasCanceled) {
|
||||||
|
loadError(
|
||||||
|
new LoadEventInfo(dataSpec, elapsedRealtimeMs, loadDurationMs, bytesLoaded),
|
||||||
|
new MediaLoadData(
|
||||||
|
windowIndex,
|
||||||
|
mediaPeriodId,
|
||||||
|
dataType,
|
||||||
|
trackType,
|
||||||
|
trackFormat,
|
||||||
|
trackSelectionReason,
|
||||||
|
trackSelectionData,
|
||||||
|
adjustMediaTime(mediaStartTimeUs),
|
||||||
|
adjustMediaTime(mediaEndTimeUs)),
|
||||||
|
error,
|
||||||
|
wasCanceled);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Dispatches {@link #onLoadError(LoadEventInfo, MediaLoadData, IOException, boolean)}. */
|
||||||
|
public void loadError(
|
||||||
|
final LoadEventInfo loadEventInfo,
|
||||||
|
final MediaLoadData mediaLoadData,
|
||||||
final IOException error,
|
final IOException error,
|
||||||
final boolean wasCanceled) {
|
final boolean wasCanceled) {
|
||||||
for (final ListenerAndHandler listenerAndHandler : listenerAndHandlers) {
|
for (ListenerAndHandler listenerAndHandler : listenerAndHandlers) {
|
||||||
listenerAndHandler.handler.post(
|
Handler handler = listenerAndHandler.handler;
|
||||||
|
final MediaSourceEventListener listener = listenerAndHandler.listener;
|
||||||
|
handler.post(
|
||||||
new Runnable() {
|
new Runnable() {
|
||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
listenerAndHandler.listener.onLoadError(
|
listener.onLoadError(loadEventInfo, mediaLoadData, error, wasCanceled);
|
||||||
new LoadEventInfo(dataSpec, elapsedRealtimeMs, loadDurationMs, bytesLoaded),
|
|
||||||
new MediaLoadData(
|
|
||||||
windowIndex,
|
|
||||||
mediaPeriodId,
|
|
||||||
dataType,
|
|
||||||
trackType,
|
|
||||||
trackFormat,
|
|
||||||
trackSelectionReason,
|
|
||||||
trackSelectionData,
|
|
||||||
adjustMediaTime(mediaStartTimeUs),
|
|
||||||
adjustMediaTime(mediaEndTimeUs)),
|
|
||||||
error,
|
|
||||||
wasCanceled);
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Dispatches {@link #onUpstreamDiscarded(MediaLoadData)}. */
|
/** Dispatches {@link #onUpstreamDiscarded(MediaLoadData)}. */
|
||||||
public void upstreamDiscarded(
|
public void upstreamDiscarded(int trackType, long mediaStartTimeUs, long mediaEndTimeUs) {
|
||||||
final int trackType, final long mediaStartTimeUs, final long mediaEndTimeUs) {
|
upstreamDiscarded(
|
||||||
for (final ListenerAndHandler listenerAndHandler : listenerAndHandlers) {
|
new MediaLoadData(
|
||||||
listenerAndHandler.handler.post(
|
windowIndex,
|
||||||
|
mediaPeriodId,
|
||||||
|
C.DATA_TYPE_MEDIA,
|
||||||
|
trackType,
|
||||||
|
/* trackFormat= */ null,
|
||||||
|
C.SELECTION_REASON_ADAPTIVE,
|
||||||
|
/* trackSelectionData= */ null,
|
||||||
|
adjustMediaTime(mediaStartTimeUs),
|
||||||
|
adjustMediaTime(mediaEndTimeUs)));
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Dispatches {@link #onUpstreamDiscarded(MediaLoadData)}. */
|
||||||
|
public void upstreamDiscarded(final MediaLoadData mediaLoadData) {
|
||||||
|
for (ListenerAndHandler listenerAndHandler : listenerAndHandlers) {
|
||||||
|
Handler handler = listenerAndHandler.handler;
|
||||||
|
final MediaSourceEventListener listener = listenerAndHandler.listener;
|
||||||
|
handler.post(
|
||||||
new Runnable() {
|
new Runnable() {
|
||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
listenerAndHandler.listener.onUpstreamDiscarded(
|
listener.onUpstreamDiscarded(mediaLoadData);
|
||||||
new MediaLoadData(
|
|
||||||
windowIndex,
|
|
||||||
mediaPeriodId,
|
|
||||||
C.DATA_TYPE_MEDIA,
|
|
||||||
trackType,
|
|
||||||
/* trackFormat= */ null,
|
|
||||||
C.SELECTION_REASON_ADAPTIVE,
|
|
||||||
/* trackSelectionData= */ null,
|
|
||||||
adjustMediaTime(mediaStartTimeUs),
|
|
||||||
adjustMediaTime(mediaEndTimeUs)));
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -529,27 +568,34 @@ public interface MediaSourceEventListener {
|
|||||||
|
|
||||||
/** Dispatches {@link #onDownstreamFormatChanged(MediaLoadData)}. */
|
/** Dispatches {@link #onDownstreamFormatChanged(MediaLoadData)}. */
|
||||||
public void downstreamFormatChanged(
|
public void downstreamFormatChanged(
|
||||||
final int trackType,
|
int trackType,
|
||||||
final @Nullable Format trackFormat,
|
@Nullable Format trackFormat,
|
||||||
final int trackSelectionReason,
|
int trackSelectionReason,
|
||||||
final @Nullable Object trackSelectionData,
|
@Nullable Object trackSelectionData,
|
||||||
final long mediaTimeUs) {
|
long mediaTimeUs) {
|
||||||
for (final ListenerAndHandler listenerAndHandler : listenerAndHandlers) {
|
downstreamFormatChanged(
|
||||||
listenerAndHandler.handler.post(
|
new MediaLoadData(
|
||||||
|
windowIndex,
|
||||||
|
mediaPeriodId,
|
||||||
|
C.DATA_TYPE_MEDIA,
|
||||||
|
trackType,
|
||||||
|
trackFormat,
|
||||||
|
trackSelectionReason,
|
||||||
|
trackSelectionData,
|
||||||
|
adjustMediaTime(mediaTimeUs),
|
||||||
|
/* mediaEndTimeMs= */ C.TIME_UNSET));
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Dispatches {@link #onDownstreamFormatChanged(MediaLoadData)}. */
|
||||||
|
public void downstreamFormatChanged(final MediaLoadData mediaLoadData) {
|
||||||
|
for (ListenerAndHandler listenerAndHandler : listenerAndHandlers) {
|
||||||
|
Handler handler = listenerAndHandler.handler;
|
||||||
|
final MediaSourceEventListener listener = listenerAndHandler.listener;
|
||||||
|
handler.post(
|
||||||
new Runnable() {
|
new Runnable() {
|
||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
listenerAndHandler.listener.onDownstreamFormatChanged(
|
listener.onDownstreamFormatChanged(mediaLoadData);
|
||||||
new MediaLoadData(
|
|
||||||
windowIndex,
|
|
||||||
mediaPeriodId,
|
|
||||||
C.DATA_TYPE_MEDIA,
|
|
||||||
trackType,
|
|
||||||
trackFormat,
|
|
||||||
trackSelectionReason,
|
|
||||||
trackSelectionData,
|
|
||||||
adjustMediaTime(mediaTimeUs),
|
|
||||||
/* mediaEndTimeMs= */ C.TIME_UNSET));
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -25,6 +25,7 @@ import com.google.android.exoplayer2.Timeline.Window;
|
|||||||
import com.google.android.exoplayer2.source.ConcatenatingMediaSource;
|
import com.google.android.exoplayer2.source.ConcatenatingMediaSource;
|
||||||
import com.google.android.exoplayer2.source.MediaSource;
|
import com.google.android.exoplayer2.source.MediaSource;
|
||||||
import com.google.android.exoplayer2.source.MediaSource.MediaPeriodId;
|
import com.google.android.exoplayer2.source.MediaSource.MediaPeriodId;
|
||||||
|
import com.google.android.exoplayer2.source.MediaSourceEventListener.EventDispatcher;
|
||||||
import com.google.android.exoplayer2.source.TrackGroup;
|
import com.google.android.exoplayer2.source.TrackGroup;
|
||||||
import com.google.android.exoplayer2.source.TrackGroupArray;
|
import com.google.android.exoplayer2.source.TrackGroupArray;
|
||||||
import com.google.android.exoplayer2.source.ads.AdPlaybackState;
|
import com.google.android.exoplayer2.source.ads.AdPlaybackState;
|
||||||
@ -573,8 +574,11 @@ public final class ExoPlayerTest {
|
|||||||
new FakeMediaSource(timeline, null, Builder.VIDEO_FORMAT) {
|
new FakeMediaSource(timeline, null, Builder.VIDEO_FORMAT) {
|
||||||
@Override
|
@Override
|
||||||
protected FakeMediaPeriod createFakeMediaPeriod(
|
protected FakeMediaPeriod createFakeMediaPeriod(
|
||||||
MediaPeriodId id, TrackGroupArray trackGroupArray, Allocator allocator) {
|
MediaPeriodId id,
|
||||||
FakeMediaPeriod mediaPeriod = new FakeMediaPeriod(trackGroupArray);
|
TrackGroupArray trackGroupArray,
|
||||||
|
Allocator allocator,
|
||||||
|
EventDispatcher eventDispatcher) {
|
||||||
|
FakeMediaPeriod mediaPeriod = new FakeMediaPeriod(trackGroupArray, eventDispatcher);
|
||||||
mediaPeriod.setSeekToUsOffset(10);
|
mediaPeriod.setSeekToUsOffset(10);
|
||||||
return mediaPeriod;
|
return mediaPeriod;
|
||||||
}
|
}
|
||||||
@ -604,8 +608,11 @@ public final class ExoPlayerTest {
|
|||||||
new FakeMediaSource(timeline, null, Builder.VIDEO_FORMAT) {
|
new FakeMediaSource(timeline, null, Builder.VIDEO_FORMAT) {
|
||||||
@Override
|
@Override
|
||||||
protected FakeMediaPeriod createFakeMediaPeriod(
|
protected FakeMediaPeriod createFakeMediaPeriod(
|
||||||
MediaPeriodId id, TrackGroupArray trackGroupArray, Allocator allocator) {
|
MediaPeriodId id,
|
||||||
FakeMediaPeriod mediaPeriod = new FakeMediaPeriod(trackGroupArray);
|
TrackGroupArray trackGroupArray,
|
||||||
|
Allocator allocator,
|
||||||
|
EventDispatcher eventDispatcher) {
|
||||||
|
FakeMediaPeriod mediaPeriod = new FakeMediaPeriod(trackGroupArray, eventDispatcher);
|
||||||
mediaPeriod.setDiscontinuityPositionUs(10);
|
mediaPeriod.setDiscontinuityPositionUs(10);
|
||||||
return mediaPeriod;
|
return mediaPeriod;
|
||||||
}
|
}
|
||||||
@ -626,8 +633,11 @@ public final class ExoPlayerTest {
|
|||||||
new FakeMediaSource(timeline, null, Builder.VIDEO_FORMAT) {
|
new FakeMediaSource(timeline, null, Builder.VIDEO_FORMAT) {
|
||||||
@Override
|
@Override
|
||||||
protected FakeMediaPeriod createFakeMediaPeriod(
|
protected FakeMediaPeriod createFakeMediaPeriod(
|
||||||
MediaPeriodId id, TrackGroupArray trackGroupArray, Allocator allocator) {
|
MediaPeriodId id,
|
||||||
FakeMediaPeriod mediaPeriod = new FakeMediaPeriod(trackGroupArray);
|
TrackGroupArray trackGroupArray,
|
||||||
|
Allocator allocator,
|
||||||
|
EventDispatcher eventDispatcher) {
|
||||||
|
FakeMediaPeriod mediaPeriod = new FakeMediaPeriod(trackGroupArray, eventDispatcher);
|
||||||
mediaPeriod.setDiscontinuityPositionUs(0);
|
mediaPeriod.setDiscontinuityPositionUs(0);
|
||||||
return mediaPeriod;
|
return mediaPeriod;
|
||||||
}
|
}
|
||||||
@ -878,10 +888,13 @@ public final class ExoPlayerTest {
|
|||||||
new FakeMediaSource(new FakeTimeline(/* windowCount= */ 1), null, Builder.VIDEO_FORMAT) {
|
new FakeMediaSource(new FakeTimeline(/* windowCount= */ 1), null, Builder.VIDEO_FORMAT) {
|
||||||
@Override
|
@Override
|
||||||
protected FakeMediaPeriod createFakeMediaPeriod(
|
protected FakeMediaPeriod createFakeMediaPeriod(
|
||||||
MediaPeriodId id, TrackGroupArray trackGroupArray, Allocator allocator) {
|
MediaPeriodId id,
|
||||||
|
TrackGroupArray trackGroupArray,
|
||||||
|
Allocator allocator,
|
||||||
|
EventDispatcher eventDispatcher) {
|
||||||
// Defer completing preparation of the period until playback parameters have been set.
|
// Defer completing preparation of the period until playback parameters have been set.
|
||||||
fakeMediaPeriodHolder[0] =
|
fakeMediaPeriodHolder[0] =
|
||||||
new FakeMediaPeriod(trackGroupArray, /* deferOnPrepared= */ true);
|
new FakeMediaPeriod(trackGroupArray, eventDispatcher, /* deferOnPrepared= */ true);
|
||||||
createPeriodCalledCountDownLatch.countDown();
|
createPeriodCalledCountDownLatch.countDown();
|
||||||
return fakeMediaPeriodHolder[0];
|
return fakeMediaPeriodHolder[0];
|
||||||
}
|
}
|
||||||
|
@ -92,7 +92,7 @@ public class SimpleDecoderAudioRendererTest {
|
|||||||
audioRenderer.enable(
|
audioRenderer.enable(
|
||||||
RendererConfiguration.DEFAULT,
|
RendererConfiguration.DEFAULT,
|
||||||
new Format[] {FORMAT},
|
new Format[] {FORMAT},
|
||||||
new FakeSampleStream(FORMAT, false),
|
new FakeSampleStream(FORMAT, /* eventDispatcher= */ null, /* shouldOutputSample= */ false),
|
||||||
0,
|
0,
|
||||||
false,
|
false,
|
||||||
0);
|
0);
|
||||||
|
@ -35,7 +35,6 @@ import java.util.List;
|
|||||||
public class FakeAdaptiveMediaPeriod extends FakeMediaPeriod
|
public class FakeAdaptiveMediaPeriod extends FakeMediaPeriod
|
||||||
implements SequenceableLoader.Callback<ChunkSampleStream<FakeChunkSource>> {
|
implements SequenceableLoader.Callback<ChunkSampleStream<FakeChunkSource>> {
|
||||||
|
|
||||||
private final EventDispatcher eventDispatcher;
|
|
||||||
private final Allocator allocator;
|
private final Allocator allocator;
|
||||||
private final FakeChunkSource.Factory chunkSourceFactory;
|
private final FakeChunkSource.Factory chunkSourceFactory;
|
||||||
private final long durationUs;
|
private final long durationUs;
|
||||||
@ -50,8 +49,7 @@ public class FakeAdaptiveMediaPeriod extends FakeMediaPeriod
|
|||||||
Allocator allocator,
|
Allocator allocator,
|
||||||
FakeChunkSource.Factory chunkSourceFactory,
|
FakeChunkSource.Factory chunkSourceFactory,
|
||||||
long durationUs) {
|
long durationUs) {
|
||||||
super(trackGroupArray);
|
super(trackGroupArray, eventDispatcher);
|
||||||
this.eventDispatcher = eventDispatcher;
|
|
||||||
this.allocator = allocator;
|
this.allocator = allocator;
|
||||||
this.chunkSourceFactory = chunkSourceFactory;
|
this.chunkSourceFactory = chunkSourceFactory;
|
||||||
this.durationUs = durationUs;
|
this.durationUs = durationUs;
|
||||||
|
@ -20,6 +20,7 @@ import com.google.android.exoplayer2.Timeline;
|
|||||||
import com.google.android.exoplayer2.Timeline.Period;
|
import com.google.android.exoplayer2.Timeline.Period;
|
||||||
import com.google.android.exoplayer2.source.MediaSource;
|
import com.google.android.exoplayer2.source.MediaSource;
|
||||||
import com.google.android.exoplayer2.source.MediaSourceEventListener;
|
import com.google.android.exoplayer2.source.MediaSourceEventListener;
|
||||||
|
import com.google.android.exoplayer2.source.MediaSourceEventListener.EventDispatcher;
|
||||||
import com.google.android.exoplayer2.source.TrackGroupArray;
|
import com.google.android.exoplayer2.source.TrackGroupArray;
|
||||||
import com.google.android.exoplayer2.upstream.Allocator;
|
import com.google.android.exoplayer2.upstream.Allocator;
|
||||||
|
|
||||||
@ -44,10 +45,12 @@ public class FakeAdaptiveMediaSource extends FakeMediaSource {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected FakeMediaPeriod createFakeMediaPeriod(MediaPeriodId id, TrackGroupArray trackGroupArray,
|
protected FakeMediaPeriod createFakeMediaPeriod(
|
||||||
Allocator allocator) {
|
MediaPeriodId id,
|
||||||
|
TrackGroupArray trackGroupArray,
|
||||||
|
Allocator allocator,
|
||||||
|
EventDispatcher eventDispatcher) {
|
||||||
Period period = timeline.getPeriod(id.periodIndex, new Period());
|
Period period = timeline.getPeriod(id.periodIndex, new Period());
|
||||||
MediaSourceEventListener.EventDispatcher eventDispatcher = createEventDispatcher(id);
|
|
||||||
return new FakeAdaptiveMediaPeriod(
|
return new FakeAdaptiveMediaPeriod(
|
||||||
trackGroupArray, eventDispatcher, allocator, chunkSourceFactory, period.durationUs);
|
trackGroupArray, eventDispatcher, allocator, chunkSourceFactory, period.durationUs);
|
||||||
}
|
}
|
||||||
|
@ -17,24 +17,32 @@ package com.google.android.exoplayer2.testutil;
|
|||||||
|
|
||||||
import static com.google.common.truth.Truth.assertThat;
|
import static com.google.common.truth.Truth.assertThat;
|
||||||
|
|
||||||
|
import android.net.Uri;
|
||||||
import android.os.Handler;
|
import android.os.Handler;
|
||||||
|
import android.os.SystemClock;
|
||||||
import android.support.annotation.Nullable;
|
import android.support.annotation.Nullable;
|
||||||
import com.google.android.exoplayer2.C;
|
import com.google.android.exoplayer2.C;
|
||||||
import com.google.android.exoplayer2.SeekParameters;
|
import com.google.android.exoplayer2.SeekParameters;
|
||||||
import com.google.android.exoplayer2.source.MediaPeriod;
|
import com.google.android.exoplayer2.source.MediaPeriod;
|
||||||
|
import com.google.android.exoplayer2.source.MediaSourceEventListener.EventDispatcher;
|
||||||
import com.google.android.exoplayer2.source.SampleStream;
|
import com.google.android.exoplayer2.source.SampleStream;
|
||||||
import com.google.android.exoplayer2.source.TrackGroup;
|
import com.google.android.exoplayer2.source.TrackGroup;
|
||||||
import com.google.android.exoplayer2.source.TrackGroupArray;
|
import com.google.android.exoplayer2.source.TrackGroupArray;
|
||||||
import com.google.android.exoplayer2.trackselection.TrackSelection;
|
import com.google.android.exoplayer2.trackselection.TrackSelection;
|
||||||
|
import com.google.android.exoplayer2.upstream.DataSpec;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Fake {@link MediaPeriod} that provides tracks from the given {@link TrackGroupArray}. Selecting
|
* Fake {@link MediaPeriod} that provides tracks from the given {@link TrackGroupArray}. Selecting
|
||||||
* tracks will give the player {@link FakeSampleStream}s.
|
* tracks will give the player {@link FakeSampleStream}s. Loading data completes immediately after
|
||||||
|
* the period has finished preparing.
|
||||||
*/
|
*/
|
||||||
public class FakeMediaPeriod implements MediaPeriod {
|
public class FakeMediaPeriod implements MediaPeriod {
|
||||||
|
|
||||||
|
public static final DataSpec FAKE_DATA_SPEC = new DataSpec(Uri.parse("http://fake.uri"));
|
||||||
|
|
||||||
private final TrackGroupArray trackGroupArray;
|
private final TrackGroupArray trackGroupArray;
|
||||||
|
protected final EventDispatcher eventDispatcher;
|
||||||
|
|
||||||
@Nullable private Handler playerHandler;
|
@Nullable private Handler playerHandler;
|
||||||
@Nullable private Callback prepareCallback;
|
@Nullable private Callback prepareCallback;
|
||||||
@ -46,19 +54,23 @@ public class FakeMediaPeriod implements MediaPeriod {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* @param trackGroupArray The track group array.
|
* @param trackGroupArray The track group array.
|
||||||
|
* @param eventDispatcher A dispatcher for media source events.
|
||||||
*/
|
*/
|
||||||
public FakeMediaPeriod(TrackGroupArray trackGroupArray) {
|
public FakeMediaPeriod(TrackGroupArray trackGroupArray, EventDispatcher eventDispatcher) {
|
||||||
this(trackGroupArray, false);
|
this(trackGroupArray, eventDispatcher, /* deferOnPrepared */ false);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param trackGroupArray The track group array.
|
* @param trackGroupArray The track group array.
|
||||||
|
* @param eventDispatcher A dispatcher for media source events.
|
||||||
* @param deferOnPrepared Whether {@link MediaPeriod.Callback#onPrepared(MediaPeriod)} should be
|
* @param deferOnPrepared Whether {@link MediaPeriod.Callback#onPrepared(MediaPeriod)} should be
|
||||||
* called only after {@link #setPreparationComplete()} has been called. If {@code false}
|
* called only after {@link #setPreparationComplete()} has been called. If {@code false}
|
||||||
* preparation completes immediately.
|
* preparation completes immediately.
|
||||||
*/
|
*/
|
||||||
public FakeMediaPeriod(TrackGroupArray trackGroupArray, boolean deferOnPrepared) {
|
public FakeMediaPeriod(
|
||||||
|
TrackGroupArray trackGroupArray, EventDispatcher eventDispatcher, boolean deferOnPrepared) {
|
||||||
this.trackGroupArray = trackGroupArray;
|
this.trackGroupArray = trackGroupArray;
|
||||||
|
this.eventDispatcher = eventDispatcher;
|
||||||
this.deferOnPrepared = deferOnPrepared;
|
this.deferOnPrepared = deferOnPrepared;
|
||||||
discontinuityPositionUs = C.TIME_UNSET;
|
discontinuityPositionUs = C.TIME_UNSET;
|
||||||
}
|
}
|
||||||
@ -79,13 +91,13 @@ public class FakeMediaPeriod implements MediaPeriod {
|
|||||||
public synchronized void setPreparationComplete() {
|
public synchronized void setPreparationComplete() {
|
||||||
deferOnPrepared = false;
|
deferOnPrepared = false;
|
||||||
if (playerHandler != null && prepareCallback != null) {
|
if (playerHandler != null && prepareCallback != null) {
|
||||||
playerHandler.post(new Runnable() {
|
playerHandler.post(
|
||||||
@Override
|
new Runnable() {
|
||||||
public void run() {
|
@Override
|
||||||
prepared = true;
|
public void run() {
|
||||||
prepareCallback.onPrepared(FakeMediaPeriod.this);
|
finishPreparation();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -104,12 +116,21 @@ public class FakeMediaPeriod implements MediaPeriod {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public synchronized void prepare(Callback callback, long positionUs) {
|
public synchronized void prepare(Callback callback, long positionUs) {
|
||||||
|
eventDispatcher.loadStarted(
|
||||||
|
FAKE_DATA_SPEC,
|
||||||
|
C.DATA_TYPE_MEDIA,
|
||||||
|
C.TRACK_TYPE_UNKNOWN,
|
||||||
|
/* trackFormat= */ null,
|
||||||
|
C.SELECTION_REASON_UNKNOWN,
|
||||||
|
/* trackSelectionData= */ null,
|
||||||
|
/* mediaStartTimeUs= */ 0,
|
||||||
|
/* mediaEndTimeUs = */ C.TIME_UNSET,
|
||||||
|
SystemClock.elapsedRealtime());
|
||||||
|
prepareCallback = callback;
|
||||||
if (deferOnPrepared) {
|
if (deferOnPrepared) {
|
||||||
playerHandler = new Handler();
|
playerHandler = new Handler();
|
||||||
prepareCallback = callback;
|
|
||||||
} else {
|
} else {
|
||||||
prepared = true;
|
finishPreparation();
|
||||||
callback.onPrepared(this);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -196,7 +217,24 @@ public class FakeMediaPeriod implements MediaPeriod {
|
|||||||
}
|
}
|
||||||
|
|
||||||
protected SampleStream createSampleStream(TrackSelection selection) {
|
protected SampleStream createSampleStream(TrackSelection selection) {
|
||||||
return new FakeSampleStream(selection.getSelectedFormat());
|
return new FakeSampleStream(
|
||||||
|
selection.getSelectedFormat(), eventDispatcher, /* shouldOutputSample= */ true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void finishPreparation() {
|
||||||
|
prepared = true;
|
||||||
|
prepareCallback.onPrepared(this);
|
||||||
|
eventDispatcher.loadCompleted(
|
||||||
|
FAKE_DATA_SPEC,
|
||||||
|
C.DATA_TYPE_MEDIA,
|
||||||
|
C.TRACK_TYPE_UNKNOWN,
|
||||||
|
/* trackFormat= */ null,
|
||||||
|
C.SELECTION_REASON_UNKNOWN,
|
||||||
|
/* trackSelectionData= */ null,
|
||||||
|
/* mediaStartTimeUs= */ 0,
|
||||||
|
/* mediaEndTimeUs = */ C.TIME_UNSET,
|
||||||
|
SystemClock.elapsedRealtime(),
|
||||||
|
/* loadDurationMs= */ 0,
|
||||||
|
/* bytesLoaded= */ 100);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -17,17 +17,25 @@ package com.google.android.exoplayer2.testutil;
|
|||||||
|
|
||||||
import static com.google.common.truth.Truth.assertThat;
|
import static com.google.common.truth.Truth.assertThat;
|
||||||
|
|
||||||
|
import android.net.Uri;
|
||||||
import android.os.Handler;
|
import android.os.Handler;
|
||||||
|
import android.os.SystemClock;
|
||||||
import android.support.annotation.Nullable;
|
import android.support.annotation.Nullable;
|
||||||
|
import com.google.android.exoplayer2.C;
|
||||||
import com.google.android.exoplayer2.ExoPlayer;
|
import com.google.android.exoplayer2.ExoPlayer;
|
||||||
import com.google.android.exoplayer2.Format;
|
import com.google.android.exoplayer2.Format;
|
||||||
import com.google.android.exoplayer2.Timeline;
|
import com.google.android.exoplayer2.Timeline;
|
||||||
|
import com.google.android.exoplayer2.Timeline.Period;
|
||||||
import com.google.android.exoplayer2.source.BaseMediaSource;
|
import com.google.android.exoplayer2.source.BaseMediaSource;
|
||||||
import com.google.android.exoplayer2.source.MediaPeriod;
|
import com.google.android.exoplayer2.source.MediaPeriod;
|
||||||
import com.google.android.exoplayer2.source.MediaSource;
|
import com.google.android.exoplayer2.source.MediaSource;
|
||||||
|
import com.google.android.exoplayer2.source.MediaSourceEventListener.EventDispatcher;
|
||||||
|
import com.google.android.exoplayer2.source.MediaSourceEventListener.LoadEventInfo;
|
||||||
|
import com.google.android.exoplayer2.source.MediaSourceEventListener.MediaLoadData;
|
||||||
import com.google.android.exoplayer2.source.TrackGroup;
|
import com.google.android.exoplayer2.source.TrackGroup;
|
||||||
import com.google.android.exoplayer2.source.TrackGroupArray;
|
import com.google.android.exoplayer2.source.TrackGroupArray;
|
||||||
import com.google.android.exoplayer2.upstream.Allocator;
|
import com.google.android.exoplayer2.upstream.Allocator;
|
||||||
|
import com.google.android.exoplayer2.upstream.DataSpec;
|
||||||
import com.google.android.exoplayer2.util.Assertions;
|
import com.google.android.exoplayer2.util.Assertions;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
@ -39,6 +47,9 @@ import java.util.List;
|
|||||||
*/
|
*/
|
||||||
public class FakeMediaSource extends BaseMediaSource {
|
public class FakeMediaSource extends BaseMediaSource {
|
||||||
|
|
||||||
|
private static final DataSpec FAKE_DATA_SPEC = new DataSpec(Uri.parse("http://manifest.uri"));
|
||||||
|
private static final int MANIFEST_LOAD_BYTES = 100;
|
||||||
|
|
||||||
private final TrackGroupArray trackGroupArray;
|
private final TrackGroupArray trackGroupArray;
|
||||||
private final ArrayList<FakeMediaPeriod> activeMediaPeriods;
|
private final ArrayList<FakeMediaPeriod> activeMediaPeriods;
|
||||||
private final ArrayList<MediaPeriodId> createdMediaPeriods;
|
private final ArrayList<MediaPeriodId> createdMediaPeriods;
|
||||||
@ -81,7 +92,7 @@ public class FakeMediaSource extends BaseMediaSource {
|
|||||||
releasedSource = false;
|
releasedSource = false;
|
||||||
sourceInfoRefreshHandler = new Handler();
|
sourceInfoRefreshHandler = new Handler();
|
||||||
if (timeline != null) {
|
if (timeline != null) {
|
||||||
refreshSourceInfo(timeline, manifest);
|
finishSourcePreparation();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -95,7 +106,11 @@ public class FakeMediaSource extends BaseMediaSource {
|
|||||||
assertThat(preparedSource).isTrue();
|
assertThat(preparedSource).isTrue();
|
||||||
assertThat(releasedSource).isFalse();
|
assertThat(releasedSource).isFalse();
|
||||||
Assertions.checkIndex(id.periodIndex, 0, timeline.getPeriodCount());
|
Assertions.checkIndex(id.periodIndex, 0, timeline.getPeriodCount());
|
||||||
FakeMediaPeriod mediaPeriod = createFakeMediaPeriod(id, trackGroupArray, allocator);
|
Period period = timeline.getPeriod(id.periodIndex, new Period());
|
||||||
|
EventDispatcher eventDispatcher =
|
||||||
|
createEventDispatcher(period.windowIndex, id, period.getPositionInWindowMs());
|
||||||
|
FakeMediaPeriod mediaPeriod =
|
||||||
|
createFakeMediaPeriod(id, trackGroupArray, allocator, eventDispatcher);
|
||||||
activeMediaPeriods.add(mediaPeriod);
|
activeMediaPeriods.add(mediaPeriod);
|
||||||
createdMediaPeriods.add(id);
|
createdMediaPeriods.add(id);
|
||||||
return mediaPeriod;
|
return mediaPeriod;
|
||||||
@ -135,7 +150,7 @@ public class FakeMediaSource extends BaseMediaSource {
|
|||||||
assertThat(preparedSource).isTrue();
|
assertThat(preparedSource).isTrue();
|
||||||
timeline = newTimeline;
|
timeline = newTimeline;
|
||||||
manifest = newManifest;
|
manifest = newManifest;
|
||||||
refreshSourceInfo(timeline, manifest);
|
finishSourcePreparation();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
@ -163,9 +178,51 @@ public class FakeMediaSource extends BaseMediaSource {
|
|||||||
return createdMediaPeriods;
|
return createdMediaPeriods;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected FakeMediaPeriod createFakeMediaPeriod(MediaPeriodId id, TrackGroupArray trackGroupArray,
|
/**
|
||||||
Allocator allocator) {
|
* Creates a {@link FakeMediaPeriod} for this media source.
|
||||||
return new FakeMediaPeriod(trackGroupArray);
|
*
|
||||||
|
* @param id The identifier of the period.
|
||||||
|
* @param trackGroupArray The {@link TrackGroupArray} supported by the media period.
|
||||||
|
* @param allocator An {@link Allocator} from which to obtain media buffer allocations.
|
||||||
|
* @param eventDispatcher An {@link EventDispatcher} to dispatch media source events.
|
||||||
|
* @return A new {@link FakeMediaPeriod}.
|
||||||
|
*/
|
||||||
|
protected FakeMediaPeriod createFakeMediaPeriod(
|
||||||
|
MediaPeriodId id,
|
||||||
|
TrackGroupArray trackGroupArray,
|
||||||
|
Allocator allocator,
|
||||||
|
EventDispatcher eventDispatcher) {
|
||||||
|
return new FakeMediaPeriod(trackGroupArray, eventDispatcher);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void finishSourcePreparation() {
|
||||||
|
refreshSourceInfo(timeline, manifest);
|
||||||
|
if (!timeline.isEmpty()) {
|
||||||
|
MediaLoadData mediaLoadData =
|
||||||
|
new MediaLoadData(
|
||||||
|
/* windowIndex= */ 0,
|
||||||
|
/* mediaPeriodId= */ null,
|
||||||
|
C.DATA_TYPE_MANIFEST,
|
||||||
|
C.TRACK_TYPE_UNKNOWN,
|
||||||
|
/* trackFormat= */ null,
|
||||||
|
C.SELECTION_REASON_UNKNOWN,
|
||||||
|
/* trackSelectionData= */ null,
|
||||||
|
/* mediaStartTimeMs= */ C.TIME_UNSET,
|
||||||
|
/* mediaEndTimeMs = */ C.TIME_UNSET);
|
||||||
|
long elapsedRealTimeMs = SystemClock.elapsedRealtime();
|
||||||
|
EventDispatcher eventDispatcher = createEventDispatcher(/* mediaPeriodId= */ null);
|
||||||
|
eventDispatcher.loadStarted(
|
||||||
|
new LoadEventInfo(
|
||||||
|
FAKE_DATA_SPEC, elapsedRealTimeMs, /* loadDurationMs= */ 0, /* bytesLoaded= */ 0),
|
||||||
|
mediaLoadData);
|
||||||
|
eventDispatcher.loadCompleted(
|
||||||
|
new LoadEventInfo(
|
||||||
|
FAKE_DATA_SPEC,
|
||||||
|
elapsedRealTimeMs,
|
||||||
|
/* loadDurationMs= */ 0,
|
||||||
|
/* bytesLoaded= */ MANIFEST_LOAD_BYTES),
|
||||||
|
mediaLoadData);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static TrackGroupArray buildTrackGroupArray(Format... formats) {
|
private static TrackGroupArray buildTrackGroupArray(Format... formats) {
|
||||||
|
@ -15,10 +15,12 @@
|
|||||||
*/
|
*/
|
||||||
package com.google.android.exoplayer2.testutil;
|
package com.google.android.exoplayer2.testutil;
|
||||||
|
|
||||||
|
import android.support.annotation.Nullable;
|
||||||
import com.google.android.exoplayer2.C;
|
import com.google.android.exoplayer2.C;
|
||||||
import com.google.android.exoplayer2.Format;
|
import com.google.android.exoplayer2.Format;
|
||||||
import com.google.android.exoplayer2.FormatHolder;
|
import com.google.android.exoplayer2.FormatHolder;
|
||||||
import com.google.android.exoplayer2.decoder.DecoderInputBuffer;
|
import com.google.android.exoplayer2.decoder.DecoderInputBuffer;
|
||||||
|
import com.google.android.exoplayer2.source.MediaSourceEventListener.EventDispatcher;
|
||||||
import com.google.android.exoplayer2.source.SampleStream;
|
import com.google.android.exoplayer2.source.SampleStream;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
|
||||||
@ -29,16 +31,23 @@ import java.io.IOException;
|
|||||||
public final class FakeSampleStream implements SampleStream {
|
public final class FakeSampleStream implements SampleStream {
|
||||||
|
|
||||||
private final Format format;
|
private final Format format;
|
||||||
|
private final @Nullable EventDispatcher eventDispatcher;
|
||||||
|
|
||||||
private boolean readFormat;
|
private boolean readFormat;
|
||||||
private boolean readSample;
|
private boolean readSample;
|
||||||
|
|
||||||
public FakeSampleStream(Format format) {
|
/**
|
||||||
this(format, true);
|
* Creates fake sample stream which outputs the given {@link Format}, optionally one sample with
|
||||||
}
|
* zero bytes, then end of stream.
|
||||||
|
*
|
||||||
public FakeSampleStream(Format format, boolean shouldOutputSample) {
|
* @param format The {@link Format} to output.
|
||||||
|
* @param eventDispatcher An {@link EventDispatcher} to notify of read events.
|
||||||
|
* @param shouldOutputSample Whether the sample stream should output a sample.
|
||||||
|
*/
|
||||||
|
public FakeSampleStream(
|
||||||
|
Format format, @Nullable EventDispatcher eventDispatcher, boolean shouldOutputSample) {
|
||||||
this.format = format;
|
this.format = format;
|
||||||
|
this.eventDispatcher = eventDispatcher;
|
||||||
readSample = !shouldOutputSample;
|
readSample = !shouldOutputSample;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -60,6 +69,14 @@ public final class FakeSampleStream implements SampleStream {
|
|||||||
buffer.data.put((byte) 0);
|
buffer.data.put((byte) 0);
|
||||||
buffer.flip();
|
buffer.flip();
|
||||||
readSample = true;
|
readSample = true;
|
||||||
|
if (eventDispatcher != null) {
|
||||||
|
eventDispatcher.downstreamFormatChanged(
|
||||||
|
C.TRACK_TYPE_UNKNOWN,
|
||||||
|
format,
|
||||||
|
C.SELECTION_REASON_UNKNOWN,
|
||||||
|
/* trackSelectionData= */ null,
|
||||||
|
/* mediaTimeUs= */ 0);
|
||||||
|
}
|
||||||
return C.RESULT_BUFFER_READ;
|
return C.RESULT_BUFFER_READ;
|
||||||
} else {
|
} else {
|
||||||
buffer.setFlags(C.BUFFER_FLAG_END_OF_STREAM);
|
buffer.setFlags(C.BUFFER_FLAG_END_OF_STREAM);
|
||||||
|
@ -16,6 +16,7 @@
|
|||||||
package com.google.android.exoplayer2.testutil;
|
package com.google.android.exoplayer2.testutil;
|
||||||
|
|
||||||
import static com.google.common.truth.Truth.assertThat;
|
import static com.google.common.truth.Truth.assertThat;
|
||||||
|
import static com.google.common.truth.Truth.assertWithMessage;
|
||||||
import static org.junit.Assert.fail;
|
import static org.junit.Assert.fail;
|
||||||
|
|
||||||
import android.os.ConditionVariable;
|
import android.os.ConditionVariable;
|
||||||
@ -29,10 +30,18 @@ import com.google.android.exoplayer2.Timeline;
|
|||||||
import com.google.android.exoplayer2.source.MediaPeriod;
|
import com.google.android.exoplayer2.source.MediaPeriod;
|
||||||
import com.google.android.exoplayer2.source.MediaSource;
|
import com.google.android.exoplayer2.source.MediaSource;
|
||||||
import com.google.android.exoplayer2.source.MediaSource.MediaPeriodId;
|
import com.google.android.exoplayer2.source.MediaSource.MediaPeriodId;
|
||||||
|
import com.google.android.exoplayer2.source.MediaSourceEventListener;
|
||||||
|
import com.google.android.exoplayer2.source.MediaSourceEventListener.LoadEventInfo;
|
||||||
|
import com.google.android.exoplayer2.source.MediaSourceEventListener.MediaLoadData;
|
||||||
import com.google.android.exoplayer2.upstream.Allocator;
|
import com.google.android.exoplayer2.upstream.Allocator;
|
||||||
import com.google.android.exoplayer2.util.Assertions;
|
import com.google.android.exoplayer2.util.Assertions;
|
||||||
import com.google.android.exoplayer2.util.Util;
|
import com.google.android.exoplayer2.util.Util;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.HashSet;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.concurrent.CopyOnWriteArraySet;
|
||||||
import java.util.concurrent.CountDownLatch;
|
import java.util.concurrent.CountDownLatch;
|
||||||
import java.util.concurrent.LinkedBlockingDeque;
|
import java.util.concurrent.LinkedBlockingDeque;
|
||||||
import java.util.concurrent.TimeUnit;
|
import java.util.concurrent.TimeUnit;
|
||||||
@ -50,6 +59,7 @@ public class MediaSourceTestRunner {
|
|||||||
private final Allocator allocator;
|
private final Allocator allocator;
|
||||||
|
|
||||||
private final LinkedBlockingDeque<Timeline> timelines;
|
private final LinkedBlockingDeque<Timeline> timelines;
|
||||||
|
private final CopyOnWriteArraySet<MediaLoadData> completedLoads;
|
||||||
private Timeline timeline;
|
private Timeline timeline;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -66,6 +76,8 @@ public class MediaSourceTestRunner {
|
|||||||
player = new EventHandlingExoPlayer(playbackLooper);
|
player = new EventHandlingExoPlayer(playbackLooper);
|
||||||
mediaSourceListener = new MediaSourceListener();
|
mediaSourceListener = new MediaSourceListener();
|
||||||
timelines = new LinkedBlockingDeque<>();
|
timelines = new LinkedBlockingDeque<>();
|
||||||
|
completedLoads = new CopyOnWriteArraySet<>();
|
||||||
|
mediaSource.addEventListener(playbackHandler, mediaSourceListener);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -280,18 +292,99 @@ public class MediaSourceTestRunner {
|
|||||||
releasePeriod(secondMediaPeriod);
|
releasePeriod(secondMediaPeriod);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Asserts that the media source reported completed loads via {@link
|
||||||
|
* MediaSourceEventListener#onLoadCompleted(LoadEventInfo, MediaLoadData)} for each specified
|
||||||
|
* window index and a null period id. Also asserts that no other loads with media period id null
|
||||||
|
* are reported.
|
||||||
|
*/
|
||||||
|
public void assertCompletedManifestLoads(Integer... windowIndices) {
|
||||||
|
List<Integer> expectedWindowIndices = new ArrayList<>(Arrays.asList(windowIndices));
|
||||||
|
for (MediaLoadData mediaLoadData : completedLoads) {
|
||||||
|
if (mediaLoadData.mediaPeriodId == null) {
|
||||||
|
boolean loadExpected = expectedWindowIndices.remove((Integer) mediaLoadData.windowIndex);
|
||||||
|
assertThat(loadExpected).isTrue();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
assertWithMessage("Not all expected media source loads have been completed.")
|
||||||
|
.that(expectedWindowIndices)
|
||||||
|
.isEmpty();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Asserts that the media source reported completed loads via {@link
|
||||||
|
* MediaSourceEventListener#onLoadCompleted(LoadEventInfo, MediaLoadData)} for each specified
|
||||||
|
* media period id, and asserts that the associated window index matches the one in the last known
|
||||||
|
* timeline returned from {@link #prepareSource()}, {@link #assertTimelineChange()} or {@link
|
||||||
|
* #assertTimelineChangeBlocking()}.
|
||||||
|
*/
|
||||||
|
public void assertCompletedMediaPeriodLoads(MediaPeriodId... mediaPeriodIds) {
|
||||||
|
Timeline.Period period = new Timeline.Period();
|
||||||
|
HashSet<MediaPeriodId> expectedLoads = new HashSet<>(Arrays.asList(mediaPeriodIds));
|
||||||
|
for (MediaLoadData mediaLoadData : completedLoads) {
|
||||||
|
if (expectedLoads.remove(mediaLoadData.mediaPeriodId)) {
|
||||||
|
assertThat(mediaLoadData.windowIndex)
|
||||||
|
.isEqualTo(
|
||||||
|
timeline.getPeriod(mediaLoadData.mediaPeriodId.periodIndex, period).windowIndex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
assertWithMessage("Not all expected media source loads have been completed.")
|
||||||
|
.that(expectedLoads)
|
||||||
|
.isEmpty();
|
||||||
|
}
|
||||||
|
|
||||||
/** Releases the runner. Should be called when the runner is no longer required. */
|
/** Releases the runner. Should be called when the runner is no longer required. */
|
||||||
public void release() {
|
public void release() {
|
||||||
playbackThread.quit();
|
playbackThread.quit();
|
||||||
}
|
}
|
||||||
|
|
||||||
private class MediaSourceListener implements MediaSource.SourceInfoRefreshListener {
|
private class MediaSourceListener
|
||||||
|
implements MediaSource.SourceInfoRefreshListener, MediaSourceEventListener {
|
||||||
|
|
||||||
|
// SourceInfoRefreshListener methods.
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onSourceInfoRefreshed(MediaSource source, Timeline timeline, Object manifest) {
|
public void onSourceInfoRefreshed(MediaSource source, Timeline timeline, Object manifest) {
|
||||||
Assertions.checkState(Looper.myLooper() == playbackThread.getLooper());
|
Assertions.checkState(Looper.myLooper() == playbackThread.getLooper());
|
||||||
timelines.addLast(timeline);
|
timelines.addLast(timeline);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// MediaSourceEventListener methods.
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onLoadStarted(LoadEventInfo loadEventInfo, MediaLoadData mediaLoadData) {
|
||||||
|
Assertions.checkState(Looper.myLooper() == playbackThread.getLooper());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onLoadCompleted(LoadEventInfo loadEventInfo, MediaLoadData mediaLoadData) {
|
||||||
|
Assertions.checkState(Looper.myLooper() == playbackThread.getLooper());
|
||||||
|
completedLoads.add(mediaLoadData);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onLoadCanceled(LoadEventInfo loadEventInfo, MediaLoadData mediaLoadData) {
|
||||||
|
Assertions.checkState(Looper.myLooper() == playbackThread.getLooper());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onLoadError(
|
||||||
|
LoadEventInfo loadEventInfo,
|
||||||
|
MediaLoadData mediaLoadData,
|
||||||
|
IOException error,
|
||||||
|
boolean wasCanceled) {
|
||||||
|
Assertions.checkState(Looper.myLooper() == playbackThread.getLooper());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onUpstreamDiscarded(MediaLoadData mediaLoadData) {
|
||||||
|
Assertions.checkState(Looper.myLooper() == playbackThread.getLooper());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onDownstreamFormatChanged(MediaLoadData mediaLoadData) {
|
||||||
|
Assertions.checkState(Looper.myLooper() == playbackThread.getLooper());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static class EventHandlingExoPlayer extends StubExoPlayer
|
private static class EventHandlingExoPlayer extends StubExoPlayer
|
||||||
|
Loading…
x
Reference in New Issue
Block a user