mirror of
https://github.com/samsonjs/media.git
synced 2026-04-27 15:07:40 +00: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
7 changed files with 100 additions and 31 deletions
|
|
@ -15,37 +15,85 @@
|
||||||
*/
|
*/
|
||||||
package com.google.android.exoplayer;
|
package com.google.android.exoplayer;
|
||||||
|
|
||||||
|
import com.google.android.exoplayer.util.Assertions;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Thrown when a non-recoverable playback failure occurs.
|
* 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 {
|
public final class ExoPlaybackException extends Exception {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* True if the cause (i.e. the {@link Throwable} returned by {@link #getCause()}) was only caught
|
* The error occurred loading data from a {@link SampleSource}.
|
||||||
* by a fail-safe at the top level of the player. False otherwise.
|
* <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);
|
* The type of the playback failure. One of {@link #TYPE_SOURCE}, {@link #TYPE_RENDERER} and
|
||||||
caughtAtTopLevel = false;
|
* {@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) {
|
public static ExoPlaybackException createForSource(IOException cause) {
|
||||||
super(cause);
|
return new ExoPlaybackException(TYPE_SOURCE, null, cause, -1);
|
||||||
caughtAtTopLevel = false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
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);
|
super(message, cause);
|
||||||
caughtAtTopLevel = false;
|
this.type = type;
|
||||||
|
this.rendererIndex = rendererIndex;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* package */ ExoPlaybackException(Throwable cause, boolean caughtAtTopLevel) {
|
/**
|
||||||
super(cause);
|
* Retrieves the underlying error when {@link #type} is {@link #TYPE_SOURCE}.
|
||||||
this.caughtAtTopLevel = caughtAtTopLevel;
|
*/
|
||||||
|
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
|
// TODO[REFACTOR]: Make sure renderer errors that will prevent prepare from being called again are
|
||||||
// always propagated properly.
|
// always propagated properly.
|
||||||
// TODO[REFACTOR]: Distinguish source and renderer errors in ExoPlaybackException.
|
|
||||||
/* package */ final class ExoPlayerImplInternal implements Handler.Callback {
|
/* package */ final class ExoPlayerImplInternal implements Handler.Callback {
|
||||||
|
|
||||||
private static final String TAG = "ExoPlayerImplInternal";
|
private static final String TAG = "ExoPlayerImplInternal";
|
||||||
|
|
@ -113,6 +112,7 @@ import java.util.concurrent.atomic.AtomicInteger;
|
||||||
MediaClock rendererMediaClock = null;
|
MediaClock rendererMediaClock = null;
|
||||||
TrackRenderer rendererMediaClockSource = null;
|
TrackRenderer rendererMediaClockSource = null;
|
||||||
for (int i = 0; i < renderers.length; i++) {
|
for (int i = 0; i < renderers.length; i++) {
|
||||||
|
renderers[i].setIndex(i);
|
||||||
MediaClock mediaClock = renderers[i].getMediaClock();
|
MediaClock mediaClock = renderers[i].getMediaClock();
|
||||||
if (mediaClock != null) {
|
if (mediaClock != null) {
|
||||||
Assertions.checkState(rendererMediaClock == null);
|
Assertions.checkState(rendererMediaClock == null);
|
||||||
|
|
@ -266,12 +266,13 @@ import java.util.concurrent.atomic.AtomicInteger;
|
||||||
return true;
|
return true;
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
Log.e(TAG, "Source track renderer error.", 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();
|
stopInternal();
|
||||||
return true;
|
return true;
|
||||||
} catch (RuntimeException e) {
|
} catch (RuntimeException e) {
|
||||||
Log.e(TAG, "Internal runtime error.", 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();
|
stopInternal();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -353,7 +353,7 @@ public class MediaCodecAudioTrackRenderer extends MediaCodecTrackRenderer implem
|
||||||
audioTrackHasData = false;
|
audioTrackHasData = false;
|
||||||
} catch (AudioTrack.InitializationException e) {
|
} catch (AudioTrack.InitializationException e) {
|
||||||
notifyAudioTrackInitializationError(e);
|
notifyAudioTrackInitializationError(e);
|
||||||
throw new ExoPlaybackException(e);
|
throw ExoPlaybackException.createForRenderer(e, getIndex());
|
||||||
}
|
}
|
||||||
if (getState() == TrackRenderer.STATE_STARTED) {
|
if (getState() == TrackRenderer.STATE_STARTED) {
|
||||||
audioTrack.play();
|
audioTrack.play();
|
||||||
|
|
@ -377,7 +377,7 @@ public class MediaCodecAudioTrackRenderer extends MediaCodecTrackRenderer implem
|
||||||
lastFeedElapsedRealtimeMs = SystemClock.elapsedRealtime();
|
lastFeedElapsedRealtimeMs = SystemClock.elapsedRealtime();
|
||||||
} catch (AudioTrack.WriteException e) {
|
} catch (AudioTrack.WriteException e) {
|
||||||
notifyAudioTrackWriteError(e);
|
notifyAudioTrackWriteError(e);
|
||||||
throw new ExoPlaybackException(e);
|
throw ExoPlaybackException.createForRenderer(e, getIndex());
|
||||||
}
|
}
|
||||||
|
|
||||||
// If we are out of sync, allow currentPositionUs to jump backwards.
|
// 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
|
return decoderInfo != null && decoderInfo.adaptive ? TrackRenderer.ADAPTIVE_SEAMLESS
|
||||||
: TrackRenderer.ADAPTIVE_NOT_SEAMLESS;
|
: TrackRenderer.ADAPTIVE_NOT_SEAMLESS;
|
||||||
} catch (DecoderQueryException e) {
|
} catch (DecoderQueryException e) {
|
||||||
throw new ExoPlaybackException(e);
|
throw ExoPlaybackException.createForRenderer(e, getIndex());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -282,7 +282,7 @@ public abstract class MediaCodecTrackRenderer extends SampleSourceTrackRenderer
|
||||||
try {
|
try {
|
||||||
return supportsFormat(mediaCodecSelector, format);
|
return supportsFormat(mediaCodecSelector, format);
|
||||||
} catch (DecoderQueryException e) {
|
} 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;
|
boolean requiresSecureDecoder = false;
|
||||||
if (drmInitData != null) {
|
if (drmInitData != null) {
|
||||||
if (drmSessionManager == null) {
|
if (drmSessionManager == null) {
|
||||||
throw new ExoPlaybackException("Media requires a DrmSessionManager");
|
throw ExoPlaybackException.createForRenderer(
|
||||||
|
new IllegalStateException("Media requires a DrmSessionManager"), getIndex());
|
||||||
}
|
}
|
||||||
if (!openedDrmSession) {
|
if (!openedDrmSession) {
|
||||||
drmSessionManager.open(drmInitData);
|
drmSessionManager.open(drmInitData);
|
||||||
|
|
@ -343,7 +344,7 @@ public abstract class MediaCodecTrackRenderer extends SampleSourceTrackRenderer
|
||||||
}
|
}
|
||||||
int drmSessionState = drmSessionManager.getState();
|
int drmSessionState = drmSessionManager.getState();
|
||||||
if (drmSessionState == DrmSessionManager.STATE_ERROR) {
|
if (drmSessionState == DrmSessionManager.STATE_ERROR) {
|
||||||
throw new ExoPlaybackException(drmSessionManager.getError());
|
throw ExoPlaybackException.createForRenderer(drmSessionManager.getError(), getIndex());
|
||||||
} else if (drmSessionState == DrmSessionManager.STATE_OPENED
|
} else if (drmSessionState == DrmSessionManager.STATE_OPENED
|
||||||
|| drmSessionState == DrmSessionManager.STATE_OPENED_WITH_KEYS) {
|
|| drmSessionState == DrmSessionManager.STATE_OPENED_WITH_KEYS) {
|
||||||
mediaCrypto = drmSessionManager.getMediaCrypto();
|
mediaCrypto = drmSessionManager.getMediaCrypto();
|
||||||
|
|
@ -403,7 +404,7 @@ public abstract class MediaCodecTrackRenderer extends SampleSourceTrackRenderer
|
||||||
private void notifyAndThrowDecoderInitError(DecoderInitializationException e)
|
private void notifyAndThrowDecoderInitError(DecoderInitializationException e)
|
||||||
throws ExoPlaybackException {
|
throws ExoPlaybackException {
|
||||||
notifyDecoderInitializationError(e);
|
notifyDecoderInitializationError(e);
|
||||||
throw new ExoPlaybackException(e);
|
throw ExoPlaybackException.createForRenderer(e, getIndex());
|
||||||
}
|
}
|
||||||
|
|
||||||
protected boolean shouldInitCodec() {
|
protected boolean shouldInitCodec() {
|
||||||
|
|
@ -636,7 +637,7 @@ public abstract class MediaCodecTrackRenderer extends SampleSourceTrackRenderer
|
||||||
}
|
}
|
||||||
} catch (CryptoException e) {
|
} catch (CryptoException e) {
|
||||||
notifyCryptoError(e);
|
notifyCryptoError(e);
|
||||||
throw new ExoPlaybackException(e);
|
throw ExoPlaybackException.createForRenderer(e, getIndex());
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
@ -678,7 +679,7 @@ public abstract class MediaCodecTrackRenderer extends SampleSourceTrackRenderer
|
||||||
codecReconfigurationState = RECONFIGURATION_STATE_NONE;
|
codecReconfigurationState = RECONFIGURATION_STATE_NONE;
|
||||||
} catch (CryptoException e) {
|
} catch (CryptoException e) {
|
||||||
notifyCryptoError(e);
|
notifyCryptoError(e);
|
||||||
throw new ExoPlaybackException(e);
|
throw ExoPlaybackException.createForRenderer(e, getIndex());
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
@ -705,7 +706,7 @@ public abstract class MediaCodecTrackRenderer extends SampleSourceTrackRenderer
|
||||||
}
|
}
|
||||||
int drmManagerState = drmSessionManager.getState();
|
int drmManagerState = drmSessionManager.getState();
|
||||||
if (drmManagerState == DrmSessionManager.STATE_ERROR) {
|
if (drmManagerState == DrmSessionManager.STATE_ERROR) {
|
||||||
throw new ExoPlaybackException(drmSessionManager.getError());
|
throw ExoPlaybackException.createForRenderer(drmSessionManager.getError(), getIndex());
|
||||||
}
|
}
|
||||||
if (drmManagerState != DrmSessionManager.STATE_OPENED_WITH_KEYS &&
|
if (drmManagerState != DrmSessionManager.STATE_OPENED_WITH_KEYS &&
|
||||||
(sampleEncrypted || !playClearSamplesWithoutKeys)) {
|
(sampleEncrypted || !playClearSamplesWithoutKeys)) {
|
||||||
|
|
|
||||||
|
|
@ -88,8 +88,27 @@ public abstract class TrackRenderer implements ExoPlayerComponent {
|
||||||
*/
|
*/
|
||||||
protected static final int STATE_STARTED = 2;
|
protected static final int STATE_STARTED = 2;
|
||||||
|
|
||||||
|
private int index;
|
||||||
private int state;
|
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
|
* 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
|
* {@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 {
|
try {
|
||||||
pendingMetadata = metadataParser.parse(sampleHolder.data.array(), sampleHolder.size);
|
pendingMetadata = metadataParser.parse(sampleHolder.data.array(), sampleHolder.size);
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
throw new ExoPlaybackException(e);
|
throw ExoPlaybackException.createForRenderer(e, getIndex());
|
||||||
}
|
}
|
||||||
} else if (result == TrackStream.END_OF_STREAM) {
|
} else if (result == TrackStream.END_OF_STREAM) {
|
||||||
inputStreamEnded = true;
|
inputStreamEnded = true;
|
||||||
|
|
|
||||||
|
|
@ -188,7 +188,7 @@ public final class TextTrackRenderer extends SampleSourceTrackRenderer implement
|
||||||
try {
|
try {
|
||||||
nextSubtitle = parserHelper.getAndClearResult();
|
nextSubtitle = parserHelper.getAndClearResult();
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
throw new ExoPlaybackException(e);
|
throw ExoPlaybackException.createForRenderer(e, getIndex());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue