mirror of
https://github.com/androidx/media.git
synced 2025-05-16 03:59:54 +08:00
Add structure to ExoPlaybackException.
- Add a top level failure type (source/renderer/unexpected), and convenience methods for retrieving the underlying cause without needing to cast. - Also add renderer index in the case of renderer failures. - setIndex/getIndex is a little . . . unclean, but alternatives involve either having the top line of the stack trace be a non-interesting line, or loads of try/catch blocks in ExoPlayerImplInternal. Issue: #777 ------------- Created by MOE: https://github.com/google/moe MOE_MIGRATED_REVID=114763073
This commit is contained in:
parent
c48dd4f3e3
commit
0e60335064
@ -15,37 +15,85 @@
|
||||
*/
|
||||
package com.google.android.exoplayer;
|
||||
|
||||
import com.google.android.exoplayer.util.Assertions;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
* Thrown when a non-recoverable playback failure occurs.
|
||||
* <p>
|
||||
* Where possible, the cause returned by {@link #getCause()} will indicate the reason for failure.
|
||||
*/
|
||||
public final class ExoPlaybackException extends Exception {
|
||||
|
||||
/**
|
||||
* True if the cause (i.e. the {@link Throwable} returned by {@link #getCause()}) was only caught
|
||||
* by a fail-safe at the top level of the player. False otherwise.
|
||||
* The error occurred loading data from a {@link SampleSource}.
|
||||
* <p>
|
||||
* Call {@link #getSourceException()} to retrieve the underlying cause.
|
||||
*/
|
||||
public final boolean caughtAtTopLevel;
|
||||
public static final int TYPE_SOURCE = 0;
|
||||
/**
|
||||
* The error occurred in a {@link TrackRenderer}.
|
||||
* <p>
|
||||
* Call {@link #getRendererException()} to retrieve the underlying cause.
|
||||
*/
|
||||
public static final int TYPE_RENDERER = 1;
|
||||
/**
|
||||
* The error was an unexpected {@link RuntimeException}.
|
||||
* <p>
|
||||
* Call {@link #getUnexpectedException()} to retrieve the underlying cause.
|
||||
*/
|
||||
public static final int TYPE_UNEXPECTED = 2;
|
||||
|
||||
public ExoPlaybackException(String message) {
|
||||
super(message);
|
||||
caughtAtTopLevel = false;
|
||||
/**
|
||||
* The type of the playback failure. One of {@link #TYPE_SOURCE}, {@link #TYPE_RENDERER} and
|
||||
* {@link #TYPE_UNEXPECTED}.
|
||||
*/
|
||||
public final int type;
|
||||
|
||||
/**
|
||||
* If {@link #type} is {@link #TYPE_RENDERER}, this is the index of the renderer.
|
||||
*/
|
||||
public final int rendererIndex;
|
||||
|
||||
public static ExoPlaybackException createForRenderer(Exception cause, int rendererIndex) {
|
||||
return new ExoPlaybackException(TYPE_RENDERER, null, cause, rendererIndex);
|
||||
}
|
||||
|
||||
public ExoPlaybackException(Throwable cause) {
|
||||
super(cause);
|
||||
caughtAtTopLevel = false;
|
||||
public static ExoPlaybackException createForSource(IOException cause) {
|
||||
return new ExoPlaybackException(TYPE_SOURCE, null, cause, -1);
|
||||
}
|
||||
|
||||
public ExoPlaybackException(String message, Throwable cause) {
|
||||
/* package */ static ExoPlaybackException createForUnexpected(RuntimeException cause) {
|
||||
return new ExoPlaybackException(TYPE_UNEXPECTED, null, cause, -1);
|
||||
}
|
||||
|
||||
private ExoPlaybackException(int type, String message, Throwable cause, int rendererIndex) {
|
||||
super(message, cause);
|
||||
caughtAtTopLevel = false;
|
||||
this.type = type;
|
||||
this.rendererIndex = rendererIndex;
|
||||
}
|
||||
|
||||
/* package */ ExoPlaybackException(Throwable cause, boolean caughtAtTopLevel) {
|
||||
super(cause);
|
||||
this.caughtAtTopLevel = caughtAtTopLevel;
|
||||
/**
|
||||
* Retrieves the underlying error when {@link #type} is {@link #TYPE_SOURCE}.
|
||||
*/
|
||||
public IOException getSourceException() {
|
||||
Assertions.checkState(type == TYPE_SOURCE);
|
||||
return (IOException) getCause();
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the underlying error when {@link #type} is {@link #TYPE_RENDERER}.
|
||||
*/
|
||||
public Exception getRendererException() {
|
||||
Assertions.checkState(type == TYPE_RENDERER);
|
||||
return (Exception) getCause();
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the underlying error when {@link #type} is {@link #TYPE_UNEXPECTED}.
|
||||
*/
|
||||
public RuntimeException getUnexpectedException() {
|
||||
Assertions.checkState(type == TYPE_UNEXPECTED);
|
||||
return (RuntimeException) getCause();
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -42,7 +42,6 @@ import java.util.concurrent.atomic.AtomicInteger;
|
||||
*/
|
||||
// TODO[REFACTOR]: Make sure renderer errors that will prevent prepare from being called again are
|
||||
// always propagated properly.
|
||||
// TODO[REFACTOR]: Distinguish source and renderer errors in ExoPlaybackException.
|
||||
/* package */ final class ExoPlayerImplInternal implements Handler.Callback {
|
||||
|
||||
private static final String TAG = "ExoPlayerImplInternal";
|
||||
@ -113,6 +112,7 @@ import java.util.concurrent.atomic.AtomicInteger;
|
||||
MediaClock rendererMediaClock = null;
|
||||
TrackRenderer rendererMediaClockSource = null;
|
||||
for (int i = 0; i < renderers.length; i++) {
|
||||
renderers[i].setIndex(i);
|
||||
MediaClock mediaClock = renderers[i].getMediaClock();
|
||||
if (mediaClock != null) {
|
||||
Assertions.checkState(rendererMediaClock == null);
|
||||
@ -266,12 +266,13 @@ import java.util.concurrent.atomic.AtomicInteger;
|
||||
return true;
|
||||
} catch (IOException e) {
|
||||
Log.e(TAG, "Source track renderer error.", e);
|
||||
eventHandler.obtainMessage(MSG_ERROR, new ExoPlaybackException(e)).sendToTarget();
|
||||
eventHandler.obtainMessage(MSG_ERROR, ExoPlaybackException.createForSource(e)).sendToTarget();
|
||||
stopInternal();
|
||||
return true;
|
||||
} catch (RuntimeException e) {
|
||||
Log.e(TAG, "Internal runtime error.", e);
|
||||
eventHandler.obtainMessage(MSG_ERROR, new ExoPlaybackException(e, true)).sendToTarget();
|
||||
eventHandler.obtainMessage(MSG_ERROR, ExoPlaybackException.createForUnexpected(e))
|
||||
.sendToTarget();
|
||||
stopInternal();
|
||||
return true;
|
||||
}
|
||||
|
@ -353,7 +353,7 @@ public class MediaCodecAudioTrackRenderer extends MediaCodecTrackRenderer implem
|
||||
audioTrackHasData = false;
|
||||
} catch (AudioTrack.InitializationException e) {
|
||||
notifyAudioTrackInitializationError(e);
|
||||
throw new ExoPlaybackException(e);
|
||||
throw ExoPlaybackException.createForRenderer(e, getIndex());
|
||||
}
|
||||
if (getState() == TrackRenderer.STATE_STARTED) {
|
||||
audioTrack.play();
|
||||
@ -377,7 +377,7 @@ public class MediaCodecAudioTrackRenderer extends MediaCodecTrackRenderer implem
|
||||
lastFeedElapsedRealtimeMs = SystemClock.elapsedRealtime();
|
||||
} catch (AudioTrack.WriteException e) {
|
||||
notifyAudioTrackWriteError(e);
|
||||
throw new ExoPlaybackException(e);
|
||||
throw ExoPlaybackException.createForRenderer(e, getIndex());
|
||||
}
|
||||
|
||||
// If we are out of sync, allow currentPositionUs to jump backwards.
|
||||
|
@ -273,7 +273,7 @@ public abstract class MediaCodecTrackRenderer extends SampleSourceTrackRenderer
|
||||
return decoderInfo != null && decoderInfo.adaptive ? TrackRenderer.ADAPTIVE_SEAMLESS
|
||||
: TrackRenderer.ADAPTIVE_NOT_SEAMLESS;
|
||||
} catch (DecoderQueryException e) {
|
||||
throw new ExoPlaybackException(e);
|
||||
throw ExoPlaybackException.createForRenderer(e, getIndex());
|
||||
}
|
||||
}
|
||||
|
||||
@ -282,7 +282,7 @@ public abstract class MediaCodecTrackRenderer extends SampleSourceTrackRenderer
|
||||
try {
|
||||
return supportsFormat(mediaCodecSelector, format);
|
||||
} catch (DecoderQueryException e) {
|
||||
throw new ExoPlaybackException(e);
|
||||
throw ExoPlaybackException.createForRenderer(e, getIndex());
|
||||
}
|
||||
}
|
||||
|
||||
@ -335,7 +335,8 @@ public abstract class MediaCodecTrackRenderer extends SampleSourceTrackRenderer
|
||||
boolean requiresSecureDecoder = false;
|
||||
if (drmInitData != null) {
|
||||
if (drmSessionManager == null) {
|
||||
throw new ExoPlaybackException("Media requires a DrmSessionManager");
|
||||
throw ExoPlaybackException.createForRenderer(
|
||||
new IllegalStateException("Media requires a DrmSessionManager"), getIndex());
|
||||
}
|
||||
if (!openedDrmSession) {
|
||||
drmSessionManager.open(drmInitData);
|
||||
@ -343,7 +344,7 @@ public abstract class MediaCodecTrackRenderer extends SampleSourceTrackRenderer
|
||||
}
|
||||
int drmSessionState = drmSessionManager.getState();
|
||||
if (drmSessionState == DrmSessionManager.STATE_ERROR) {
|
||||
throw new ExoPlaybackException(drmSessionManager.getError());
|
||||
throw ExoPlaybackException.createForRenderer(drmSessionManager.getError(), getIndex());
|
||||
} else if (drmSessionState == DrmSessionManager.STATE_OPENED
|
||||
|| drmSessionState == DrmSessionManager.STATE_OPENED_WITH_KEYS) {
|
||||
mediaCrypto = drmSessionManager.getMediaCrypto();
|
||||
@ -403,7 +404,7 @@ public abstract class MediaCodecTrackRenderer extends SampleSourceTrackRenderer
|
||||
private void notifyAndThrowDecoderInitError(DecoderInitializationException e)
|
||||
throws ExoPlaybackException {
|
||||
notifyDecoderInitializationError(e);
|
||||
throw new ExoPlaybackException(e);
|
||||
throw ExoPlaybackException.createForRenderer(e, getIndex());
|
||||
}
|
||||
|
||||
protected boolean shouldInitCodec() {
|
||||
@ -636,7 +637,7 @@ public abstract class MediaCodecTrackRenderer extends SampleSourceTrackRenderer
|
||||
}
|
||||
} catch (CryptoException e) {
|
||||
notifyCryptoError(e);
|
||||
throw new ExoPlaybackException(e);
|
||||
throw ExoPlaybackException.createForRenderer(e, getIndex());
|
||||
}
|
||||
return false;
|
||||
}
|
||||
@ -678,7 +679,7 @@ public abstract class MediaCodecTrackRenderer extends SampleSourceTrackRenderer
|
||||
codecReconfigurationState = RECONFIGURATION_STATE_NONE;
|
||||
} catch (CryptoException e) {
|
||||
notifyCryptoError(e);
|
||||
throw new ExoPlaybackException(e);
|
||||
throw ExoPlaybackException.createForRenderer(e, getIndex());
|
||||
}
|
||||
return true;
|
||||
}
|
||||
@ -705,7 +706,7 @@ public abstract class MediaCodecTrackRenderer extends SampleSourceTrackRenderer
|
||||
}
|
||||
int drmManagerState = drmSessionManager.getState();
|
||||
if (drmManagerState == DrmSessionManager.STATE_ERROR) {
|
||||
throw new ExoPlaybackException(drmSessionManager.getError());
|
||||
throw ExoPlaybackException.createForRenderer(drmSessionManager.getError(), getIndex());
|
||||
}
|
||||
if (drmManagerState != DrmSessionManager.STATE_OPENED_WITH_KEYS &&
|
||||
(sampleEncrypted || !playClearSamplesWithoutKeys)) {
|
||||
|
@ -88,8 +88,27 @@ public abstract class TrackRenderer implements ExoPlayerComponent {
|
||||
*/
|
||||
protected static final int STATE_STARTED = 2;
|
||||
|
||||
private int index;
|
||||
private int state;
|
||||
|
||||
/**
|
||||
* Sets the index of this renderer within the player.
|
||||
*
|
||||
* @param index The renderer index.
|
||||
*/
|
||||
/* package */ final void setIndex(int index) {
|
||||
this.index = index;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the index of the renderer within the player.
|
||||
*
|
||||
* @return The index of the renderer within the player.
|
||||
*/
|
||||
protected final int getIndex() {
|
||||
return index;
|
||||
}
|
||||
|
||||
/**
|
||||
* If the renderer advances its own playback position then this method returns a corresponding
|
||||
* {@link MediaClock}. If provided, the player will use the returned {@link MediaClock} as its
|
||||
|
@ -108,7 +108,7 @@ public final class MetadataTrackRenderer<T> extends SampleSourceTrackRenderer im
|
||||
try {
|
||||
pendingMetadata = metadataParser.parse(sampleHolder.data.array(), sampleHolder.size);
|
||||
} catch (IOException e) {
|
||||
throw new ExoPlaybackException(e);
|
||||
throw ExoPlaybackException.createForRenderer(e, getIndex());
|
||||
}
|
||||
} else if (result == TrackStream.END_OF_STREAM) {
|
||||
inputStreamEnded = true;
|
||||
|
@ -188,7 +188,7 @@ public final class TextTrackRenderer extends SampleSourceTrackRenderer implement
|
||||
try {
|
||||
nextSubtitle = parserHelper.getAndClearResult();
|
||||
} catch (IOException e) {
|
||||
throw new ExoPlaybackException(e);
|
||||
throw ExoPlaybackException.createForRenderer(e, getIndex());
|
||||
}
|
||||
}
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user