88import android .net .Uri ;
99import android .util .Log ;
1010
11+ import androidx .annotation .Nullable ;
12+
1113import com .google .android .exoplayer2 .C ;
1214import com .google .android .exoplayer2 .MediaItem ;
1315import com .google .android .exoplayer2 .source .MediaSource ;
4143import org .schabi .newpipe .player .mediaitem .StreamInfoTag ;
4244import org .schabi .newpipe .util .StreamTypeUtil ;
4345
44- import androidx .annotation .NonNull ;
45- import androidx .annotation .Nullable ;
46-
4746import java .io .ByteArrayInputStream ;
4847import java .io .IOException ;
4948import java .nio .charset .StandardCharsets ;
5049import java .util .Objects ;
5150
51+ /**
52+ * This interface is just a shorthand for {@link Resolver} with {@link StreamInfo} as source and
53+ * {@link MediaSource} as product. It contains many static methods that can be used by classes
54+ * implementing this interface, and nothing else.
55+ */
5256public interface PlaybackResolver extends Resolver <StreamInfo , MediaSource > {
5357 String TAG = PlaybackResolver .class .getSimpleName ();
5458
55- @ NonNull
56- private static StringBuilder commonCacheKeyOf (@ NonNull final StreamInfo info ,
57- @ NonNull final Stream stream ,
59+
60+ //region Cache key generation
61+ private static StringBuilder commonCacheKeyOf (final StreamInfo info ,
62+ final Stream stream ,
5863 final boolean resolutionOrBitrateUnknown ) {
5964 // stream info service id
6065 final StringBuilder cacheKey = new StringBuilder (info .getServiceId ());
@@ -91,9 +96,20 @@ private static StringBuilder commonCacheKeyOf(@NonNull final StreamInfo info,
9196 return cacheKey ;
9297 }
9398
94- @ NonNull
95- static String cacheKeyOf (@ NonNull final StreamInfo info ,
96- @ NonNull final VideoStream videoStream ) {
99+ /**
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.
106+ *
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
111+ */
112+ static String cacheKeyOf (final StreamInfo info , final VideoStream videoStream ) {
97113 final boolean resolutionUnknown = videoStream .getResolution ().equals (RESOLUTION_UNKNOWN );
98114 final StringBuilder cacheKey = commonCacheKeyOf (info , videoStream , resolutionUnknown );
99115
@@ -110,9 +126,20 @@ static String cacheKeyOf(@NonNull final StreamInfo info,
110126 return cacheKey .toString ();
111127 }
112128
113- @ NonNull
114- static String cacheKeyOf (@ NonNull final StreamInfo info ,
115- @ NonNull final AudioStream audioStream ) {
129+ /**
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.
136+ *
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
141+ */
142+ static String cacheKeyOf (final StreamInfo info , final AudioStream audioStream ) {
116143 final boolean averageBitrateUnknown = audioStream .getAverageBitrate () == UNKNOWN_BITRATE ;
117144 final StringBuilder cacheKey = commonCacheKeyOf (info , audioStream , averageBitrateUnknown );
118145
@@ -124,10 +151,13 @@ static String cacheKeyOf(@NonNull final StreamInfo info,
124151
125152 return cacheKey .toString ();
126153 }
154+ //endregion
155+
127156
157+ //region Live media sources
128158 @ Nullable
129- static MediaSource maybeBuildLiveMediaSource (@ NonNull final PlayerDataSource dataSource ,
130- @ NonNull final StreamInfo info ) {
159+ static MediaSource maybeBuildLiveMediaSource (final PlayerDataSource dataSource ,
160+ final StreamInfo info ) {
131161 final StreamType streamType = info .getStreamType ();
132162 if (!StreamTypeUtil .isLiveStream (streamType )) {
133163 return null ;
@@ -143,11 +173,10 @@ static MediaSource maybeBuildLiveMediaSource(@NonNull final PlayerDataSource dat
143173 return null ;
144174 }
145175
146- @ NonNull
147- static MediaSource buildLiveMediaSource (@ NonNull final PlayerDataSource dataSource ,
148- @ NonNull final String sourceUrl ,
176+ static MediaSource buildLiveMediaSource (final PlayerDataSource dataSource ,
177+ final String sourceUrl ,
149178 @ C .ContentType final int type ,
150- @ NonNull final MediaItemTag metadata ) {
179+ final MediaItemTag metadata ) {
151180 final MediaSource .Factory factory ;
152181 switch (type ) {
153182 case C .TYPE_SS :
@@ -159,7 +188,7 @@ static MediaSource buildLiveMediaSource(@NonNull final PlayerDataSource dataSour
159188 case C .TYPE_HLS :
160189 factory = dataSource .getLiveHlsMediaSourceFactory ();
161190 break ;
162- default :
191+ case C . TYPE_OTHER : case C . TYPE_RTSP : default :
163192 throw new IllegalStateException ("Unsupported type: " + type );
164193 }
165194
@@ -173,13 +202,15 @@ static MediaSource buildLiveMediaSource(@NonNull final PlayerDataSource dataSour
173202 .build ())
174203 .build ());
175204 }
205+ //endregion
176206
177- @ NonNull
178- static MediaSource buildMediaSource (@ NonNull final PlayerDataSource dataSource ,
179- @ NonNull final Stream stream ,
180- @ NonNull final StreamInfo streamInfo ,
181- @ NonNull final String cacheKey ,
182- @ NonNull final MediaItemTag metadata )
207+
208+ //region Generic media sources
209+ static MediaSource buildMediaSource (final PlayerDataSource dataSource ,
210+ final Stream stream ,
211+ final StreamInfo streamInfo ,
212+ final String cacheKey ,
213+ final MediaItemTag metadata )
183214 throws IOException {
184215 if (streamInfo .getService () == ServiceList .YouTube ) {
185216 return createYoutubeMediaSource (stream , streamInfo , dataSource , cacheKey , metadata );
@@ -201,12 +232,11 @@ static MediaSource buildMediaSource(@NonNull final PlayerDataSource dataSource,
201232 }
202233 }
203234
204- @ NonNull
205- private static <T extends Stream > ProgressiveMediaSource buildProgressiveMediaSource (
206- @ NonNull final PlayerDataSource dataSource ,
207- @ NonNull final T stream ,
208- @ NonNull final String cacheKey ,
209- @ NonNull final MediaItemTag metadata ) throws IOException {
235+ private static ProgressiveMediaSource buildProgressiveMediaSource (
236+ final PlayerDataSource dataSource ,
237+ final Stream stream ,
238+ final String cacheKey ,
239+ final MediaItemTag metadata ) throws IOException {
210240 final String url = stream .getContent ();
211241
212242 if (isNullOrEmpty (url )) {
@@ -223,12 +253,11 @@ private static <T extends Stream> ProgressiveMediaSource buildProgressiveMediaSo
223253 }
224254 }
225255
226- @ NonNull
227- private static <T extends Stream > DashMediaSource buildDashMediaSource (
228- @ NonNull final PlayerDataSource dataSource ,
229- @ NonNull final T stream ,
230- @ NonNull final String cacheKey ,
231- @ NonNull final MediaItemTag metadata ) throws IOException {
256+ private static DashMediaSource buildDashMediaSource (final PlayerDataSource dataSource ,
257+ final Stream stream ,
258+ final String cacheKey ,
259+ final MediaItemTag metadata )
260+ throws IOException {
232261 final boolean isUrlStream = stream .isUrl ();
233262 if (isUrlStream && isNullOrEmpty (stream .getContent ())) {
234263 throw new IOException ("Try to generate a DASH media source from an empty string or "
@@ -260,10 +289,8 @@ private static <T extends Stream> DashMediaSource buildDashMediaSource(
260289 }
261290 }
262291
263- @ NonNull
264- private static <T extends Stream > DashManifest createDashManifest (
265- @ NonNull final String manifestContent ,
266- @ NonNull final T stream ) throws IOException {
292+ private static DashManifest createDashManifest (final String manifestContent ,
293+ final Stream stream ) throws IOException {
267294 try {
268295 final ByteArrayInputStream dashManifestInput = new ByteArrayInputStream (
269296 manifestContent .getBytes (StandardCharsets .UTF_8 ));
@@ -278,12 +305,11 @@ private static <T extends Stream> DashManifest createDashManifest(
278305 }
279306 }
280307
281- @ NonNull
282- private static <T extends Stream > HlsMediaSource buildHlsMediaSource (
283- @ NonNull final PlayerDataSource dataSource ,
284- @ NonNull final T stream ,
285- @ NonNull final String cacheKey ,
286- @ NonNull final MediaItemTag metadata ) throws IOException {
308+ private static HlsMediaSource buildHlsMediaSource (final PlayerDataSource dataSource ,
309+ final Stream stream ,
310+ final String cacheKey ,
311+ final MediaItemTag metadata )
312+ throws IOException {
287313 final boolean isUrlStream = stream .isUrl ();
288314 if (isUrlStream && isNullOrEmpty (stream .getContent ())) {
289315 throw new IOException ("Try to generate an HLS media source from an empty string or "
@@ -324,12 +350,11 @@ private static <T extends Stream> HlsMediaSource buildHlsMediaSource(
324350 }
325351 }
326352
327- @ NonNull
328- private static <T extends Stream > SsMediaSource buildSSMediaSource (
329- @ NonNull final PlayerDataSource dataSource ,
330- @ NonNull final T stream ,
331- @ NonNull final String cacheKey ,
332- @ NonNull final MediaItemTag metadata ) throws IOException {
353+ private static SsMediaSource buildSSMediaSource (final PlayerDataSource dataSource ,
354+ final Stream stream ,
355+ final String cacheKey ,
356+ final MediaItemTag metadata )
357+ throws IOException {
333358 final boolean isUrlStream = stream .isUrl ();
334359 if (isUrlStream && isNullOrEmpty (stream .getContent ())) {
335360 throw new IOException ("Try to generate an SmoothStreaming media source from an empty "
@@ -370,13 +395,16 @@ private static <T extends Stream> SsMediaSource buildSSMediaSource(
370395 .build ());
371396 }
372397 }
398+ //endregion
373399
374- private static <T extends Stream > MediaSource createYoutubeMediaSource (
375- final T stream ,
376- final StreamInfo streamInfo ,
377- final PlayerDataSource dataSource ,
378- final String cacheKey ,
379- final MediaItemTag metadata ) throws IOException {
400+
401+ //region YouTube media sources
402+ private static MediaSource createYoutubeMediaSource (final Stream stream ,
403+ final StreamInfo streamInfo ,
404+ final PlayerDataSource dataSource ,
405+ final String cacheKey ,
406+ final MediaItemTag metadata )
407+ throws IOException {
380408 if (!(stream instanceof AudioStream || stream instanceof VideoStream )) {
381409 throw new IOException ("Try to generate a DASH manifest of a YouTube "
382410 + stream .getClass () + " " + stream .getContent ());
@@ -414,12 +442,12 @@ private static <T extends Stream> MediaSource createYoutubeMediaSource(
414442 }
415443 }
416444
417- private static < T extends Stream > MediaSource createYoutubeMediaSourceOfVideoStreamType (
418- @ NonNull final PlayerDataSource dataSource ,
419- @ NonNull final T stream ,
420- @ NonNull final StreamInfo streamInfo ,
421- @ NonNull final String cacheKey ,
422- @ NonNull final MediaItemTag metadata ) throws IOException {
445+ private static MediaSource createYoutubeMediaSourceOfVideoStreamType (
446+ final PlayerDataSource dataSource ,
447+ final Stream stream ,
448+ final StreamInfo streamInfo ,
449+ final String cacheKey ,
450+ final MediaItemTag metadata ) throws IOException {
423451 final DeliveryMethod deliveryMethod = stream .getDeliveryMethod ();
424452 switch (deliveryMethod ) {
425453 case PROGRESSIVE_HTTP :
@@ -480,13 +508,12 @@ private static <T extends Stream> MediaSource createYoutubeMediaSourceOfVideoStr
480508 }
481509 }
482510
483- @ NonNull
484- private static <T extends Stream > DashMediaSource buildYoutubeManualDashMediaSource (
485- @ NonNull final PlayerDataSource dataSource ,
486- @ NonNull final DashManifest dashManifest ,
487- @ NonNull final T stream ,
488- @ NonNull final String cacheKey ,
489- @ NonNull final MediaItemTag metadata ) {
511+ private static DashMediaSource buildYoutubeManualDashMediaSource (
512+ final PlayerDataSource dataSource ,
513+ final DashManifest dashManifest ,
514+ final Stream stream ,
515+ final String cacheKey ,
516+ final MediaItemTag metadata ) {
490517 return dataSource .getYoutubeDashMediaSourceFactory ().createMediaSource (dashManifest ,
491518 new MediaItem .Builder ()
492519 .setTag (metadata )
@@ -495,17 +522,17 @@ private static <T extends Stream> DashMediaSource buildYoutubeManualDashMediaSou
495522 .build ());
496523 }
497524
498- @ NonNull
499- private static <T extends Stream > ProgressiveMediaSource buildYoutubeProgressiveMediaSource (
500- @ NonNull final PlayerDataSource dataSource ,
501- @ NonNull final T stream ,
502- @ NonNull final String cacheKey ,
503- @ NonNull final MediaItemTag metadata ) {
525+ private static ProgressiveMediaSource buildYoutubeProgressiveMediaSource (
526+ final PlayerDataSource dataSource ,
527+ final Stream stream ,
528+ final String cacheKey ,
529+ final MediaItemTag metadata ) {
504530 return dataSource .getYoutubeProgressiveMediaSourceFactory ()
505531 .createMediaSource (new MediaItem .Builder ()
506532 .setTag (metadata )
507533 .setUri (Uri .parse (stream .getContent ()))
508534 .setCustomCacheKey (cacheKey )
509535 .build ());
510536 }
537+ //endregion
511538}
0 commit comments