diff --git a/library/core/src/main/java/com/google/android/exoplayer2/ExoPlaybackException.java b/library/core/src/main/java/com/google/android/exoplayer2/ExoPlaybackException.java index ba00d1163f..d591876a51 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/ExoPlaybackException.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/ExoPlaybackException.java @@ -64,16 +64,7 @@ public final class ExoPlaybackException extends Exception { */ public final int rendererIndex; - /** - * Creates an instance of type {@link #TYPE_RENDERER}. - * - * @param cause The cause of the failure. - * @param rendererIndex The index of the renderer in which the failure occurred. - * @return The created instance. - */ - public static ExoPlaybackException createForRenderer(Exception cause, int rendererIndex) { - return new ExoPlaybackException(TYPE_RENDERER, null, cause, rendererIndex); - } + private final Throwable cause; /** * Creates an instance of type {@link #TYPE_SOURCE}. @@ -82,7 +73,18 @@ public final class ExoPlaybackException extends Exception { * @return The created instance. */ public static ExoPlaybackException createForSource(IOException cause) { - return new ExoPlaybackException(TYPE_SOURCE, null, cause, C.INDEX_UNSET); + return new ExoPlaybackException(TYPE_SOURCE, cause, C.INDEX_UNSET); + } + + /** + * Creates an instance of type {@link #TYPE_RENDERER}. + * + * @param cause The cause of the failure. + * @param rendererIndex The index of the renderer in which the failure occurred. + * @return The created instance. + */ + public static ExoPlaybackException createForRenderer(Exception cause, int rendererIndex) { + return new ExoPlaybackException(TYPE_RENDERER, cause, rendererIndex); } /** @@ -92,13 +94,13 @@ public final class ExoPlaybackException extends Exception { * @return The created instance. */ /* package */ static ExoPlaybackException createForUnexpected(RuntimeException cause) { - return new ExoPlaybackException(TYPE_UNEXPECTED, null, cause, C.INDEX_UNSET); + return new ExoPlaybackException(TYPE_UNEXPECTED, cause, C.INDEX_UNSET); } - private ExoPlaybackException(@Type int type, String message, Throwable cause, - int rendererIndex) { - super(message, cause); + private ExoPlaybackException(@Type int type, Throwable cause, int rendererIndex) { + super(cause); this.type = type; + this.cause = cause; this.rendererIndex = rendererIndex; } @@ -109,7 +111,7 @@ public final class ExoPlaybackException extends Exception { */ public IOException getSourceException() { Assertions.checkState(type == TYPE_SOURCE); - return (IOException) getCause(); + return (IOException) cause; } /** @@ -119,7 +121,7 @@ public final class ExoPlaybackException extends Exception { */ public Exception getRendererException() { Assertions.checkState(type == TYPE_RENDERER); - return (Exception) getCause(); + return (Exception) cause; } /** @@ -129,7 +131,7 @@ public final class ExoPlaybackException extends Exception { */ public RuntimeException getUnexpectedException() { Assertions.checkState(type == TYPE_UNEXPECTED); - return (RuntimeException) getCause(); + return (RuntimeException) cause; } } diff --git a/library/core/src/main/java/com/google/android/exoplayer2/extractor/mp3/VbriSeeker.java b/library/core/src/main/java/com/google/android/exoplayer2/extractor/mp3/VbriSeeker.java index f918b5c43d..87391af46a 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/extractor/mp3/VbriSeeker.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/extractor/mp3/VbriSeeker.java @@ -15,6 +15,7 @@ */ package com.google.android.exoplayer2.extractor.mp3; +import android.support.annotation.Nullable; import android.util.Log; import com.google.android.exoplayer2.C; import com.google.android.exoplayer2.extractor.MpegAudioHeader; @@ -42,8 +43,8 @@ import com.google.android.exoplayer2.util.Util; * @return A {@link VbriSeeker} for seeking in the stream, or {@code null} if the required * information is not present. */ - public static VbriSeeker create(long inputLength, long position, MpegAudioHeader mpegAudioHeader, - ParsableByteArray frame) { + public static @Nullable VbriSeeker create( + long inputLength, long position, MpegAudioHeader mpegAudioHeader, ParsableByteArray frame) { frame.skipBytes(10); int numFrames = frame.readInt(); if (numFrames <= 0) { diff --git a/library/core/src/main/java/com/google/android/exoplayer2/extractor/mp3/XingSeeker.java b/library/core/src/main/java/com/google/android/exoplayer2/extractor/mp3/XingSeeker.java index a3bd5a2da2..5e7b0a6048 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/extractor/mp3/XingSeeker.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/extractor/mp3/XingSeeker.java @@ -15,10 +15,12 @@ */ package com.google.android.exoplayer2.extractor.mp3; +import android.support.annotation.Nullable; import android.util.Log; import com.google.android.exoplayer2.C; import com.google.android.exoplayer2.extractor.MpegAudioHeader; import com.google.android.exoplayer2.extractor.SeekPoint; +import com.google.android.exoplayer2.util.Assertions; import com.google.android.exoplayer2.util.ParsableByteArray; import com.google.android.exoplayer2.util.Util; @@ -38,12 +40,12 @@ import com.google.android.exoplayer2.util.Util; * @param position The position of the start of this frame in the stream. * @param mpegAudioHeader The MPEG audio header associated with the frame. * @param frame The data in this audio frame, with its position set to immediately after the - * 'Xing' or 'Info' tag. + * 'Xing' or 'Info' tag. * @return A {@link XingSeeker} for seeking in the stream, or {@code null} if the required * information is not present. */ - public static XingSeeker create(long inputLength, long position, MpegAudioHeader mpegAudioHeader, - ParsableByteArray frame) { + public static @Nullable XingSeeker create( + long inputLength, long position, MpegAudioHeader mpegAudioHeader, ParsableByteArray frame) { int samplesPerFrame = mpegAudioHeader.samplesPerFrame; int sampleRate = mpegAudioHeader.sampleRate; @@ -85,16 +87,21 @@ import com.google.android.exoplayer2.util.Util; */ private final long dataSize; /** - * Entries are in the range [0, 255], but are stored as long integers for convenience. + * Entries are in the range [0, 255], but are stored as long integers for convenience. Null if the + * table of contents was missing from the header, in which case seeking is not be supported. */ - private final long[] tableOfContents; + private final @Nullable long[] tableOfContents; private XingSeeker(long dataStartPosition, int xingFrameSize, long durationUs) { this(dataStartPosition, xingFrameSize, durationUs, C.LENGTH_UNSET, null); } - private XingSeeker(long dataStartPosition, int xingFrameSize, long durationUs, long dataSize, - long[] tableOfContents) { + private XingSeeker( + long dataStartPosition, + int xingFrameSize, + long durationUs, + long dataSize, + @Nullable long[] tableOfContents) { this.dataStartPosition = dataStartPosition; this.xingFrameSize = xingFrameSize; this.durationUs = durationUs; @@ -121,6 +128,7 @@ import com.google.android.exoplayer2.util.Util; scaledPosition = 256; } else { int prevTableIndex = (int) percent; + long[] tableOfContents = Assertions.checkNotNull(this.tableOfContents); double prevScaledPosition = tableOfContents[prevTableIndex]; double nextScaledPosition = prevTableIndex == 99 ? 256 : tableOfContents[prevTableIndex + 1]; // Linearly interpolate between the two scaled positions. @@ -140,6 +148,7 @@ import com.google.android.exoplayer2.util.Util; if (!isSeekable() || positionOffset <= xingFrameSize) { return 0L; } + long[] tableOfContents = Assertions.checkNotNull(this.tableOfContents); double scaledPosition = (positionOffset * 256d) / dataSize; int prevTableIndex = Util.binarySearchFloor(tableOfContents, (long) scaledPosition, true, true); long prevTimeUs = getTimeUsForTableIndex(prevTableIndex);