Report mediaPeriodCreated/Released in MaskingMediaSource.

Creating a period in MaskingMediaSource may result in delayed event reporting
depending on when the actual period gets created. To avoid event reporting
inaccuracies, report the mediaPeriodCreated and mediaPeriodReleased events
directly.

Issue:#5407
PiperOrigin-RevId: 259737170
This commit is contained in:
tonihei 2019-07-24 15:34:07 +01:00 committed by Oliver Woodman
parent a0ca79abcc
commit 59331c3c88
2 changed files with 43 additions and 8 deletions

View file

@ -96,11 +96,11 @@ public abstract class CompositeMediaSource<T> extends BaseMediaSource {
/**
* Prepares a child source.
*
* <p>{@link #onChildSourceInfoRefreshed(Object, MediaSource, Timeline)} will be called when the
* child source updates its timeline with the same {@code id} passed to this method.
* <p>{@link #onChildSourceInfoRefreshed(T, MediaSource, Timeline)} will be called when the child
* source updates its timeline with the same {@code id} passed to this method.
*
* <p>Any child sources that aren't explicitly released with {@link #releaseChildSource(Object)}
* will be released in {@link #releaseSourceInternal()}.
* <p>Any child sources that aren't explicitly released with {@link #releaseChildSource(T)} will
* be released in {@link #releaseSourceInternal()}.
*
* @param id A unique id to identify the child source preparation. Null is allowed as an id.
* @param mediaSource The child {@link MediaSource}.
@ -188,6 +188,18 @@ public abstract class CompositeMediaSource<T> extends BaseMediaSource {
return mediaTimeMs;
}
/**
* Returns whether {@link MediaSourceEventListener#onMediaPeriodCreated(int, MediaPeriodId)} and
* {@link MediaSourceEventListener#onMediaPeriodReleased(int, MediaPeriodId)} events of the given
* media period should be reported. The default implementation is to always report these events.
*
* @param mediaPeriodId A {@link MediaPeriodId} in the composite media source.
* @return Whether create and release events for this media period should be reported.
*/
protected boolean shouldDispatchCreateOrReleaseEvent(MediaPeriodId mediaPeriodId) {
return true;
}
private static final class MediaSourceAndListener {
public final MediaSource mediaSource;
@ -215,14 +227,20 @@ public abstract class CompositeMediaSource<T> extends BaseMediaSource {
@Override
public void onMediaPeriodCreated(int windowIndex, MediaPeriodId mediaPeriodId) {
if (maybeUpdateEventDispatcher(windowIndex, mediaPeriodId)) {
eventDispatcher.mediaPeriodCreated();
if (shouldDispatchCreateOrReleaseEvent(
Assertions.checkNotNull(eventDispatcher.mediaPeriodId))) {
eventDispatcher.mediaPeriodCreated();
}
}
}
@Override
public void onMediaPeriodReleased(int windowIndex, MediaPeriodId mediaPeriodId) {
if (maybeUpdateEventDispatcher(windowIndex, mediaPeriodId)) {
eventDispatcher.mediaPeriodReleased();
if (shouldDispatchCreateOrReleaseEvent(
Assertions.checkNotNull(eventDispatcher.mediaPeriodId))) {
eventDispatcher.mediaPeriodReleased();
}
}
}

View file

@ -19,8 +19,10 @@ import androidx.annotation.Nullable;
import android.util.Pair;
import com.google.android.exoplayer2.C;
import com.google.android.exoplayer2.Timeline;
import com.google.android.exoplayer2.source.MediaSourceEventListener.EventDispatcher;
import com.google.android.exoplayer2.upstream.Allocator;
import com.google.android.exoplayer2.upstream.TransferListener;
import com.google.android.exoplayer2.util.Assertions;
import com.google.android.exoplayer2.util.Util;
import java.io.IOException;
@ -37,6 +39,7 @@ public final class MaskingMediaSource extends CompositeMediaSource<Void> {
private MaskingTimeline timeline;
@Nullable private MaskingMediaPeriod unpreparedMaskingMediaPeriod;
@Nullable private EventDispatcher unpreparedMaskingMediaPeriodEventDispatcher;
private boolean hasStartedPreparing;
private boolean isPrepared;
@ -96,6 +99,9 @@ public final class MaskingMediaSource extends CompositeMediaSource<Void> {
// unset and we don't load beyond periods with unset duration. We need to figure out how to
// handle the prepare positions of multiple deferred media periods, should that ever change.
unpreparedMaskingMediaPeriod = mediaPeriod;
unpreparedMaskingMediaPeriodEventDispatcher =
createEventDispatcher(/* windowIndex= */ 0, id, /* mediaTimeOffsetMs= */ 0);
unpreparedMaskingMediaPeriodEventDispatcher.mediaPeriodCreated();
if (!hasStartedPreparing) {
hasStartedPreparing = true;
prepareChildSource(/* id= */ null, mediaSource);
@ -107,7 +113,11 @@ public final class MaskingMediaSource extends CompositeMediaSource<Void> {
@Override
public void releasePeriod(MediaPeriod mediaPeriod) {
((MaskingMediaPeriod) mediaPeriod).releasePeriod();
unpreparedMaskingMediaPeriod = null;
if (mediaPeriod == unpreparedMaskingMediaPeriod) {
Assertions.checkNotNull(unpreparedMaskingMediaPeriodEventDispatcher).mediaPeriodReleased();
unpreparedMaskingMediaPeriodEventDispatcher = null;
unpreparedMaskingMediaPeriod = null;
}
}
@Override
@ -154,7 +164,6 @@ public final class MaskingMediaSource extends CompositeMediaSource<Void> {
timeline = MaskingTimeline.createWithRealTimeline(newTimeline, periodUid);
if (unpreparedMaskingMediaPeriod != null) {
MaskingMediaPeriod maskingPeriod = unpreparedMaskingMediaPeriod;
unpreparedMaskingMediaPeriod = null;
maskingPeriod.overridePreparePositionUs(periodPositionUs);
MediaPeriodId idInSource =
maskingPeriod.id.copyWithPeriodUid(getInternalPeriodUid(maskingPeriod.id.periodUid));
@ -172,6 +181,14 @@ public final class MaskingMediaSource extends CompositeMediaSource<Void> {
return mediaPeriodId.copyWithPeriodUid(getExternalPeriodUid(mediaPeriodId.periodUid));
}
@Override
protected boolean shouldDispatchCreateOrReleaseEvent(MediaPeriodId mediaPeriodId) {
// Suppress create and release events for the period created while the source was still
// unprepared, as we send these events from this class.
return unpreparedMaskingMediaPeriod == null
|| !mediaPeriodId.equals(unpreparedMaskingMediaPeriod.id);
}
private Object getInternalPeriodUid(Object externalPeriodUid) {
return externalPeriodUid.equals(MaskingTimeline.DUMMY_EXTERNAL_ID)
? timeline.replacedInternalId