-Improved null checks in player stream resolution.

-Improved naming in MediaSourceManager
This commit is contained in:
John Zhen Mo 2017-10-29 12:39:53 -07:00
parent 52cdf96dfe
commit 0b1eda3050
4 changed files with 23 additions and 16 deletions

View file

@ -380,9 +380,10 @@ public final class BackgroundPlayer extends Service {
} }
@Override @Override
@Nullable
public MediaSource sourceOf(final PlayQueueItem item, final StreamInfo info) { public MediaSource sourceOf(final PlayQueueItem item, final StreamInfo info) {
final int index = ListHelper.getDefaultAudioFormat(context, info.audio_streams); final int index = ListHelper.getDefaultAudioFormat(context, info.audio_streams);
if (index < 0) return null; if (index < 0 || index >= info.audio_streams.size()) return null;
final AudioStream audio = info.audio_streams.get(index); final AudioStream audio = info.audio_streams.get(index);
return buildMediaSource(audio.url, MediaFormat.getSuffixById(audio.format)); return buildMediaSource(audio.url, MediaFormat.getSuffixById(audio.format));

View file

@ -272,17 +272,18 @@ public abstract class VideoPlayer extends BasePlayer implements SimpleExoPlayer.
} }
@Override @Override
@Nullable
public MediaSource sourceOf(final PlayQueueItem item, final StreamInfo info) { public MediaSource sourceOf(final PlayQueueItem item, final StreamInfo info) {
final List<VideoStream> videos = ListHelper.getSortedStreamVideosList(context, info.video_streams, info.video_only_streams, false); final List<VideoStream> videos = ListHelper.getSortedStreamVideosList(context, info.video_streams, info.video_only_streams, false);
final VideoStream video; final int index;
if (playbackQuality == null) { if (playbackQuality == null) {
final int index = getDefaultResolutionIndex(videos); index = getDefaultResolutionIndex(videos);
video = videos.get(index);
} else { } else {
final int index = getOverrideResolutionIndex(videos, getPlaybackQuality()); index = getOverrideResolutionIndex(videos, getPlaybackQuality());
video = videos.get(index);
} }
if (index < 0 || index >= videos.size()) return null;
final VideoStream video = videos.get(index);
final MediaSource streamSource = buildMediaSource(video.url, MediaFormat.getSuffixById(video.format)); final MediaSource streamSource = buildMediaSource(video.url, MediaFormat.getSuffixById(video.format));
final AudioStream audio = ListHelper.getHighestQualityAudio(info.audio_streams); final AudioStream audio = ListHelper.getHighestQualityAudio(info.audio_streams);

View file

@ -29,7 +29,7 @@ import io.reactivex.subjects.PublishSubject;
public class MediaSourceManager { public class MediaSourceManager {
private final String TAG = "MediaSourceManager@" + Integer.toHexString(hashCode()); private final String TAG = "MediaSourceManager@" + Integer.toHexString(hashCode());
// One-side rolling window size for default loading // One-side rolling window size for default loading
// Effectively loads windowSize * 2 + 1 streams, must be greater than 0 // Effectively loads windowSize * 2 + 1 streams per call to load, must be greater than 0
private final int windowSize; private final int windowSize;
private final PlaybackListener playbackListener; private final PlaybackListener playbackListener;
private final PlayQueue playQueue; private final PlayQueue playQueue;
@ -38,7 +38,7 @@ public class MediaSourceManager {
// The higher it is, the less loading occurs during rapid noncritical timeline changes // The higher it is, the less loading occurs during rapid noncritical timeline changes
// Not recommended to go below 100ms // Not recommended to go below 100ms
private final long loadDebounceMillis; private final long loadDebounceMillis;
private final PublishSubject<Long> loadSignal; private final PublishSubject<Long> debouncedLoadSignal;
private final Disposable debouncedLoader; private final Disposable debouncedLoader;
private final DeferredMediaSource.Callback sourceBuilder; private final DeferredMediaSource.Callback sourceBuilder;
@ -69,7 +69,7 @@ public class MediaSourceManager {
this.loadDebounceMillis = loadDebounceMillis; this.loadDebounceMillis = loadDebounceMillis;
this.syncReactor = new SerialDisposable(); this.syncReactor = new SerialDisposable();
this.loadSignal = PublishSubject.create(); this.debouncedLoadSignal = PublishSubject.create();
this.debouncedLoader = getDebouncedLoader(); this.debouncedLoader = getDebouncedLoader();
this.sourceBuilder = getSourceBuilder(); this.sourceBuilder = getSourceBuilder();
@ -101,7 +101,7 @@ public class MediaSourceManager {
* Dispose the manager and releases all message buses and loaders. * Dispose the manager and releases all message buses and loaders.
* */ * */
public void dispose() { public void dispose() {
if (loadSignal != null) loadSignal.onComplete(); if (debouncedLoadSignal != null) debouncedLoadSignal.onComplete();
if (debouncedLoader != null) debouncedLoader.dispose(); if (debouncedLoader != null) debouncedLoader.dispose();
if (playQueueReactor != null) playQueueReactor.cancel(); if (playQueueReactor != null) playQueueReactor.cancel();
if (syncReactor != null) syncReactor.dispose(); if (syncReactor != null) syncReactor.dispose();
@ -118,7 +118,7 @@ public class MediaSourceManager {
* Unblocks the player once the item at the current index is loaded. * Unblocks the player once the item at the current index is loaded.
* */ * */
public void load() { public void load() {
loadSignal.onNext(System.currentTimeMillis()); loadDebounced();
} }
/** /**
@ -195,14 +195,14 @@ public class MediaSourceManager {
case REORDER: case REORDER:
case ERROR: case ERROR:
case APPEND: case APPEND:
loadInternal(); // low frequency, critical events loadImmediate(); // low frequency, critical events
break; break;
case REMOVE: case REMOVE:
case SELECT: case SELECT:
case MOVE: case MOVE:
case RECOVERY: case RECOVERY:
default: default:
load(); // high frequency or noncritical events loadDebounced(); // high frequency or noncritical events
break; break;
} }
@ -262,7 +262,11 @@ public class MediaSourceManager {
syncReactor.set(currentItem.getStream().subscribe(syncPlayback, onError)); syncReactor.set(currentItem.getStream().subscribe(syncPlayback, onError));
} }
private void loadInternal() { private void loadDebounced() {
debouncedLoadSignal.onNext(System.currentTimeMillis());
}
private void loadImmediate() {
// The current item has higher priority // The current item has higher priority
final int currentIndex = playQueue.getIndex(); final int currentIndex = playQueue.getIndex();
final PlayQueueItem currentItem = playQueue.getItem(currentIndex); final PlayQueueItem currentItem = playQueue.getItem(currentIndex);
@ -307,13 +311,13 @@ public class MediaSourceManager {
} }
private Disposable getDebouncedLoader() { private Disposable getDebouncedLoader() {
return loadSignal return debouncedLoadSignal
.debounce(loadDebounceMillis, TimeUnit.MILLISECONDS) .debounce(loadDebounceMillis, TimeUnit.MILLISECONDS)
.observeOn(AndroidSchedulers.mainThread()) .observeOn(AndroidSchedulers.mainThread())
.subscribe(new Consumer<Long>() { .subscribe(new Consumer<Long>() {
@Override @Override
public void accept(Long timestamp) throws Exception { public void accept(Long timestamp) throws Exception {
loadInternal(); loadImmediate();
} }
}); });
} }

View file

@ -43,6 +43,7 @@ public interface PlaybackListener {
* *
* May be called at any time. * May be called at any time.
* */ * */
@Nullable
MediaSource sourceOf(final PlayQueueItem item, final StreamInfo info); MediaSource sourceOf(final PlayQueueItem item, final StreamInfo info);
/** /**