blob: 7c9dc34b4f77a990494d96326520f6b60d6e8bdc [file] [log] [blame]
/*
* 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 com.google.android.exoplayer2.source;
import androidx.annotation.Nullable;
import com.google.android.exoplayer2.C;
import com.google.android.exoplayer2.Format;
import com.google.android.exoplayer2.Player;
import com.google.android.exoplayer2.source.MediaSource.MediaPeriodId;
import com.google.android.exoplayer2.util.Assertions;
import com.google.android.exoplayer2.util.CopyOnWriteMultiset;
import com.google.android.exoplayer2.util.MediaSourceEventDispatcher;
import java.io.IOException;
/** Interface for callbacks to be notified of {@link MediaSource} events. */
public interface MediaSourceEventListener {
/**
* 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) {}
/** @deprecated Use {@link MediaSourceEventDispatcher} directly instead. */
@Deprecated
final class EventDispatcher extends MediaSourceEventDispatcher {
public EventDispatcher() {
super();
}
private EventDispatcher(
CopyOnWriteMultiset<ListenerInfo> listeners,
int windowIndex,
@Nullable MediaPeriodId mediaPeriodId,
long mediaTimeOffsetMs) {
super(listeners, windowIndex, mediaPeriodId, mediaTimeOffsetMs);
}
@Override
public EventDispatcher withParameters(
int windowIndex, @Nullable MediaPeriodId mediaPeriodId, long mediaTimeOffsetMs) {
return new EventDispatcher(listenerInfos, windowIndex, mediaPeriodId, mediaTimeOffsetMs);
}
public void mediaPeriodCreated() {
dispatch(
(listener, windowIndex, mediaPeriodId) ->
listener.onMediaPeriodCreated(windowIndex, Assertions.checkNotNull(mediaPeriodId)),
MediaSourceEventListener.class);
}
public void mediaPeriodReleased() {
dispatch(
(listener, windowIndex, mediaPeriodId) ->
listener.onMediaPeriodReleased(windowIndex, Assertions.checkNotNull(mediaPeriodId)),
MediaSourceEventListener.class);
}
public void loadStarted(LoadEventInfo loadEventInfo, int dataType) {
loadStarted(
loadEventInfo,
dataType,
/* trackType= */ C.TRACK_TYPE_UNKNOWN,
/* trackFormat= */ null,
/* trackSelectionReason= */ C.SELECTION_REASON_UNKNOWN,
/* trackSelectionData= */ null,
/* mediaStartTimeUs= */ C.TIME_UNSET,
/* mediaEndTimeUs= */ C.TIME_UNSET);
}
public void loadStarted(
LoadEventInfo loadEventInfo,
int dataType,
int trackType,
@Nullable Format trackFormat,
int trackSelectionReason,
@Nullable Object trackSelectionData,
long mediaStartTimeUs,
long mediaEndTimeUs) {
loadStarted(
loadEventInfo,
new MediaLoadData(
dataType,
trackType,
trackFormat,
trackSelectionReason,
trackSelectionData,
adjustMediaTime(mediaStartTimeUs),
adjustMediaTime(mediaEndTimeUs)));
}
public void loadStarted(LoadEventInfo loadEventInfo, MediaLoadData mediaLoadData) {
dispatch(
(listener, windowIndex, mediaPeriodId) ->
listener.onLoadStarted(windowIndex, mediaPeriodId, loadEventInfo, mediaLoadData),
MediaSourceEventListener.class);
}
public void loadCompleted(LoadEventInfo loadEventInfo, int dataType) {
loadCompleted(
loadEventInfo,
dataType,
/* trackType= */ C.TRACK_TYPE_UNKNOWN,
/* trackFormat= */ null,
/* trackSelectionReason= */ C.SELECTION_REASON_UNKNOWN,
/* trackSelectionData= */ null,
/* mediaStartTimeUs= */ C.TIME_UNSET,
/* mediaEndTimeUs= */ C.TIME_UNSET);
}
public void loadCompleted(
LoadEventInfo loadEventInfo,
int dataType,
int trackType,
@Nullable Format trackFormat,
int trackSelectionReason,
@Nullable Object trackSelectionData,
long mediaStartTimeUs,
long mediaEndTimeUs) {
loadCompleted(
loadEventInfo,
new MediaLoadData(
dataType,
trackType,
trackFormat,
trackSelectionReason,
trackSelectionData,
adjustMediaTime(mediaStartTimeUs),
adjustMediaTime(mediaEndTimeUs)));
}
public void loadCompleted(LoadEventInfo loadEventInfo, MediaLoadData mediaLoadData) {
dispatch(
(listener, windowIndex, mediaPeriodId) ->
listener.onLoadCompleted(windowIndex, mediaPeriodId, loadEventInfo, mediaLoadData),
MediaSourceEventListener.class);
}
public void loadCanceled(LoadEventInfo loadEventInfo, int dataType) {
loadCanceled(
loadEventInfo,
dataType,
/* trackType= */ C.TRACK_TYPE_UNKNOWN,
/* trackFormat= */ null,
/* trackSelectionReason= */ C.SELECTION_REASON_UNKNOWN,
/* trackSelectionData= */ null,
/* mediaStartTimeUs= */ C.TIME_UNSET,
/* mediaEndTimeUs= */ C.TIME_UNSET);
}
public void loadCanceled(
LoadEventInfo loadEventInfo,
int dataType,
int trackType,
@Nullable Format trackFormat,
int trackSelectionReason,
@Nullable Object trackSelectionData,
long mediaStartTimeUs,
long mediaEndTimeUs) {
loadCanceled(
loadEventInfo,
new MediaLoadData(
dataType,
trackType,
trackFormat,
trackSelectionReason,
trackSelectionData,
adjustMediaTime(mediaStartTimeUs),
adjustMediaTime(mediaEndTimeUs)));
}
public void loadCanceled(LoadEventInfo loadEventInfo, MediaLoadData mediaLoadData) {
dispatch(
(listener, windowIndex, mediaPeriodId) ->
listener.onLoadCanceled(windowIndex, mediaPeriodId, loadEventInfo, mediaLoadData),
MediaSourceEventListener.class);
}
public void loadError(
LoadEventInfo loadEventInfo, int dataType, IOException error, boolean wasCanceled) {
loadError(
loadEventInfo,
dataType,
/* trackType= */ C.TRACK_TYPE_UNKNOWN,
/* trackFormat= */ null,
/* trackSelectionReason= */ C.SELECTION_REASON_UNKNOWN,
/* trackSelectionData= */ null,
/* mediaStartTimeUs= */ C.TIME_UNSET,
/* mediaEndTimeUs= */ C.TIME_UNSET,
error,
wasCanceled);
}
public void loadError(
LoadEventInfo loadEventInfo,
int dataType,
int trackType,
@Nullable Format trackFormat,
int trackSelectionReason,
@Nullable Object trackSelectionData,
long mediaStartTimeUs,
long mediaEndTimeUs,
IOException error,
boolean wasCanceled) {
loadError(
loadEventInfo,
new MediaLoadData(
dataType,
trackType,
trackFormat,
trackSelectionReason,
trackSelectionData,
adjustMediaTime(mediaStartTimeUs),
adjustMediaTime(mediaEndTimeUs)),
error,
wasCanceled);
}
public void loadError(
LoadEventInfo loadEventInfo,
MediaLoadData mediaLoadData,
IOException error,
boolean wasCanceled) {
dispatch(
(listener, windowIndex, mediaPeriodId) ->
listener.onLoadError(
windowIndex, mediaPeriodId, loadEventInfo, mediaLoadData, error, wasCanceled),
MediaSourceEventListener.class);
}
public void readingStarted() {
dispatch(
(listener, windowIndex, mediaPeriodId) ->
listener.onReadingStarted(windowIndex, Assertions.checkNotNull(mediaPeriodId)),
MediaSourceEventListener.class);
}
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)));
}
public void upstreamDiscarded(MediaLoadData mediaLoadData) {
dispatch(
(listener, windowIndex, mediaPeriodId) ->
listener.onUpstreamDiscarded(
windowIndex, Assertions.checkNotNull(mediaPeriodId), mediaLoadData),
MediaSourceEventListener.class);
}
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));
}
public void downstreamFormatChanged(MediaLoadData mediaLoadData) {
dispatch(
(listener, windowIndex, mediaPeriodId) ->
listener.onDownstreamFormatChanged(windowIndex, mediaPeriodId, mediaLoadData),
MediaSourceEventListener.class);
}
private long adjustMediaTime(long mediaTimeUs) {
return adjustMediaTime(mediaTimeUs, mediaTimeOffsetMs);
}
}
}