1
0
mirror of https://github.com/TeamNewPipe/NewPipe synced 2024-12-23 16:40:32 +00: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:
John Zhen Mo 2018-05-16 18:18:32 -07:00
parent 0a2dbc4688
commit f1f5996975
8 changed files with 219 additions and 102 deletions

View File

@ -37,6 +37,7 @@ import android.widget.RemoteViews;
import com.google.android.exoplayer2.PlaybackParameters;
import com.google.android.exoplayer2.Player;
import com.google.android.exoplayer2.source.MediaSource;
import com.nostra13.universalimageloader.core.assist.FailReason;
import org.schabi.newpipe.BuildConfig;
import org.schabi.newpipe.R;
@ -264,16 +265,16 @@ public final class BackgroundPlayer extends Service {
protected class BasePlayerImpl extends BasePlayer {
@Nullable private AudioPlaybackResolver resolver;
@NonNull final private AudioPlaybackResolver resolver;
BasePlayerImpl(Context context) {
super(context);
this.resolver = new AudioPlaybackResolver(context, dataSource);
}
@Override
public void initPlayer(boolean playOnReady) {
super.initPlayer(playOnReady);
resolver = new AudioPlaybackResolver(context, dataSource);
}
@Override
@ -286,30 +287,65 @@ public final class BackgroundPlayer extends Service {
startForeground(NOTIFICATION_ID, notBuilder.build());
}
@Override
public void initThumbnail(final String url) {
/*//////////////////////////////////////////////////////////////////////////
// Thumbnail Loading
//////////////////////////////////////////////////////////////////////////*/
private void setDummyRemoteViewThumbnail() {
resetNotification();
if (notRemoteView != null) notRemoteView.setImageViewResource(R.id.notificationCover, R.drawable.dummy_thumbnail);
if (bigNotRemoteView != null) bigNotRemoteView.setImageViewResource(R.id.notificationCover, R.drawable.dummy_thumbnail);
if (notRemoteView != null) {
notRemoteView.setImageViewResource(R.id.notificationCover,
R.drawable.dummy_thumbnail);
}
if (bigNotRemoteView != null) {
bigNotRemoteView.setImageViewResource(R.id.notificationCover,
R.drawable.dummy_thumbnail);
}
updateNotification(-1);
super.initThumbnail(url);
}
@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) {
// 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);
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);
}
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
public void onPrepared(boolean playWhenReady) {
super.onPrepared(playWhenReady);
@ -385,17 +421,15 @@ public final class BackgroundPlayer extends Service {
protected void onMetadataChanged(@NonNull final MediaSourceTag tag) {
super.onMetadataChanged(tag);
if (shouldUpdateOnProgress) {
resetNotification();
updateNotification(-1);
updateMetadata();
}
resetNotification();
updateNotification(-1);
updateMetadata();
}
@Override
@Nullable
public MediaSource sourceOf(final PlayQueueItem item, final StreamInfo info) {
return resolver == null ? null : resolver.resolve(info);
return resolver.resolve(info);
}
@Override
@ -515,18 +549,40 @@ public final class BackgroundPlayer extends Service {
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
public void onPlaying() {
super.onPlaying();
updateNotification(R.drawable.ic_pause_white);
lockManager.acquireWifiAndCpu();
startForeground(NOTIFICATION_ID, notBuilder.build());
}
@Override
public void onPaused() {
super.onPaused();
updateNotification(R.drawable.ic_play_arrow_white);
lockManager.releaseWifiAndCpu();
stopForeground(false);
}
@Override
@ -539,6 +595,7 @@ public final class BackgroundPlayer extends Service {
updateNotification(R.drawable.ic_replay_white);
lockManager.releaseWifiAndCpu();
stopForeground(false);
}
}
}

View File

@ -68,6 +68,7 @@ import org.schabi.newpipe.player.playqueue.PlayQueue;
import org.schabi.newpipe.player.playqueue.PlayQueueAdapter;
import org.schabi.newpipe.player.playqueue.PlayQueueItem;
import org.schabi.newpipe.player.resolver.MediaSourceTag;
import org.schabi.newpipe.util.ImageDisplayConstants;
import org.schabi.newpipe.util.SerializedCache;
import java.io.IOException;
@ -78,6 +79,7 @@ import io.reactivex.Observable;
import io.reactivex.android.schedulers.AndroidSchedulers;
import io.reactivex.disposables.CompositeDisposable;
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_PERIOD_TRANSITION;
@ -104,6 +106,14 @@ public abstract class BasePlayer implements
@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
//////////////////////////////////////////////////////////////////////////*/
@ -142,9 +152,6 @@ public abstract class BasePlayer implements
protected final static int PROGRESS_LOOP_INTERVAL_MILLIS = 500;
protected final static int RECOVERY_SKIP_THRESHOLD_MILLIS = 3000; // 3 seconds
protected CustomTrackSelector trackSelector;
protected PlayerDataSource dataSource;
protected SimpleExoPlayer simpleExoPlayer;
protected AudioReactor audioReactor;
protected MediaSessionManager mediaSessionManager;
@ -152,9 +159,6 @@ public abstract class BasePlayer implements
private boolean isPrepared = false;
private boolean isSynchronizing = false;
protected Disposable progressUpdateReactor;
protected CompositeDisposable databaseUpdateReactor;
//////////////////////////////////////////////////////////////////////////*/
public BasePlayer(@NonNull final Context context) {
@ -171,29 +175,32 @@ public abstract class BasePlayer implements
context.registerReceiver(broadcastReceiver, intentFilter);
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() {
if (simpleExoPlayer == null) initPlayer(/*playOnInit=*/true);
if (simpleExoPlayer == null) {
initPlayer(/*playOnInit=*/true);
}
initListeners();
}
public void initPlayer(final boolean playOnReady) {
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.addListener(this);
simpleExoPlayer.setPlayWhenReady(playOnReady);
@ -287,7 +294,6 @@ public abstract class BasePlayer implements
if (mediaSessionManager != null) mediaSessionManager.dispose();
trackSelector = null;
mediaSessionManager = null;
simpleExoPlayer = null;
}
@ -296,11 +302,12 @@ public abstract class BasePlayer implements
// Thumbnail Loading
//////////////////////////////////////////////////////////////////////////*/
public void initThumbnail(final String url) {
private void initThumbnail(final String url) {
if (DEBUG) Log.d(TAG, "Thumbnail - initThumbnail() called");
if (url == null || url.isEmpty()) return;
ImageLoader.getInstance().resume();
ImageLoader.getInstance().loadImage(url, this);
ImageLoader.getInstance().loadImage(url, ImageDisplayConstants.DISPLAY_THUMBNAIL_OPTIONS,
this);
}
@Override
@ -461,13 +468,11 @@ public abstract class BasePlayer implements
public abstract void onUpdateProgress(int currentProgress, int duration, int bufferPercent);
protected void startProgressLoop() {
if (progressUpdateReactor != null) progressUpdateReactor.dispose();
progressUpdateReactor = getProgressReactor();
progressUpdateReactor.set(getProgressReactor());
}
protected void stopProgressLoop() {
if (progressUpdateReactor != null) progressUpdateReactor.dispose();
progressUpdateReactor = null;
progressUpdateReactor.set(null);
}
public void triggerProgressUpdate() {
@ -482,7 +487,8 @@ public abstract class BasePlayer implements
private Disposable getProgressReactor() {
return Observable.interval(PROGRESS_LOOP_INTERVAL_MILLIS, TimeUnit.MILLISECONDS)
.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") + ", " +
"timeline size = [" + timeline.getWindowCount() + "], " +
"reason = [" + reason + "]");
maybeUpdateCurrentMetadata();
}
@Override
public void onTracksChanged(TrackGroupArray trackGroups, TrackSelectionArray trackSelections) {
if (DEBUG) Log.d(TAG, "ExoPlayer - onTracksChanged(), " +
"track group size = " + trackGroups.length);
maybeUpdateCurrentMetadata();
}
@Override
@ -521,6 +531,8 @@ public abstract class BasePlayer implements
} else if (isLoading && !isProgressLoopRunning()) {
startProgressLoop();
}
maybeUpdateCurrentMetadata();
}
@Override
@ -665,24 +677,22 @@ public abstract class BasePlayer implements
if (DEBUG) Log.d(TAG, "ExoPlayer - onPositionDiscontinuity() called with " +
"reason = [" + reason + "]");
maybeUpdateCurrentMetadata();
// Refresh the playback if there is a transition to the next video
final int newPeriodIndex = simpleExoPlayer.getCurrentPeriodIndex();
/* Discontinuity reasons!! Thank you ExoPlayer lords */
switch (reason) {
case DISCONTINUITY_REASON_PERIOD_TRANSITION:
if (newPeriodIndex == playQueue.getIndex()) {
registerView();
} else {
playQueue.offsetIndex(+1);
playQueue.setIndex(newPeriodIndex);
}
case DISCONTINUITY_REASON_SEEK:
case DISCONTINUITY_REASON_SEEK_ADJUSTMENT:
case DISCONTINUITY_REASON_INTERNAL:
break;
}
maybeUpdateCurrentMetadata();
}
@Override
@ -794,14 +804,6 @@ public abstract class BasePlayer implements
initThumbnail(info.getThumbnailUrl());
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
@ -960,7 +962,7 @@ public abstract class BasePlayer implements
//////////////////////////////////////////////////////////////////////////*/
private void registerView() {
if (databaseUpdateReactor == null || currentMetadata == null) return;
if (currentMetadata == null) return;
final StreamInfo currentInfo = currentMetadata.getMetadata();
databaseUpdateReactor.add(recordManager.onViewed(currentInfo).onErrorComplete()
.subscribe(
@ -980,7 +982,7 @@ public abstract class BasePlayer implements
}
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)
.observeOn(AndroidSchedulers.mainThread())
.onErrorComplete()
@ -1012,12 +1014,23 @@ public abstract class BasePlayer implements
return;
}
if (metadata == null || currentMetadata == metadata) return;
if (metadata == null) return;
maybeAutoQueueNextStream(metadata);
if (currentMetadata == metadata) return;
currentMetadata = 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
//////////////////////////////////////////////////////////////////////////*/
@ -1135,7 +1148,7 @@ public abstract class BasePlayer implements
}
public boolean isProgressLoopRunning() {
return progressUpdateReactor != null && !progressUpdateReactor.isDisposed();
return progressUpdateReactor.get() != null;
}
public void setRecovery() {

View File

@ -127,7 +127,7 @@ public final class MainVideoPlayer extends AppCompatActivity
hideSystemUi();
setContentView(R.layout.activity_main_player);
playerImpl = new VideoPlayerImpl(this);
playerImpl = new VideoPlayerImpl(this);
playerImpl.setup(findViewById(android.R.id.content));
if (savedInstanceState != null && savedInstanceState.get(KEY_SAVED_STATE) != null) {
@ -498,11 +498,11 @@ public final class MainVideoPlayer extends AppCompatActivity
// Playback Listener
//////////////////////////////////////////////////////////////////////////*/
protected void onMetadataChanged(@Nullable final MediaSourceTag tag) {
protected void onMetadataChanged(@NonNull final MediaSourceTag tag) {
super.onMetadataChanged(tag);
titleTextView.setText(getVideoTitle());
channelTextView.setText(getUploaderName());
titleTextView.setText(tag.getMetadata().getName());
channelTextView.setText(tag.getMetadata().getUploaderName());
}
@Override

View File

@ -56,6 +56,7 @@ import com.google.android.exoplayer2.Player;
import com.google.android.exoplayer2.text.CaptionStyleCompat;
import com.google.android.exoplayer2.ui.AspectRatioFrameLayout;
import com.google.android.exoplayer2.ui.SubtitleView;
import com.nostra13.universalimageloader.core.assist.FailReason;
import org.schabi.newpipe.BuildConfig;
import org.schabi.newpipe.R;
@ -428,21 +429,6 @@ public final class PopupVideoPlayer extends Service {
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
public void 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
//////////////////////////////////////////////////////////////////////////*/
@ -578,8 +612,8 @@ public final class PopupVideoPlayer extends Service {
public void onRepeatModeChanged(int i) {
super.onRepeatModeChanged(i);
setRepeatModeRemote(notRemoteView, i);
updateNotification(-1);
updatePlayback();
updateNotification(-1);
}
@Override
@ -592,7 +626,7 @@ public final class PopupVideoPlayer extends Service {
// Playback Listener
//////////////////////////////////////////////////////////////////////////*/
protected void onMetadataChanged(@Nullable final MediaSourceTag tag) {
protected void onMetadataChanged(@NonNull final MediaSourceTag tag) {
super.onMetadataChanged(tag);
updateMetadata();
}
@ -651,12 +685,14 @@ public final class PopupVideoPlayer extends Service {
public void changeState(int state) {
super.changeState(state);
updatePlayback();
updateNotification(-1);
}
@Override
public void onBlocked() {
super.onBlocked();
updateNotification(R.drawable.ic_play_arrow_white);
startForeground(NOTIFICATION_ID, notBuilder.build());
}
@Override
@ -664,19 +700,21 @@ public final class PopupVideoPlayer extends Service {
super.onPlaying();
updateNotification(R.drawable.ic_pause_white);
videoPlayPause.setBackgroundResource(R.drawable.ic_pause_white);
lockManager.acquireWifiAndCpu();
hideControls(DEFAULT_CONTROLS_DURATION, DEFAULT_CONTROLS_HIDE_TIME);
windowLayoutParams.flags = WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON
| WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;
windowManager.updateViewLayout(playerImpl.getRootView(), windowLayoutParams);
startForeground(NOTIFICATION_ID, notBuilder.build());
lockManager.acquireWifiAndCpu();
}
@Override
public void onBuffering() {
super.onBuffering();
updateNotification(R.drawable.ic_play_arrow_white);
startForeground(NOTIFICATION_ID, notBuilder.build());
}
@Override
@ -684,10 +722,13 @@ public final class PopupVideoPlayer extends Service {
super.onPaused();
updateNotification(R.drawable.ic_play_arrow_white);
videoPlayPause.setBackgroundResource(R.drawable.ic_play_arrow_white);
lockManager.releaseWifiAndCpu();
windowLayoutParams.flags = WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;
windowManager.updateViewLayout(playerImpl.getRootView(), windowLayoutParams);
stopForeground(false);
}
@Override
@ -695,6 +736,7 @@ public final class PopupVideoPlayer extends Service {
super.onPausedSeek();
videoPlayPause.setBackgroundResource(R.drawable.ic_pause_white);
updateNotification(R.drawable.ic_play_arrow_white);
startForeground(NOTIFICATION_ID, notBuilder.build());
}
@Override
@ -702,10 +744,13 @@ public final class PopupVideoPlayer extends Service {
super.onCompleted();
updateNotification(R.drawable.ic_replay_white);
videoPlayPause.setBackgroundResource(R.drawable.ic_replay_white);
lockManager.releaseWifiAndCpu();
windowLayoutParams.flags = WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;
windowManager.updateViewLayout(playerImpl.getRootView(), windowLayoutParams);
stopForeground(false);
}
@Override
@ -731,7 +776,7 @@ public final class PopupVideoPlayer extends Service {
/*package-private*/ void enableVideoRenderer(final boolean enable) {
final int videoRendererIndex = getRendererIndex(C.TRACK_TYPE_VIDEO);
if (trackSelector != null && videoRendererIndex != RENDERER_UNAVAILABLE) {
if (videoRendererIndex != RENDERER_UNAVAILABLE) {
trackSelector.setParameters(trackSelector.buildUponParameters()
.setRendererDisabled(videoRendererIndex, !enable));
}

View File

@ -103,7 +103,7 @@ public abstract class VideoPlayer extends BasePlayer
protected boolean wasPlaying = false;
@Nullable private VideoPlaybackResolver resolver;
@NonNull final private VideoPlaybackResolver resolver;
/*//////////////////////////////////////////////////////////////////////////
// Views
//////////////////////////////////////////////////////////////////////////*/
@ -154,6 +154,7 @@ public abstract class VideoPlayer extends BasePlayer
public VideoPlayer(String debugTag, Context context) {
super(context);
this.TAG = debugTag;
this.resolver = new VideoPlaybackResolver(context, dataSource, getQualityResolver());
}
public void setup(View rootView) {
@ -236,8 +237,6 @@ public abstract class VideoPlayer extends BasePlayer
trackSelector.setParameters(trackSelector.buildUponParameters()
.setTunnelingAudioSessionId(C.generateAudioSessionIdV21(context)));
}
resolver = new VideoPlaybackResolver(context, dataSource, getQualityResolver());
}
@Override
@ -292,7 +291,7 @@ public abstract class VideoPlayer extends BasePlayer
0, Menu.NONE, R.string.caption_none);
captionOffItem.setOnMenuItemClickListener(menuItem -> {
final int textRendererIndex = getRendererIndex(C.TRACK_TYPE_TEXT);
if (trackSelector != null && textRendererIndex != RENDERER_UNAVAILABLE) {
if (textRendererIndex != RENDERER_UNAVAILABLE) {
trackSelector.setParameters(trackSelector.buildUponParameters()
.setRendererDisabled(textRendererIndex, true));
}
@ -306,7 +305,7 @@ public abstract class VideoPlayer extends BasePlayer
i + 1, Menu.NONE, captionLanguage);
captionItem.setOnMenuItemClickListener(menuItem -> {
final int textRendererIndex = getRendererIndex(C.TRACK_TYPE_TEXT);
if (trackSelector != null && textRendererIndex != RENDERER_UNAVAILABLE) {
if (textRendererIndex != RENDERER_UNAVAILABLE) {
trackSelector.setPreferredTextLanguage(captionLanguage);
trackSelector.setParameters(trackSelector.buildUponParameters()
.setRendererDisabled(textRendererIndex, false));
@ -369,7 +368,7 @@ public abstract class VideoPlayer extends BasePlayer
@Override
@Nullable
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);
if (captionTextView == null) return;
if (trackSelector == null || trackSelector.getCurrentMappedTrackInfo() == null ||
textRenderer == RENDERER_UNAVAILABLE) {
if (trackSelector.getCurrentMappedTrackInfo() == null || textRenderer == RENDERER_UNAVAILABLE) {
captionTextView.setVisibility(View.GONE);
return;
}
@ -833,12 +831,12 @@ public abstract class VideoPlayer extends BasePlayer
//////////////////////////////////////////////////////////////////////////*/
public void setPlaybackQuality(final String quality) {
if (resolver != null) resolver.setPlaybackQuality(quality);
this.resolver.setPlaybackQuality(quality);
}
@Nullable
public String getPlaybackQuality() {
return resolver == null ? null : resolver.getPlaybackQuality();
return resolver.getPlaybackQuality();
}
public AspectRatioFrameLayout getAspectRatioFrameLayout() {

View File

@ -2,6 +2,7 @@ package org.schabi.newpipe.player.resolver;
import android.content.Context;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import com.google.android.exoplayer2.source.MediaSource;
@ -24,6 +25,7 @@ public class AudioPlaybackResolver implements PlaybackResolver {
}
@Override
@Nullable
public MediaSource resolve(@NonNull StreamInfo info) {
final MediaSource liveSource = maybeBuildLiveMediaSource(dataSource, info);
if (liveSource != null) return liveSource;

View File

@ -1,7 +1,8 @@
package org.schabi.newpipe.player.resolver;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
public interface Resolver<Source, Product> {
Product resolve(@NonNull Source source);
@Nullable Product resolve(@NonNull Source source);
}

View File

@ -47,6 +47,7 @@ public class VideoPlaybackResolver implements PlaybackResolver {
}
@Override
@Nullable
public MediaSource resolve(@NonNull StreamInfo info) {
final MediaSource liveSource = maybeBuildLiveMediaSource(dataSource, info);
if (liveSource != null) return liveSource;