Controlling playback and zapping between streams
To view and test the full “controlbar” example code referenced here, please see the (5.33.x) Android SDK 5 Example Code Quick Start guide.
The CONNECT Player does not provide a control bar UI for pausing, playing and seeking through content, or zapping between different content, so the application must provide one. There is an implementation of a control bar provided in the example code that provides guidance.
Note that the OTVVideoView
class requires all operations to be executed from the Android app's UI thread. This is particularly important when we want the application to act programatically to events, which may be triggered in background threads.
Pause and play
The play and pause button - here named mPlayButton
- is provided with an OnClickListener
object that will pause or resume the content as appropriate. It will then update the button to display a play or pause icon.
private final OnClickListener mPlayListener = new OnClickListener() {
@Override
public void onClick(View view) {
showController(VIEW_TIMEOUT_DELAY);
if(mPlayerView.isPlaying()){
mPlayerView.pause();
} else {
mPlayerView.start();
}
updateButtonImage();
}
};
public void updateButtonImage() {
// ...
if (mPlayerView.isPlaying()) {
mPlayButton.setImageResource(R.drawable.pause_light);
} else {
mPlayButton.setImageResource(R.drawable.play_light);
}
// ...
}
Find the play/pause button in the layout, and attach OnClickListener:
mPlayButton = mControllerView.findViewById(R.id.play_btn);
mPlayButton.setOnClickListener(mPlayListener);
Seeking
The example code demonstrates two methods of seeking: Using a seekbar (sometimes referred to as a scrubber) to seek to arbitrary points in the content, and fast-forward and rewind buttons to seek in ten-second increments.
Using a seek bar
Android provides the SeekBar class that is instantiated in the layout - here it is called mProgress - and the example code provides the implementation of the OnSeekBarChangeListener that defines what happens when the user interacts with the SeekBar.
onProgressChanged() will track the location of the cursor on the SeekBar to determine where in the stream to seek. If the seek is performed using the fast-forward or rewind button, it will also perform the seek
onStartTrackingTouch() will ensure the controller remains on screen while the seeking is being performed
onStopTrackingTouch() will perform a seek when the cursor is released (or no longer being moved)
handleVodProgress() will update the UI to show the current position and length of a VOD stream
handleLiveProgress() will update the to UI to show how far the stream is behind the live broadcast
private OnSeekBarChangeListener mSeekListener = new OnSeekBarChangeListener() {
@Override
public void onStartTrackingTouch(SeekBar bar) {
showController(VIEW_TIMEOUT_DELAY);
setSeeking(true);
}
@Override
public void onStopTrackingTouch(SeekBar bar) {
if (mSeekingTouch) {
mPlayerView.seekTo(mSeekedTime);
}
setSeeking(false);
mPlayerView.resume();
}
@Override
public void onProgressChanged(SeekBar bar, int progress, boolean fromuser) {
mSeekedTime = progress;
if(mSeekingButton){
//seek on button press
mPlayerView.seekTo(mSeekedTime);
}
if (mProgress != null) {
//get duration returns -1 for live streams, can be used to tell between vod/live
if (mPlayerView.getDuration() > 0) {
// VOD Content
handleVodProgress();
} else {
// Live Content
handleLiveProgress();
}
}
// ...
}
};
// ...
private void setSeeking(boolean seeking) {
if (mSeekingTouch && !seeking) {
mPlayerView.seekTo(mSeekedTime);
mPlayerView.setOnSeekCompleteListener(new MediaPlayer.OnSeekCompleteListener() {
@Override
public void onSeekComplete(MediaPlayer mediaPlayer) {
startProgressUpdater();
}
});
}
mSeekingTouch = seeking;
}
The OnSeekBarChangeListener
must be attached to the SeekBar in the layout:
private SeekBar mProgress;
// ...
mProgress = mControllerView.findViewById(R.id.mediacontroller_progress);
mProgress.setOnSeekBarChangeListener(mSeekListener);
Fast-forward and rewind buttons
The fast-forward and rewind buttons will get the current position in the stream, calculate a point ten seconds ahead or behind, and then update the SeekBar with the calculated position. This will then trigger the SeekBar’s onProgressChanged()
method that will perform the actual seek operation.
The fast-forward implementation is shown below. The rewind operation has been omitted for brevity.
private final OnClickListener mFastForwardListener = new OnClickListener() {
@Override
public void onClick(View view) {
showController(VIEW_TIMEOUT_DELAY);
int skipTime = 10000;
int currentTime = mPlayerView.getCurrentPosition();
int seekPos = currentTime + skipTime;
mSeekingButton = true;
//if live make sure that seek pos is less than seekable range. if you would seek past end, does not seek
if((mPlayerView.getSeekableRangeInfo() != null && mPlayerView.getSeekableRangeInfo()[1] > seekPos) || seekPos < mPlayerView.getDuration()){
mProgress.setProgress(seekPos);
} else {
mProgress.setProgress(mPlayerView.getDuration());
}
mSeekingButton = false;
}
};
Zapping
The example code provides a simplified implementation using buttons with hard-coded stream URIs.
Zapping to different content is done by calling OTVVideoView’s setVideoPath() method which handles the player lifecycle and plays the selected content:
private final View.OnClickListener mClickListener = (view -> {
if(mCurrentStream != ((Button) view).getText().toString()){
//...
switch (mCurrentStream){
case "Clear Stream":
mOTVVideoView.setVideoPath(STREAM_URI_CLEAR);
break;
case "Live Stream":
mOTVVideoView.setVideoPath(STREAM_URI_LIVE);
break;
case "Multi Audio":
mOTVVideoView.setVideoPath(STREAM_URI_AUDIO);
break;
case "Subtitles":
mOTVVideoView.setVideoPath(STREAM_URI_SUBTITLE);
break;
default:
return;
}
}
});
Stopping playback
This is not demonstrated in the control bar example
To stop the currently-playing content - usually to return to the previous screen, for instance a main menu - the SDK provides the stopPlayback method.
mOTVVideoView.stopPlayback();