mirror of
https://github.com/MaintainTeam/LastPipeBender.git
synced 2025-03-01 13:58:20 +03:00
-Refactored playback resolvers and other persistent player objects to instantiate once only during player creation to enforce non-nullity.
-Fixed background and popup player service staying in foreground when playback is paused or completed. -Fixed player metadata not updating on new stream. -Fixed player intent playback quality not applied. -Fixed player auto-queue not applied after stream transition or swapping.
This commit is contained in:
parent
0a2dbc4688
commit
f1f5996975
8 changed files with 219 additions and 102 deletions
|
@ -37,6 +37,7 @@ import android.widget.RemoteViews;
|
||||||
import com.google.android.exoplayer2.PlaybackParameters;
|
import com.google.android.exoplayer2.PlaybackParameters;
|
||||||
import com.google.android.exoplayer2.Player;
|
import com.google.android.exoplayer2.Player;
|
||||||
import com.google.android.exoplayer2.source.MediaSource;
|
import com.google.android.exoplayer2.source.MediaSource;
|
||||||
|
import com.nostra13.universalimageloader.core.assist.FailReason;
|
||||||
|
|
||||||
import org.schabi.newpipe.BuildConfig;
|
import org.schabi.newpipe.BuildConfig;
|
||||||
import org.schabi.newpipe.R;
|
import org.schabi.newpipe.R;
|
||||||
|
@ -264,16 +265,16 @@ public final class BackgroundPlayer extends Service {
|
||||||
|
|
||||||
protected class BasePlayerImpl extends BasePlayer {
|
protected class BasePlayerImpl extends BasePlayer {
|
||||||
|
|
||||||
@Nullable private AudioPlaybackResolver resolver;
|
@NonNull final private AudioPlaybackResolver resolver;
|
||||||
|
|
||||||
BasePlayerImpl(Context context) {
|
BasePlayerImpl(Context context) {
|
||||||
super(context);
|
super(context);
|
||||||
|
this.resolver = new AudioPlaybackResolver(context, dataSource);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void initPlayer(boolean playOnReady) {
|
public void initPlayer(boolean playOnReady) {
|
||||||
super.initPlayer(playOnReady);
|
super.initPlayer(playOnReady);
|
||||||
resolver = new AudioPlaybackResolver(context, dataSource);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -286,30 +287,65 @@ public final class BackgroundPlayer extends Service {
|
||||||
startForeground(NOTIFICATION_ID, notBuilder.build());
|
startForeground(NOTIFICATION_ID, notBuilder.build());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
/*//////////////////////////////////////////////////////////////////////////
|
||||||
public void initThumbnail(final String url) {
|
// Thumbnail Loading
|
||||||
|
//////////////////////////////////////////////////////////////////////////*/
|
||||||
|
|
||||||
|
private void setDummyRemoteViewThumbnail() {
|
||||||
resetNotification();
|
resetNotification();
|
||||||
if (notRemoteView != null) notRemoteView.setImageViewResource(R.id.notificationCover, R.drawable.dummy_thumbnail);
|
if (notRemoteView != null) {
|
||||||
if (bigNotRemoteView != null) bigNotRemoteView.setImageViewResource(R.id.notificationCover, R.drawable.dummy_thumbnail);
|
notRemoteView.setImageViewResource(R.id.notificationCover,
|
||||||
|
R.drawable.dummy_thumbnail);
|
||||||
|
}
|
||||||
|
if (bigNotRemoteView != null) {
|
||||||
|
bigNotRemoteView.setImageViewResource(R.id.notificationCover,
|
||||||
|
R.drawable.dummy_thumbnail);
|
||||||
|
}
|
||||||
updateNotification(-1);
|
updateNotification(-1);
|
||||||
super.initThumbnail(url);
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onLoadingStarted(String imageUri, View view) {
|
||||||
|
super.onLoadingStarted(imageUri, view);
|
||||||
|
setDummyRemoteViewThumbnail();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onLoadingComplete(String imageUri, View view, Bitmap loadedImage) {
|
public void onLoadingComplete(String imageUri, View view, Bitmap loadedImage) {
|
||||||
super.onLoadingComplete(imageUri, view, loadedImage);
|
super.onLoadingComplete(imageUri, view, loadedImage);
|
||||||
|
if (loadedImage == null) {
|
||||||
if (loadedImage != null) {
|
setDummyRemoteViewThumbnail();
|
||||||
// rebuild notification here since remote view does not release bitmaps, causing memory leaks
|
return;
|
||||||
resetNotification();
|
|
||||||
|
|
||||||
if (notRemoteView != null) notRemoteView.setImageViewBitmap(R.id.notificationCover, loadedImage);
|
|
||||||
if (bigNotRemoteView != null) bigNotRemoteView.setImageViewBitmap(R.id.notificationCover, loadedImage);
|
|
||||||
|
|
||||||
updateNotification(-1);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// rebuild notification here since remote view does not release bitmaps,
|
||||||
|
// causing memory leaks
|
||||||
|
resetNotification();
|
||||||
|
if (notRemoteView != null) {
|
||||||
|
notRemoteView.setImageViewBitmap(R.id.notificationCover, loadedImage);
|
||||||
|
}
|
||||||
|
if (bigNotRemoteView != null) {
|
||||||
|
bigNotRemoteView.setImageViewBitmap(R.id.notificationCover, loadedImage);
|
||||||
|
}
|
||||||
|
updateNotification(-1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onLoadingFailed(String imageUri, View view, FailReason failReason) {
|
||||||
|
super.onLoadingFailed(imageUri, view, failReason);
|
||||||
|
setDummyRemoteViewThumbnail();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onLoadingCancelled(String imageUri, View view) {
|
||||||
|
super.onLoadingCancelled(imageUri, view);
|
||||||
|
setDummyRemoteViewThumbnail();
|
||||||
|
}
|
||||||
|
|
||||||
|
/*//////////////////////////////////////////////////////////////////////////
|
||||||
|
// States Implementation
|
||||||
|
//////////////////////////////////////////////////////////////////////////*/
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onPrepared(boolean playWhenReady) {
|
public void onPrepared(boolean playWhenReady) {
|
||||||
super.onPrepared(playWhenReady);
|
super.onPrepared(playWhenReady);
|
||||||
|
@ -385,17 +421,15 @@ public final class BackgroundPlayer extends Service {
|
||||||
|
|
||||||
protected void onMetadataChanged(@NonNull final MediaSourceTag tag) {
|
protected void onMetadataChanged(@NonNull final MediaSourceTag tag) {
|
||||||
super.onMetadataChanged(tag);
|
super.onMetadataChanged(tag);
|
||||||
if (shouldUpdateOnProgress) {
|
resetNotification();
|
||||||
resetNotification();
|
updateNotification(-1);
|
||||||
updateNotification(-1);
|
updateMetadata();
|
||||||
updateMetadata();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@Nullable
|
@Nullable
|
||||||
public MediaSource sourceOf(final PlayQueueItem item, final StreamInfo info) {
|
public MediaSource sourceOf(final PlayQueueItem item, final StreamInfo info) {
|
||||||
return resolver == null ? null : resolver.resolve(info);
|
return resolver.resolve(info);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -515,18 +549,40 @@ public final class BackgroundPlayer extends Service {
|
||||||
updateNotification(-1);
|
updateNotification(-1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onBlocked() {
|
||||||
|
super.onBlocked();
|
||||||
|
startForeground(NOTIFICATION_ID, notBuilder.build());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onBuffering() {
|
||||||
|
super.onBuffering();
|
||||||
|
startForeground(NOTIFICATION_ID, notBuilder.build());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onPausedSeek() {
|
||||||
|
super.onPausedSeek();
|
||||||
|
startForeground(NOTIFICATION_ID, notBuilder.build());
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onPlaying() {
|
public void onPlaying() {
|
||||||
super.onPlaying();
|
super.onPlaying();
|
||||||
updateNotification(R.drawable.ic_pause_white);
|
updateNotification(R.drawable.ic_pause_white);
|
||||||
|
|
||||||
lockManager.acquireWifiAndCpu();
|
lockManager.acquireWifiAndCpu();
|
||||||
|
startForeground(NOTIFICATION_ID, notBuilder.build());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onPaused() {
|
public void onPaused() {
|
||||||
super.onPaused();
|
super.onPaused();
|
||||||
updateNotification(R.drawable.ic_play_arrow_white);
|
updateNotification(R.drawable.ic_play_arrow_white);
|
||||||
|
|
||||||
lockManager.releaseWifiAndCpu();
|
lockManager.releaseWifiAndCpu();
|
||||||
|
stopForeground(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -539,6 +595,7 @@ public final class BackgroundPlayer extends Service {
|
||||||
updateNotification(R.drawable.ic_replay_white);
|
updateNotification(R.drawable.ic_replay_white);
|
||||||
|
|
||||||
lockManager.releaseWifiAndCpu();
|
lockManager.releaseWifiAndCpu();
|
||||||
|
stopForeground(false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -68,6 +68,7 @@ import org.schabi.newpipe.player.playqueue.PlayQueue;
|
||||||
import org.schabi.newpipe.player.playqueue.PlayQueueAdapter;
|
import org.schabi.newpipe.player.playqueue.PlayQueueAdapter;
|
||||||
import org.schabi.newpipe.player.playqueue.PlayQueueItem;
|
import org.schabi.newpipe.player.playqueue.PlayQueueItem;
|
||||||
import org.schabi.newpipe.player.resolver.MediaSourceTag;
|
import org.schabi.newpipe.player.resolver.MediaSourceTag;
|
||||||
|
import org.schabi.newpipe.util.ImageDisplayConstants;
|
||||||
import org.schabi.newpipe.util.SerializedCache;
|
import org.schabi.newpipe.util.SerializedCache;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
@ -78,6 +79,7 @@ import io.reactivex.Observable;
|
||||||
import io.reactivex.android.schedulers.AndroidSchedulers;
|
import io.reactivex.android.schedulers.AndroidSchedulers;
|
||||||
import io.reactivex.disposables.CompositeDisposable;
|
import io.reactivex.disposables.CompositeDisposable;
|
||||||
import io.reactivex.disposables.Disposable;
|
import io.reactivex.disposables.Disposable;
|
||||||
|
import io.reactivex.disposables.SerialDisposable;
|
||||||
|
|
||||||
import static com.google.android.exoplayer2.Player.DISCONTINUITY_REASON_INTERNAL;
|
import static com.google.android.exoplayer2.Player.DISCONTINUITY_REASON_INTERNAL;
|
||||||
import static com.google.android.exoplayer2.Player.DISCONTINUITY_REASON_PERIOD_TRANSITION;
|
import static com.google.android.exoplayer2.Player.DISCONTINUITY_REASON_PERIOD_TRANSITION;
|
||||||
|
@ -104,6 +106,14 @@ public abstract class BasePlayer implements
|
||||||
|
|
||||||
@NonNull final protected HistoryRecordManager recordManager;
|
@NonNull final protected HistoryRecordManager recordManager;
|
||||||
|
|
||||||
|
@NonNull final protected CustomTrackSelector trackSelector;
|
||||||
|
@NonNull final protected PlayerDataSource dataSource;
|
||||||
|
|
||||||
|
@NonNull final private LoadControl loadControl;
|
||||||
|
@NonNull final private RenderersFactory renderFactory;
|
||||||
|
|
||||||
|
@NonNull final private SerialDisposable progressUpdateReactor;
|
||||||
|
@NonNull final private CompositeDisposable databaseUpdateReactor;
|
||||||
/*//////////////////////////////////////////////////////////////////////////
|
/*//////////////////////////////////////////////////////////////////////////
|
||||||
// Intent
|
// Intent
|
||||||
//////////////////////////////////////////////////////////////////////////*/
|
//////////////////////////////////////////////////////////////////////////*/
|
||||||
|
@ -142,9 +152,6 @@ public abstract class BasePlayer implements
|
||||||
protected final static int PROGRESS_LOOP_INTERVAL_MILLIS = 500;
|
protected final static int PROGRESS_LOOP_INTERVAL_MILLIS = 500;
|
||||||
protected final static int RECOVERY_SKIP_THRESHOLD_MILLIS = 3000; // 3 seconds
|
protected final static int RECOVERY_SKIP_THRESHOLD_MILLIS = 3000; // 3 seconds
|
||||||
|
|
||||||
protected CustomTrackSelector trackSelector;
|
|
||||||
protected PlayerDataSource dataSource;
|
|
||||||
|
|
||||||
protected SimpleExoPlayer simpleExoPlayer;
|
protected SimpleExoPlayer simpleExoPlayer;
|
||||||
protected AudioReactor audioReactor;
|
protected AudioReactor audioReactor;
|
||||||
protected MediaSessionManager mediaSessionManager;
|
protected MediaSessionManager mediaSessionManager;
|
||||||
|
@ -152,9 +159,6 @@ public abstract class BasePlayer implements
|
||||||
private boolean isPrepared = false;
|
private boolean isPrepared = false;
|
||||||
private boolean isSynchronizing = false;
|
private boolean isSynchronizing = false;
|
||||||
|
|
||||||
protected Disposable progressUpdateReactor;
|
|
||||||
protected CompositeDisposable databaseUpdateReactor;
|
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////////*/
|
//////////////////////////////////////////////////////////////////////////*/
|
||||||
|
|
||||||
public BasePlayer(@NonNull final Context context) {
|
public BasePlayer(@NonNull final Context context) {
|
||||||
|
@ -171,29 +175,32 @@ public abstract class BasePlayer implements
|
||||||
context.registerReceiver(broadcastReceiver, intentFilter);
|
context.registerReceiver(broadcastReceiver, intentFilter);
|
||||||
|
|
||||||
this.recordManager = new HistoryRecordManager(context);
|
this.recordManager = new HistoryRecordManager(context);
|
||||||
|
|
||||||
|
this.progressUpdateReactor = new SerialDisposable();
|
||||||
|
this.databaseUpdateReactor = new CompositeDisposable();
|
||||||
|
|
||||||
|
final String userAgent = Downloader.USER_AGENT;
|
||||||
|
final DefaultBandwidthMeter bandwidthMeter = new DefaultBandwidthMeter();
|
||||||
|
this.dataSource = new PlayerDataSource(context, userAgent, bandwidthMeter);
|
||||||
|
|
||||||
|
final TrackSelection.Factory trackSelectionFactory =
|
||||||
|
PlayerHelper.getQualitySelector(context, bandwidthMeter);
|
||||||
|
this.trackSelector = new CustomTrackSelector(trackSelectionFactory);
|
||||||
|
|
||||||
|
this.loadControl = new LoadController(context);
|
||||||
|
this.renderFactory = new DefaultRenderersFactory(context);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setup() {
|
public void setup() {
|
||||||
if (simpleExoPlayer == null) initPlayer(/*playOnInit=*/true);
|
if (simpleExoPlayer == null) {
|
||||||
|
initPlayer(/*playOnInit=*/true);
|
||||||
|
}
|
||||||
initListeners();
|
initListeners();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void initPlayer(final boolean playOnReady) {
|
public void initPlayer(final boolean playOnReady) {
|
||||||
if (DEBUG) Log.d(TAG, "initPlayer() called with: context = [" + context + "]");
|
if (DEBUG) Log.d(TAG, "initPlayer() called with: context = [" + context + "]");
|
||||||
|
|
||||||
if (databaseUpdateReactor != null) databaseUpdateReactor.dispose();
|
|
||||||
databaseUpdateReactor = new CompositeDisposable();
|
|
||||||
|
|
||||||
final String userAgent = Downloader.USER_AGENT;
|
|
||||||
final DefaultBandwidthMeter bandwidthMeter = new DefaultBandwidthMeter();
|
|
||||||
dataSource = new PlayerDataSource(context, userAgent, bandwidthMeter);
|
|
||||||
|
|
||||||
final TrackSelection.Factory trackSelectionFactory =
|
|
||||||
PlayerHelper.getQualitySelector(context, bandwidthMeter);
|
|
||||||
trackSelector = new CustomTrackSelector(trackSelectionFactory);
|
|
||||||
|
|
||||||
final LoadControl loadControl = new LoadController(context);
|
|
||||||
final RenderersFactory renderFactory = new DefaultRenderersFactory(context);
|
|
||||||
simpleExoPlayer = ExoPlayerFactory.newSimpleInstance(renderFactory, trackSelector, loadControl);
|
simpleExoPlayer = ExoPlayerFactory.newSimpleInstance(renderFactory, trackSelector, loadControl);
|
||||||
simpleExoPlayer.addListener(this);
|
simpleExoPlayer.addListener(this);
|
||||||
simpleExoPlayer.setPlayWhenReady(playOnReady);
|
simpleExoPlayer.setPlayWhenReady(playOnReady);
|
||||||
|
@ -287,7 +294,6 @@ public abstract class BasePlayer implements
|
||||||
|
|
||||||
if (mediaSessionManager != null) mediaSessionManager.dispose();
|
if (mediaSessionManager != null) mediaSessionManager.dispose();
|
||||||
|
|
||||||
trackSelector = null;
|
|
||||||
mediaSessionManager = null;
|
mediaSessionManager = null;
|
||||||
simpleExoPlayer = null;
|
simpleExoPlayer = null;
|
||||||
}
|
}
|
||||||
|
@ -296,11 +302,12 @@ public abstract class BasePlayer implements
|
||||||
// Thumbnail Loading
|
// Thumbnail Loading
|
||||||
//////////////////////////////////////////////////////////////////////////*/
|
//////////////////////////////////////////////////////////////////////////*/
|
||||||
|
|
||||||
public void initThumbnail(final String url) {
|
private void initThumbnail(final String url) {
|
||||||
if (DEBUG) Log.d(TAG, "Thumbnail - initThumbnail() called");
|
if (DEBUG) Log.d(TAG, "Thumbnail - initThumbnail() called");
|
||||||
if (url == null || url.isEmpty()) return;
|
if (url == null || url.isEmpty()) return;
|
||||||
ImageLoader.getInstance().resume();
|
ImageLoader.getInstance().resume();
|
||||||
ImageLoader.getInstance().loadImage(url, this);
|
ImageLoader.getInstance().loadImage(url, ImageDisplayConstants.DISPLAY_THUMBNAIL_OPTIONS,
|
||||||
|
this);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -461,13 +468,11 @@ public abstract class BasePlayer implements
|
||||||
public abstract void onUpdateProgress(int currentProgress, int duration, int bufferPercent);
|
public abstract void onUpdateProgress(int currentProgress, int duration, int bufferPercent);
|
||||||
|
|
||||||
protected void startProgressLoop() {
|
protected void startProgressLoop() {
|
||||||
if (progressUpdateReactor != null) progressUpdateReactor.dispose();
|
progressUpdateReactor.set(getProgressReactor());
|
||||||
progressUpdateReactor = getProgressReactor();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void stopProgressLoop() {
|
protected void stopProgressLoop() {
|
||||||
if (progressUpdateReactor != null) progressUpdateReactor.dispose();
|
progressUpdateReactor.set(null);
|
||||||
progressUpdateReactor = null;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void triggerProgressUpdate() {
|
public void triggerProgressUpdate() {
|
||||||
|
@ -482,7 +487,8 @@ public abstract class BasePlayer implements
|
||||||
private Disposable getProgressReactor() {
|
private Disposable getProgressReactor() {
|
||||||
return Observable.interval(PROGRESS_LOOP_INTERVAL_MILLIS, TimeUnit.MILLISECONDS)
|
return Observable.interval(PROGRESS_LOOP_INTERVAL_MILLIS, TimeUnit.MILLISECONDS)
|
||||||
.observeOn(AndroidSchedulers.mainThread())
|
.observeOn(AndroidSchedulers.mainThread())
|
||||||
.subscribe(ignored -> triggerProgressUpdate());
|
.subscribe(ignored -> triggerProgressUpdate(),
|
||||||
|
error -> Log.e(TAG, "Progress update failure: ", error));
|
||||||
}
|
}
|
||||||
|
|
||||||
/*//////////////////////////////////////////////////////////////////////////
|
/*//////////////////////////////////////////////////////////////////////////
|
||||||
|
@ -496,12 +502,16 @@ public abstract class BasePlayer implements
|
||||||
(manifest == null ? "no manifest" : "available manifest") + ", " +
|
(manifest == null ? "no manifest" : "available manifest") + ", " +
|
||||||
"timeline size = [" + timeline.getWindowCount() + "], " +
|
"timeline size = [" + timeline.getWindowCount() + "], " +
|
||||||
"reason = [" + reason + "]");
|
"reason = [" + reason + "]");
|
||||||
|
|
||||||
|
maybeUpdateCurrentMetadata();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onTracksChanged(TrackGroupArray trackGroups, TrackSelectionArray trackSelections) {
|
public void onTracksChanged(TrackGroupArray trackGroups, TrackSelectionArray trackSelections) {
|
||||||
if (DEBUG) Log.d(TAG, "ExoPlayer - onTracksChanged(), " +
|
if (DEBUG) Log.d(TAG, "ExoPlayer - onTracksChanged(), " +
|
||||||
"track group size = " + trackGroups.length);
|
"track group size = " + trackGroups.length);
|
||||||
|
|
||||||
|
maybeUpdateCurrentMetadata();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -521,6 +531,8 @@ public abstract class BasePlayer implements
|
||||||
} else if (isLoading && !isProgressLoopRunning()) {
|
} else if (isLoading && !isProgressLoopRunning()) {
|
||||||
startProgressLoop();
|
startProgressLoop();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
maybeUpdateCurrentMetadata();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -665,24 +677,22 @@ public abstract class BasePlayer implements
|
||||||
if (DEBUG) Log.d(TAG, "ExoPlayer - onPositionDiscontinuity() called with " +
|
if (DEBUG) Log.d(TAG, "ExoPlayer - onPositionDiscontinuity() called with " +
|
||||||
"reason = [" + reason + "]");
|
"reason = [" + reason + "]");
|
||||||
|
|
||||||
maybeUpdateCurrentMetadata();
|
|
||||||
|
|
||||||
// Refresh the playback if there is a transition to the next video
|
// Refresh the playback if there is a transition to the next video
|
||||||
final int newPeriodIndex = simpleExoPlayer.getCurrentPeriodIndex();
|
final int newPeriodIndex = simpleExoPlayer.getCurrentPeriodIndex();
|
||||||
|
|
||||||
/* Discontinuity reasons!! Thank you ExoPlayer lords */
|
|
||||||
switch (reason) {
|
switch (reason) {
|
||||||
case DISCONTINUITY_REASON_PERIOD_TRANSITION:
|
case DISCONTINUITY_REASON_PERIOD_TRANSITION:
|
||||||
if (newPeriodIndex == playQueue.getIndex()) {
|
if (newPeriodIndex == playQueue.getIndex()) {
|
||||||
registerView();
|
registerView();
|
||||||
} else {
|
} else {
|
||||||
playQueue.offsetIndex(+1);
|
playQueue.setIndex(newPeriodIndex);
|
||||||
}
|
}
|
||||||
case DISCONTINUITY_REASON_SEEK:
|
case DISCONTINUITY_REASON_SEEK:
|
||||||
case DISCONTINUITY_REASON_SEEK_ADJUSTMENT:
|
case DISCONTINUITY_REASON_SEEK_ADJUSTMENT:
|
||||||
case DISCONTINUITY_REASON_INTERNAL:
|
case DISCONTINUITY_REASON_INTERNAL:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
maybeUpdateCurrentMetadata();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -794,14 +804,6 @@ public abstract class BasePlayer implements
|
||||||
|
|
||||||
initThumbnail(info.getThumbnailUrl());
|
initThumbnail(info.getThumbnailUrl());
|
||||||
registerView();
|
registerView();
|
||||||
|
|
||||||
// when starting playback on the last item when not repeating, maybe auto queue
|
|
||||||
if (playQueue.getIndex() == playQueue.size() - 1 &&
|
|
||||||
getRepeatMode() == Player.REPEAT_MODE_OFF &&
|
|
||||||
PlayerHelper.isAutoQueueEnabled(context)) {
|
|
||||||
final PlayQueue autoQueue = PlayerHelper.autoQueueOf(info, playQueue.getStreams());
|
|
||||||
if (autoQueue != null) playQueue.append(autoQueue.getStreams());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -960,7 +962,7 @@ public abstract class BasePlayer implements
|
||||||
//////////////////////////////////////////////////////////////////////////*/
|
//////////////////////////////////////////////////////////////////////////*/
|
||||||
|
|
||||||
private void registerView() {
|
private void registerView() {
|
||||||
if (databaseUpdateReactor == null || currentMetadata == null) return;
|
if (currentMetadata == null) return;
|
||||||
final StreamInfo currentInfo = currentMetadata.getMetadata();
|
final StreamInfo currentInfo = currentMetadata.getMetadata();
|
||||||
databaseUpdateReactor.add(recordManager.onViewed(currentInfo).onErrorComplete()
|
databaseUpdateReactor.add(recordManager.onViewed(currentInfo).onErrorComplete()
|
||||||
.subscribe(
|
.subscribe(
|
||||||
|
@ -980,7 +982,7 @@ public abstract class BasePlayer implements
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void savePlaybackState(final StreamInfo info, final long progress) {
|
protected void savePlaybackState(final StreamInfo info, final long progress) {
|
||||||
if (info == null || databaseUpdateReactor == null) return;
|
if (info == null) return;
|
||||||
final Disposable stateSaver = recordManager.saveStreamState(info, progress)
|
final Disposable stateSaver = recordManager.saveStreamState(info, progress)
|
||||||
.observeOn(AndroidSchedulers.mainThread())
|
.observeOn(AndroidSchedulers.mainThread())
|
||||||
.onErrorComplete()
|
.onErrorComplete()
|
||||||
|
@ -1012,12 +1014,23 @@ public abstract class BasePlayer implements
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (metadata == null || currentMetadata == metadata) return;
|
if (metadata == null) return;
|
||||||
|
maybeAutoQueueNextStream(metadata);
|
||||||
|
|
||||||
|
if (currentMetadata == metadata) return;
|
||||||
currentMetadata = metadata;
|
currentMetadata = metadata;
|
||||||
onMetadataChanged(metadata);
|
onMetadataChanged(metadata);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void maybeAutoQueueNextStream(@NonNull final MediaSourceTag currentMetadata) {
|
||||||
|
if (playQueue == null || playQueue.getIndex() != playQueue.size() - 1 ||
|
||||||
|
getRepeatMode() != Player.REPEAT_MODE_OFF ||
|
||||||
|
!PlayerHelper.isAutoQueueEnabled(context)) return;
|
||||||
|
// auto queue when starting playback on the last item when not repeating
|
||||||
|
final PlayQueue autoQueue = PlayerHelper.autoQueueOf(currentMetadata.getMetadata(),
|
||||||
|
playQueue.getStreams());
|
||||||
|
if (autoQueue != null) playQueue.append(autoQueue.getStreams());
|
||||||
|
}
|
||||||
/*//////////////////////////////////////////////////////////////////////////
|
/*//////////////////////////////////////////////////////////////////////////
|
||||||
// Getters and Setters
|
// Getters and Setters
|
||||||
//////////////////////////////////////////////////////////////////////////*/
|
//////////////////////////////////////////////////////////////////////////*/
|
||||||
|
@ -1135,7 +1148,7 @@ public abstract class BasePlayer implements
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean isProgressLoopRunning() {
|
public boolean isProgressLoopRunning() {
|
||||||
return progressUpdateReactor != null && !progressUpdateReactor.isDisposed();
|
return progressUpdateReactor.get() != null;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setRecovery() {
|
public void setRecovery() {
|
||||||
|
|
|
@ -127,7 +127,7 @@ public final class MainVideoPlayer extends AppCompatActivity
|
||||||
|
|
||||||
hideSystemUi();
|
hideSystemUi();
|
||||||
setContentView(R.layout.activity_main_player);
|
setContentView(R.layout.activity_main_player);
|
||||||
playerImpl = new VideoPlayerImpl(this);
|
playerImpl = new VideoPlayerImpl(this);
|
||||||
playerImpl.setup(findViewById(android.R.id.content));
|
playerImpl.setup(findViewById(android.R.id.content));
|
||||||
|
|
||||||
if (savedInstanceState != null && savedInstanceState.get(KEY_SAVED_STATE) != null) {
|
if (savedInstanceState != null && savedInstanceState.get(KEY_SAVED_STATE) != null) {
|
||||||
|
@ -498,11 +498,11 @@ public final class MainVideoPlayer extends AppCompatActivity
|
||||||
// Playback Listener
|
// Playback Listener
|
||||||
//////////////////////////////////////////////////////////////////////////*/
|
//////////////////////////////////////////////////////////////////////////*/
|
||||||
|
|
||||||
protected void onMetadataChanged(@Nullable final MediaSourceTag tag) {
|
protected void onMetadataChanged(@NonNull final MediaSourceTag tag) {
|
||||||
super.onMetadataChanged(tag);
|
super.onMetadataChanged(tag);
|
||||||
|
|
||||||
titleTextView.setText(getVideoTitle());
|
titleTextView.setText(tag.getMetadata().getName());
|
||||||
channelTextView.setText(getUploaderName());
|
channelTextView.setText(tag.getMetadata().getUploaderName());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -56,6 +56,7 @@ import com.google.android.exoplayer2.Player;
|
||||||
import com.google.android.exoplayer2.text.CaptionStyleCompat;
|
import com.google.android.exoplayer2.text.CaptionStyleCompat;
|
||||||
import com.google.android.exoplayer2.ui.AspectRatioFrameLayout;
|
import com.google.android.exoplayer2.ui.AspectRatioFrameLayout;
|
||||||
import com.google.android.exoplayer2.ui.SubtitleView;
|
import com.google.android.exoplayer2.ui.SubtitleView;
|
||||||
|
import com.nostra13.universalimageloader.core.assist.FailReason;
|
||||||
|
|
||||||
import org.schabi.newpipe.BuildConfig;
|
import org.schabi.newpipe.BuildConfig;
|
||||||
import org.schabi.newpipe.R;
|
import org.schabi.newpipe.R;
|
||||||
|
@ -428,21 +429,6 @@ public final class PopupVideoPlayer extends Service {
|
||||||
super.destroy();
|
super.destroy();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onLoadingComplete(String imageUri, View view, Bitmap loadedImage) {
|
|
||||||
super.onLoadingComplete(imageUri, view, loadedImage);
|
|
||||||
if (loadedImage != null) {
|
|
||||||
// rebuild notification here since remote view does not release bitmaps, causing memory leaks
|
|
||||||
notBuilder = createNotification();
|
|
||||||
|
|
||||||
if (notRemoteView != null) {
|
|
||||||
notRemoteView.setImageViewBitmap(R.id.notificationCover, loadedImage);
|
|
||||||
}
|
|
||||||
|
|
||||||
updateNotification(-1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onFullScreenButtonClicked() {
|
public void onFullScreenButtonClicked() {
|
||||||
super.onFullScreenButtonClicked();
|
super.onFullScreenButtonClicked();
|
||||||
|
@ -527,6 +513,54 @@ public final class PopupVideoPlayer extends Service {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*//////////////////////////////////////////////////////////////////////////
|
||||||
|
// Thumbnail Loading
|
||||||
|
//////////////////////////////////////////////////////////////////////////*/
|
||||||
|
|
||||||
|
private void setDummyRemoteViewThumbnail() {
|
||||||
|
resetNotification();
|
||||||
|
if (notRemoteView != null) {
|
||||||
|
notRemoteView.setImageViewResource(R.id.notificationCover,
|
||||||
|
R.drawable.dummy_thumbnail);
|
||||||
|
}
|
||||||
|
updateNotification(-1);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onLoadingStarted(String imageUri, View view) {
|
||||||
|
super.onLoadingStarted(imageUri, view);
|
||||||
|
setDummyRemoteViewThumbnail();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onLoadingComplete(String imageUri, View view, Bitmap loadedImage) {
|
||||||
|
super.onLoadingComplete(imageUri, view, loadedImage);
|
||||||
|
if (loadedImage == null) {
|
||||||
|
setDummyRemoteViewThumbnail();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// rebuild notification here since remote view does not release bitmaps,
|
||||||
|
// causing memory leaks
|
||||||
|
resetNotification();
|
||||||
|
if (notRemoteView != null) {
|
||||||
|
notRemoteView.setImageViewBitmap(R.id.notificationCover, loadedImage);
|
||||||
|
}
|
||||||
|
updateNotification(-1);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onLoadingFailed(String imageUri, View view, FailReason failReason) {
|
||||||
|
super.onLoadingFailed(imageUri, view, failReason);
|
||||||
|
setDummyRemoteViewThumbnail();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onLoadingCancelled(String imageUri, View view) {
|
||||||
|
super.onLoadingCancelled(imageUri, view);
|
||||||
|
setDummyRemoteViewThumbnail();
|
||||||
|
}
|
||||||
|
|
||||||
/*//////////////////////////////////////////////////////////////////////////
|
/*//////////////////////////////////////////////////////////////////////////
|
||||||
// Activity Event Listener
|
// Activity Event Listener
|
||||||
//////////////////////////////////////////////////////////////////////////*/
|
//////////////////////////////////////////////////////////////////////////*/
|
||||||
|
@ -578,8 +612,8 @@ public final class PopupVideoPlayer extends Service {
|
||||||
public void onRepeatModeChanged(int i) {
|
public void onRepeatModeChanged(int i) {
|
||||||
super.onRepeatModeChanged(i);
|
super.onRepeatModeChanged(i);
|
||||||
setRepeatModeRemote(notRemoteView, i);
|
setRepeatModeRemote(notRemoteView, i);
|
||||||
updateNotification(-1);
|
|
||||||
updatePlayback();
|
updatePlayback();
|
||||||
|
updateNotification(-1);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -592,7 +626,7 @@ public final class PopupVideoPlayer extends Service {
|
||||||
// Playback Listener
|
// Playback Listener
|
||||||
//////////////////////////////////////////////////////////////////////////*/
|
//////////////////////////////////////////////////////////////////////////*/
|
||||||
|
|
||||||
protected void onMetadataChanged(@Nullable final MediaSourceTag tag) {
|
protected void onMetadataChanged(@NonNull final MediaSourceTag tag) {
|
||||||
super.onMetadataChanged(tag);
|
super.onMetadataChanged(tag);
|
||||||
updateMetadata();
|
updateMetadata();
|
||||||
}
|
}
|
||||||
|
@ -651,12 +685,14 @@ public final class PopupVideoPlayer extends Service {
|
||||||
public void changeState(int state) {
|
public void changeState(int state) {
|
||||||
super.changeState(state);
|
super.changeState(state);
|
||||||
updatePlayback();
|
updatePlayback();
|
||||||
|
updateNotification(-1);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onBlocked() {
|
public void onBlocked() {
|
||||||
super.onBlocked();
|
super.onBlocked();
|
||||||
updateNotification(R.drawable.ic_play_arrow_white);
|
updateNotification(R.drawable.ic_play_arrow_white);
|
||||||
|
startForeground(NOTIFICATION_ID, notBuilder.build());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -664,19 +700,21 @@ public final class PopupVideoPlayer extends Service {
|
||||||
super.onPlaying();
|
super.onPlaying();
|
||||||
updateNotification(R.drawable.ic_pause_white);
|
updateNotification(R.drawable.ic_pause_white);
|
||||||
videoPlayPause.setBackgroundResource(R.drawable.ic_pause_white);
|
videoPlayPause.setBackgroundResource(R.drawable.ic_pause_white);
|
||||||
lockManager.acquireWifiAndCpu();
|
|
||||||
|
|
||||||
hideControls(DEFAULT_CONTROLS_DURATION, DEFAULT_CONTROLS_HIDE_TIME);
|
hideControls(DEFAULT_CONTROLS_DURATION, DEFAULT_CONTROLS_HIDE_TIME);
|
||||||
|
|
||||||
windowLayoutParams.flags = WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON
|
windowLayoutParams.flags = WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON
|
||||||
| WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;
|
| WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;
|
||||||
windowManager.updateViewLayout(playerImpl.getRootView(), windowLayoutParams);
|
windowManager.updateViewLayout(playerImpl.getRootView(), windowLayoutParams);
|
||||||
|
|
||||||
|
startForeground(NOTIFICATION_ID, notBuilder.build());
|
||||||
|
lockManager.acquireWifiAndCpu();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onBuffering() {
|
public void onBuffering() {
|
||||||
super.onBuffering();
|
super.onBuffering();
|
||||||
updateNotification(R.drawable.ic_play_arrow_white);
|
updateNotification(R.drawable.ic_play_arrow_white);
|
||||||
|
startForeground(NOTIFICATION_ID, notBuilder.build());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -684,10 +722,13 @@ public final class PopupVideoPlayer extends Service {
|
||||||
super.onPaused();
|
super.onPaused();
|
||||||
updateNotification(R.drawable.ic_play_arrow_white);
|
updateNotification(R.drawable.ic_play_arrow_white);
|
||||||
videoPlayPause.setBackgroundResource(R.drawable.ic_play_arrow_white);
|
videoPlayPause.setBackgroundResource(R.drawable.ic_play_arrow_white);
|
||||||
|
|
||||||
lockManager.releaseWifiAndCpu();
|
lockManager.releaseWifiAndCpu();
|
||||||
|
|
||||||
windowLayoutParams.flags = WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;
|
windowLayoutParams.flags = WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;
|
||||||
windowManager.updateViewLayout(playerImpl.getRootView(), windowLayoutParams);
|
windowManager.updateViewLayout(playerImpl.getRootView(), windowLayoutParams);
|
||||||
|
|
||||||
|
stopForeground(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -695,6 +736,7 @@ public final class PopupVideoPlayer extends Service {
|
||||||
super.onPausedSeek();
|
super.onPausedSeek();
|
||||||
videoPlayPause.setBackgroundResource(R.drawable.ic_pause_white);
|
videoPlayPause.setBackgroundResource(R.drawable.ic_pause_white);
|
||||||
updateNotification(R.drawable.ic_play_arrow_white);
|
updateNotification(R.drawable.ic_play_arrow_white);
|
||||||
|
startForeground(NOTIFICATION_ID, notBuilder.build());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -702,10 +744,13 @@ public final class PopupVideoPlayer extends Service {
|
||||||
super.onCompleted();
|
super.onCompleted();
|
||||||
updateNotification(R.drawable.ic_replay_white);
|
updateNotification(R.drawable.ic_replay_white);
|
||||||
videoPlayPause.setBackgroundResource(R.drawable.ic_replay_white);
|
videoPlayPause.setBackgroundResource(R.drawable.ic_replay_white);
|
||||||
|
|
||||||
lockManager.releaseWifiAndCpu();
|
lockManager.releaseWifiAndCpu();
|
||||||
|
|
||||||
windowLayoutParams.flags = WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;
|
windowLayoutParams.flags = WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;
|
||||||
windowManager.updateViewLayout(playerImpl.getRootView(), windowLayoutParams);
|
windowManager.updateViewLayout(playerImpl.getRootView(), windowLayoutParams);
|
||||||
|
|
||||||
|
stopForeground(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -731,7 +776,7 @@ public final class PopupVideoPlayer extends Service {
|
||||||
|
|
||||||
/*package-private*/ void enableVideoRenderer(final boolean enable) {
|
/*package-private*/ void enableVideoRenderer(final boolean enable) {
|
||||||
final int videoRendererIndex = getRendererIndex(C.TRACK_TYPE_VIDEO);
|
final int videoRendererIndex = getRendererIndex(C.TRACK_TYPE_VIDEO);
|
||||||
if (trackSelector != null && videoRendererIndex != RENDERER_UNAVAILABLE) {
|
if (videoRendererIndex != RENDERER_UNAVAILABLE) {
|
||||||
trackSelector.setParameters(trackSelector.buildUponParameters()
|
trackSelector.setParameters(trackSelector.buildUponParameters()
|
||||||
.setRendererDisabled(videoRendererIndex, !enable));
|
.setRendererDisabled(videoRendererIndex, !enable));
|
||||||
}
|
}
|
||||||
|
|
|
@ -103,7 +103,7 @@ public abstract class VideoPlayer extends BasePlayer
|
||||||
|
|
||||||
protected boolean wasPlaying = false;
|
protected boolean wasPlaying = false;
|
||||||
|
|
||||||
@Nullable private VideoPlaybackResolver resolver;
|
@NonNull final private VideoPlaybackResolver resolver;
|
||||||
/*//////////////////////////////////////////////////////////////////////////
|
/*//////////////////////////////////////////////////////////////////////////
|
||||||
// Views
|
// Views
|
||||||
//////////////////////////////////////////////////////////////////////////*/
|
//////////////////////////////////////////////////////////////////////////*/
|
||||||
|
@ -154,6 +154,7 @@ public abstract class VideoPlayer extends BasePlayer
|
||||||
public VideoPlayer(String debugTag, Context context) {
|
public VideoPlayer(String debugTag, Context context) {
|
||||||
super(context);
|
super(context);
|
||||||
this.TAG = debugTag;
|
this.TAG = debugTag;
|
||||||
|
this.resolver = new VideoPlaybackResolver(context, dataSource, getQualityResolver());
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setup(View rootView) {
|
public void setup(View rootView) {
|
||||||
|
@ -236,8 +237,6 @@ public abstract class VideoPlayer extends BasePlayer
|
||||||
trackSelector.setParameters(trackSelector.buildUponParameters()
|
trackSelector.setParameters(trackSelector.buildUponParameters()
|
||||||
.setTunnelingAudioSessionId(C.generateAudioSessionIdV21(context)));
|
.setTunnelingAudioSessionId(C.generateAudioSessionIdV21(context)));
|
||||||
}
|
}
|
||||||
|
|
||||||
resolver = new VideoPlaybackResolver(context, dataSource, getQualityResolver());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -292,7 +291,7 @@ public abstract class VideoPlayer extends BasePlayer
|
||||||
0, Menu.NONE, R.string.caption_none);
|
0, Menu.NONE, R.string.caption_none);
|
||||||
captionOffItem.setOnMenuItemClickListener(menuItem -> {
|
captionOffItem.setOnMenuItemClickListener(menuItem -> {
|
||||||
final int textRendererIndex = getRendererIndex(C.TRACK_TYPE_TEXT);
|
final int textRendererIndex = getRendererIndex(C.TRACK_TYPE_TEXT);
|
||||||
if (trackSelector != null && textRendererIndex != RENDERER_UNAVAILABLE) {
|
if (textRendererIndex != RENDERER_UNAVAILABLE) {
|
||||||
trackSelector.setParameters(trackSelector.buildUponParameters()
|
trackSelector.setParameters(trackSelector.buildUponParameters()
|
||||||
.setRendererDisabled(textRendererIndex, true));
|
.setRendererDisabled(textRendererIndex, true));
|
||||||
}
|
}
|
||||||
|
@ -306,7 +305,7 @@ public abstract class VideoPlayer extends BasePlayer
|
||||||
i + 1, Menu.NONE, captionLanguage);
|
i + 1, Menu.NONE, captionLanguage);
|
||||||
captionItem.setOnMenuItemClickListener(menuItem -> {
|
captionItem.setOnMenuItemClickListener(menuItem -> {
|
||||||
final int textRendererIndex = getRendererIndex(C.TRACK_TYPE_TEXT);
|
final int textRendererIndex = getRendererIndex(C.TRACK_TYPE_TEXT);
|
||||||
if (trackSelector != null && textRendererIndex != RENDERER_UNAVAILABLE) {
|
if (textRendererIndex != RENDERER_UNAVAILABLE) {
|
||||||
trackSelector.setPreferredTextLanguage(captionLanguage);
|
trackSelector.setPreferredTextLanguage(captionLanguage);
|
||||||
trackSelector.setParameters(trackSelector.buildUponParameters()
|
trackSelector.setParameters(trackSelector.buildUponParameters()
|
||||||
.setRendererDisabled(textRendererIndex, false));
|
.setRendererDisabled(textRendererIndex, false));
|
||||||
|
@ -369,7 +368,7 @@ public abstract class VideoPlayer extends BasePlayer
|
||||||
@Override
|
@Override
|
||||||
@Nullable
|
@Nullable
|
||||||
public MediaSource sourceOf(final PlayQueueItem item, final StreamInfo info) {
|
public MediaSource sourceOf(final PlayQueueItem item, final StreamInfo info) {
|
||||||
return resolver == null ? null : resolver.resolve(info);
|
return resolver.resolve(info);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*//////////////////////////////////////////////////////////////////////////
|
/*//////////////////////////////////////////////////////////////////////////
|
||||||
|
@ -480,8 +479,7 @@ public abstract class VideoPlayer extends BasePlayer
|
||||||
final int textRenderer = getRendererIndex(C.TRACK_TYPE_TEXT);
|
final int textRenderer = getRendererIndex(C.TRACK_TYPE_TEXT);
|
||||||
|
|
||||||
if (captionTextView == null) return;
|
if (captionTextView == null) return;
|
||||||
if (trackSelector == null || trackSelector.getCurrentMappedTrackInfo() == null ||
|
if (trackSelector.getCurrentMappedTrackInfo() == null || textRenderer == RENDERER_UNAVAILABLE) {
|
||||||
textRenderer == RENDERER_UNAVAILABLE) {
|
|
||||||
captionTextView.setVisibility(View.GONE);
|
captionTextView.setVisibility(View.GONE);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -833,12 +831,12 @@ public abstract class VideoPlayer extends BasePlayer
|
||||||
//////////////////////////////////////////////////////////////////////////*/
|
//////////////////////////////////////////////////////////////////////////*/
|
||||||
|
|
||||||
public void setPlaybackQuality(final String quality) {
|
public void setPlaybackQuality(final String quality) {
|
||||||
if (resolver != null) resolver.setPlaybackQuality(quality);
|
this.resolver.setPlaybackQuality(quality);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Nullable
|
@Nullable
|
||||||
public String getPlaybackQuality() {
|
public String getPlaybackQuality() {
|
||||||
return resolver == null ? null : resolver.getPlaybackQuality();
|
return resolver.getPlaybackQuality();
|
||||||
}
|
}
|
||||||
|
|
||||||
public AspectRatioFrameLayout getAspectRatioFrameLayout() {
|
public AspectRatioFrameLayout getAspectRatioFrameLayout() {
|
||||||
|
|
|
@ -2,6 +2,7 @@ package org.schabi.newpipe.player.resolver;
|
||||||
|
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.support.annotation.NonNull;
|
import android.support.annotation.NonNull;
|
||||||
|
import android.support.annotation.Nullable;
|
||||||
|
|
||||||
import com.google.android.exoplayer2.source.MediaSource;
|
import com.google.android.exoplayer2.source.MediaSource;
|
||||||
|
|
||||||
|
@ -24,6 +25,7 @@ public class AudioPlaybackResolver implements PlaybackResolver {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@Nullable
|
||||||
public MediaSource resolve(@NonNull StreamInfo info) {
|
public MediaSource resolve(@NonNull StreamInfo info) {
|
||||||
final MediaSource liveSource = maybeBuildLiveMediaSource(dataSource, info);
|
final MediaSource liveSource = maybeBuildLiveMediaSource(dataSource, info);
|
||||||
if (liveSource != null) return liveSource;
|
if (liveSource != null) return liveSource;
|
||||||
|
|
|
@ -1,7 +1,8 @@
|
||||||
package org.schabi.newpipe.player.resolver;
|
package org.schabi.newpipe.player.resolver;
|
||||||
|
|
||||||
import android.support.annotation.NonNull;
|
import android.support.annotation.NonNull;
|
||||||
|
import android.support.annotation.Nullable;
|
||||||
|
|
||||||
public interface Resolver<Source, Product> {
|
public interface Resolver<Source, Product> {
|
||||||
Product resolve(@NonNull Source source);
|
@Nullable Product resolve(@NonNull Source source);
|
||||||
}
|
}
|
||||||
|
|
|
@ -47,6 +47,7 @@ public class VideoPlaybackResolver implements PlaybackResolver {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@Nullable
|
||||||
public MediaSource resolve(@NonNull StreamInfo info) {
|
public MediaSource resolve(@NonNull StreamInfo info) {
|
||||||
final MediaSource liveSource = maybeBuildLiveMediaSource(dataSource, info);
|
final MediaSource liveSource = maybeBuildLiveMediaSource(dataSource, info);
|
||||||
if (liveSource != null) return liveSource;
|
if (liveSource != null) return liveSource;
|
||||||
|
|
Loading…
Add table
Reference in a new issue