Remove mediaTimeOffsetMs from EventDispatcher

The `DashMediaSource` wrongly added an offset to the media times set
to the `MediaLoadData`. With this the `startTimeMS` and `endTimeMs`
don't represent the positions in the period but in the stream.

`DashMediaSource` was the only call site that was setting the offset
to a non-zero value. So if we are using 0 for the `DashMediaSource`
as well, the offset is redundant and we can remove it everywhere.

PiperOrigin-RevId: 520682026
This commit is contained in:
bachinger 2023-03-30 18:41:09 +01:00 committed by Marc Baechinger
parent 104cfc322c
commit d7010da614
12 changed files with 74 additions and 61 deletions

View File

@ -21,6 +21,13 @@
AdPlaybackState>)` by adding a timeline parameter that contains the
periods with the UIDs used as keys in the map. This is required to avoid
concurrency issues with multi-period live streams.
* Deprecate `EventDispatcher.withParameters(int windowIndex, @Nullable
MediaPeriodId mediaPeriodId, long mediaTimeOffsetMs)` and
`BaseMediaSource.createEventDispatcher(..., long mediaTimeOffsetMs)`.
The variant of the methods without the `mediaTimeOffsetUs` can be called
instead. Note that even for the deprecated variants, the offset is not
anymore added to `startTimeUs` and `endTimeUs` of the `MediaLoadData`
objects that are dispatched by the dispatcher.
* Audio:
* Fix bug where some playbacks fail when tunneling is enabled and
`AudioProcessors` are active, e.g. for gapless trimming
@ -52,6 +59,8 @@
* DASH:
* Fix handling of empty segment timelines
([#11014](https://github.com/google/ExoPlayer/issues/11014)).
* Remove the media time offset from `MediaLoadData.startTimeMs` and
`MediaLoadData.endTimeMs` for multi period DASH streams.
* RTSP:
* Retry with TCP if RTSP Setup with UDP fails with RTSP Error 461
UnsupportedTransport

View File

@ -101,37 +101,46 @@ public abstract class BaseMediaSource implements MediaSource {
*/
protected final MediaSourceEventListener.EventDispatcher createEventDispatcher(
@Nullable MediaPeriodId mediaPeriodId) {
return eventDispatcher.withParameters(
/* windowIndex= */ 0, mediaPeriodId, /* mediaTimeOffsetMs= */ 0);
return eventDispatcher.withParameters(/* windowIndex= */ 0, mediaPeriodId);
}
/**
* Returns a {@link MediaSourceEventListener.EventDispatcher} which dispatches all events to the
* registered listeners with the specified {@link MediaPeriodId} and time offset.
*
* @param mediaPeriodId The {@link MediaPeriodId} to be reported with the events.
* @param mediaTimeOffsetMs The offset to be added to all media times, in milliseconds.
* @return An event dispatcher with pre-configured media period id and time offset.
*/
protected final MediaSourceEventListener.EventDispatcher createEventDispatcher(
MediaPeriodId mediaPeriodId, long mediaTimeOffsetMs) {
Assertions.checkNotNull(mediaPeriodId);
return eventDispatcher.withParameters(/* windowIndex= */ 0, mediaPeriodId, mediaTimeOffsetMs);
}
/**
* Returns a {@link MediaSourceEventListener.EventDispatcher} which dispatches all events to the
* registered listeners with the specified window index, {@link MediaPeriodId} and time offset.
* registered listeners with the specified window index and {@link MediaPeriodId}.
*
* @param windowIndex The timeline window index to be reported with the events.
* @param mediaPeriodId The {@link MediaPeriodId} to be reported with the events. May be null, if
* the events do not belong to a specific media period.
* @param mediaTimeOffsetMs The offset to be added to all media times, in milliseconds.
* @return An event dispatcher with pre-configured media period id and time offset.
* @return An event dispatcher with pre-configured media period id.
*/
protected final MediaSourceEventListener.EventDispatcher createEventDispatcher(
int windowIndex, @Nullable MediaPeriodId mediaPeriodId) {
return eventDispatcher.withParameters(windowIndex, mediaPeriodId);
}
/**
* Note: The {@code mediaTimeOffsetMs} passed to this method is ignored and not added to media
* times in any way.
*
* @deprecated Use {@link #createEventDispatcher(MediaPeriodId)} instead.
*/
@Deprecated
protected final MediaSourceEventListener.EventDispatcher createEventDispatcher(
MediaPeriodId mediaPeriodId, long mediaTimeOffsetMs) {
Assertions.checkNotNull(mediaPeriodId);
return eventDispatcher.withParameters(/* windowIndex= */ 0, mediaPeriodId);
}
/**
* Note: The {@code mediaTimeOffsetMs} passed to this method is ignored and not added to media
* times in any way.
*
* @deprecated Use {@link #createEventDispatcher(int, MediaPeriodId)} instead.
*/
@Deprecated
protected final MediaSourceEventListener.EventDispatcher createEventDispatcher(
int windowIndex, @Nullable MediaPeriodId mediaPeriodId, long mediaTimeOffsetMs) {
return eventDispatcher.withParameters(windowIndex, mediaPeriodId, mediaTimeOffsetMs);
return eventDispatcher.withParameters(windowIndex, mediaPeriodId);
}
/**

View File

@ -357,8 +357,7 @@ public abstract class CompositeMediaSource<T> extends BaseMediaSource {
int windowIndex = getWindowIndexForChildWindowIndex(id, childWindowIndex);
if (mediaSourceEventDispatcher.windowIndex != windowIndex
|| !Util.areEqual(mediaSourceEventDispatcher.mediaPeriodId, mediaPeriodId)) {
mediaSourceEventDispatcher =
createEventDispatcher(windowIndex, mediaPeriodId, /* mediaTimeOffsetMs= */ 0);
mediaSourceEventDispatcher = createEventDispatcher(windowIndex, mediaPeriodId);
}
if (drmEventDispatcher.windowIndex != windowIndex
|| !Util.areEqual(drmEventDispatcher.mediaPeriodId, mediaPeriodId)) {

View File

@ -16,6 +16,7 @@
package androidx.media3.exoplayer.source;
import static androidx.media3.common.util.Util.postOrRun;
import static androidx.media3.common.util.Util.usToMs;
import android.os.Handler;
import androidx.annotation.CheckResult;
@ -26,7 +27,6 @@ import androidx.media3.common.Format;
import androidx.media3.common.Player;
import androidx.media3.common.util.Assertions;
import androidx.media3.common.util.UnstableApi;
import androidx.media3.common.util.Util;
import androidx.media3.exoplayer.source.MediaSource.MediaPeriodId;
import java.io.IOException;
import java.util.concurrent.CopyOnWriteArrayList;
@ -152,26 +152,22 @@ public interface MediaSourceEventListener {
@Nullable public final MediaPeriodId mediaPeriodId;
private final CopyOnWriteArrayList<ListenerAndHandler> listenerAndHandlers;
private final long mediaTimeOffsetMs;
/** Creates an event dispatcher. */
public EventDispatcher() {
this(
/* listenerAndHandlers= */ new CopyOnWriteArrayList<>(),
/* windowIndex= */ 0,
/* mediaPeriodId= */ null,
/* mediaTimeOffsetMs= */ 0);
/* mediaPeriodId= */ null);
}
private EventDispatcher(
CopyOnWriteArrayList<ListenerAndHandler> listenerAndHandlers,
int windowIndex,
@Nullable MediaPeriodId mediaPeriodId,
long mediaTimeOffsetMs) {
@Nullable MediaPeriodId mediaPeriodId) {
this.listenerAndHandlers = listenerAndHandlers;
this.windowIndex = windowIndex;
this.mediaPeriodId = mediaPeriodId;
this.mediaTimeOffsetMs = mediaTimeOffsetMs;
}
/**
@ -180,14 +176,24 @@ public interface MediaSourceEventListener {
*
* @param windowIndex The timeline window index to be reported with the events.
* @param mediaPeriodId The {@link MediaPeriodId} to be reported with the events.
* @param mediaTimeOffsetMs The offset to be added to all media times, in milliseconds.
* @return A view of the event dispatcher with the pre-configured parameters.
*/
@CheckResult
public EventDispatcher withParameters(int windowIndex, @Nullable MediaPeriodId mediaPeriodId) {
return new EventDispatcher(listenerAndHandlers, windowIndex, mediaPeriodId);
}
/**
* Note: The {@code mediaTimeOffsetMs} passed to this method is ignored and not added to media
* times in any way.
*
* @deprecated Use {@link #withParameters(int, MediaPeriodId)} instead.
*/
@Deprecated
@CheckResult
public EventDispatcher withParameters(
int windowIndex, @Nullable MediaPeriodId mediaPeriodId, long mediaTimeOffsetMs) {
return new EventDispatcher(
listenerAndHandlers, windowIndex, mediaPeriodId, mediaTimeOffsetMs);
return new EventDispatcher(listenerAndHandlers, windowIndex, mediaPeriodId);
}
/**
@ -246,8 +252,8 @@ public interface MediaSourceEventListener {
trackFormat,
trackSelectionReason,
trackSelectionData,
adjustMediaTime(mediaStartTimeUs),
adjustMediaTime(mediaEndTimeUs)));
usToMs(mediaStartTimeUs),
usToMs(mediaEndTimeUs)));
}
/** Dispatches {@link #onLoadStarted(int, MediaPeriodId, LoadEventInfo, MediaLoadData)}. */
@ -291,8 +297,8 @@ public interface MediaSourceEventListener {
trackFormat,
trackSelectionReason,
trackSelectionData,
adjustMediaTime(mediaStartTimeUs),
adjustMediaTime(mediaEndTimeUs)));
usToMs(mediaStartTimeUs),
usToMs(mediaEndTimeUs)));
}
/** Dispatches {@link #onLoadCompleted(int, MediaPeriodId, LoadEventInfo, MediaLoadData)}. */
@ -337,8 +343,8 @@ public interface MediaSourceEventListener {
trackFormat,
trackSelectionReason,
trackSelectionData,
adjustMediaTime(mediaStartTimeUs),
adjustMediaTime(mediaEndTimeUs)));
usToMs(mediaStartTimeUs),
usToMs(mediaEndTimeUs)));
}
/** Dispatches {@link #onLoadCanceled(int, MediaPeriodId, LoadEventInfo, MediaLoadData)}. */
@ -397,8 +403,8 @@ public interface MediaSourceEventListener {
trackFormat,
trackSelectionReason,
trackSelectionData,
adjustMediaTime(mediaStartTimeUs),
adjustMediaTime(mediaEndTimeUs)),
usToMs(mediaStartTimeUs),
usToMs(mediaEndTimeUs)),
error,
wasCanceled);
}
@ -431,8 +437,8 @@ public interface MediaSourceEventListener {
/* trackFormat= */ null,
C.SELECTION_REASON_ADAPTIVE,
/* trackSelectionData= */ null,
adjustMediaTime(mediaStartTimeUs),
adjustMediaTime(mediaEndTimeUs)));
usToMs(mediaStartTimeUs),
usToMs(mediaEndTimeUs)));
}
/** Dispatches {@link #onUpstreamDiscarded(int, MediaPeriodId, MediaLoadData)}. */
@ -460,7 +466,7 @@ public interface MediaSourceEventListener {
trackFormat,
trackSelectionReason,
trackSelectionData,
adjustMediaTime(mediaTimeUs),
usToMs(mediaTimeUs),
/* mediaEndTimeMs= */ C.TIME_UNSET));
}
@ -474,11 +480,6 @@ public interface MediaSourceEventListener {
}
}
private long adjustMediaTime(long mediaTimeUs) {
long mediaTimeMs = Util.usToMs(mediaTimeUs);
return mediaTimeMs == C.TIME_UNSET ? C.TIME_UNSET : mediaTimeOffsetMs + mediaTimeMs;
}
private static final class ListenerAndHandler {
public Handler handler;

View File

@ -517,8 +517,7 @@ public class DownloadHelperTest {
trackGroupArrays[periodIndex],
allocator,
TEST_TIMELINE.getWindow(0, new Timeline.Window()).positionInFirstPeriodUs,
new EventDispatcher()
.withParameters(/* windowIndex= */ 0, id, /* mediaTimeOffsetMs= */ 0)) {
new EventDispatcher().withParameters(/* windowIndex= */ 0, id)) {
@Override
public List<StreamKey> getStreamKeys(List<ExoTrackSelection> trackSelections) {
List<StreamKey> result = new ArrayList<>();

View File

@ -246,10 +246,7 @@ public final class MergingMediaPeriodTest {
new FakeMediaPeriodWithSelectionParameters(
new TrackGroupArray(trackGroups),
new EventDispatcher()
.withParameters(
/* windowIndex= */ i,
new MediaPeriodId(/* periodUid= */ i),
/* mediaTimeOffsetMs= */ 0),
.withParameters(/* windowIndex= */ i, new MediaPeriodId(/* periodUid= */ i)),
/* trackDataFactory= */ (unusedFormat, unusedMediaPeriodId) ->
ImmutableList.of(
oneByteSample(definition.singleSampleTimeUs, C.BUFFER_FLAG_KEY_FRAME),

View File

@ -69,7 +69,7 @@ public final class ProgressiveMediaPeriodTest {
.withParameters(/* windowIndex= */ 0, mediaPeriodId),
new DefaultLoadErrorHandlingPolicy(),
new MediaSourceEventListener.EventDispatcher()
.withParameters(/* windowIndex= */ 0, mediaPeriodId, /* mediaTimeOffsetMs= */ 0),
.withParameters(/* windowIndex= */ 0, mediaPeriodId),
sourceInfoRefreshListener,
new DefaultAllocator(/* trimOnReset= */ true, C.DEFAULT_BUFFER_SEGMENT_SIZE),
/* customCacheKey= */ null,

View File

@ -469,8 +469,7 @@ public final class DashMediaSource extends BaseMediaSource {
@Override
public MediaPeriod createPeriod(MediaPeriodId id, Allocator allocator, long startPositionUs) {
int periodIndex = (Integer) id.periodUid - firstPeriodId;
MediaSourceEventListener.EventDispatcher periodEventDispatcher =
createEventDispatcher(id, manifest.getPeriod(periodIndex).startMs);
MediaSourceEventListener.EventDispatcher periodEventDispatcher = createEventDispatcher(id);
DrmSessionEventListener.EventDispatcher drmEventDispatcher = createDrmEventDispatcher(id);
DashMediaPeriod mediaPeriod =
new DashMediaPeriod(

View File

@ -216,7 +216,7 @@ public final class DashMediaPeriodTest {
.withParameters(/* windowIndex= */ 0, mediaPeriodId),
mock(LoadErrorHandlingPolicy.class),
new MediaSourceEventListener.EventDispatcher()
.withParameters(/* windowIndex= */ 0, mediaPeriodId, /* mediaTimeOffsetMs= */ 0),
.withParameters(/* windowIndex= */ 0, mediaPeriodId),
/* elapsedRealtimeOffsetMs= */ 0,
mock(LoaderErrorThrower.class),
mock(Allocator.class),

View File

@ -89,7 +89,7 @@ public final class HlsMediaPeriodTest {
.withParameters(/* windowIndex= */ 0, mediaPeriodId),
mock(LoadErrorHandlingPolicy.class),
new MediaSourceEventListener.EventDispatcher()
.withParameters(/* windowIndex= */ 0, mediaPeriodId, /* mediaTimeOffsetMs= */ 0),
.withParameters(/* windowIndex= */ 0, mediaPeriodId),
mock(Allocator.class),
mock(CompositeSequenceableLoaderFactory.class),
/* allowChunklessPreparation= */ true,

View File

@ -72,7 +72,7 @@ public class SsMediaPeriodTest {
.withParameters(/* windowIndex= */ 0, mediaPeriodId),
mock(LoadErrorHandlingPolicy.class),
new MediaSourceEventListener.EventDispatcher()
.withParameters(/* windowIndex= */ 0, mediaPeriodId, /* mediaTimeOffsetMs= */ 0),
.withParameters(/* windowIndex= */ 0, mediaPeriodId),
mock(LoaderErrorThrower.class),
mock(Allocator.class));
};

View File

@ -239,7 +239,7 @@ public class FakeMediaSource extends BaseMediaSource {
Assertions.checkArgument(periodIndex != C.INDEX_UNSET);
Period period = timeline.getPeriod(periodIndex, new Period());
MediaSourceEventListener.EventDispatcher mediaSourceEventDispatcher =
createEventDispatcher(period.windowIndex, id, period.getPositionInWindowMs());
createEventDispatcher(period.windowIndex, id);
DrmSessionEventListener.EventDispatcher drmEventDispatcher =
createDrmEventDispatcher(period.windowIndex, id);
MediaPeriod mediaPeriod =