-Fixed potential NPE when obtaining broadcast receiver.
-Extracted expiration time in media source manager. -Re-enabled long click on live stream info items. -Fixed dash source building to use mpd instead of extractor.
This commit is contained in:
parent
ac431e3ece
commit
1444fe5468
|
@ -59,23 +59,20 @@ public class StreamMiniInfoItemHolder extends InfoItemHolder {
|
||||||
itemBuilder.getImageLoader()
|
itemBuilder.getImageLoader()
|
||||||
.displayImage(item.thumbnail_url, itemThumbnailView, StreamInfoItemHolder.DISPLAY_THUMBNAIL_OPTIONS);
|
.displayImage(item.thumbnail_url, itemThumbnailView, StreamInfoItemHolder.DISPLAY_THUMBNAIL_OPTIONS);
|
||||||
|
|
||||||
itemView.setOnClickListener(new View.OnClickListener() {
|
itemView.setOnClickListener(view -> {
|
||||||
@Override
|
if (itemBuilder.getOnStreamSelectedListener() != null) {
|
||||||
public void onClick(View view) {
|
itemBuilder.getOnStreamSelectedListener().selected(item);
|
||||||
if (itemBuilder.getOnStreamSelectedListener() != null) {
|
|
||||||
itemBuilder.getOnStreamSelectedListener().selected(item);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
switch (item.stream_type) {
|
switch (item.stream_type) {
|
||||||
case AUDIO_STREAM:
|
case AUDIO_STREAM:
|
||||||
case VIDEO_STREAM:
|
case VIDEO_STREAM:
|
||||||
case FILE:
|
|
||||||
enableLongClick(item);
|
|
||||||
break;
|
|
||||||
case LIVE_STREAM:
|
case LIVE_STREAM:
|
||||||
case AUDIO_LIVE_STREAM:
|
case AUDIO_LIVE_STREAM:
|
||||||
|
enableLongClick(item);
|
||||||
|
break;
|
||||||
|
case FILE:
|
||||||
case NONE:
|
case NONE:
|
||||||
default:
|
default:
|
||||||
disableLongClick();
|
disableLongClick();
|
||||||
|
@ -85,14 +82,11 @@ public class StreamMiniInfoItemHolder extends InfoItemHolder {
|
||||||
|
|
||||||
private void enableLongClick(final StreamInfoItem item) {
|
private void enableLongClick(final StreamInfoItem item) {
|
||||||
itemView.setLongClickable(true);
|
itemView.setLongClickable(true);
|
||||||
itemView.setOnLongClickListener(new View.OnLongClickListener() {
|
itemView.setOnLongClickListener(view -> {
|
||||||
@Override
|
if (itemBuilder.getOnStreamSelectedListener() != null) {
|
||||||
public boolean onLongClick(View view) {
|
itemBuilder.getOnStreamSelectedListener().held(item);
|
||||||
if (itemBuilder.getOnStreamSelectedListener() != null) {
|
|
||||||
itemBuilder.getOnStreamSelectedListener().held(item);
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
return true;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -319,35 +319,27 @@ public abstract class BasePlayer implements Player.EventListener, PlaybackListen
|
||||||
recordManager = null;
|
recordManager = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
public MediaSource buildMediaSource(String url) {
|
|
||||||
return buildMediaSource(url, "");
|
|
||||||
}
|
|
||||||
|
|
||||||
public MediaSource buildMediaSource(String url, String overrideExtension) {
|
public MediaSource buildMediaSource(String url, String overrideExtension) {
|
||||||
if (DEBUG) {
|
if (DEBUG) {
|
||||||
Log.d(TAG, "buildMediaSource() called with: url = [" + url + "], overrideExtension = [" + overrideExtension + "]");
|
Log.d(TAG, "buildMediaSource() called with: url = [" + url +
|
||||||
|
"], overrideExtension = [" + overrideExtension + "]");
|
||||||
}
|
}
|
||||||
Uri uri = Uri.parse(url);
|
Uri uri = Uri.parse(url);
|
||||||
int type = TextUtils.isEmpty(overrideExtension) ? Util.inferContentType(uri) : Util.inferContentType("." + overrideExtension);
|
int type = TextUtils.isEmpty(overrideExtension) ? Util.inferContentType(uri) :
|
||||||
MediaSource mediaSource;
|
Util.inferContentType("." + overrideExtension);
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case C.TYPE_SS:
|
case C.TYPE_SS:
|
||||||
mediaSource = ssMediaSourceFactory.createMediaSource(uri);
|
return ssMediaSourceFactory.createMediaSource(uri);
|
||||||
break;
|
|
||||||
case C.TYPE_DASH:
|
case C.TYPE_DASH:
|
||||||
mediaSource = dashMediaSourceFactory.createMediaSource(uri);
|
return dashMediaSourceFactory.createMediaSource(uri);
|
||||||
break;
|
|
||||||
case C.TYPE_HLS:
|
case C.TYPE_HLS:
|
||||||
mediaSource = hlsMediaSourceFactory.createMediaSource(uri);
|
return hlsMediaSourceFactory.createMediaSource(uri);
|
||||||
break;
|
|
||||||
case C.TYPE_OTHER:
|
case C.TYPE_OTHER:
|
||||||
mediaSource = extractorMediaSourceFactory.createMediaSource(uri);
|
return extractorMediaSourceFactory.createMediaSource(uri);
|
||||||
break;
|
|
||||||
default: {
|
default: {
|
||||||
throw new IllegalStateException("Unsupported type: " + type);
|
throw new IllegalStateException("Unsupported type: " + type);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return mediaSource;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*//////////////////////////////////////////////////////////////////////////
|
/*//////////////////////////////////////////////////////////////////////////
|
||||||
|
@ -514,8 +506,13 @@ public abstract class BasePlayer implements Player.EventListener, PlaybackListen
|
||||||
public void onTimelineChanged(Timeline timeline, Object manifest, int reason) {
|
public void onTimelineChanged(Timeline timeline, Object manifest, int reason) {
|
||||||
if (DEBUG) Log.d(TAG, "onTimelineChanged(), timeline size = " + timeline.getWindowCount());
|
if (DEBUG) Log.d(TAG, "onTimelineChanged(), timeline size = " + timeline.getWindowCount());
|
||||||
|
|
||||||
if (playbackManager != null) {
|
switch (reason) {
|
||||||
playbackManager.load();
|
case Player.TIMELINE_CHANGE_REASON_PREPARED:
|
||||||
|
case Player.TIMELINE_CHANGE_REASON_RESET:
|
||||||
|
case Player.TIMELINE_CHANGE_REASON_DYNAMIC:
|
||||||
|
default:
|
||||||
|
if (playbackManager != null) playbackManager.load();
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -526,7 +523,8 @@ public abstract class BasePlayer implements Player.EventListener, PlaybackListen
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onPlaybackParametersChanged(PlaybackParameters playbackParameters) {
|
public void onPlaybackParametersChanged(PlaybackParameters playbackParameters) {
|
||||||
if (DEBUG) Log.d(TAG, "playbackParameters(), speed: " + playbackParameters.speed + ", pitch: " + playbackParameters.pitch);
|
if (DEBUG) Log.d(TAG, "playbackParameters(), speed: " + playbackParameters.speed +
|
||||||
|
", pitch: " + playbackParameters.pitch);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -732,9 +730,9 @@ public abstract class BasePlayer implements Player.EventListener, PlaybackListen
|
||||||
@Override
|
@Override
|
||||||
public MediaSource sourceOf(PlayQueueItem item, StreamInfo info) {
|
public MediaSource sourceOf(PlayQueueItem item, StreamInfo info) {
|
||||||
if (!info.getHlsUrl().isEmpty()) {
|
if (!info.getHlsUrl().isEmpty()) {
|
||||||
return buildMediaSource(info.getHlsUrl());
|
return buildMediaSource(info.getHlsUrl(), "m3u8");
|
||||||
} else if (!info.getDashMpdUrl().isEmpty()) {
|
} else if (!info.getDashMpdUrl().isEmpty()) {
|
||||||
return buildMediaSource(info.getDashMpdUrl());
|
return buildMediaSource(info.getDashMpdUrl(), "mpd");
|
||||||
}
|
}
|
||||||
|
|
||||||
return null;
|
return null;
|
||||||
|
|
|
@ -25,6 +25,10 @@ public class FailedMediaSource implements ManagedMediaSource {
|
||||||
this.retryTimestamp = retryTimestamp;
|
this.retryTimestamp = retryTimestamp;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Permanently fail the play queue item associated with this source, with no hope of retrying.
|
||||||
|
* The error will always be propagated to ExoPlayer.
|
||||||
|
* */
|
||||||
public FailedMediaSource(@NonNull final PlayQueueItem playQueueItem,
|
public FailedMediaSource(@NonNull final PlayQueueItem playQueueItem,
|
||||||
@NonNull final Throwable error) {
|
@NonNull final Throwable error) {
|
||||||
this.playQueueItem = playQueueItem;
|
this.playQueueItem = playQueueItem;
|
||||||
|
|
|
@ -40,6 +40,8 @@ public class MediaSourceManager {
|
||||||
private final int windowSize;
|
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 TimeUnit expirationTimeUnit;
|
||||||
|
|
||||||
// Process only the last load order when receiving a stream of load orders (lessens I/O)
|
// Process only the last load order when receiving a stream of load orders (lessens I/O)
|
||||||
// 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
|
||||||
|
@ -61,13 +63,15 @@ 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);
|
this(listener, playQueue, 1, 400L, 2, 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 int windowSize,
|
||||||
final long loadDebounceMillis) {
|
final long loadDebounceMillis,
|
||||||
|
final long expirationTimeMillis,
|
||||||
|
@NonNull final TimeUnit expirationTimeUnit) {
|
||||||
if (windowSize <= 0) {
|
if (windowSize <= 0) {
|
||||||
throw new UnsupportedOperationException(
|
throw new UnsupportedOperationException(
|
||||||
"MediaSourceManager window size must be greater than 0");
|
"MediaSourceManager window size must be greater than 0");
|
||||||
|
@ -77,6 +81,8 @@ public class MediaSourceManager {
|
||||||
this.playQueue = playQueue;
|
this.playQueue = playQueue;
|
||||||
this.windowSize = windowSize;
|
this.windowSize = windowSize;
|
||||||
this.loadDebounceMillis = loadDebounceMillis;
|
this.loadDebounceMillis = loadDebounceMillis;
|
||||||
|
this.expirationTimeMillis = expirationTimeMillis;
|
||||||
|
this.expirationTimeUnit = expirationTimeUnit;
|
||||||
|
|
||||||
this.loaderReactor = new CompositeDisposable();
|
this.loaderReactor = new CompositeDisposable();
|
||||||
this.debouncedLoadSignal = PublishSubject.create();
|
this.debouncedLoadSignal = PublishSubject.create();
|
||||||
|
@ -87,9 +93,11 @@ public class MediaSourceManager {
|
||||||
this.syncReactor = new SerialDisposable();
|
this.syncReactor = new SerialDisposable();
|
||||||
this.loadingItems = Collections.synchronizedSet(new HashSet<>());
|
this.loadingItems = Collections.synchronizedSet(new HashSet<>());
|
||||||
|
|
||||||
playQueue.getBroadcastReceiver()
|
if (playQueue.getBroadcastReceiver() != null) {
|
||||||
.observeOn(AndroidSchedulers.mainThread())
|
playQueue.getBroadcastReceiver()
|
||||||
.subscribe(getReactor());
|
.observeOn(AndroidSchedulers.mainThread())
|
||||||
|
.subscribe(getReactor());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*//////////////////////////////////////////////////////////////////////////
|
/*//////////////////////////////////////////////////////////////////////////
|
||||||
|
@ -225,7 +233,7 @@ public class MediaSourceManager {
|
||||||
return playQueue.isComplete() || isWindowLoaded;
|
return playQueue.isComplete() || isWindowLoaded;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Checks if the current playback media source is a placeholder, if so, then it is not ready
|
// Checks if the current playback media source is a placeholder, if so, then it is not ready.
|
||||||
private boolean isPlaybackReady() {
|
private boolean isPlaybackReady() {
|
||||||
return sources != null && playQueue != null && sources.getSize() > playQueue.getIndex() &&
|
return sources != null && playQueue != null && sources.getSize() > playQueue.getIndex() &&
|
||||||
!(sources.getMediaSource(playQueue.getIndex()) instanceof PlaceholderMediaSource);
|
!(sources.getMediaSource(playQueue.getIndex()) instanceof PlaceholderMediaSource);
|
||||||
|
@ -351,11 +359,11 @@ public class MediaSourceManager {
|
||||||
final MediaSource source = playbackListener.sourceOf(stream, streamInfo);
|
final MediaSource source = playbackListener.sourceOf(stream, streamInfo);
|
||||||
if (source == null) {
|
if (source == null) {
|
||||||
return new FailedMediaSource(stream, new IllegalStateException(
|
return new FailedMediaSource(stream, new IllegalStateException(
|
||||||
"MediaSource resolution is null"));
|
"MediaSource cannot be resolved"));
|
||||||
}
|
}
|
||||||
|
|
||||||
final long expiration = System.currentTimeMillis() +
|
final long expiration = System.currentTimeMillis() +
|
||||||
TimeUnit.MILLISECONDS.convert(2, TimeUnit.HOURS);
|
TimeUnit.MILLISECONDS.convert(expirationTimeMillis, expirationTimeUnit);
|
||||||
return new LoadedMediaSource(source, expiration);
|
return new LoadedMediaSource(source, expiration);
|
||||||
}).onErrorReturn(throwable -> new FailedMediaSource(stream, throwable));
|
}).onErrorReturn(throwable -> new FailedMediaSource(stream, throwable));
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
package org.schabi.newpipe.playlist;
|
package org.schabi.newpipe.playlist;
|
||||||
|
|
||||||
import android.support.annotation.NonNull;
|
import android.support.annotation.NonNull;
|
||||||
|
import android.support.annotation.Nullable;
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
|
|
||||||
import org.reactivestreams.Subscriber;
|
import org.reactivestreams.Subscriber;
|
||||||
|
@ -170,7 +171,7 @@ public abstract class PlayQueue implements Serializable {
|
||||||
* Returns the play queue's update broadcast.
|
* Returns the play queue's update broadcast.
|
||||||
* May be null if the play queue message bus is not initialized.
|
* May be null if the play queue message bus is not initialized.
|
||||||
* */
|
* */
|
||||||
@NonNull
|
@Nullable
|
||||||
public Flowable<PlayQueueEvent> getBroadcastReceiver() {
|
public Flowable<PlayQueueEvent> getBroadcastReceiver() {
|
||||||
return broadcastReceiver;
|
return broadcastReceiver;
|
||||||
}
|
}
|
||||||
|
|
|
@ -99,7 +99,9 @@ public class PlayQueueAdapter extends RecyclerView.Adapter<RecyclerView.ViewHold
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
playQueue.getBroadcastReceiver().toObservable().subscribe(observer);
|
if (playQueue.getBroadcastReceiver() != null) {
|
||||||
|
playQueue.getBroadcastReceiver().toObservable().subscribe(observer);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void onPlayQueueChanged(final PlayQueueEvent message) {
|
private void onPlayQueueChanged(final PlayQueueEvent message) {
|
||||||
|
|
Loading…
Reference in New Issue