-Added on change event bus to Play Queue.
-Added playback manager for player interaction.
This commit is contained in:
parent
7c9c3de644
commit
dcdcf17f5e
9 changed files with 419 additions and 122 deletions
|
|
@ -47,9 +47,7 @@ import com.google.android.exoplayer2.RenderersFactory;
|
|||
import com.google.android.exoplayer2.SimpleExoPlayer;
|
||||
import com.google.android.exoplayer2.Timeline;
|
||||
import com.google.android.exoplayer2.extractor.DefaultExtractorsFactory;
|
||||
import com.google.android.exoplayer2.source.DynamicConcatenatingMediaSource;
|
||||
import com.google.android.exoplayer2.source.ExtractorMediaSource;
|
||||
import com.google.android.exoplayer2.source.LoopingMediaSource;
|
||||
import com.google.android.exoplayer2.source.MediaSource;
|
||||
import com.google.android.exoplayer2.source.TrackGroupArray;
|
||||
import com.google.android.exoplayer2.source.dash.DashMediaSource;
|
||||
|
|
@ -72,6 +70,7 @@ import com.nostra13.universalimageloader.core.listener.SimpleImageLoadingListene
|
|||
|
||||
import org.schabi.newpipe.Downloader;
|
||||
import org.schabi.newpipe.R;
|
||||
import org.schabi.newpipe.playlist.PlayQueue;
|
||||
|
||||
import java.io.File;
|
||||
import java.text.DecimalFormat;
|
||||
|
|
@ -86,9 +85,9 @@ import java.util.concurrent.atomic.AtomicBoolean;
|
|||
* @author mauriciocolli
|
||||
*/
|
||||
@SuppressWarnings({"WeakerAccess", "unused"})
|
||||
public abstract class BasePlayer implements Player.EventListener, AudioManager.OnAudioFocusChangeListener {
|
||||
public abstract class BasePlayer implements Player.EventListener,
|
||||
AudioManager.OnAudioFocusChangeListener, PlaybackManager.PlaybackListener {
|
||||
// TODO: Check api version for deprecated audio manager methods
|
||||
|
||||
public static final boolean DEBUG = false;
|
||||
public static final String TAG = "BasePlayer";
|
||||
|
||||
|
|
@ -117,6 +116,13 @@ public abstract class BasePlayer implements Player.EventListener, AudioManager.O
|
|||
protected long videoStartPos = -1;
|
||||
protected String uploaderName = "";
|
||||
|
||||
/*//////////////////////////////////////////////////////////////////////////
|
||||
// Playlist
|
||||
//////////////////////////////////////////////////////////////////////////*/
|
||||
|
||||
protected PlaybackManager playbackManager;
|
||||
protected PlayQueue playQueue;
|
||||
|
||||
/*//////////////////////////////////////////////////////////////////////////
|
||||
// Player
|
||||
//////////////////////////////////////////////////////////////////////////*/
|
||||
|
|
@ -540,6 +546,22 @@ public abstract class BasePlayer implements Player.EventListener, AudioManager.O
|
|||
|
||||
@Override
|
||||
public void onPositionDiscontinuity() {
|
||||
int newIndex = simpleExoPlayer.getCurrentWindowIndex();
|
||||
|
||||
}
|
||||
|
||||
/*//////////////////////////////////////////////////////////////////////////
|
||||
// Playback Listener
|
||||
//////////////////////////////////////////////////////////////////////////*/
|
||||
|
||||
@Override
|
||||
public void block() {
|
||||
if (currentState != STATE_LOADING) changeState(STATE_LOADING);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void unblock() {
|
||||
if (currentState != STATE_PLAYING) changeState(STATE_PLAYING);
|
||||
}
|
||||
|
||||
/*//////////////////////////////////////////////////////////////////////////
|
||||
|
|
|
|||
|
|
@ -3,31 +3,200 @@ package org.schabi.newpipe.player;
|
|||
import com.google.android.exoplayer2.source.DynamicConcatenatingMediaSource;
|
||||
import com.google.android.exoplayer2.source.MediaSource;
|
||||
|
||||
import org.reactivestreams.Subscriber;
|
||||
import org.reactivestreams.Subscription;
|
||||
import org.schabi.newpipe.extractor.stream_info.StreamInfo;
|
||||
import org.schabi.newpipe.playlist.PlayQueue;
|
||||
import org.schabi.newpipe.playlist.PlayQueueEvent;
|
||||
import org.schabi.newpipe.playlist.PlayQueueItem;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
import io.reactivex.Maybe;
|
||||
import io.reactivex.annotations.NonNull;
|
||||
|
||||
public class PlaybackManager {
|
||||
|
||||
private DynamicConcatenatingMediaSource source;
|
||||
private DynamicConcatenatingMediaSource mediaSource;
|
||||
private List<PlayQueueItem> queueSource;
|
||||
private int sourceIndex;
|
||||
|
||||
private PlaybackListener listener;
|
||||
private PlayQueue playQueue;
|
||||
private int index;
|
||||
|
||||
private List<MediaSource> sources;
|
||||
|
||||
public PlaybackManager(PlayQueue playQueue, int index) {
|
||||
this.source = new DynamicConcatenatingMediaSource();
|
||||
|
||||
this.playQueue = playQueue;
|
||||
this.index = index;
|
||||
|
||||
private Subscription playQueueReactor;
|
||||
|
||||
interface PlaybackListener {
|
||||
void block();
|
||||
void unblock();
|
||||
void sync();
|
||||
|
||||
MediaSource sourceOf(StreamInfo info);
|
||||
}
|
||||
|
||||
interface OnChangeListener {
|
||||
void isLoading();
|
||||
void isLoaded();
|
||||
public PlaybackManager(@NonNull final PlaybackListener listener,
|
||||
@NonNull final PlayQueue playQueue) {
|
||||
this.mediaSource = new DynamicConcatenatingMediaSource();
|
||||
this.queueSource = Collections.synchronizedList(new ArrayList<PlayQueueItem>(10));
|
||||
this.sourceIndex = 0;
|
||||
|
||||
this.listener = listener;
|
||||
this.playQueue = playQueue;
|
||||
|
||||
playQueue.getPlayQueueFlowable().subscribe(getReactor());
|
||||
}
|
||||
|
||||
@NonNull
|
||||
public DynamicConcatenatingMediaSource getMediaSource() {
|
||||
return mediaSource;
|
||||
}
|
||||
|
||||
private void reload() {
|
||||
listener.block();
|
||||
load(0);
|
||||
}
|
||||
|
||||
public void refreshMedia(final int newMediaIndex) {
|
||||
if (newMediaIndex == sourceIndex) return;
|
||||
|
||||
if (newMediaIndex == sourceIndex + 1) {
|
||||
playQueue.incrementIndex();
|
||||
mediaSource.removeMediaSource(0);
|
||||
queueSource.remove(0);
|
||||
} else {
|
||||
//something went wrong
|
||||
onInit();
|
||||
}
|
||||
}
|
||||
|
||||
private void removeCurrent() {
|
||||
listener.block();
|
||||
mediaSource.removeMediaSource(0);
|
||||
queueSource.remove(0);
|
||||
listener.unblock();
|
||||
}
|
||||
|
||||
private Subscription loaderReactor;
|
||||
|
||||
private void load() {
|
||||
if (mediaSource.getSize() < 5 && queueSource.size() < 5) load(mediaSource.getSize());
|
||||
}
|
||||
|
||||
private void load(final int from) {
|
||||
clear(from);
|
||||
|
||||
if (loaderReactor != null) loaderReactor.cancel();
|
||||
|
||||
List<Maybe<StreamInfo>> maybes = new ArrayList<>();
|
||||
for (int i = from; i < 5; i++) {
|
||||
final int index = playQueue.getIndex() + i;
|
||||
final PlayQueueItem item = playQueue.get(index);
|
||||
queueSource.set(i, item);
|
||||
maybes.add(item.getStream());
|
||||
}
|
||||
|
||||
Maybe.concat(maybes).subscribe(new Subscriber<StreamInfo>() {
|
||||
@Override
|
||||
public void onSubscribe(Subscription s) {
|
||||
loaderReactor = s;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onNext(StreamInfo streamInfo) {
|
||||
mediaSource.addMediaSource(listener.sourceOf(streamInfo));
|
||||
onLoaded();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onError(Throwable t) {
|
||||
playQueue.remove(queueSource.size());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onComplete() {
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void onLoaded() {
|
||||
if (mediaSource.getSize() > 0 && queueSource.size() > 0) listener.unblock();
|
||||
}
|
||||
|
||||
private void onInit() {
|
||||
listener.block();
|
||||
load();
|
||||
}
|
||||
|
||||
private void clear(int from) {
|
||||
listener.block();
|
||||
while (mediaSource.getSize() > from) {
|
||||
queueSource.remove(from);
|
||||
mediaSource.removeMediaSource(from);
|
||||
}
|
||||
listener.unblock();
|
||||
}
|
||||
|
||||
private Subscriber<PlayQueueEvent> getReactor() {
|
||||
return new Subscriber<PlayQueueEvent>() {
|
||||
@Override
|
||||
public void onSubscribe(@NonNull Subscription d) {
|
||||
if (playQueueReactor != null) playQueueReactor.cancel();
|
||||
playQueueReactor = d;
|
||||
playQueueReactor.request(1);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onNext(@NonNull PlayQueueEvent event) {
|
||||
if (playQueue.getStreams().size() - playQueue.getIndex() < 10 && !playQueue.isComplete()) {
|
||||
listener.block();
|
||||
playQueue.fetch();
|
||||
}
|
||||
|
||||
switch (event) {
|
||||
case INIT:
|
||||
onInit();
|
||||
break;
|
||||
case APPEND:
|
||||
load();
|
||||
break;
|
||||
case REMOVE_CURRENT:
|
||||
removeCurrent();
|
||||
load();
|
||||
break;
|
||||
case SELECT:
|
||||
reload();
|
||||
break;
|
||||
case REMOVE:
|
||||
case SWAP:
|
||||
load(1);
|
||||
break;
|
||||
case CLEAR:
|
||||
clear(0);
|
||||
break;
|
||||
case NEXT:
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
onLoaded();
|
||||
if (playQueueReactor != null) playQueueReactor.request(1);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onError(@NonNull Throwable e) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onComplete() {
|
||||
// Never completes, only canceled
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
public void dispose() {
|
||||
if (playQueueReactor != null) playQueueReactor.cancel();
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue