mirror of
				https://github.com/TeamNewPipe/NewPipe
				synced 2025-10-31 07:13:00 +00:00 
			
		
		
		
	-Added perpetual extractor source loading on network failures.
-Fixed play queue playlist desynchronization caused by media source manager window loading expansion on sublist prior to current item. -Fixed failed media source not treated as ready for playback.
This commit is contained in:
		| @@ -16,6 +16,7 @@ import com.google.android.exoplayer2.upstream.TransferListener; | |||||||
|  |  | ||||||
| public class PlayerDataSource { | public class PlayerDataSource { | ||||||
|     private static final int MANIFEST_MINIMUM_RETRY = 5; |     private static final int MANIFEST_MINIMUM_RETRY = 5; | ||||||
|  |     private static final int EXTRACTOR_MINIMUM_RETRY = Integer.MAX_VALUE; | ||||||
|     private static final int LIVE_STREAM_EDGE_GAP_MILLIS = 10000; |     private static final int LIVE_STREAM_EDGE_GAP_MILLIS = 10000; | ||||||
|  |  | ||||||
|     private final DataSource.Factory cacheDataSourceFactory; |     private final DataSource.Factory cacheDataSourceFactory; | ||||||
| @@ -63,11 +64,12 @@ public class PlayerDataSource { | |||||||
|     } |     } | ||||||
|  |  | ||||||
|     public ExtractorMediaSource.Factory getExtractorMediaSourceFactory() { |     public ExtractorMediaSource.Factory getExtractorMediaSourceFactory() { | ||||||
|         return new ExtractorMediaSource.Factory(cacheDataSourceFactory); |         return new ExtractorMediaSource.Factory(cacheDataSourceFactory) | ||||||
|  |                 .setMinLoadableRetryCount(EXTRACTOR_MINIMUM_RETRY); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     public ExtractorMediaSource.Factory getExtractorMediaSourceFactory(@NonNull final String key) { |     public ExtractorMediaSource.Factory getExtractorMediaSourceFactory(@NonNull final String key) { | ||||||
|         return new ExtractorMediaSource.Factory(cacheDataSourceFactory).setCustomCacheKey(key); |         return getExtractorMediaSourceFactory().setCustomCacheKey(key); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     public SingleSampleMediaSource.Factory getSampleMediaSourceFactory() { |     public SingleSampleMediaSource.Factory getSampleMediaSourceFactory() { | ||||||
|   | |||||||
| @@ -38,11 +38,12 @@ import io.reactivex.subjects.PublishSubject; | |||||||
| import static org.schabi.newpipe.playlist.PlayQueue.DEBUG; | import static org.schabi.newpipe.playlist.PlayQueue.DEBUG; | ||||||
|  |  | ||||||
| public class MediaSourceManager { | public class MediaSourceManager { | ||||||
|     private final String TAG = "MediaSourceManager"; |     private final static String TAG = "MediaSourceManager"; | ||||||
|  |  | ||||||
|  |     // WINDOW_SIZE determines how many streams AFTER the current stream should be loaded. | ||||||
|  |     // The default value (1) ensures seamless playback under typical network settings. | ||||||
|  |     private final static int WINDOW_SIZE = 1; | ||||||
|  |  | ||||||
|     // One-side rolling window size for default loading |  | ||||||
|     // Effectively loads windowSize * 2 + 1 streams per call to load, must be greater than 0 |  | ||||||
|     private final int windowSize; |  | ||||||
|     private final PlaybackListener playbackListener; |     private final PlaybackListener playbackListener; | ||||||
|     private final PlayQueue playQueue; |     private final PlayQueue playQueue; | ||||||
|     private final long expirationTimeMillis; |     private final long expirationTimeMillis; | ||||||
| @@ -68,23 +69,19 @@ public class MediaSourceManager { | |||||||
|  |  | ||||||
|     public MediaSourceManager(@NonNull final PlaybackListener listener, |     public MediaSourceManager(@NonNull final PlaybackListener listener, | ||||||
|                               @NonNull final PlayQueue playQueue) { |                               @NonNull final PlayQueue playQueue) { | ||||||
|         this(listener, playQueue, 1, 400L, 2, TimeUnit.HOURS); |         this(listener, playQueue, | ||||||
|  |                 /*loadDebounceMillis=*/400L, | ||||||
|  |                 /*expirationTimeMillis=*/2, | ||||||
|  |                 /*expirationTimeUnit=*/TimeUnit.HOURS); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     private MediaSourceManager(@NonNull final PlaybackListener listener, |     private MediaSourceManager(@NonNull final PlaybackListener listener, | ||||||
|                                @NonNull final PlayQueue playQueue, |                                @NonNull final PlayQueue playQueue, | ||||||
|                                final int windowSize, |  | ||||||
|                                final long loadDebounceMillis, |                                final long loadDebounceMillis, | ||||||
|                                final long expirationTimeMillis, |                                final long expirationTimeMillis, | ||||||
|                                @NonNull final TimeUnit expirationTimeUnit) { |                                @NonNull final TimeUnit expirationTimeUnit) { | ||||||
|         if (windowSize <= 0) { |  | ||||||
|             throw new UnsupportedOperationException( |  | ||||||
|                     "MediaSourceManager window size must be greater than 0"); |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         this.playbackListener = listener; |         this.playbackListener = listener; | ||||||
|         this.playQueue = playQueue; |         this.playQueue = playQueue; | ||||||
|         this.windowSize = windowSize; |  | ||||||
|         this.loadDebounceMillis = loadDebounceMillis; |         this.loadDebounceMillis = loadDebounceMillis; | ||||||
|         this.expirationTimeMillis = expirationTimeMillis; |         this.expirationTimeMillis = expirationTimeMillis; | ||||||
|         this.expirationTimeUnit = expirationTimeUnit; |         this.expirationTimeUnit = expirationTimeUnit; | ||||||
| @@ -234,7 +231,7 @@ public class MediaSourceManager { | |||||||
|     private boolean isPlayQueueReady() { |     private boolean isPlayQueueReady() { | ||||||
|         if (playQueue == null) return false; |         if (playQueue == null) return false; | ||||||
|  |  | ||||||
|         final boolean isWindowLoaded = playQueue.size() - playQueue.getIndex() > windowSize; |         final boolean isWindowLoaded = playQueue.size() - playQueue.getIndex() > WINDOW_SIZE; | ||||||
|         return playQueue.isComplete() || isWindowLoaded; |         return playQueue.isComplete() || isWindowLoaded; | ||||||
|     } |     } | ||||||
|  |  | ||||||
| @@ -244,10 +241,14 @@ public class MediaSourceManager { | |||||||
|         } |         } | ||||||
|  |  | ||||||
|         final MediaSource mediaSource = sources.getMediaSource(playQueue.getIndex()); |         final MediaSource mediaSource = sources.getMediaSource(playQueue.getIndex()); | ||||||
|         if (!(mediaSource instanceof LoadedMediaSource)) return false; |  | ||||||
|  |  | ||||||
|         final PlayQueueItem playQueueItem = playQueue.getItem(); |         final PlayQueueItem playQueueItem = playQueue.getItem(); | ||||||
|         return playQueueItem == ((LoadedMediaSource) mediaSource).getStream(); |  | ||||||
|  |         if (mediaSource instanceof LoadedMediaSource) { | ||||||
|  |             return playQueueItem == ((LoadedMediaSource) mediaSource).getStream(); | ||||||
|  |         } else if (mediaSource instanceof FailedMediaSource) { | ||||||
|  |             return playQueueItem == ((FailedMediaSource) mediaSource).getStream(); | ||||||
|  |         } | ||||||
|  |         return false; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     private void tryBlock() { |     private void tryBlock() { | ||||||
| @@ -318,11 +319,11 @@ public class MediaSourceManager { | |||||||
|         loadItem(currentItem); |         loadItem(currentItem); | ||||||
|  |  | ||||||
|         // The rest are just for seamless playback |         // The rest are just for seamless playback | ||||||
|         final int leftBound = Math.max(0, currentIndex - windowSize); |         final int leftBound = currentIndex + 1; | ||||||
|         final int rightLimit = currentIndex + windowSize + 1; |         final int rightLimit = leftBound + WINDOW_SIZE; | ||||||
|         final int rightBound = Math.min(playQueue.size(), rightLimit); |         final int rightBound = Math.min(playQueue.size(), rightLimit); | ||||||
|         final List<PlayQueueItem> items = new ArrayList<>(playQueue.getStreams().subList(leftBound, |         final List<PlayQueueItem> items = new ArrayList<>( | ||||||
|                 rightBound)); |                 playQueue.getStreams().subList(leftBound,rightBound)); | ||||||
|  |  | ||||||
|         // Do a round robin |         // Do a round robin | ||||||
|         final int excess = rightLimit - playQueue.size(); |         final int excess = rightLimit - playQueue.size(); | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user
	 John Zhen Mo
					John Zhen Mo