• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2016 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 package com.google.android.exoplayer2;
17 
18 import android.os.SystemClock;
19 import android.text.TextUtils;
20 import androidx.annotation.IntDef;
21 import androidx.annotation.Nullable;
22 import com.google.android.exoplayer2.RendererCapabilities.FormatSupport;
23 import com.google.android.exoplayer2.source.MediaSource;
24 import com.google.android.exoplayer2.util.Assertions;
25 import java.io.IOException;
26 import java.lang.annotation.Documented;
27 import java.lang.annotation.Retention;
28 import java.lang.annotation.RetentionPolicy;
29 
30 /**
31  * Thrown when a non-recoverable playback failure occurs.
32  */
33 public final class ExoPlaybackException extends Exception {
34 
35   /**
36    * The type of source that produced the error. One of {@link #TYPE_SOURCE}, {@link #TYPE_RENDERER}
37    * {@link #TYPE_UNEXPECTED}, {@link #TYPE_REMOTE} or {@link #TYPE_OUT_OF_MEMORY}. Note that new
38    * types may be added in the future and error handling should handle unknown type values.
39    */
40   @Documented
41   @Retention(RetentionPolicy.SOURCE)
42   @IntDef({TYPE_SOURCE, TYPE_RENDERER, TYPE_UNEXPECTED, TYPE_REMOTE, TYPE_OUT_OF_MEMORY})
43   public @interface Type {}
44   /**
45    * The error occurred loading data from a {@link MediaSource}.
46    * <p>
47    * Call {@link #getSourceException()} to retrieve the underlying cause.
48    */
49   public static final int TYPE_SOURCE = 0;
50   /**
51    * The error occurred in a {@link Renderer}.
52    * <p>
53    * Call {@link #getRendererException()} to retrieve the underlying cause.
54    */
55   public static final int TYPE_RENDERER = 1;
56   /**
57    * The error was an unexpected {@link RuntimeException}.
58    * <p>
59    * Call {@link #getUnexpectedException()} to retrieve the underlying cause.
60    */
61   public static final int TYPE_UNEXPECTED = 2;
62   /**
63    * The error occurred in a remote component.
64    *
65    * <p>Call {@link #getMessage()} to retrieve the message associated with the error.
66    */
67   public static final int TYPE_REMOTE = 3;
68   /** The error was an {@link OutOfMemoryError}. */
69   public static final int TYPE_OUT_OF_MEMORY = 4;
70 
71   /** The {@link Type} of the playback failure. */
72   @Type public final int type;
73 
74   /** If {@link #type} is {@link #TYPE_RENDERER}, this is the name of the renderer. */
75   @Nullable public final String rendererName;
76 
77   /** If {@link #type} is {@link #TYPE_RENDERER}, this is the index of the renderer. */
78   public final int rendererIndex;
79 
80   /**
81    * If {@link #type} is {@link #TYPE_RENDERER}, this is the {@link Format} the renderer was using
82    * at the time of the exception, or null if the renderer wasn't using a {@link Format}.
83    */
84   @Nullable public final Format rendererFormat;
85 
86   /**
87    * If {@link #type} is {@link #TYPE_RENDERER}, this is the level of {@link FormatSupport} of the
88    * renderer for {@link #rendererFormat}. If {@link #rendererFormat} is null, this is {@link
89    * RendererCapabilities#FORMAT_HANDLED}.
90    */
91   @FormatSupport public final int rendererFormatSupport;
92 
93   /** The value of {@link SystemClock#elapsedRealtime()} when this exception was created. */
94   public final long timestampMs;
95 
96   @Nullable private final Throwable cause;
97 
98   /**
99    * Creates an instance of type {@link #TYPE_SOURCE}.
100    *
101    * @param cause The cause of the failure.
102    * @return The created instance.
103    */
createForSource(IOException cause)104   public static ExoPlaybackException createForSource(IOException cause) {
105     return new ExoPlaybackException(TYPE_SOURCE, cause);
106   }
107 
108   /**
109    * Creates an instance of type {@link #TYPE_RENDERER}.
110    *
111    * @param cause The cause of the failure.
112    * @param rendererIndex The index of the renderer in which the failure occurred.
113    * @param rendererFormat The {@link Format} the renderer was using at the time of the exception,
114    *     or null if the renderer wasn't using a {@link Format}.
115    * @param rendererFormatSupport The {@link FormatSupport} of the renderer for {@code
116    *     rendererFormat}. Ignored if {@code rendererFormat} is null.
117    * @return The created instance.
118    */
createForRenderer( Exception cause, String rendererName, int rendererIndex, @Nullable Format rendererFormat, @FormatSupport int rendererFormatSupport)119   public static ExoPlaybackException createForRenderer(
120       Exception cause,
121       String rendererName,
122       int rendererIndex,
123       @Nullable Format rendererFormat,
124       @FormatSupport int rendererFormatSupport) {
125     return new ExoPlaybackException(
126         TYPE_RENDERER,
127         cause,
128         /* customMessage= */ null,
129         rendererName,
130         rendererIndex,
131         rendererFormat,
132         rendererFormat == null ? RendererCapabilities.FORMAT_HANDLED : rendererFormatSupport);
133   }
134 
135   /**
136    * Creates an instance of type {@link #TYPE_UNEXPECTED}.
137    *
138    * @param cause The cause of the failure.
139    * @return The created instance.
140    */
createForUnexpected(RuntimeException cause)141   public static ExoPlaybackException createForUnexpected(RuntimeException cause) {
142     return new ExoPlaybackException(TYPE_UNEXPECTED, cause);
143   }
144 
145   /**
146    * Creates an instance of type {@link #TYPE_REMOTE}.
147    *
148    * @param message The message associated with the error.
149    * @return The created instance.
150    */
createForRemote(String message)151   public static ExoPlaybackException createForRemote(String message) {
152     return new ExoPlaybackException(TYPE_REMOTE, message);
153   }
154 
155   /**
156    * Creates an instance of type {@link #TYPE_OUT_OF_MEMORY}.
157    *
158    * @param cause The cause of the failure.
159    * @return The created instance.
160    */
createForOutOfMemoryError(OutOfMemoryError cause)161   public static ExoPlaybackException createForOutOfMemoryError(OutOfMemoryError cause) {
162     return new ExoPlaybackException(TYPE_OUT_OF_MEMORY, cause);
163   }
164 
ExoPlaybackException(@ype int type, Throwable cause)165   private ExoPlaybackException(@Type int type, Throwable cause) {
166     this(
167         type,
168         cause,
169         /* customMessage= */ null,
170         /* rendererName= */ null,
171         /* rendererIndex= */ C.INDEX_UNSET,
172         /* rendererFormat= */ null,
173         /* rendererFormatSupport= */ RendererCapabilities.FORMAT_HANDLED);
174   }
175 
ExoPlaybackException(@ype int type, String message)176   private ExoPlaybackException(@Type int type, String message) {
177     this(
178         type,
179         /* cause= */ null,
180         /* customMessage= */ message,
181         /* rendererName= */ null,
182         /* rendererIndex= */ C.INDEX_UNSET,
183         /* rendererFormat= */ null,
184         /* rendererFormatSupport= */ RendererCapabilities.FORMAT_HANDLED);
185   }
186 
ExoPlaybackException( @ype int type, @Nullable Throwable cause, @Nullable String customMessage, @Nullable String rendererName, int rendererIndex, @Nullable Format rendererFormat, @FormatSupport int rendererFormatSupport)187   private ExoPlaybackException(
188       @Type int type,
189       @Nullable Throwable cause,
190       @Nullable String customMessage,
191       @Nullable String rendererName,
192       int rendererIndex,
193       @Nullable Format rendererFormat,
194       @FormatSupport int rendererFormatSupport) {
195     super(
196         deriveMessage(
197             type,
198             customMessage,
199             rendererName,
200             rendererIndex,
201             rendererFormat,
202             rendererFormatSupport),
203         cause);
204     this.type = type;
205     this.cause = cause;
206     this.rendererName = rendererName;
207     this.rendererIndex = rendererIndex;
208     this.rendererFormat = rendererFormat;
209     this.rendererFormatSupport = rendererFormatSupport;
210     timestampMs = SystemClock.elapsedRealtime();
211   }
212 
213   /**
214    * Retrieves the underlying error when {@link #type} is {@link #TYPE_SOURCE}.
215    *
216    * @throws IllegalStateException If {@link #type} is not {@link #TYPE_SOURCE}.
217    */
getSourceException()218   public IOException getSourceException() {
219     Assertions.checkState(type == TYPE_SOURCE);
220     return (IOException) Assertions.checkNotNull(cause);
221   }
222 
223   /**
224    * Retrieves the underlying error when {@link #type} is {@link #TYPE_RENDERER}.
225    *
226    * @throws IllegalStateException If {@link #type} is not {@link #TYPE_RENDERER}.
227    */
getRendererException()228   public Exception getRendererException() {
229     Assertions.checkState(type == TYPE_RENDERER);
230     return (Exception) Assertions.checkNotNull(cause);
231   }
232 
233   /**
234    * Retrieves the underlying error when {@link #type} is {@link #TYPE_UNEXPECTED}.
235    *
236    * @throws IllegalStateException If {@link #type} is not {@link #TYPE_UNEXPECTED}.
237    */
getUnexpectedException()238   public RuntimeException getUnexpectedException() {
239     Assertions.checkState(type == TYPE_UNEXPECTED);
240     return (RuntimeException) Assertions.checkNotNull(cause);
241   }
242 
243   /**
244    * Retrieves the underlying error when {@link #type} is {@link #TYPE_OUT_OF_MEMORY}.
245    *
246    * @throws IllegalStateException If {@link #type} is not {@link #TYPE_OUT_OF_MEMORY}.
247    */
getOutOfMemoryError()248   public OutOfMemoryError getOutOfMemoryError() {
249     Assertions.checkState(type == TYPE_OUT_OF_MEMORY);
250     return (OutOfMemoryError) Assertions.checkNotNull(cause);
251   }
252 
253   @Nullable
deriveMessage( @ype int type, @Nullable String customMessage, @Nullable String rendererName, int rendererIndex, @Nullable Format rendererFormat, @FormatSupport int rendererFormatSupport)254   private static String deriveMessage(
255       @Type int type,
256       @Nullable String customMessage,
257       @Nullable String rendererName,
258       int rendererIndex,
259       @Nullable Format rendererFormat,
260       @FormatSupport int rendererFormatSupport) {
261     @Nullable String message;
262     switch (type) {
263       case TYPE_SOURCE:
264         message = "Source error";
265         break;
266       case TYPE_RENDERER:
267         message =
268             rendererName
269                 + " error"
270                 + ", index="
271                 + rendererIndex
272                 + ", format="
273                 + rendererFormat
274                 + ", format_supported="
275                 + RendererCapabilities.getFormatSupportString(rendererFormatSupport);
276         break;
277       case TYPE_REMOTE:
278         message = "Remote error";
279         break;
280       case TYPE_OUT_OF_MEMORY:
281         message = "Out of memory error";
282         break;
283       case TYPE_UNEXPECTED:
284       default:
285         message = "Unexpected runtime error";
286         break;
287     }
288     if (!TextUtils.isEmpty(customMessage)) {
289       message += ": " + customMessage;
290     }
291     return message;
292   }
293 }
294