summaryrefslogtreecommitdiffstats
path: root/mobile/android/exoplayer2/src/main/java/org/mozilla/thirdparty/com/google/android/exoplayer2/source/MediaSourceEventListener.java
diff options
context:
space:
mode:
Diffstat (limited to 'mobile/android/exoplayer2/src/main/java/org/mozilla/thirdparty/com/google/android/exoplayer2/source/MediaSourceEventListener.java')
-rw-r--r--mobile/android/exoplayer2/src/main/java/org/mozilla/thirdparty/com/google/android/exoplayer2/source/MediaSourceEventListener.java740
1 files changed, 740 insertions, 0 deletions
diff --git a/mobile/android/exoplayer2/src/main/java/org/mozilla/thirdparty/com/google/android/exoplayer2/source/MediaSourceEventListener.java b/mobile/android/exoplayer2/src/main/java/org/mozilla/thirdparty/com/google/android/exoplayer2/source/MediaSourceEventListener.java
new file mode 100644
index 0000000000..53c50d8a26
--- /dev/null
+++ b/mobile/android/exoplayer2/src/main/java/org/mozilla/thirdparty/com/google/android/exoplayer2/source/MediaSourceEventListener.java
@@ -0,0 +1,740 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.mozilla.thirdparty.com.google.android.exoplayer2.source;
+
+import android.net.Uri;
+import android.os.Handler;
+import android.os.Looper;
+import android.os.SystemClock;
+import androidx.annotation.CheckResult;
+import androidx.annotation.Nullable;
+import org.mozilla.thirdparty.com.google.android.exoplayer2.C;
+import org.mozilla.thirdparty.com.google.android.exoplayer2.Format;
+import org.mozilla.thirdparty.com.google.android.exoplayer2.Player;
+import org.mozilla.thirdparty.com.google.android.exoplayer2.source.MediaSource.MediaPeriodId;
+import org.mozilla.thirdparty.com.google.android.exoplayer2.upstream.DataSpec;
+import org.mozilla.thirdparty.com.google.android.exoplayer2.util.Assertions;
+import java.io.IOException;
+import java.util.Collections;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.CopyOnWriteArrayList;
+
+/** Interface for callbacks to be notified of {@link MediaSource} events. */
+public interface MediaSourceEventListener {
+
+ /** Media source load event information. */
+ final class LoadEventInfo {
+
+ /** Defines the requested data. */
+ public final DataSpec dataSpec;
+ /**
+ * The {@link Uri} from which data is being read. The uri will be identical to the one in {@link
+ * #dataSpec}.uri unless redirection has occurred. If redirection has occurred, this is the uri
+ * after redirection.
+ */
+ public final Uri uri;
+ /** The response headers associated with the load, or an empty map if unavailable. */
+ public final Map<String, List<String>> responseHeaders;
+ /** The value of {@link SystemClock#elapsedRealtime} at the time of the load event. */
+ public final long elapsedRealtimeMs;
+ /** The duration of the load up to the event time. */
+ public final long loadDurationMs;
+ /** The number of bytes that were loaded up to the event time. */
+ public final long bytesLoaded;
+
+ /**
+ * Creates load event info.
+ *
+ * @param dataSpec Defines the requested data.
+ * @param uri The {@link Uri} from which data is being read. The uri must be identical to the
+ * one in {@code dataSpec.uri} unless redirection has occurred. If redirection has occurred,
+ * this is the uri after redirection.
+ * @param responseHeaders The response headers associated with the load, or an empty map if
+ * unavailable.
+ * @param elapsedRealtimeMs The value of {@link SystemClock#elapsedRealtime} at the time of the
+ * load event.
+ * @param loadDurationMs The duration of the load up to the event time.
+ * @param bytesLoaded The number of bytes that were loaded up to the event time. For compressed
+ * network responses, this is the decompressed size.
+ */
+ public LoadEventInfo(
+ DataSpec dataSpec,
+ Uri uri,
+ Map<String, List<String>> responseHeaders,
+ long elapsedRealtimeMs,
+ long loadDurationMs,
+ long bytesLoaded) {
+ this.dataSpec = dataSpec;
+ this.uri = uri;
+ this.responseHeaders = responseHeaders;
+ this.elapsedRealtimeMs = elapsedRealtimeMs;
+ this.loadDurationMs = loadDurationMs;
+ this.bytesLoaded = bytesLoaded;
+ }
+ }
+
+ /** Descriptor for data being loaded or selected by a media source. */
+ final class MediaLoadData {
+
+ /** One of the {@link C} {@code DATA_TYPE_*} constants defining the type of data. */
+ public final int dataType;
+ /**
+ * One of the {@link C} {@code TRACK_TYPE_*} constants if the data corresponds to media of a
+ * specific type. {@link C#TRACK_TYPE_UNKNOWN} otherwise.
+ */
+ public final int trackType;
+ /**
+ * The format of the track to which the data belongs. Null if the data does not belong to a
+ * specific track.
+ */
+ @Nullable public final Format trackFormat;
+ /**
+ * One of the {@link C} {@code SELECTION_REASON_*} constants if the data belongs to a track.
+ * {@link C#SELECTION_REASON_UNKNOWN} otherwise.
+ */
+ public final int trackSelectionReason;
+ /**
+ * Optional data associated with the selection of the track to which the data belongs. Null if
+ * the data does not belong to a track.
+ */
+ @Nullable public final Object trackSelectionData;
+ /**
+ * The start time of the media, or {@link C#TIME_UNSET} if the data does not belong to a
+ * specific media period.
+ */
+ public final long mediaStartTimeMs;
+ /**
+ * The end time of the media, or {@link C#TIME_UNSET} if the data does not belong to a specific
+ * media period or the end time is unknown.
+ */
+ public final long mediaEndTimeMs;
+
+ /**
+ * Creates media load data.
+ *
+ * @param dataType One of the {@link C} {@code DATA_TYPE_*} constants defining the type of data.
+ * @param trackType One of the {@link C} {@code TRACK_TYPE_*} constants if the data corresponds
+ * to media of a specific type. {@link C#TRACK_TYPE_UNKNOWN} otherwise.
+ * @param trackFormat The format of the track to which the data belongs. Null if the data does
+ * not belong to a track.
+ * @param trackSelectionReason One of the {@link C} {@code SELECTION_REASON_*} constants if the
+ * data belongs to a track. {@link C#SELECTION_REASON_UNKNOWN} otherwise.
+ * @param trackSelectionData Optional data associated with the selection of the track to which
+ * the data belongs. Null if the data does not belong to a track.
+ * @param mediaStartTimeMs The start time of the media, or {@link C#TIME_UNSET} if the data does
+ * not belong to a specific media period.
+ * @param mediaEndTimeMs The end time of the media, or {@link C#TIME_UNSET} if the data does not
+ * belong to a specific media period or the end time is unknown.
+ */
+ public MediaLoadData(
+ int dataType,
+ int trackType,
+ @Nullable Format trackFormat,
+ int trackSelectionReason,
+ @Nullable Object trackSelectionData,
+ long mediaStartTimeMs,
+ long mediaEndTimeMs) {
+ this.dataType = dataType;
+ this.trackType = trackType;
+ this.trackFormat = trackFormat;
+ this.trackSelectionReason = trackSelectionReason;
+ this.trackSelectionData = trackSelectionData;
+ this.mediaStartTimeMs = mediaStartTimeMs;
+ this.mediaEndTimeMs = mediaEndTimeMs;
+ }
+ }
+
+ /**
+ * Called when a media period is created by the media source.
+ *
+ * @param windowIndex The window index in the timeline this media period belongs to.
+ * @param mediaPeriodId The {@link MediaPeriodId} of the created media period.
+ */
+ default void onMediaPeriodCreated(int windowIndex, MediaPeriodId mediaPeriodId) {}
+
+ /**
+ * Called when a media period is released by the media source.
+ *
+ * @param windowIndex The window index in the timeline this media period belongs to.
+ * @param mediaPeriodId The {@link MediaPeriodId} of the released media period.
+ */
+ default void onMediaPeriodReleased(int windowIndex, MediaPeriodId mediaPeriodId) {}
+
+ /**
+ * Called when a load begins.
+ *
+ * @param windowIndex The window index in the timeline of the media source this load belongs to.
+ * @param mediaPeriodId The {@link MediaPeriodId} this load belongs to. Null if the load does not
+ * belong to a specific media period.
+ * @param loadEventInfo The {@link LoadEventInfo} corresponding to the event. The value of {@link
+ * LoadEventInfo#uri} won't reflect potential redirection yet and {@link
+ * LoadEventInfo#responseHeaders} will be empty.
+ * @param mediaLoadData The {@link MediaLoadData} defining the data being loaded.
+ */
+ default void onLoadStarted(
+ int windowIndex,
+ @Nullable MediaPeriodId mediaPeriodId,
+ LoadEventInfo loadEventInfo,
+ MediaLoadData mediaLoadData) {}
+
+ /**
+ * Called when a load ends.
+ *
+ * @param windowIndex The window index in the timeline of the media source this load belongs to.
+ * @param mediaPeriodId The {@link MediaPeriodId} this load belongs to. Null if the load does not
+ * belong to a specific media period.
+ * @param loadEventInfo The {@link LoadEventInfo} corresponding to the event. The values of {@link
+ * LoadEventInfo#elapsedRealtimeMs} and {@link LoadEventInfo#bytesLoaded} are relative to the
+ * corresponding {@link #onLoadStarted(int, MediaPeriodId, LoadEventInfo, MediaLoadData)}
+ * event.
+ * @param mediaLoadData The {@link MediaLoadData} defining the data being loaded.
+ */
+ default void onLoadCompleted(
+ int windowIndex,
+ @Nullable MediaPeriodId mediaPeriodId,
+ LoadEventInfo loadEventInfo,
+ MediaLoadData mediaLoadData) {}
+
+ /**
+ * Called when a load is canceled.
+ *
+ * @param windowIndex The window index in the timeline of the media source this load belongs to.
+ * @param mediaPeriodId The {@link MediaPeriodId} this load belongs to. Null if the load does not
+ * belong to a specific media period.
+ * @param loadEventInfo The {@link LoadEventInfo} corresponding to the event. The values of {@link
+ * LoadEventInfo#elapsedRealtimeMs} and {@link LoadEventInfo#bytesLoaded} are relative to the
+ * corresponding {@link #onLoadStarted(int, MediaPeriodId, LoadEventInfo, MediaLoadData)}
+ * event.
+ * @param mediaLoadData The {@link MediaLoadData} defining the data being loaded.
+ */
+ default void onLoadCanceled(
+ int windowIndex,
+ @Nullable MediaPeriodId mediaPeriodId,
+ LoadEventInfo loadEventInfo,
+ MediaLoadData mediaLoadData) {}
+
+ /**
+ * Called when a load error occurs.
+ *
+ * <p>The error may or may not have resulted in the load being canceled, as indicated by the
+ * {@code wasCanceled} parameter. If the load was canceled, {@link #onLoadCanceled} will
+ * <em>not</em> be called in addition to this method.
+ *
+ * <p>This method being called does not indicate that playback has failed, or that it will fail.
+ * The player may be able to recover from the error and continue. Hence applications should
+ * <em>not</em> implement this method to display a user visible error or initiate an application
+ * level retry ({@link Player.EventListener#onPlayerError} is the appropriate place to implement
+ * such behavior). This method is called to provide the application with an opportunity to log the
+ * error if it wishes to do so.
+ *
+ * @param windowIndex The window index in the timeline of the media source this load belongs to.
+ * @param mediaPeriodId The {@link MediaPeriodId} this load belongs to. Null if the load does not
+ * belong to a specific media period.
+ * @param loadEventInfo The {@link LoadEventInfo} corresponding to the event. The values of {@link
+ * LoadEventInfo#elapsedRealtimeMs} and {@link LoadEventInfo#bytesLoaded} are relative to the
+ * corresponding {@link #onLoadStarted(int, MediaPeriodId, LoadEventInfo, MediaLoadData)}
+ * event.
+ * @param mediaLoadData The {@link MediaLoadData} defining the data being loaded.
+ * @param error The load error.
+ * @param wasCanceled Whether the load was canceled as a result of the error.
+ */
+ default void onLoadError(
+ int windowIndex,
+ @Nullable MediaPeriodId mediaPeriodId,
+ LoadEventInfo loadEventInfo,
+ MediaLoadData mediaLoadData,
+ IOException error,
+ boolean wasCanceled) {}
+
+ /**
+ * Called when a media period is first being read from.
+ *
+ * @param windowIndex The window index in the timeline this media period belongs to.
+ * @param mediaPeriodId The {@link MediaPeriodId} of the media period being read from.
+ */
+ default void onReadingStarted(int windowIndex, MediaPeriodId mediaPeriodId) {}
+
+ /**
+ * Called when data is removed from the back of a media buffer, typically so that it can be
+ * re-buffered in a different format.
+ *
+ * @param windowIndex The window index in the timeline of the media source this load belongs to.
+ * @param mediaPeriodId The {@link MediaPeriodId} the media belongs to.
+ * @param mediaLoadData The {@link MediaLoadData} defining the media being discarded.
+ */
+ default void onUpstreamDiscarded(
+ int windowIndex, MediaPeriodId mediaPeriodId, MediaLoadData mediaLoadData) {}
+
+ /**
+ * Called when a downstream format change occurs (i.e. when the format of the media being read
+ * from one or more {@link SampleStream}s provided by the source changes).
+ *
+ * @param windowIndex The window index in the timeline of the media source this load belongs to.
+ * @param mediaPeriodId The {@link MediaPeriodId} the media belongs to.
+ * @param mediaLoadData The {@link MediaLoadData} defining the newly selected downstream data.
+ */
+ default void onDownstreamFormatChanged(
+ int windowIndex, @Nullable MediaPeriodId mediaPeriodId, MediaLoadData mediaLoadData) {}
+
+ /** Dispatches events to {@link MediaSourceEventListener}s. */
+ final class EventDispatcher {
+
+ /** The timeline window index reported with the events. */
+ public final int windowIndex;
+ /** The {@link MediaPeriodId} reported with the events. */
+ @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);
+ }
+
+ private EventDispatcher(
+ CopyOnWriteArrayList<ListenerAndHandler> listenerAndHandlers,
+ int windowIndex,
+ @Nullable MediaPeriodId mediaPeriodId,
+ long mediaTimeOffsetMs) {
+ this.listenerAndHandlers = listenerAndHandlers;
+ this.windowIndex = windowIndex;
+ this.mediaPeriodId = mediaPeriodId;
+ this.mediaTimeOffsetMs = mediaTimeOffsetMs;
+ }
+
+ /**
+ * Creates a view of the event dispatcher with pre-configured window index, media period id, and
+ * media time offset.
+ *
+ * @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, long mediaTimeOffsetMs) {
+ return new EventDispatcher(
+ listenerAndHandlers, windowIndex, mediaPeriodId, mediaTimeOffsetMs);
+ }
+
+ /**
+ * Adds a listener to the event dispatcher.
+ *
+ * @param handler A handler on the which listener events will be posted.
+ * @param eventListener The listener to be added.
+ */
+ public void addEventListener(Handler handler, MediaSourceEventListener eventListener) {
+ Assertions.checkArgument(handler != null && eventListener != null);
+ listenerAndHandlers.add(new ListenerAndHandler(handler, eventListener));
+ }
+
+ /**
+ * Removes a listener from the event dispatcher.
+ *
+ * @param eventListener The listener to be removed.
+ */
+ public void removeEventListener(MediaSourceEventListener eventListener) {
+ for (ListenerAndHandler listenerAndHandler : listenerAndHandlers) {
+ if (listenerAndHandler.listener == eventListener) {
+ listenerAndHandlers.remove(listenerAndHandler);
+ }
+ }
+ }
+
+ /** Dispatches {@link #onMediaPeriodCreated(int, MediaPeriodId)}. */
+ public void mediaPeriodCreated() {
+ MediaPeriodId mediaPeriodId = Assertions.checkNotNull(this.mediaPeriodId);
+ for (ListenerAndHandler listenerAndHandler : listenerAndHandlers) {
+ final MediaSourceEventListener listener = listenerAndHandler.listener;
+ postOrRun(
+ listenerAndHandler.handler,
+ () -> listener.onMediaPeriodCreated(windowIndex, mediaPeriodId));
+ }
+ }
+
+ /** Dispatches {@link #onMediaPeriodReleased(int, MediaPeriodId)}. */
+ public void mediaPeriodReleased() {
+ MediaPeriodId mediaPeriodId = Assertions.checkNotNull(this.mediaPeriodId);
+ for (ListenerAndHandler listenerAndHandler : listenerAndHandlers) {
+ final MediaSourceEventListener listener = listenerAndHandler.listener;
+ postOrRun(
+ listenerAndHandler.handler,
+ () -> listener.onMediaPeriodReleased(windowIndex, mediaPeriodId));
+ }
+ }
+
+ /** Dispatches {@link #onLoadStarted(int, MediaPeriodId, LoadEventInfo, MediaLoadData)}. */
+ public void loadStarted(DataSpec dataSpec, int dataType, long elapsedRealtimeMs) {
+ loadStarted(
+ dataSpec,
+ dataType,
+ C.TRACK_TYPE_UNKNOWN,
+ null,
+ C.SELECTION_REASON_UNKNOWN,
+ null,
+ C.TIME_UNSET,
+ C.TIME_UNSET,
+ elapsedRealtimeMs);
+ }
+
+ /** Dispatches {@link #onLoadStarted(int, MediaPeriodId, LoadEventInfo, MediaLoadData)}. */
+ public void loadStarted(
+ DataSpec dataSpec,
+ int dataType,
+ int trackType,
+ @Nullable Format trackFormat,
+ int trackSelectionReason,
+ @Nullable Object trackSelectionData,
+ long mediaStartTimeUs,
+ long mediaEndTimeUs,
+ long elapsedRealtimeMs) {
+ loadStarted(
+ new LoadEventInfo(
+ dataSpec,
+ dataSpec.uri,
+ /* responseHeaders= */ Collections.emptyMap(),
+ elapsedRealtimeMs,
+ /* loadDurationMs= */ 0,
+ /* bytesLoaded= */ 0),
+ new MediaLoadData(
+ dataType,
+ trackType,
+ trackFormat,
+ trackSelectionReason,
+ trackSelectionData,
+ adjustMediaTime(mediaStartTimeUs),
+ adjustMediaTime(mediaEndTimeUs)));
+ }
+
+ /** Dispatches {@link #onLoadStarted(int, MediaPeriodId, LoadEventInfo, MediaLoadData)}. */
+ public void loadStarted(LoadEventInfo loadEventInfo, MediaLoadData mediaLoadData) {
+ for (ListenerAndHandler listenerAndHandler : listenerAndHandlers) {
+ final MediaSourceEventListener listener = listenerAndHandler.listener;
+ postOrRun(
+ listenerAndHandler.handler,
+ () -> listener.onLoadStarted(windowIndex, mediaPeriodId, loadEventInfo, mediaLoadData));
+ }
+ }
+
+ /** Dispatches {@link #onLoadCompleted(int, MediaPeriodId, LoadEventInfo, MediaLoadData)}. */
+ public void loadCompleted(
+ DataSpec dataSpec,
+ Uri uri,
+ Map<String, List<String>> responseHeaders,
+ int dataType,
+ long elapsedRealtimeMs,
+ long loadDurationMs,
+ long bytesLoaded) {
+ loadCompleted(
+ dataSpec,
+ uri,
+ responseHeaders,
+ dataType,
+ C.TRACK_TYPE_UNKNOWN,
+ null,
+ C.SELECTION_REASON_UNKNOWN,
+ null,
+ C.TIME_UNSET,
+ C.TIME_UNSET,
+ elapsedRealtimeMs,
+ loadDurationMs,
+ bytesLoaded);
+ }
+
+ /** Dispatches {@link #onLoadCompleted(int, MediaPeriodId, LoadEventInfo, MediaLoadData)}. */
+ public void loadCompleted(
+ DataSpec dataSpec,
+ Uri uri,
+ Map<String, List<String>> responseHeaders,
+ int dataType,
+ int trackType,
+ @Nullable Format trackFormat,
+ int trackSelectionReason,
+ @Nullable Object trackSelectionData,
+ long mediaStartTimeUs,
+ long mediaEndTimeUs,
+ long elapsedRealtimeMs,
+ long loadDurationMs,
+ long bytesLoaded) {
+ loadCompleted(
+ new LoadEventInfo(
+ dataSpec, uri, responseHeaders, elapsedRealtimeMs, loadDurationMs, bytesLoaded),
+ new MediaLoadData(
+ dataType,
+ trackType,
+ trackFormat,
+ trackSelectionReason,
+ trackSelectionData,
+ adjustMediaTime(mediaStartTimeUs),
+ adjustMediaTime(mediaEndTimeUs)));
+ }
+
+ /** Dispatches {@link #onLoadCompleted(int, MediaPeriodId, LoadEventInfo, MediaLoadData)}. */
+ public void loadCompleted(LoadEventInfo loadEventInfo, MediaLoadData mediaLoadData) {
+ for (ListenerAndHandler listenerAndHandler : listenerAndHandlers) {
+ final MediaSourceEventListener listener = listenerAndHandler.listener;
+ postOrRun(
+ listenerAndHandler.handler,
+ () ->
+ listener.onLoadCompleted(windowIndex, mediaPeriodId, loadEventInfo, mediaLoadData));
+ }
+ }
+
+ /** Dispatches {@link #onLoadCanceled(int, MediaPeriodId, LoadEventInfo, MediaLoadData)}. */
+ public void loadCanceled(
+ DataSpec dataSpec,
+ Uri uri,
+ Map<String, List<String>> responseHeaders,
+ int dataType,
+ long elapsedRealtimeMs,
+ long loadDurationMs,
+ long bytesLoaded) {
+ loadCanceled(
+ dataSpec,
+ uri,
+ responseHeaders,
+ dataType,
+ C.TRACK_TYPE_UNKNOWN,
+ null,
+ C.SELECTION_REASON_UNKNOWN,
+ null,
+ C.TIME_UNSET,
+ C.TIME_UNSET,
+ elapsedRealtimeMs,
+ loadDurationMs,
+ bytesLoaded);
+ }
+
+ /** Dispatches {@link #onLoadCanceled(int, MediaPeriodId, LoadEventInfo, MediaLoadData)}. */
+ public void loadCanceled(
+ DataSpec dataSpec,
+ Uri uri,
+ Map<String, List<String>> responseHeaders,
+ int dataType,
+ int trackType,
+ @Nullable Format trackFormat,
+ int trackSelectionReason,
+ @Nullable Object trackSelectionData,
+ long mediaStartTimeUs,
+ long mediaEndTimeUs,
+ long elapsedRealtimeMs,
+ long loadDurationMs,
+ long bytesLoaded) {
+ loadCanceled(
+ new LoadEventInfo(
+ dataSpec, uri, responseHeaders, elapsedRealtimeMs, loadDurationMs, bytesLoaded),
+ new MediaLoadData(
+ dataType,
+ trackType,
+ trackFormat,
+ trackSelectionReason,
+ trackSelectionData,
+ adjustMediaTime(mediaStartTimeUs),
+ adjustMediaTime(mediaEndTimeUs)));
+ }
+
+ /** Dispatches {@link #onLoadCanceled(int, MediaPeriodId, LoadEventInfo, MediaLoadData)}. */
+ public void loadCanceled(LoadEventInfo loadEventInfo, MediaLoadData mediaLoadData) {
+ for (ListenerAndHandler listenerAndHandler : listenerAndHandlers) {
+ MediaSourceEventListener listener = listenerAndHandler.listener;
+ postOrRun(
+ listenerAndHandler.handler,
+ () ->
+ listener.onLoadCanceled(windowIndex, mediaPeriodId, loadEventInfo, mediaLoadData));
+ }
+ }
+
+ /**
+ * Dispatches {@link #onLoadError(int, MediaPeriodId, LoadEventInfo, MediaLoadData, IOException,
+ * boolean)}.
+ */
+ public void loadError(
+ DataSpec dataSpec,
+ Uri uri,
+ Map<String, List<String>> responseHeaders,
+ int dataType,
+ long elapsedRealtimeMs,
+ long loadDurationMs,
+ long bytesLoaded,
+ IOException error,
+ boolean wasCanceled) {
+ loadError(
+ dataSpec,
+ uri,
+ responseHeaders,
+ dataType,
+ C.TRACK_TYPE_UNKNOWN,
+ null,
+ C.SELECTION_REASON_UNKNOWN,
+ null,
+ C.TIME_UNSET,
+ C.TIME_UNSET,
+ elapsedRealtimeMs,
+ loadDurationMs,
+ bytesLoaded,
+ error,
+ wasCanceled);
+ }
+
+ /**
+ * Dispatches {@link #onLoadError(int, MediaPeriodId, LoadEventInfo, MediaLoadData, IOException,
+ * boolean)}.
+ */
+ public void loadError(
+ DataSpec dataSpec,
+ Uri uri,
+ Map<String, List<String>> responseHeaders,
+ int dataType,
+ int trackType,
+ @Nullable Format trackFormat,
+ int trackSelectionReason,
+ @Nullable Object trackSelectionData,
+ long mediaStartTimeUs,
+ long mediaEndTimeUs,
+ long elapsedRealtimeMs,
+ long loadDurationMs,
+ long bytesLoaded,
+ IOException error,
+ boolean wasCanceled) {
+ loadError(
+ new LoadEventInfo(
+ dataSpec, uri, responseHeaders, elapsedRealtimeMs, loadDurationMs, bytesLoaded),
+ new MediaLoadData(
+ dataType,
+ trackType,
+ trackFormat,
+ trackSelectionReason,
+ trackSelectionData,
+ adjustMediaTime(mediaStartTimeUs),
+ adjustMediaTime(mediaEndTimeUs)),
+ error,
+ wasCanceled);
+ }
+
+ /**
+ * Dispatches {@link #onLoadError(int, MediaPeriodId, LoadEventInfo, MediaLoadData, IOException,
+ * boolean)}.
+ */
+ public void loadError(
+ LoadEventInfo loadEventInfo,
+ MediaLoadData mediaLoadData,
+ IOException error,
+ boolean wasCanceled) {
+ for (ListenerAndHandler listenerAndHandler : listenerAndHandlers) {
+ final MediaSourceEventListener listener = listenerAndHandler.listener;
+ postOrRun(
+ listenerAndHandler.handler,
+ () ->
+ listener.onLoadError(
+ windowIndex, mediaPeriodId, loadEventInfo, mediaLoadData, error, wasCanceled));
+ }
+ }
+
+ /** Dispatches {@link #onReadingStarted(int, MediaPeriodId)}. */
+ public void readingStarted() {
+ MediaPeriodId mediaPeriodId = Assertions.checkNotNull(this.mediaPeriodId);
+ for (ListenerAndHandler listenerAndHandler : listenerAndHandlers) {
+ final MediaSourceEventListener listener = listenerAndHandler.listener;
+ postOrRun(
+ listenerAndHandler.handler,
+ () -> listener.onReadingStarted(windowIndex, mediaPeriodId));
+ }
+ }
+
+ /** Dispatches {@link #onUpstreamDiscarded(int, MediaPeriodId, MediaLoadData)}. */
+ public void upstreamDiscarded(int trackType, long mediaStartTimeUs, long mediaEndTimeUs) {
+ upstreamDiscarded(
+ new MediaLoadData(
+ C.DATA_TYPE_MEDIA,
+ trackType,
+ /* trackFormat= */ null,
+ C.SELECTION_REASON_ADAPTIVE,
+ /* trackSelectionData= */ null,
+ adjustMediaTime(mediaStartTimeUs),
+ adjustMediaTime(mediaEndTimeUs)));
+ }
+
+ /** Dispatches {@link #onUpstreamDiscarded(int, MediaPeriodId, MediaLoadData)}. */
+ public void upstreamDiscarded(MediaLoadData mediaLoadData) {
+ MediaPeriodId mediaPeriodId = Assertions.checkNotNull(this.mediaPeriodId);
+ for (ListenerAndHandler listenerAndHandler : listenerAndHandlers) {
+ final MediaSourceEventListener listener = listenerAndHandler.listener;
+ postOrRun(
+ listenerAndHandler.handler,
+ () -> listener.onUpstreamDiscarded(windowIndex, mediaPeriodId, mediaLoadData));
+ }
+ }
+
+ /** Dispatches {@link #onDownstreamFormatChanged(int, MediaPeriodId, MediaLoadData)}. */
+ public void downstreamFormatChanged(
+ int trackType,
+ @Nullable Format trackFormat,
+ int trackSelectionReason,
+ @Nullable Object trackSelectionData,
+ long mediaTimeUs) {
+ downstreamFormatChanged(
+ new MediaLoadData(
+ C.DATA_TYPE_MEDIA,
+ trackType,
+ trackFormat,
+ trackSelectionReason,
+ trackSelectionData,
+ adjustMediaTime(mediaTimeUs),
+ /* mediaEndTimeMs= */ C.TIME_UNSET));
+ }
+
+ /** Dispatches {@link #onDownstreamFormatChanged(int, MediaPeriodId, MediaLoadData)}. */
+ public void downstreamFormatChanged(MediaLoadData mediaLoadData) {
+ for (ListenerAndHandler listenerAndHandler : listenerAndHandlers) {
+ final MediaSourceEventListener listener = listenerAndHandler.listener;
+ postOrRun(
+ listenerAndHandler.handler,
+ () -> listener.onDownstreamFormatChanged(windowIndex, mediaPeriodId, mediaLoadData));
+ }
+ }
+
+ private long adjustMediaTime(long mediaTimeUs) {
+ long mediaTimeMs = C.usToMs(mediaTimeUs);
+ return mediaTimeMs == C.TIME_UNSET ? C.TIME_UNSET : mediaTimeOffsetMs + mediaTimeMs;
+ }
+
+ private void postOrRun(Handler handler, Runnable runnable) {
+ if (handler.getLooper() == Looper.myLooper()) {
+ runnable.run();
+ } else {
+ handler.post(runnable);
+ }
+ }
+
+ private static final class ListenerAndHandler {
+
+ public final Handler handler;
+ public final MediaSourceEventListener listener;
+
+ public ListenerAndHandler(Handler handler, MediaSourceEventListener listener) {
+ this.handler = handler;
+ this.listener = listener;
+ }
+ }
+ }
+}