Make onPlayerError take a PlaybackException

PiperOrigin-RevId: 380174672
This commit is contained in:
aquilescanta 2021-06-18 14:35:41 +01:00 committed by Oliver Woodman
parent 1ef6326385
commit fc1d3dd192
18 changed files with 81 additions and 61 deletions

View File

@ -32,7 +32,6 @@ import androidx.annotation.NonNull;
import androidx.annotation.Nullable; import androidx.annotation.Nullable;
import androidx.appcompat.app.AppCompatActivity; import androidx.appcompat.app.AppCompatActivity;
import com.google.android.exoplayer2.C; import com.google.android.exoplayer2.C;
import com.google.android.exoplayer2.ExoPlaybackException;
import com.google.android.exoplayer2.MediaItem; import com.google.android.exoplayer2.MediaItem;
import com.google.android.exoplayer2.PlaybackException; import com.google.android.exoplayer2.PlaybackException;
import com.google.android.exoplayer2.Player; import com.google.android.exoplayer2.Player;
@ -424,7 +423,7 @@ public class PlayerActivity extends AppCompatActivity
} }
@Override @Override
public void onPlayerError(@NonNull ExoPlaybackException e) { public void onPlayerError(@NonNull PlaybackException e) {
if (e.errorCode == PlaybackException.ERROR_CODE_BEHIND_LIVE_WINDOW) { if (e.errorCode == PlaybackException.ERROR_CODE_BEHIND_LIVE_WINDOW) {
player.seekToDefaultPosition(); player.seekToDefaultPosition();
player.prepare(); player.prepare();

View File

@ -67,21 +67,23 @@ public void onIsPlayingChanged(boolean isPlaying) {
### Playback errors ### ### Playback errors ###
Errors that cause playback to fail can be received by implementing Errors that cause playback to fail can be received by implementing
`onPlayerError(ExoPlaybackException error)` in a registered `onPlayerError(PlaybackException error)` in a registered
`Player.Listener`. When a failure occurs, this method will be called `Player.Listener`. When a failure occurs, this method will be called
immediately before the playback state transitions to `Player.STATE_IDLE`. immediately before the playback state transitions to `Player.STATE_IDLE`.
Failed or stopped playbacks can be retried by calling `ExoPlayer.retry`. Failed or stopped playbacks can be retried by calling `ExoPlayer.retry`.
[`ExoPlaybackException`][] has a `type` field, as well as corresponding getter Note that some [`Player`][] implementations pass instances of subclasses of
methods that return cause exceptions providing more information about the `PlaybackException` to provide additional information about the failure. For
failure. The example below shows how to detect when a playback has failed due to example, [`ExoPlayer`][] passes [`ExoPlaybackException`][] which has `type`,
a HTTP networking issue. `rendererIndex` and other ExoPlayer-specific fields.
The following example shows how to detect when a playback has failed due to an
HTTP networking issue:
~~~ ~~~
@Override @Override
public void onPlayerError(ExoPlaybackException error) { public void onPlayerError(PlaybackException error) {
if (error.type == ExoPlaybackException.TYPE_SOURCE) { Throwable cause = error.getCause();
IOException cause = error.getSourceException();
if (cause instanceof HttpDataSourceException) { if (cause instanceof HttpDataSourceException) {
// An HTTP error occurred. // An HTTP error occurred.
HttpDataSourceException httpError = (HttpDataSourceException) cause; HttpDataSourceException httpError = (HttpDataSourceException) cause;
@ -98,7 +100,6 @@ public void onPlayerError(ExoPlaybackException error) {
} }
} }
} }
}
~~~ ~~~
{: .language-java } {: .language-java }
@ -228,6 +229,8 @@ player
[`Player.Listener`]: {{ site.exo_sdk }}/Player.Listener.html [`Player.Listener`]: {{ site.exo_sdk }}/Player.Listener.html
[Javadoc]: {{ site.exo_sdk }}/Player.Listener.html [Javadoc]: {{ site.exo_sdk }}/Player.Listener.html
[`Individual callbacks vs onEvents`]: #individual-callbacks-vs-onevents [`Individual callbacks vs onEvents`]: #individual-callbacks-vs-onevents
[`Player`]: {{ site.exo_sdk }}/Player.html
[`ExoPlayer`]: {{ site.exo_sdk }}/ExoPlayer.html
[`ExoPlaybackException`]: {{ site.exo_sdk }}/ExoPlaybackException.html [`ExoPlaybackException`]: {{ site.exo_sdk }}/ExoPlaybackException.html
[log output]: event-logger.html [log output]: event-logger.html
[`Parameters`]: {{ site.exo_sdk }}/trackselection/DefaultTrackSelector.Parameters.html [`Parameters`]: {{ site.exo_sdk }}/trackselection/DefaultTrackSelector.Parameters.html

View File

@ -142,7 +142,7 @@ the demo app exemplifies this approach.
~~~ ~~~
@Override @Override
public void onPlayerError(ExoPlaybackException e) { public void onPlayerError(PlaybackException e) {
if (e.errorCode == PlaybackException.ERROR_CODE_BEHIND_LIVE_WINDOW) { if (e.errorCode == PlaybackException.ERROR_CODE_BEHIND_LIVE_WINDOW) {
// Re-initialize player at the current live window default position. // Re-initialize player at the current live window default position.
player.seekToDefaultPosition(); player.seekToDefaultPosition();

View File

@ -23,8 +23,8 @@ import android.os.Looper;
import androidx.annotation.Nullable; import androidx.annotation.Nullable;
import androidx.test.core.app.ApplicationProvider; import androidx.test.core.app.ApplicationProvider;
import androidx.test.ext.junit.runners.AndroidJUnit4; import androidx.test.ext.junit.runners.AndroidJUnit4;
import com.google.android.exoplayer2.ExoPlaybackException;
import com.google.android.exoplayer2.MediaItem; import com.google.android.exoplayer2.MediaItem;
import com.google.android.exoplayer2.PlaybackException;
import com.google.android.exoplayer2.Player; import com.google.android.exoplayer2.Player;
import com.google.android.exoplayer2.Renderer; import com.google.android.exoplayer2.Renderer;
import com.google.android.exoplayer2.RenderersFactory; import com.google.android.exoplayer2.RenderersFactory;
@ -96,7 +96,7 @@ public class FlacPlaybackTest {
private final AudioSink audioSink; private final AudioSink audioSink;
@Nullable private SimpleExoPlayer player; @Nullable private SimpleExoPlayer player;
@Nullable private ExoPlaybackException playbackException; @Nullable private PlaybackException playbackException;
public TestPlaybackRunnable(Uri uri, Context context, AudioSink audioSink) { public TestPlaybackRunnable(Uri uri, Context context, AudioSink audioSink) {
this.uri = uri; this.uri = uri;
@ -129,7 +129,7 @@ public class FlacPlaybackTest {
} }
@Override @Override
public void onPlayerError(ExoPlaybackException error) { public void onPlayerError(PlaybackException error) {
playbackException = error; playbackException = error;
} }

View File

@ -51,8 +51,8 @@ import com.google.ads.interactivemedia.v3.api.player.ContentProgressProvider;
import com.google.ads.interactivemedia.v3.api.player.VideoAdPlayer; import com.google.ads.interactivemedia.v3.api.player.VideoAdPlayer;
import com.google.ads.interactivemedia.v3.api.player.VideoProgressUpdate; import com.google.ads.interactivemedia.v3.api.player.VideoProgressUpdate;
import com.google.android.exoplayer2.C; import com.google.android.exoplayer2.C;
import com.google.android.exoplayer2.ExoPlaybackException;
import com.google.android.exoplayer2.ExoPlayerLibraryInfo; import com.google.android.exoplayer2.ExoPlayerLibraryInfo;
import com.google.android.exoplayer2.PlaybackException;
import com.google.android.exoplayer2.Player; import com.google.android.exoplayer2.Player;
import com.google.android.exoplayer2.Timeline; import com.google.android.exoplayer2.Timeline;
import com.google.android.exoplayer2.source.ads.AdPlaybackState; import com.google.android.exoplayer2.source.ads.AdPlaybackState;
@ -514,7 +514,7 @@ import java.util.Map;
} }
@Override @Override
public void onPlayerError(ExoPlaybackException error) { public void onPlayerError(PlaybackException error) {
if (imaAdState != IMA_AD_STATE_NONE) { if (imaAdState != IMA_AD_STATE_NONE) {
AdMediaInfo adMediaInfo = checkNotNull(imaAdMediaInfo); AdMediaInfo adMediaInfo = checkNotNull(imaAdMediaInfo);
for (int i = 0; i < adCallbacks.size(); i++) { for (int i = 0; i < adCallbacks.size(); i++) {

View File

@ -255,15 +255,16 @@ public final class LeanbackPlayerAdapter extends PlayerAdapter implements Runnab
} }
@Override @Override
public void onPlayerError(ExoPlaybackException exception) { public void onPlayerError(PlaybackException exception) {
Callback callback = getCallback(); Callback callback = getCallback();
if (errorMessageProvider != null) { if (errorMessageProvider != null) {
Pair<Integer, String> errorMessage = errorMessageProvider.getErrorMessage(exception); Pair<Integer, String> errorMessage = errorMessageProvider.getErrorMessage(exception);
callback.onError(LeanbackPlayerAdapter.this, errorMessage.first, errorMessage.second); callback.onError(LeanbackPlayerAdapter.this, errorMessage.first, errorMessage.second);
} else { } else {
// TODO: Conditionally assign the rendererIndex depending on whether the exception is an int rendererIndex = C.INDEX_UNSET;
// ExoPlaybackException once onPlayerError takes a PlaybackException. if (exception instanceof ExoPlaybackException) {
int rendererIndex = exception.rendererIndex; rendererIndex = ((ExoPlaybackException) exception).rendererIndex;
}
callback.onError( callback.onError(
LeanbackPlayerAdapter.this, LeanbackPlayerAdapter.this,
exception.errorCode, exception.errorCode,

View File

@ -27,8 +27,8 @@ import androidx.media2.common.SessionPlayer;
import com.google.android.exoplayer2.C; import com.google.android.exoplayer2.C;
import com.google.android.exoplayer2.ControlDispatcher; import com.google.android.exoplayer2.ControlDispatcher;
import com.google.android.exoplayer2.DefaultControlDispatcher; import com.google.android.exoplayer2.DefaultControlDispatcher;
import com.google.android.exoplayer2.ExoPlaybackException;
import com.google.android.exoplayer2.MediaItem; import com.google.android.exoplayer2.MediaItem;
import com.google.android.exoplayer2.PlaybackException;
import com.google.android.exoplayer2.PlaybackParameters; import com.google.android.exoplayer2.PlaybackParameters;
import com.google.android.exoplayer2.Player; import com.google.android.exoplayer2.Player;
import com.google.android.exoplayer2.Timeline; import com.google.android.exoplayer2.Timeline;
@ -597,7 +597,7 @@ import java.util.List;
} }
@Override @Override
public void onPlayerError(ExoPlaybackException error) { public void onPlayerError(PlaybackException error) {
updateSessionPlayerState(); updateSessionPlayerState();
} }

View File

@ -23,8 +23,8 @@ import android.os.Looper;
import androidx.annotation.Nullable; import androidx.annotation.Nullable;
import androidx.test.core.app.ApplicationProvider; import androidx.test.core.app.ApplicationProvider;
import androidx.test.ext.junit.runners.AndroidJUnit4; import androidx.test.ext.junit.runners.AndroidJUnit4;
import com.google.android.exoplayer2.ExoPlaybackException;
import com.google.android.exoplayer2.MediaItem; import com.google.android.exoplayer2.MediaItem;
import com.google.android.exoplayer2.PlaybackException;
import com.google.android.exoplayer2.Player; import com.google.android.exoplayer2.Player;
import com.google.android.exoplayer2.Renderer; import com.google.android.exoplayer2.Renderer;
import com.google.android.exoplayer2.RenderersFactory; import com.google.android.exoplayer2.RenderersFactory;
@ -79,7 +79,7 @@ public class OpusPlaybackTest {
private final Uri uri; private final Uri uri;
@Nullable private SimpleExoPlayer player; @Nullable private SimpleExoPlayer player;
@Nullable private ExoPlaybackException playbackException; @Nullable private PlaybackException playbackException;
public TestPlaybackRunnable(Uri uri, Context context) { public TestPlaybackRunnable(Uri uri, Context context) {
this.uri = uri; this.uri = uri;
@ -109,7 +109,7 @@ public class OpusPlaybackTest {
} }
@Override @Override
public void onPlayerError(ExoPlaybackException error) { public void onPlayerError(PlaybackException error) {
playbackException = error; playbackException = error;
} }

View File

@ -24,8 +24,8 @@ import android.os.Looper;
import androidx.annotation.Nullable; import androidx.annotation.Nullable;
import androidx.test.core.app.ApplicationProvider; import androidx.test.core.app.ApplicationProvider;
import androidx.test.ext.junit.runners.AndroidJUnit4; import androidx.test.ext.junit.runners.AndroidJUnit4;
import com.google.android.exoplayer2.ExoPlaybackException;
import com.google.android.exoplayer2.MediaItem; import com.google.android.exoplayer2.MediaItem;
import com.google.android.exoplayer2.PlaybackException;
import com.google.android.exoplayer2.Player; import com.google.android.exoplayer2.Player;
import com.google.android.exoplayer2.Renderer; import com.google.android.exoplayer2.Renderer;
import com.google.android.exoplayer2.RenderersFactory; import com.google.android.exoplayer2.RenderersFactory;
@ -107,7 +107,7 @@ public class VpxPlaybackTest {
private final Uri uri; private final Uri uri;
@Nullable private SimpleExoPlayer player; @Nullable private SimpleExoPlayer player;
@Nullable private ExoPlaybackException playbackException; @Nullable private PlaybackException playbackException;
public TestPlaybackRunnable(Uri uri, Context context) { public TestPlaybackRunnable(Uri uri, Context context) {
this.uri = uri; this.uri = uri;
@ -144,7 +144,7 @@ public class VpxPlaybackTest {
} }
@Override @Override
public void onPlayerError(ExoPlaybackException error) { public void onPlayerError(PlaybackException error) {
playbackException = error; playbackException = error;
} }

View File

@ -681,7 +681,7 @@ public class ForwardingPlayer implements Player {
} }
@Override @Override
public void onPlayerError(ExoPlaybackException error) { public void onPlayerError(PlaybackException error) {
eventListener.onPlayerError(error); eventListener.onPlayerError(error);
} }

View File

@ -267,9 +267,12 @@ public interface Player {
* <p>{@link #onEvents(Player, Events)} will also be called to report this event along with * <p>{@link #onEvents(Player, Events)} will also be called to report this event along with
* other events that happen in the same {@link Looper} message queue iteration. * other events that happen in the same {@link Looper} message queue iteration.
* *
* <p>Implementations of Player may pass an instance of a subclass of {@link PlaybackException}
* to this method in order to include more information about the error.
*
* @param error The error. * @param error The error.
*/ */
default void onPlayerError(ExoPlaybackException error) {} default void onPlayerError(PlaybackException error) {}
/** /**
* @deprecated Use {@link #onPositionDiscontinuity(PositionInfo, PositionInfo, int)} instead. * @deprecated Use {@link #onPositionDiscontinuity(PositionInfo, PositionInfo, int)} instead.
@ -1488,14 +1491,14 @@ public interface Player {
/** /**
* Returns the error that caused playback to fail. This is the same error that will have been * Returns the error that caused playback to fail. This is the same error that will have been
* reported via {@link Listener#onPlayerError(ExoPlaybackException)} at the time of failure. It * reported via {@link Listener#onPlayerError(PlaybackException)} at the time of failure. It can
* can be queried using this method until the player is re-prepared. * be queried using this method until the player is re-prepared.
* *
* <p>Note that this method will always return {@code null} if {@link #getPlaybackState()} is not * <p>Note that this method will always return {@code null} if {@link #getPlaybackState()} is not
* {@link #STATE_IDLE}. * {@link #STATE_IDLE}.
* *
* @return The error, or {@code null}. * @return The error, or {@code null}.
* @see Listener#onPlayerError(ExoPlaybackException) * @see Listener#onPlayerError(PlaybackException)
*/ */
@Nullable @Nullable
PlaybackException getPlayerError(); PlaybackException getPlayerError();

View File

@ -245,8 +245,7 @@ public final class PlayerMessage {
/** /**
* Sends the message. If the target throws an {@link ExoPlaybackException} then it is propagated * Sends the message. If the target throws an {@link ExoPlaybackException} then it is propagated
* out of the player as an error using {@link * out of the player as an error using {@link Player.Listener#onPlayerError(PlaybackException)}.
* Player.Listener#onPlayerError(ExoPlaybackException)}.
* *
* @return This message. * @return This message.
* @throws IllegalStateException If this message has already been sent. * @throws IllegalStateException If this message has already been sent.

View File

@ -26,6 +26,7 @@ import com.google.android.exoplayer2.ExoPlaybackException;
import com.google.android.exoplayer2.Format; import com.google.android.exoplayer2.Format;
import com.google.android.exoplayer2.MediaItem; import com.google.android.exoplayer2.MediaItem;
import com.google.android.exoplayer2.MediaMetadata; import com.google.android.exoplayer2.MediaMetadata;
import com.google.android.exoplayer2.PlaybackException;
import com.google.android.exoplayer2.PlaybackParameters; import com.google.android.exoplayer2.PlaybackParameters;
import com.google.android.exoplayer2.Player; import com.google.android.exoplayer2.Player;
import com.google.android.exoplayer2.Player.PlaybackSuppressionReason; import com.google.android.exoplayer2.Player.PlaybackSuppressionReason;
@ -708,15 +709,22 @@ public class AnalyticsCollector
} }
@Override @Override
public final void onPlayerError(ExoPlaybackException error) { public final void onPlayerError(PlaybackException error) {
EventTime eventTime = EventTime eventTime = null;
error.mediaPeriodId != null if (error instanceof ExoPlaybackException) {
? generateEventTime(new MediaPeriodId(error.mediaPeriodId)) ExoPlaybackException exoError = (ExoPlaybackException) error;
: generateCurrentPlayerMediaPeriodEventTime(); if (exoError.mediaPeriodId != null) {
eventTime = generateEventTime(new MediaPeriodId(exoError.mediaPeriodId));
}
}
if (eventTime == null) {
eventTime = generateCurrentPlayerMediaPeriodEventTime();
}
EventTime finalEventTime = eventTime;
sendEvent( sendEvent(
eventTime, eventTime,
AnalyticsListener.EVENT_PLAYER_ERROR, AnalyticsListener.EVENT_PLAYER_ERROR,
listener -> listener.onPlayerError(eventTime, error)); listener -> listener.onPlayerError(finalEventTime, error));
} }
// Calling deprecated callback. // Calling deprecated callback.

View File

@ -650,6 +650,9 @@ public interface AnalyticsListener {
/** /**
* Called when a fatal player error occurred. * Called when a fatal player error occurred.
* *
* <p>Implementations of {@link Player} may pass an instance of a subclass of {@link
* PlaybackException} to this method in order to include more information about the error.
*
* @param eventTime The event time. * @param eventTime The event time.
* @param error The error. * @param error The error.
*/ */

View File

@ -21,6 +21,7 @@ import androidx.annotation.Nullable;
import com.google.android.exoplayer2.C; import com.google.android.exoplayer2.C;
import com.google.android.exoplayer2.ExoPlaybackException; import com.google.android.exoplayer2.ExoPlaybackException;
import com.google.android.exoplayer2.Format; import com.google.android.exoplayer2.Format;
import com.google.android.exoplayer2.PlaybackException;
import com.google.android.exoplayer2.PlaybackParameters; import com.google.android.exoplayer2.PlaybackParameters;
import com.google.android.exoplayer2.Player; import com.google.android.exoplayer2.Player;
import java.lang.annotation.Documented; import java.lang.annotation.Documented;
@ -122,7 +123,7 @@ public interface AudioSink {
* wishes to do so. * wishes to do so.
* *
* <p>Fatal errors that cannot be recovered will be reported wrapped in a {@link * <p>Fatal errors that cannot be recovered will be reported wrapped in a {@link
* ExoPlaybackException} by {@link Player.Listener#onPlayerError(ExoPlaybackException)}. * ExoPlaybackException} by {@link Player.Listener#onPlayerError(PlaybackException)}.
* *
* @param audioSinkError The error that occurred. Typically an {@link InitializationException}, * @param audioSinkError The error that occurred. Typically an {@link InitializationException},
* a {@link WriteException}, or an {@link UnexpectedDiscontinuityException}. * a {@link WriteException}, or an {@link UnexpectedDiscontinuityException}.

View File

@ -20,8 +20,8 @@ import static com.google.common.truth.Truth.assertThat;
import android.net.Uri; import android.net.Uri;
import androidx.test.core.app.ApplicationProvider; import androidx.test.core.app.ApplicationProvider;
import androidx.test.ext.junit.runners.AndroidJUnit4; import androidx.test.ext.junit.runners.AndroidJUnit4;
import com.google.android.exoplayer2.ExoPlaybackException;
import com.google.android.exoplayer2.MediaItem; import com.google.android.exoplayer2.MediaItem;
import com.google.android.exoplayer2.PlaybackException;
import com.google.android.exoplayer2.Player.Listener; import com.google.android.exoplayer2.Player.Listener;
import com.google.android.exoplayer2.SimpleExoPlayer; import com.google.android.exoplayer2.SimpleExoPlayer;
import com.google.android.exoplayer2.robolectric.RobolectricUtil; import com.google.android.exoplayer2.robolectric.RobolectricUtil;
@ -95,7 +95,7 @@ public final class RtspPlaybackTest {
player.addListener( player.addListener(
new Listener() { new Listener() {
@Override @Override
public void onPlayerError(ExoPlaybackException error) { public void onPlayerError(PlaybackException error) {
playbackError.set(error); playbackError.set(error);
} }
}); });

View File

@ -22,6 +22,7 @@ import static com.google.common.truth.Truth.assertThat;
import android.os.Looper; import android.os.Looper;
import com.google.android.exoplayer2.ExoPlaybackException; import com.google.android.exoplayer2.ExoPlaybackException;
import com.google.android.exoplayer2.ExoPlayer; import com.google.android.exoplayer2.ExoPlayer;
import com.google.android.exoplayer2.PlaybackException;
import com.google.android.exoplayer2.Player; import com.google.android.exoplayer2.Player;
import com.google.android.exoplayer2.SimpleExoPlayer; import com.google.android.exoplayer2.SimpleExoPlayer;
import com.google.android.exoplayer2.Timeline; import com.google.android.exoplayer2.Timeline;
@ -199,8 +200,9 @@ public class TestPlayerRunHelper {
Player.Listener listener = Player.Listener listener =
new Player.Listener() { new Player.Listener() {
@Override @Override
public void onPlayerError(ExoPlaybackException error) { public void onPlayerError(PlaybackException error) {
receivedError.set(error); // ExoPlayer is guaranteed to throw an ExoPlaybackException.
receivedError.set((ExoPlaybackException) error);
player.removeListener(this); player.removeListener(this);
} }
}; };

View File

@ -29,6 +29,7 @@ import com.google.android.exoplayer2.ExoPlaybackException;
import com.google.android.exoplayer2.Format; import com.google.android.exoplayer2.Format;
import com.google.android.exoplayer2.LoadControl; import com.google.android.exoplayer2.LoadControl;
import com.google.android.exoplayer2.MediaItem; import com.google.android.exoplayer2.MediaItem;
import com.google.android.exoplayer2.PlaybackException;
import com.google.android.exoplayer2.Player; import com.google.android.exoplayer2.Player;
import com.google.android.exoplayer2.Renderer; import com.google.android.exoplayer2.Renderer;
import com.google.android.exoplayer2.RenderersFactory; import com.google.android.exoplayer2.RenderersFactory;
@ -692,7 +693,7 @@ public final class ExoPlayerTestRunner implements Player.Listener, ActionSchedul
} }
@Override @Override
public void onPlayerError(ExoPlaybackException error) { public void onPlayerError(PlaybackException error) {
handleException(error); handleException(error);
} }