@@ -97,17 +97,22 @@ private static StringBuilder commonCacheKeyOf(final StreamInfo info,
9797 }
9898
9999 /**
100- * Builds the cache key of a video stream. A cache key is unique to the features of the
101- * provided video stream, and when possible independent of <i>transient</i> parameters (such as
102- * the url of the stream). This ensures that there are no conflicts, but also that the cache is
103- * used as much as possible: the same cache should be used for two streams which have the same
104- * features but e.g. a different url, since the url might have been reloaded in the meantime,
105- * but the stream actually referenced by the url is still the same.
100+ * Builds the cache key of a {@link VideoStream video stream}.
106101 *
107- * @param info the stream info, to distinguish between streams with the same features but coming
108- * from different stream infos
109- * @param videoStream the video stream for which the cache key should be created
110- * @return a key to be used to store the cache of the provided video stream
102+ * <p>
103+ * A cache key is unique to the features of the provided video stream, and when possible
104+ * independent of <i>transient</i> parameters (such as the URL of the stream).
105+ * This ensures that there are no conflicts, but also that the cache is used as much as
106+ * possible: the same cache should be used for two streams which have the same features but
107+ * e.g. a different URL, since the URL might have been reloaded in the meantime, but the stream
108+ * actually referenced by the URL is still the same.
109+ * </p>
110+ *
111+ * @param info the {@link StreamInfo stream info}, to distinguish between streams with
112+ * the same features but coming from different stream infos
113+ * @param videoStream the {@link VideoStream video stream} for which the cache key should be
114+ * created
115+ * @return a key to be used to store the cache of the provided {@link VideoStream video stream}
111116 */
112117 static String cacheKeyOf (final StreamInfo info , final VideoStream videoStream ) {
113118 final boolean resolutionUnknown = videoStream .getResolution ().equals (RESOLUTION_UNKNOWN );
@@ -127,17 +132,22 @@ static String cacheKeyOf(final StreamInfo info, final VideoStream videoStream) {
127132 }
128133
129134 /**
130- * Builds the cache key of an audio stream. A cache key is unique to the features of the
131- * provided audio stream, and when possible independent of <i>transient</i> parameters (such as
132- * the url of the stream). This ensures that there are no conflicts, but also that the cache is
133- * used as much as possible: the same cache should be used for two streams which have the same
134- * features but e.g. a different url, since the url might have been reloaded in the meantime,
135- * but the stream actually referenced by the url is still the same.
135+ * Builds the cache key of an audio stream.
136+ *
137+ * <p>
138+ * A cache key is unique to the features of the provided {@link AudioStream audio stream}, and
139+ * when possible independent of <i>transient</i> parameters (such as the URL of the stream).
140+ * This ensures that there are no conflicts, but also that the cache is used as much as
141+ * possible: the same cache should be used for two streams which have the same features but
142+ * e.g. a different URL, since the URL might have been reloaded in the meantime, but the stream
143+ * actually referenced by the URL is still the same.
144+ * </p>
136145 *
137- * @param info the stream info, to distinguish between streams with the same features but coming
138- * from different stream infos
139- * @param audioStream the audio stream for which the cache key should be created
140- * @return a key to be used to store the cache of the provided audio stream
146+ * @param info the {@link StreamInfo stream info}, to distinguish between streams with
147+ * the same features but coming from different stream infos
148+ * @param audioStream the {@link AudioStream audio stream} for which the cache key should be
149+ * created
150+ * @return a key to be used to store the cache of the provided {@link AudioStream audio stream}
141151 */
142152 static String cacheKeyOf (final StreamInfo info , final AudioStream audioStream ) {
143153 final boolean averageBitrateUnknown = audioStream .getAverageBitrate () == UNKNOWN_BITRATE ;
@@ -158,16 +168,20 @@ static String cacheKeyOf(final StreamInfo info, final AudioStream audioStream) {
158168 @ Nullable
159169 static MediaSource maybeBuildLiveMediaSource (final PlayerDataSource dataSource ,
160170 final StreamInfo info ) {
161- final StreamType streamType = info .getStreamType ();
162- if (!StreamTypeUtil .isLiveStream (streamType )) {
171+ if (!StreamTypeUtil .isLiveStream (info .getStreamType ())) {
163172 return null ;
164173 }
165174
166- final StreamInfoTag tag = StreamInfoTag .of (info );
167- if (!info .getHlsUrl ().isEmpty ()) {
168- return buildLiveMediaSource (dataSource , info .getHlsUrl (), C .TYPE_HLS , tag );
169- } else if (!info .getDashMpdUrl ().isEmpty ()) {
170- return buildLiveMediaSource (dataSource , info .getDashMpdUrl (), C .TYPE_DASH , tag );
175+ try {
176+ final StreamInfoTag tag = StreamInfoTag .of (info );
177+ if (!info .getHlsUrl ().isEmpty ()) {
178+ return buildLiveMediaSource (dataSource , info .getHlsUrl (), C .TYPE_HLS , tag );
179+ } else if (!info .getDashMpdUrl ().isEmpty ()) {
180+ return buildLiveMediaSource (dataSource , info .getDashMpdUrl (), C .TYPE_DASH , tag );
181+ }
182+ } catch (final Exception e ) {
183+ Log .w (TAG , "Error when generating live media source, falling back to standard sources" ,
184+ e );
171185 }
172186
173187 return null ;
@@ -176,7 +190,7 @@ static MediaSource maybeBuildLiveMediaSource(final PlayerDataSource dataSource,
176190 static MediaSource buildLiveMediaSource (final PlayerDataSource dataSource ,
177191 final String sourceUrl ,
178192 @ C .ContentType final int type ,
179- final MediaItemTag metadata ) {
193+ final MediaItemTag metadata ) throws ResolverException {
180194 final MediaSource .Factory factory ;
181195 switch (type ) {
182196 case C .TYPE_SS :
@@ -188,8 +202,10 @@ static MediaSource buildLiveMediaSource(final PlayerDataSource dataSource,
188202 case C .TYPE_HLS :
189203 factory = dataSource .getLiveHlsMediaSourceFactory ();
190204 break ;
191- case C .TYPE_OTHER : case C .TYPE_RTSP : default :
192- throw new IllegalStateException ("Unsupported type: " + type );
205+ case C .TYPE_OTHER :
206+ case C .TYPE_RTSP :
207+ default :
208+ throw new ResolverException ("Unsupported type: " + type );
193209 }
194210
195211 return factory .createMediaSource (
@@ -210,8 +226,7 @@ static MediaSource buildMediaSource(final PlayerDataSource dataSource,
210226 final Stream stream ,
211227 final StreamInfo streamInfo ,
212228 final String cacheKey ,
213- final MediaItemTag metadata )
214- throws IOException {
229+ final MediaItemTag metadata ) throws ResolverException {
215230 if (streamInfo .getService () == ServiceList .YouTube ) {
216231 return createYoutubeMediaSource (stream , streamInfo , dataSource , cacheKey , metadata );
217232 }
@@ -228,19 +243,19 @@ static MediaSource buildMediaSource(final PlayerDataSource dataSource,
228243 return buildSSMediaSource (dataSource , stream , cacheKey , metadata );
229244 // Torrent streams are not supported by ExoPlayer
230245 default :
231- throw new IllegalArgumentException ("Unsupported delivery type: " + deliveryMethod );
246+ throw new ResolverException ("Unsupported delivery type: " + deliveryMethod );
232247 }
233248 }
234249
235250 private static ProgressiveMediaSource buildProgressiveMediaSource (
236251 final PlayerDataSource dataSource ,
237252 final Stream stream ,
238253 final String cacheKey ,
239- final MediaItemTag metadata ) throws IOException {
254+ final MediaItemTag metadata ) throws ResolverException {
240255 final String url = stream .getContent ();
241256
242257 if (isNullOrEmpty (url )) {
243- throw new IOException (
258+ throw new ResolverException (
244259 "Try to generate a progressive media source from an empty string or from a "
245260 + "null object" );
246261 } else {
@@ -257,11 +272,11 @@ private static DashMediaSource buildDashMediaSource(final PlayerDataSource dataS
257272 final Stream stream ,
258273 final String cacheKey ,
259274 final MediaItemTag metadata )
260- throws IOException {
275+ throws ResolverException {
261276 final boolean isUrlStream = stream .isUrl ();
262277 if (isUrlStream && isNullOrEmpty (stream .getContent ())) {
263- throw new IOException ( "Try to generate a DASH media source from an empty string or "
264- + " from a null object " );
278+ throw new ResolverException (
279+ "Could not build a DASH media source from an empty or a null URL content " );
265280 }
266281
267282 if (isUrlStream ) {
@@ -279,41 +294,42 @@ private static DashMediaSource buildDashMediaSource(final PlayerDataSource dataS
279294
280295 final Uri uri = Uri .parse (baseUrl );
281296
282- return dataSource .getDashMediaSourceFactory ().createMediaSource (
283- createDashManifest (stream .getContent (), stream ),
284- new MediaItem .Builder ()
285- .setTag (metadata )
286- .setUri (uri )
287- .setCustomCacheKey (cacheKey )
288- .build ());
297+ try {
298+ return dataSource .getDashMediaSourceFactory ().createMediaSource (
299+ createDashManifest (stream .getContent (), stream ),
300+ new MediaItem .Builder ()
301+ .setTag (metadata )
302+ .setUri (uri )
303+ .setCustomCacheKey (cacheKey )
304+ .build ());
305+ } catch (final IOException e ) {
306+ throw new ResolverException (
307+ "Could not create a DASH media source/manifest from the manifest text" );
308+ }
289309 }
290310 }
291311
292312 private static DashManifest createDashManifest (final String manifestContent ,
293313 final Stream stream ) throws IOException {
294- try {
295- final ByteArrayInputStream dashManifestInput = new ByteArrayInputStream (
296- manifestContent .getBytes (StandardCharsets .UTF_8 ));
297- String baseUrl = stream .getManifestUrl ();
298- if (baseUrl == null ) {
299- baseUrl = "" ;
300- }
301-
302- return new DashManifestParser ().parse (Uri .parse (baseUrl ), dashManifestInput );
303- } catch (final IOException e ) {
304- throw new IOException ("Error when parsing manual DASH manifest" , e );
314+ final ByteArrayInputStream dashManifestInput = new ByteArrayInputStream (
315+ manifestContent .getBytes (StandardCharsets .UTF_8 ));
316+ String baseUrl = stream .getManifestUrl ();
317+ if (baseUrl == null ) {
318+ baseUrl = "" ;
305319 }
320+
321+ return new DashManifestParser ().parse (Uri .parse (baseUrl ), dashManifestInput );
306322 }
307323
308324 private static HlsMediaSource buildHlsMediaSource (final PlayerDataSource dataSource ,
309325 final Stream stream ,
310326 final String cacheKey ,
311327 final MediaItemTag metadata )
312- throws IOException {
328+ throws ResolverException {
313329 final boolean isUrlStream = stream .isUrl ();
314330 if (isUrlStream && isNullOrEmpty (stream .getContent ())) {
315- throw new IOException ( "Try to generate an HLS media source from an empty string or "
316- + " from a null object " );
331+ throw new ResolverException (
332+ "Could not build a HLS media source from an empty or a null URL content " );
317333 }
318334
319335 if (isUrlStream ) {
@@ -337,7 +353,7 @@ private static HlsMediaSource buildHlsMediaSource(final PlayerDataSource dataSou
337353 stream .getContent ().getBytes (StandardCharsets .UTF_8 ));
338354 hlsPlaylist = new HlsPlaylistParser ().parse (uri , hlsManifestInput );
339355 } catch (final IOException e ) {
340- throw new IOException ("Error when parsing manual HLS manifest" , e );
356+ throw new ResolverException ("Error when parsing manual HLS manifest" , e );
341357 }
342358
343359 return dataSource .getHlsMediaSourceFactory (
@@ -354,11 +370,11 @@ private static SsMediaSource buildSSMediaSource(final PlayerDataSource dataSourc
354370 final Stream stream ,
355371 final String cacheKey ,
356372 final MediaItemTag metadata )
357- throws IOException {
373+ throws ResolverException {
358374 final boolean isUrlStream = stream .isUrl ();
359375 if (isUrlStream && isNullOrEmpty (stream .getContent ())) {
360- throw new IOException ( "Try to generate an SmoothStreaming media source from an empty "
361- + "string or from a null object " );
376+ throw new ResolverException (
377+ "Could not build a SS media source from an empty or a null URL content " );
362378 }
363379
364380 if (isUrlStream ) {
@@ -383,7 +399,7 @@ private static SsMediaSource buildSSMediaSource(final PlayerDataSource dataSourc
383399 smoothStreamingManifest = new SsManifestParser ().parse (uri ,
384400 smoothStreamingManifestInput );
385401 } catch (final IOException e ) {
386- throw new IOException ("Error when parsing manual SmoothStreaming manifest" , e );
402+ throw new ResolverException ("Error when parsing manual SS manifest" , e );
387403 }
388404
389405 return dataSource .getSSMediaSourceFactory ().createMediaSource (
@@ -404,10 +420,10 @@ private static MediaSource createYoutubeMediaSource(final Stream stream,
404420 final PlayerDataSource dataSource ,
405421 final String cacheKey ,
406422 final MediaItemTag metadata )
407- throws IOException {
423+ throws ResolverException {
408424 if (!(stream instanceof AudioStream || stream instanceof VideoStream )) {
409- throw new IOException ( "Try to generate a DASH manifest of a YouTube "
410- + stream .getClass () + " " + stream . getContent () );
425+ throw new ResolverException ( "Generation of YouTube DASH manifest for "
426+ + stream .getClass (). getSimpleName () + " is not supported" );
411427 }
412428
413429 final StreamType streamType = streamInfo .getStreamType ();
@@ -430,15 +446,15 @@ private static MediaSource createYoutubeMediaSource(final Stream stream,
430446 return buildYoutubeManualDashMediaSource (dataSource ,
431447 createDashManifest (manifestString , stream ), stream , cacheKey ,
432448 metadata );
433- } catch (final CreationException | NullPointerException e ) {
449+ } catch (final CreationException | IOException | NullPointerException e ) {
434450 Log .e (TAG , "Error when generating the DASH manifest of YouTube ended live stream" ,
435451 e );
436- throw new IOException ( "Error when generating the DASH manifest of YouTube ended "
437- + "live stream " + stream . getContent () , e );
452+ throw new ResolverException (
453+ "Error when generating the DASH manifest of YouTube ended live stream" , e );
438454 }
439455 } else {
440- throw new IllegalArgumentException ( "DASH manifest generation of YouTube livestreams is "
441- + " not supported" );
456+ throw new ResolverException (
457+ "DASH manifest generation of YouTube livestreams is not supported" );
442458 }
443459 }
444460
@@ -447,7 +463,7 @@ private static MediaSource createYoutubeMediaSourceOfVideoStreamType(
447463 final Stream stream ,
448464 final StreamInfo streamInfo ,
449465 final String cacheKey ,
450- final MediaItemTag metadata ) throws IOException {
466+ final MediaItemTag metadata ) throws ResolverException {
451467 final DeliveryMethod deliveryMethod = stream .getDeliveryMethod ();
452468 switch (deliveryMethod ) {
453469 case PROGRESSIVE_HTTP :
@@ -488,12 +504,11 @@ private static MediaSource createYoutubeMediaSourceOfVideoStreamType(
488504 return buildYoutubeManualDashMediaSource (dataSource ,
489505 createDashManifest (manifestString , stream ), stream , cacheKey ,
490506 metadata );
491- } catch (final CreationException | NullPointerException e ) {
507+ } catch (final CreationException | IOException | NullPointerException e ) {
492508 Log .e (TAG ,
493509 "Error when generating the DASH manifest of YouTube OTF stream" , e );
494- throw new IOException (
495- "Error when generating the DASH manifest of YouTube OTF stream "
496- + stream .getContent (), e );
510+ throw new ResolverException (
511+ "Error when generating the DASH manifest of YouTube OTF stream" , e );
497512 }
498513 case HLS :
499514 return dataSource .getYoutubeHlsMediaSourceFactory ().createMediaSource (
@@ -503,7 +518,7 @@ private static MediaSource createYoutubeMediaSourceOfVideoStreamType(
503518 .setCustomCacheKey (cacheKey )
504519 .build ());
505520 default :
506- throw new IOException ("Unsupported delivery method for YouTube contents: "
521+ throw new ResolverException ("Unsupported delivery method for YouTube contents: "
507522 + deliveryMethod );
508523 }
509524 }
@@ -535,4 +550,17 @@ private static ProgressiveMediaSource buildYoutubeProgressiveMediaSource(
535550 .build ());
536551 }
537552 //endregion
553+
554+
555+ //region resolver exception
556+ final class ResolverException extends Exception {
557+ public ResolverException (final String message ) {
558+ super (message );
559+ }
560+
561+ public ResolverException (final String message , final Throwable cause ) {
562+ super (message , cause );
563+ }
564+ }
565+ //endregion
538566}
0 commit comments