Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Refactor existing callbacks into interface #1575

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@
import kotlin.Lazy;
import timber.log.Timber;

public class PlaybackController {
public class PlaybackController implements PlaybackControllerNotifiable {
nielsvanvelzen marked this conversation as resolved.
Show resolved Hide resolved
// Frequency to report playback progress
private final static long PROGRESS_REPORTING_INTERVAL = TimeUtils.secondsToMillis(3);
// Frequency to report paused state
Expand Down Expand Up @@ -143,11 +143,11 @@ public CustomPlaybackOverlayFragment getFragment() {
return mFragment;
}

public void init(VideoManager mgr, CustomPlaybackOverlayFragment fragment) {
public void init(@NonNull VideoManager mgr, @NonNull CustomPlaybackOverlayFragment fragment) {
mVideoManager = mgr;
mVideoManager.subscribe(this);
mFragment = fragment;
directStreamLiveTv = userPreferences.getValue().get(UserPreferences.Companion.getLiveTvDirectPlayEnabled());
setupCallbacks();
}

public void setItems(List<BaseItemDto> items) {
Expand Down Expand Up @@ -1396,107 +1396,98 @@ private void itemComplete() {
}
}

private void setupCallbacks() {

mVideoManager.setOnErrorListener(new PlaybackListener() {

@Override
public void onEvent() {
if (mFragment == null) {
playerErrorEncountered();
return;
}

if (isLiveTv && directStreamLiveTv) {
Utils.showToast(mFragment.getContext(), mFragment.getString(R.string.msg_error_live_stream));
directStreamLiveTv = false;
} else {
String msg = mFragment.getString(R.string.video_error_unknown_error);
Timber.e("Playback error - %s", msg);
}
playerErrorEncountered();
}
});

@Override
public void onPlaybackSpeedChange(float newSpeed) {
// TODO, implement speed change handling
}

mVideoManager.setOnPreparedListener(new PlaybackListener() {
@Override
public void onEvent() {
if (mPlaybackState == PlaybackState.BUFFERING) {
if (mFragment != null) mFragment.setFadingEnabled(true);
@Override
public void onPrepared() {
if (mPlaybackState == PlaybackState.BUFFERING) {
if (mFragment != null) mFragment.setFadingEnabled(true);

mPlaybackState = PlaybackState.PLAYING;
mCurrentTranscodeStartTime = mCurrentStreamInfo.getPlayMethod() == PlayMethod.Transcode ? System.currentTimeMillis() : 0;
startReportLoop();
}
mPlaybackState = PlaybackState.PLAYING;
mCurrentTranscodeStartTime = mCurrentStreamInfo.getPlayMethod() == PlayMethod.Transcode ? System.currentTimeMillis() : 0;
startReportLoop();
}

Timber.i("Play method: %s", mCurrentStreamInfo.getPlayMethod() == PlayMethod.Transcode ? "Trans" : "Direct");
Timber.i("Play method: %s", mCurrentStreamInfo.getPlayMethod() == PlayMethod.Transcode ? "Trans" : "Direct");

if (mPlaybackState == PlaybackState.PAUSED) {
mPlaybackState = PlaybackState.PLAYING;
} else {
// select or disable subtitles
Integer currentSubtitleIndex = mCurrentOptions.getSubtitleStreamIndex();
if (mDefaultSubIndex >= 0 && currentSubtitleIndex != null && currentSubtitleIndex == mDefaultSubIndex) {
Timber.i("subtitle stream %s is already selected", mDefaultSubIndex);
} else {
if (mDefaultSubIndex < 0)
Timber.i("Turning off subs");
else
Timber.i("Enabling default sub stream: %d", mDefaultSubIndex);
switchSubtitleStream(mDefaultSubIndex);
}
if (mPlaybackState == PlaybackState.PAUSED) {
mPlaybackState = PlaybackState.PLAYING;
} else {
// select or disable subtitles
Integer currentSubtitleIndex = mCurrentOptions.getSubtitleStreamIndex();
if (mDefaultSubIndex >= 0 && currentSubtitleIndex != null && currentSubtitleIndex == mDefaultSubIndex) {
Timber.i("subtitle stream %s is already selected", mDefaultSubIndex);
} else {
if (mDefaultSubIndex < 0)
Timber.i("Turning off subs");
else
Timber.i("Enabling default sub stream: %d", mDefaultSubIndex);
switchSubtitleStream(mDefaultSubIndex);
}

// select an audio track
int eligibleAudioTrack = mDefaultAudioIndex;
// select an audio track
int eligibleAudioTrack = mDefaultAudioIndex;

// if track switching is done without rebuilding the stream, mCurrentOptions is updated
// otherwise, use the server default
if (mCurrentOptions.getAudioStreamIndex() != null) {
eligibleAudioTrack = mCurrentOptions.getAudioStreamIndex();
} else if (getCurrentMediaSource().getDefaultAudioStreamIndex() != null) {
eligibleAudioTrack = getCurrentMediaSource().getDefaultAudioStreamIndex();
}
switchAudioStream(eligibleAudioTrack);
}
// if track switching is done without rebuilding the stream, mCurrentOptions is updated
// otherwise, use the server default
if (mCurrentOptions.getAudioStreamIndex() != null) {
eligibleAudioTrack = mCurrentOptions.getAudioStreamIndex();
} else if (getCurrentMediaSource().getDefaultAudioStreamIndex() != null) {
eligibleAudioTrack = getCurrentMediaSource().getDefaultAudioStreamIndex();
}
});
switchAudioStream(eligibleAudioTrack);
}
}

@Override
public void onError() {
if (mFragment == null) {
playerErrorEncountered();
return;
}

mVideoManager.setOnProgressListener(new PlaybackListener() {
@Override
public void onEvent() {
refreshCurrentPosition();
if (isPlaying()) {
if (!spinnerOff) {
if (mStartPosition > 0) {
initialSeek(mStartPosition);
mStartPosition = 0;
} else {
finishedInitialSeek = true;
stopSpinner();
}
}
if (isLiveTv && directStreamLiveTv) {
Utils.showToast(mFragment.getContext(), mFragment.getString(R.string.msg_error_live_stream));
directStreamLiveTv = false;
} else {
String msg = mFragment.getString(R.string.video_error_unknown_error);
Timber.e("Playback error - %s", msg);
}
playerErrorEncountered();
}

if (isLiveTv && mCurrentProgramEndTime > 0 && System.currentTimeMillis() >= mCurrentProgramEndTime) {
// crossed fire off an async routine to update the program info
updateTvProgramInfo();
}
if (mFragment != null && finishedInitialSeek)
mFragment.updateSubtitles(mCurrentPosition);
@Override
public void onCompletion() {
Timber.d("On Completion fired");
itemComplete();
}

@Override
public void onProgress() {
refreshCurrentPosition();
if (isPlaying()) {
if (!spinnerOff) {
if (mStartPosition > 0) {
initialSeek(mStartPosition);
mStartPosition = 0;
} else {
finishedInitialSeek = true;
stopSpinner();
}
if (mFragment != null)
mFragment.setCurrentTime(mCurrentPosition);
}
});

mVideoManager.setOnCompletionListener(new PlaybackListener() {
@Override
public void onEvent() {
Timber.d("On Completion fired");
itemComplete();
if (isLiveTv && mCurrentProgramEndTime > 0 && System.currentTimeMillis() >= mCurrentProgramEndTime) {
// crossed fire off an async routine to update the program info
updateTvProgramInfo();
}
});
if (mFragment != null && finishedInitialSeek)
mFragment.updateSubtitles(mCurrentPosition);
}
if (mFragment != null)
mFragment.setCurrentTime(mCurrentPosition);
}

public long getDuration() {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
package org.jellyfin.androidtv.ui.playback

interface PlaybackControllerNotifiable {
fun onCompletion()
fun onError()
fun onPrepared()
fun onProgress()
fun onPlaybackSpeedChange(newSpeed: Float)
}
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,7 @@ public class VideoManager implements IVLCVout.OnNewVideoLayoutListener {
private int mZoomMode = ZOOM_FIT;

private PlaybackOverlayActivity mActivity;
private PlaybackControllerNotifiable mPlaybackControllerNotifiable;
private SurfaceHolder mSurfaceHolder;
private SurfaceView mSurfaceView;
private SurfaceView mSubtitlesSurface;
Expand Down Expand Up @@ -88,9 +89,6 @@ public class VideoManager implements IVLCVout.OnNewVideoLayoutListener {
private boolean nativeMode = false;
private boolean mSurfaceReady = false;
public boolean isContracted = false;
private PlaybackListener errorListener;
private PlaybackListener completionListener;
private PlaybackListener preparedListener;

public VideoManager(PlaybackOverlayActivity activity, View view) {
mActivity = activity;
Expand All @@ -114,14 +112,14 @@ public VideoManager(PlaybackOverlayActivity activity, View view) {
@Override
public void onPlayerError(@NonNull PlaybackException error) {
Timber.e("***** Got error from player");
if (errorListener != null) errorListener.onEvent();
if (mPlaybackControllerNotifiable != null) mPlaybackControllerNotifiable.onError();
stopProgressLoop();
}

@Override
public void onIsPlayingChanged(boolean isPlaying) {
if (isPlaying) {
if (preparedListener != null) preparedListener.onEvent();
if (mPlaybackControllerNotifiable != null) mPlaybackControllerNotifiable.onPrepared();
startProgressLoop();
} else {
stopProgressLoop();
Expand All @@ -135,11 +133,18 @@ public void onPlaybackStateChanged(int playbackState) {
}

if (playbackState == Player.STATE_ENDED) {
if (completionListener != null) completionListener.onEvent();
if (mPlaybackControllerNotifiable != null) mPlaybackControllerNotifiable.onCompletion();
stopProgressLoop();
}
}

@Override
public void onPlaybackParametersChanged(@NonNull PlaybackParameters playbackParameters) {
if (mPlaybackControllerNotifiable != null){
mPlaybackControllerNotifiable.onPlaybackSpeedChange(playbackParameters.speed);
}
}

@Override
public void onPositionDiscontinuity(@NonNull Player.PositionInfo oldPosition, @NonNull Player.PositionInfo newPosition, int reason) {
// discontinuity for reason internal usually indicates an error, and that the player will reset to its default timestamp
Expand All @@ -161,6 +166,11 @@ public void onTracksInfoChanged(TracksInfo tracksInfo) {
});
}

public void subscribe(@NonNull PlaybackControllerNotifiable notifier){
mPlaybackControllerNotifiable = notifier;
setupVLCListeners();
}

/**
* Configures Exoplayer for video playback. Initially we try with core decoders, but allow
* ExoPlayer to silently fallback to software renderers.
Expand Down Expand Up @@ -686,6 +696,10 @@ public void setPlaybackSpeed(float speed) {
mExoPlayer.setPlaybackParameters(new PlaybackParameters(speed));
} else {
mVlcPlayer.setRate(speed);
// VLC will always change rate, so we can post this immediately
if (mPlaybackControllerNotifiable != null){
mPlaybackControllerNotifiable.onPlaybackSpeedChange(speed);
}
}
}

Expand Down Expand Up @@ -741,6 +755,7 @@ public org.videolan.libvlc.MediaPlayer.TrackDescription[] getSubtitleTracks() {
}

public void destroy() {
mPlaybackControllerNotifiable = null;
stopPlayback();
releasePlayer();
}
Expand Down Expand Up @@ -814,7 +829,6 @@ private void releasePlayer() {
mExoPlayer.release();
mExoPlayer = null;
}
clearPlayerListeners();
}

int normalWidth;
Expand Down Expand Up @@ -929,43 +943,36 @@ private void changeSurfaceLayout(int videoWidth, int videoHeight, int videoVisib
mSubtitlesSurface.invalidate();
}

public void setOnErrorListener(final PlaybackListener listener) {
mVlcHandler.setOnErrorListener(listener);
errorListener = listener;
}

public void setOnCompletionListener(final PlaybackListener listener) {
completionListener = listener;
mVlcHandler.setOnCompletionListener(listener);
}

public void setOnPreparedListener(final PlaybackListener listener) {
preparedListener = listener;

mVlcHandler.setOnPreparedListener(listener);
}

public void setOnProgressListener(PlaybackListener listener) {
progressListener = listener;
mVlcHandler.setOnProgressListener(listener);
}

public void clearPlayerListeners() {
mVlcHandler.setOnErrorListener(null);
mVlcHandler.setOnCompletionListener(null);
mVlcHandler.setOnPreparedListener(null);
mVlcHandler.setOnProgressListener(null);
private void setupVLCListeners() {
mVlcHandler.setOnCompletionListener(() -> {
if (mPlaybackControllerNotifiable != null) {
mPlaybackControllerNotifiable.onCompletion();
}
});
mVlcHandler.setOnErrorListener(() -> {
if (mPlaybackControllerNotifiable != null) {
mPlaybackControllerNotifiable.onError();
}
});
mVlcHandler.setOnPreparedListener(() -> {
if (mPlaybackControllerNotifiable != null) {
mPlaybackControllerNotifiable.onPrepared();
}
});
mVlcHandler.setOnProgressListener(() -> {
if (mPlaybackControllerNotifiable != null) {
mPlaybackControllerNotifiable.onProgress();
}
});
}

private PlaybackListener progressListener;
private Runnable progressLoop;

private void startProgressLoop() {
stopProgressLoop();
progressLoop = new Runnable() {
@Override
public void run() {
if (progressListener != null) progressListener.onEvent();
if (mPlaybackControllerNotifiable != null) mPlaybackControllerNotifiable.onProgress();
mHandler.postDelayed(this, 500);
}
};
Expand Down