-Changed media source manager near edge loading to no longer load while player position is not progressing.
-Changed main video player to always self-destruct on stop. -Extracted main video player lifecycle states into separate data class. -Fixed play queue in full repeat mode does not load first item after expiring.
This commit is contained in:
parent
c9915bba18
commit
42d19d98ad
|
@ -164,6 +164,11 @@ public final class BackgroundPlayer extends Service {
|
||||||
if (DEBUG) Log.d(TAG, "onScreenOnOff() called with: on = [" + on + "]");
|
if (DEBUG) Log.d(TAG, "onScreenOnOff() called with: on = [" + on + "]");
|
||||||
shouldUpdateOnProgress = on;
|
shouldUpdateOnProgress = on;
|
||||||
basePlayerImpl.triggerProgressUpdate();
|
basePlayerImpl.triggerProgressUpdate();
|
||||||
|
if (on) {
|
||||||
|
basePlayerImpl.startProgressLoop();
|
||||||
|
} else {
|
||||||
|
basePlayerImpl.stopProgressLoop();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*//////////////////////////////////////////////////////////////////////////
|
/*//////////////////////////////////////////////////////////////////////////
|
||||||
|
@ -549,7 +554,6 @@ public final class BackgroundPlayer extends Service {
|
||||||
super.onPaused();
|
super.onPaused();
|
||||||
|
|
||||||
updateNotification(R.drawable.ic_play_arrow_white);
|
updateNotification(R.drawable.ic_play_arrow_white);
|
||||||
if (isProgressLoopRunning()) stopProgressLoop();
|
|
||||||
|
|
||||||
lockManager.releaseWifiAndCpu();
|
lockManager.releaseWifiAndCpu();
|
||||||
}
|
}
|
||||||
|
|
|
@ -177,11 +177,11 @@ public abstract class BasePlayer implements
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setup() {
|
public void setup() {
|
||||||
if (simpleExoPlayer == null) initPlayer();
|
if (simpleExoPlayer == null) initPlayer(/*playOnInit=*/true);
|
||||||
initListeners();
|
initListeners();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void initPlayer() {
|
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();
|
if (databaseUpdateReactor != null) databaseUpdateReactor.dispose();
|
||||||
|
@ -199,7 +199,7 @@ public abstract class BasePlayer implements
|
||||||
final RenderersFactory renderFactory = new DefaultRenderersFactory(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(true);
|
simpleExoPlayer.setPlayWhenReady(playOnReady);
|
||||||
simpleExoPlayer.setSeekParameters(PlayerHelper.getSeekParameters(context));
|
simpleExoPlayer.setSeekParameters(PlayerHelper.getSeekParameters(context));
|
||||||
|
|
||||||
audioReactor = new AudioReactor(context, simpleExoPlayer);
|
audioReactor = new AudioReactor(context, simpleExoPlayer);
|
||||||
|
@ -237,15 +237,16 @@ public abstract class BasePlayer implements
|
||||||
final float playbackPitch = intent.getFloatExtra(PLAYBACK_PITCH, getPlaybackPitch());
|
final float playbackPitch = intent.getFloatExtra(PLAYBACK_PITCH, getPlaybackPitch());
|
||||||
|
|
||||||
// Good to go...
|
// Good to go...
|
||||||
initPlayback(queue, repeatMode, playbackSpeed, playbackPitch);
|
initPlayback(queue, repeatMode, playbackSpeed, playbackPitch, /*playOnInit=*/true);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void initPlayback(@NonNull final PlayQueue queue,
|
protected void initPlayback(@NonNull final PlayQueue queue,
|
||||||
@Player.RepeatMode final int repeatMode,
|
@Player.RepeatMode final int repeatMode,
|
||||||
final float playbackSpeed,
|
final float playbackSpeed,
|
||||||
final float playbackPitch) {
|
final float playbackPitch,
|
||||||
|
final boolean playOnReady) {
|
||||||
destroyPlayer();
|
destroyPlayer();
|
||||||
initPlayer();
|
initPlayer(playOnReady);
|
||||||
setRepeatMode(repeatMode);
|
setRepeatMode(repeatMode);
|
||||||
setPlaybackParameters(playbackSpeed, playbackPitch);
|
setPlaybackParameters(playbackSpeed, playbackPitch);
|
||||||
|
|
||||||
|
@ -770,9 +771,10 @@ public abstract class BasePlayer implements
|
||||||
//////////////////////////////////////////////////////////////////////////*/
|
//////////////////////////////////////////////////////////////////////////*/
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean isNearPlaybackEdge(final long timeToEndMillis) {
|
public boolean isApproachingPlaybackEdge(final long timeToEndMillis) {
|
||||||
// If live, then not near playback edge
|
// If live, then not near playback edge
|
||||||
if (simpleExoPlayer == null || isLive()) return false;
|
// If not playing, then not approaching playback edge
|
||||||
|
if (simpleExoPlayer == null || isLive() || !isPlaying()) return false;
|
||||||
|
|
||||||
final long currentPositionMillis = simpleExoPlayer.getCurrentPosition();
|
final long currentPositionMillis = simpleExoPlayer.getCurrentPosition();
|
||||||
final long currentDurationMillis = simpleExoPlayer.getDuration();
|
final long currentDurationMillis = simpleExoPlayer.getDuration();
|
||||||
|
|
|
@ -61,7 +61,6 @@ import org.schabi.newpipe.extractor.stream.VideoStream;
|
||||||
import org.schabi.newpipe.fragments.OnScrollBelowItemsListener;
|
import org.schabi.newpipe.fragments.OnScrollBelowItemsListener;
|
||||||
import org.schabi.newpipe.player.helper.PlaybackParameterDialog;
|
import org.schabi.newpipe.player.helper.PlaybackParameterDialog;
|
||||||
import org.schabi.newpipe.player.helper.PlayerHelper;
|
import org.schabi.newpipe.player.helper.PlayerHelper;
|
||||||
import org.schabi.newpipe.playlist.PlayQueue;
|
|
||||||
import org.schabi.newpipe.playlist.PlayQueueItem;
|
import org.schabi.newpipe.playlist.PlayQueueItem;
|
||||||
import org.schabi.newpipe.playlist.PlayQueueItemBuilder;
|
import org.schabi.newpipe.playlist.PlayQueueItemBuilder;
|
||||||
import org.schabi.newpipe.playlist.PlayQueueItemHolder;
|
import org.schabi.newpipe.playlist.PlayQueueItemHolder;
|
||||||
|
@ -97,12 +96,12 @@ public final class MainVideoPlayer extends AppCompatActivity
|
||||||
|
|
||||||
private GestureDetector gestureDetector;
|
private GestureDetector gestureDetector;
|
||||||
|
|
||||||
private boolean activityPaused;
|
|
||||||
private VideoPlayerImpl playerImpl;
|
private VideoPlayerImpl playerImpl;
|
||||||
|
|
||||||
private SharedPreferences defaultPreferences;
|
private SharedPreferences defaultPreferences;
|
||||||
|
|
||||||
@Nullable private StateSaver.SavedState savedState;
|
@Nullable private PlayerState playerState;
|
||||||
|
private boolean isInMultiWindow;
|
||||||
|
|
||||||
/*//////////////////////////////////////////////////////////////////////////
|
/*//////////////////////////////////////////////////////////////////////////
|
||||||
// Activity LifeCycle
|
// Activity LifeCycle
|
||||||
|
@ -137,8 +136,9 @@ public final class MainVideoPlayer extends AppCompatActivity
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void onRestoreInstanceState(@NonNull Bundle bundle) {
|
protected void onRestoreInstanceState(@NonNull Bundle bundle) {
|
||||||
|
if (DEBUG) Log.d(TAG, "onRestoreInstanceState() called");
|
||||||
super.onRestoreInstanceState(bundle);
|
super.onRestoreInstanceState(bundle);
|
||||||
savedState = StateSaver.tryToRestore(bundle, this);
|
StateSaver.tryToRestore(bundle, this);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -150,27 +150,28 @@ public final class MainVideoPlayer extends AppCompatActivity
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void onResume() {
|
protected void onResume() {
|
||||||
super.onResume();
|
|
||||||
if (DEBUG) Log.d(TAG, "onResume() called");
|
if (DEBUG) Log.d(TAG, "onResume() called");
|
||||||
if (isInMultiWindow()) return;
|
super.onResume();
|
||||||
if (playerImpl.getPlayer() != null && activityPaused && playerImpl.wasPlaying()
|
|
||||||
&& !playerImpl.isPlaying()) {
|
|
||||||
playerImpl.onPlay();
|
|
||||||
}
|
|
||||||
activityPaused = false;
|
|
||||||
|
|
||||||
if(globalScreenOrientationLocked()) {
|
if (globalScreenOrientationLocked()) {
|
||||||
boolean lastOrientationWasLandscape
|
boolean lastOrientationWasLandscape = defaultPreferences.getBoolean(
|
||||||
= defaultPreferences.getBoolean(getString(R.string.last_orientation_landscape_key), false);
|
getString(R.string.last_orientation_landscape_key), false);
|
||||||
setLandscape(lastOrientationWasLandscape);
|
setLandscape(lastOrientationWasLandscape);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
// Upon going in or out of multiwindow mode, isInMultiWindow will always be false,
|
||||||
public void onBackPressed() {
|
// since the first onResume needs to restore the player.
|
||||||
if (DEBUG) Log.d(TAG, "onBackPressed() called");
|
// Subsequent onResume calls while multiwindow mode remains the same and the player is
|
||||||
super.onBackPressed();
|
// prepared should be ignored.
|
||||||
if (playerImpl.isPlaying()) playerImpl.getPlayer().setPlayWhenReady(false);
|
if (isInMultiWindow) return;
|
||||||
|
isInMultiWindow = isInMultiWindow();
|
||||||
|
|
||||||
|
if (playerState != null) {
|
||||||
|
playerImpl.setPlaybackQuality(playerState.getPlaybackQuality());
|
||||||
|
playerImpl.initPlayback(playerState.getPlayQueue(), playerState.getRepeatMode(),
|
||||||
|
playerState.getPlaybackSpeed(), playerState.getPlaybackPitch(),
|
||||||
|
playerState.wasPlaying());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -183,33 +184,24 @@ public final class MainVideoPlayer extends AppCompatActivity
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void onPause() {
|
|
||||||
super.onPause();
|
|
||||||
if (DEBUG) Log.d(TAG, "onPause() called");
|
|
||||||
if (isInMultiWindow()) return;
|
|
||||||
if (playerImpl != null && playerImpl.getPlayer() != null && !activityPaused) {
|
|
||||||
playerImpl.wasPlaying = playerImpl.isPlaying();
|
|
||||||
playerImpl.onPause();
|
|
||||||
}
|
|
||||||
activityPaused = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void onSaveInstanceState(Bundle outState) {
|
protected void onSaveInstanceState(Bundle outState) {
|
||||||
|
if (DEBUG) Log.d(TAG, "onSaveInstanceState() called");
|
||||||
super.onSaveInstanceState(outState);
|
super.onSaveInstanceState(outState);
|
||||||
if (playerImpl == null) return;
|
if (playerImpl == null) return;
|
||||||
|
|
||||||
playerImpl.setRecovery();
|
playerImpl.setRecovery();
|
||||||
savedState = StateSaver.tryToSave(isChangingConfigurations(), savedState,
|
playerState = new PlayerState(playerImpl.getPlayQueue(), playerImpl.getRepeatMode(),
|
||||||
outState, this);
|
playerImpl.getPlaybackSpeed(), playerImpl.getPlaybackPitch(),
|
||||||
|
playerImpl.getPlaybackQuality(), playerImpl.isPlaying());
|
||||||
|
StateSaver.tryToSave(isChangingConfigurations(), null, outState, this);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void onDestroy() {
|
protected void onStop() {
|
||||||
super.onDestroy();
|
if (DEBUG) Log.d(TAG, "onStop() called");
|
||||||
if (DEBUG) Log.d(TAG, "onDestroy() called");
|
super.onStop();
|
||||||
if (playerImpl != null) playerImpl.destroy();
|
playerImpl.destroy();
|
||||||
}
|
}
|
||||||
|
|
||||||
/*//////////////////////////////////////////////////////////////////////////
|
/*//////////////////////////////////////////////////////////////////////////
|
||||||
|
@ -224,26 +216,13 @@ public final class MainVideoPlayer extends AppCompatActivity
|
||||||
@Override
|
@Override
|
||||||
public void writeTo(Queue<Object> objectsToSave) {
|
public void writeTo(Queue<Object> objectsToSave) {
|
||||||
if (objectsToSave == null) return;
|
if (objectsToSave == null) return;
|
||||||
objectsToSave.add(playerImpl.getPlayQueue());
|
objectsToSave.add(playerState);
|
||||||
objectsToSave.add(playerImpl.getRepeatMode());
|
|
||||||
objectsToSave.add(playerImpl.getPlaybackSpeed());
|
|
||||||
objectsToSave.add(playerImpl.getPlaybackPitch());
|
|
||||||
objectsToSave.add(playerImpl.getPlaybackQuality());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
public void readFrom(@NonNull Queue<Object> savedObjects) throws Exception {
|
public void readFrom(@NonNull Queue<Object> savedObjects) {
|
||||||
@NonNull final PlayQueue queue = (PlayQueue) savedObjects.poll();
|
playerState = (PlayerState) savedObjects.poll();
|
||||||
final int repeatMode = (int) savedObjects.poll();
|
|
||||||
final float playbackSpeed = (float) savedObjects.poll();
|
|
||||||
final float playbackPitch = (float) savedObjects.poll();
|
|
||||||
@NonNull final String playbackQuality = (String) savedObjects.poll();
|
|
||||||
|
|
||||||
playerImpl.setPlaybackQuality(playbackQuality);
|
|
||||||
playerImpl.initPlayback(queue, repeatMode, playbackSpeed, playbackPitch);
|
|
||||||
|
|
||||||
StateSaver.onDestroy(savedState);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*//////////////////////////////////////////////////////////////////////////
|
/*//////////////////////////////////////////////////////////////////////////
|
||||||
|
|
|
@ -0,0 +1,88 @@
|
||||||
|
package org.schabi.newpipe.player;
|
||||||
|
|
||||||
|
import android.support.annotation.NonNull;
|
||||||
|
import android.support.annotation.Nullable;
|
||||||
|
import android.util.Log;
|
||||||
|
|
||||||
|
import com.google.gson.Gson;
|
||||||
|
import com.google.gson.JsonSyntaxException;
|
||||||
|
|
||||||
|
import org.schabi.newpipe.playlist.PlayQueue;
|
||||||
|
|
||||||
|
import java.io.Serializable;
|
||||||
|
|
||||||
|
public class PlayerState implements Serializable {
|
||||||
|
private final static String TAG = "PlayerState";
|
||||||
|
|
||||||
|
@NonNull private final PlayQueue playQueue;
|
||||||
|
private final int repeatMode;
|
||||||
|
private final float playbackSpeed;
|
||||||
|
private final float playbackPitch;
|
||||||
|
@Nullable private final String playbackQuality;
|
||||||
|
private final boolean wasPlaying;
|
||||||
|
|
||||||
|
PlayerState(@NonNull final PlayQueue playQueue, final int repeatMode,
|
||||||
|
final float playbackSpeed, final float playbackPitch, final boolean wasPlaying) {
|
||||||
|
this(playQueue, repeatMode, playbackSpeed, playbackPitch, null, wasPlaying);
|
||||||
|
}
|
||||||
|
|
||||||
|
PlayerState(@NonNull final PlayQueue playQueue, final int repeatMode,
|
||||||
|
final float playbackSpeed, final float playbackPitch,
|
||||||
|
@Nullable final String playbackQuality, final boolean wasPlaying) {
|
||||||
|
this.playQueue = playQueue;
|
||||||
|
this.repeatMode = repeatMode;
|
||||||
|
this.playbackSpeed = playbackSpeed;
|
||||||
|
this.playbackPitch = playbackPitch;
|
||||||
|
this.playbackQuality = playbackQuality;
|
||||||
|
this.wasPlaying = wasPlaying;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*//////////////////////////////////////////////////////////////////////////
|
||||||
|
// Serdes
|
||||||
|
//////////////////////////////////////////////////////////////////////////*/
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
public static PlayerState fromJson(@NonNull final String json) {
|
||||||
|
try {
|
||||||
|
return new Gson().fromJson(json, PlayerState.class);
|
||||||
|
} catch (JsonSyntaxException error) {
|
||||||
|
Log.e(TAG, "Failed to deserialize PlayerState from json=[" + json + "]", error);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@NonNull
|
||||||
|
public String toJson() {
|
||||||
|
return new Gson().toJson(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*//////////////////////////////////////////////////////////////////////////
|
||||||
|
// Getters
|
||||||
|
//////////////////////////////////////////////////////////////////////////*/
|
||||||
|
|
||||||
|
@NonNull
|
||||||
|
public PlayQueue getPlayQueue() {
|
||||||
|
return playQueue;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getRepeatMode() {
|
||||||
|
return repeatMode;
|
||||||
|
}
|
||||||
|
|
||||||
|
public float getPlaybackSpeed() {
|
||||||
|
return playbackSpeed;
|
||||||
|
}
|
||||||
|
|
||||||
|
public float getPlaybackPitch() {
|
||||||
|
return playbackPitch;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
public String getPlaybackQuality() {
|
||||||
|
return playbackQuality;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean wasPlaying() {
|
||||||
|
return wasPlaying;
|
||||||
|
}
|
||||||
|
}
|
|
@ -228,8 +228,8 @@ public abstract class VideoPlayer extends BasePlayer
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void initPlayer() {
|
public void initPlayer(final boolean playOnReady) {
|
||||||
super.initPlayer();
|
super.initPlayer(playOnReady);
|
||||||
|
|
||||||
// Setup video view
|
// Setup video view
|
||||||
simpleExoPlayer.setVideoSurfaceView(surfaceView);
|
simpleExoPlayer.setVideoSurfaceView(surfaceView);
|
||||||
|
|
|
@ -87,16 +87,6 @@ public class ManagedMediaSourcePlaylist {
|
||||||
internalSource.moveMediaSource(source, target);
|
internalSource.moveMediaSource(source, target);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Invalidates the {@link ManagedMediaSource} at the given index by replacing it
|
|
||||||
* with a {@link PlaceholderMediaSource}.
|
|
||||||
* @see #invalidate(int, Runnable)
|
|
||||||
* @see #update(int, ManagedMediaSource, Runnable)
|
|
||||||
* */
|
|
||||||
public synchronized void invalidate(final int index) {
|
|
||||||
invalidate(index, /*doNothing=*/null);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Invalidates the {@link ManagedMediaSource} at the given index by replacing it
|
* Invalidates the {@link ManagedMediaSource} at the given index by replacing it
|
||||||
* with a {@link PlaceholderMediaSource}.
|
* with a {@link PlaceholderMediaSource}.
|
||||||
|
|
|
@ -24,8 +24,10 @@ import org.schabi.newpipe.playlist.events.RemoveEvent;
|
||||||
import org.schabi.newpipe.playlist.events.ReorderEvent;
|
import org.schabi.newpipe.playlist.events.ReorderEvent;
|
||||||
import org.schabi.newpipe.util.ServiceHelper;
|
import org.schabi.newpipe.util.ServiceHelper;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
|
import java.util.List;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import java.util.concurrent.TimeUnit;
|
import java.util.concurrent.TimeUnit;
|
||||||
import java.util.concurrent.atomic.AtomicBoolean;
|
import java.util.concurrent.atomic.AtomicBoolean;
|
||||||
|
@ -38,6 +40,7 @@ import io.reactivex.disposables.Disposable;
|
||||||
import io.reactivex.disposables.SerialDisposable;
|
import io.reactivex.disposables.SerialDisposable;
|
||||||
import io.reactivex.functions.Consumer;
|
import io.reactivex.functions.Consumer;
|
||||||
import io.reactivex.internal.subscriptions.EmptySubscription;
|
import io.reactivex.internal.subscriptions.EmptySubscription;
|
||||||
|
import io.reactivex.schedulers.Schedulers;
|
||||||
import io.reactivex.subjects.PublishSubject;
|
import io.reactivex.subjects.PublishSubject;
|
||||||
|
|
||||||
import static org.schabi.newpipe.player.mediasource.FailedMediaSource.MediaSourceResolutionException;
|
import static org.schabi.newpipe.player.mediasource.FailedMediaSource.MediaSourceResolutionException;
|
||||||
|
@ -338,12 +341,14 @@ public class MediaSourceManager {
|
||||||
|
|
||||||
private Observable<Long> getEdgeIntervalSignal() {
|
private Observable<Long> getEdgeIntervalSignal() {
|
||||||
return Observable.interval(progressUpdateIntervalMillis, TimeUnit.MILLISECONDS)
|
return Observable.interval(progressUpdateIntervalMillis, TimeUnit.MILLISECONDS)
|
||||||
.filter(ignored -> playbackListener.isNearPlaybackEdge(playbackNearEndGapMillis));
|
.filter(ignored ->
|
||||||
|
playbackListener.isApproachingPlaybackEdge(playbackNearEndGapMillis));
|
||||||
}
|
}
|
||||||
|
|
||||||
private Disposable getDebouncedLoader() {
|
private Disposable getDebouncedLoader() {
|
||||||
return debouncedSignal.mergeWith(nearEndIntervalSignal)
|
return debouncedSignal.mergeWith(nearEndIntervalSignal)
|
||||||
.debounce(loadDebounceMillis, TimeUnit.MILLISECONDS)
|
.debounce(loadDebounceMillis, TimeUnit.MILLISECONDS)
|
||||||
|
.subscribeOn(Schedulers.single())
|
||||||
.observeOn(AndroidSchedulers.mainThread())
|
.observeOn(AndroidSchedulers.mainThread())
|
||||||
.subscribe(timestamp -> loadImmediate());
|
.subscribe(timestamp -> loadImmediate());
|
||||||
}
|
}
|
||||||
|
@ -352,7 +357,7 @@ public class MediaSourceManager {
|
||||||
debouncedSignal.onNext(System.currentTimeMillis());
|
debouncedSignal.onNext(System.currentTimeMillis());
|
||||||
}
|
}
|
||||||
|
|
||||||
private synchronized void loadImmediate() {
|
private void loadImmediate() {
|
||||||
if (DEBUG) Log.d(TAG, "MediaSource - loadImmediate() called");
|
if (DEBUG) Log.d(TAG, "MediaSource - loadImmediate() called");
|
||||||
final ItemsToLoad itemsToLoad = getItemsToLoad(playQueue, WINDOW_SIZE);
|
final ItemsToLoad itemsToLoad = getItemsToLoad(playQueue, WINDOW_SIZE);
|
||||||
if (itemsToLoad == null) return;
|
if (itemsToLoad == null) return;
|
||||||
|
@ -411,7 +416,7 @@ public class MediaSourceManager {
|
||||||
|
|
||||||
final int itemIndex = playQueue.indexOf(item);
|
final int itemIndex = playQueue.indexOf(item);
|
||||||
// Only update the playlist timeline for items at the current index or after.
|
// Only update the playlist timeline for items at the current index or after.
|
||||||
if (itemIndex >= playQueue.getIndex() && isCorrectionNeeded(item)) {
|
if (isCorrectionNeeded(item)) {
|
||||||
if (DEBUG) Log.d(TAG, "MediaSource - Updating index=[" + itemIndex + "] with " +
|
if (DEBUG) Log.d(TAG, "MediaSource - Updating index=[" + itemIndex + "] with " +
|
||||||
"title=[" + item.getTitle() + "] at url=[" + item.getUrl() + "]");
|
"title=[" + item.getTitle() + "] at url=[" + item.getUrl() + "]");
|
||||||
playlist.update(itemIndex, mediaSource, this::maybeSynchronizePlayer);
|
playlist.update(itemIndex, mediaSource, this::maybeSynchronizePlayer);
|
||||||
|
|
|
@ -13,13 +13,13 @@ import java.util.List;
|
||||||
public interface PlaybackListener {
|
public interface PlaybackListener {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Called to check if the currently playing stream is close to the end of its playback.
|
* Called to check if the currently playing stream is approaching the end of its playback.
|
||||||
* Implementation should return true when the current playback position is within
|
* Implementation should return true when the current playback position is progressing within
|
||||||
* timeToEndMillis or less until its playback completes or transitions.
|
* timeToEndMillis or less to its playback during.
|
||||||
*
|
*
|
||||||
* May be called at any time.
|
* May be called at any time.
|
||||||
* */
|
* */
|
||||||
boolean isNearPlaybackEdge(final long timeToEndMillis);
|
boolean isApproachingPlaybackEdge(final long timeToEndMillis);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Called when the stream at the current queue index is not ready yet.
|
* Called when the stream at the current queue index is not ready yet.
|
||||||
|
|
Loading…
Reference in New Issue