Load error handling in ExoPlayer
ExoPlayer version 2.9 provides error handling customization via LoadErrorHandlingPolicy
. Historically, error handling has been one of the less flexible aspects of ExoPlayer. By using custom implementations of the LoadErrorHandlingPolicy
interface, apps can now tweak load error handling.
ExoPlayer 2.9 also includes a default implementation of the load error handling policy: DefaultLoadErrorHandlingPolicy.
ExoPlayer’s default error handling policy is (and has historically been):
- Blacklisting: In the case of adaptive media (HLS, DASH, and SmoothStreaming), ExoPlayer works around HTTP error codes 404 or 410 by trying alternative variants (if available). The process of switching variants to work around errors is called blacklisting. Blacklisted resources are not selected for playback by ExoPlayer for a predefined period of time.
- Immediate propagation: In the case of load errors caused by
ParserException
loads are not retried.ParserException
is usually related to malformed media, which is unlikely to be fixed by retrying. - Retrying: Anything else is retried at least a configurable number of times (called
minLoadableRetryCount
, whose default value is 3) before surfacing the load error exception.
Apps can tweak error handling by providing a LoadErrorHandlingPolicy
implementation when creating any non-composite media source (ExtractorMediaSource
, HlsMediaSource
, DashMediaSource
, SsMediaSource
, SingleSampleMediaSource
). The following figure provides a high level overview of how decision making works upon load errors:
Blacklisting is not always possible, since it requires adaptive media (like DASH, HLS or SmoothStreaming) and non-blacklisted alternatives to the resource that caused the load error. The LoadErrorHandlingPolicy
is always asked for a blacklist duration in the case of adaptive media, but blacklisting will fail if no viable alternatives are available. After exhausting blacklisting alternatives, the retry logic takes place.
This section walks through some use cases that take advantage of LoadErrorHandlingPolicy
.
Do not retry some types of errors (GitHub issue #2844)
Retrying is unlikely to help in some erroneous conditions. FileNotFoundException
and HTTP 403 Forbidden response code are both unlikely to benefit from retrying, and failing fast may be a better approach. The default error handling policy can be extended to prevent retrying in the case of FileNotFoundException
in the following way:
Blacklist server errors (GitHub issue #2981)
In some scenarios, apps would blacklist HTTP errors other than 404 and 410. For example, let’s imagine a group of servers each serving a different quality of an HLS master playlist. One of these servers is in an erroneous state which makes it return HTTP 500 to every request. Assuming the servers serving other qualities are working normally, the app could continue normal playback by blacklisting the failing quality. The following snippet extends the default behavior blacklisting policy by also handling the HTTP 500 response:
When the app requests a segment or a playlist from the faulty server, it will receive an HTTP 500 and blacklist the variant. If a different variant works, then playback will continue normally.
Customize back off logic (GitHub issue #3370)
Apps can implement exponential back-off to retry loads related to network errors using a custom LoadErrorHandlingPolicy
. Exponential back-off is a common technique for rescheduling data transmission to minimize network congestion. For example, the implementation could be:
Do not surface load errors due to lack of network connectivity (GitHub issue #1186)
The LoadErrorHandlingPolicy
can be used to prevent ExoPlayer from surfacing errors. A possible use case is entering the buffering state when connectivity is lost, as opposed to having the player fail. To prevent loss of connectivity from stopping playback, an implementation similar to the following one can be used:
Combining custom components: Custom DataSource and LoadErrorHandlingPolicy
The error handling policy can be used in conjunction with other injectable components to achieve robust playback behavior. To exemplify this, let us suppose we want to cancel HLS segment buffering to try a different variant.
As of version 2.9, ExoPlayer’s HLS implementation allows blacklisting variants whose segments fail mid-download. This allows apps to adapt when a segment download seems to be stuck due to a server condition. There are 3 required steps:
- Create an
IOException
which can be thrown byDataSource#read
and later identified by the load error handling policy. For example, let’s sayDataSourceTimeoutException
. - Create a
DataSource
implementation which throws aDataSourceTimeoutException
from itsread(...)
method when a certain timeout condition is met. The customDataSource
must be injected using anHlsDataSourceFactory
implementation. Note that theDataSource
with timeout can wrap an existing implementation (for example,DefaultDataSource
) instead of being a full implementation. - Create and use a load error handling policy that blacklists the resource associated with
DataSourceTimeoutException
. The implementation of the customLoadErrorHandlingPolicy
can be similar to the following:
This post provides an overview of how to customize load error handling. By injecting custom policies to media sources, apps can provide a more robust experience to users. Please give it a try and let us know what you think.