Two classes are provided to facilitate the development of custom player controls -
CustomAudioPlayer and CustomVideoPlayer. Both classes are in
the com.bramosystems.oss.player.core.client.skin package.
Both implementation takes care of the media player plugin integration. All that is required is the development of the UI controls and how it reacts to the state of the underlying media plugin.
As the names suggest, CustomAudioPlayer is provided for custom audio player
controls while CustomVideoPlayer is provided for custom video player controls.
CustomAudioPlayer integrates the player plugin and makes it invisible on
the page. But CustomVideoPlayer makes the player plugin visible replacing
the plugins' controls with that specified by you - that is, the video display is placed
directly on top of the player controls.
The ability to seek through media playback in an important feature of media players. The API provides simple implementation that can be customised to taste.
The MediaSeekBar abstract class in the
com.bramosystems.oss.player.core.client.skin package presents two indicators -
loading and progress indicators. The loading indicator is placed directly under the
playing indicator. The loading indicator shows the progress of a media loading
operation while the playing indicator shows the progress of media playback. The length of
both indicators show the progress of the operation they represent.
An implementation of the MediaSeekBar - the CSSSeekBar class,
provides the ability to customise the appearance of the seekbar via CSS. The class defines
the following CSS styles:
.player-CSSSeekBar { the seekbar itself }
.player-CSSSeekBar .loading { the loading progress indicator }
.player-CSSSeekBar .playing { the playing progress indicator }This example illustrates how simple it can be:
public class MyPlayer extends CustomAudioPlayer {
public MyPlayer(String url, String height, String width) throws
PluginNotFoundException, PluginVersionException, LoadException {
super(Plugin.Auto, url, false, height, width);
// of course, you can specify any plugin you wish
// create the UI components
Button play = new Button("Play", new ClickHandler() {
@Override
public void onClick(ClickEvent event) {
try {
playMedia();
} catch (PlayException ex) {}
}
});
Button pause = new Button("Pause", new ClickHandler() {
@Override
public void onClick(ClickEvent event) {
pauseMedia();
}
});
Button stop = new Button("Stop", new ClickHandler() {
@Override
public void onClick(ClickEvent event) {
stopMedia();
}
});
Label label = new Label("0 / 0");
// create a seekbar with CSS styling ...
CSSSeekBar seekbar = new CSSSeekBar(10);
seekbar.addSeekChangeHandler(new SeekChangeHandler() {
// change play position when the seek is changed by user
@Override
public void onSeekChanged(SeekChangeEvent event) {
setPlayPosition(event.getSeekPosition() * getMediaDuration());
}
});
// arrange the UI
FlowPanel fp = new FlowPanel();
fp.setStyleName("my-style");
fp.add(seekbar);
fp.add(play);
fp.add(pause);
fp.add(stop);
fp.add(label);
// put the player control on the panel < IMPORTANT >
setPlayerControlWidget(fp);
// update controls based on playback state ...
addPlayStateHandler(new PlayStateHandler() {
@Override
public void onPlayStateChanged(PlayStateEvent event) {
switch(event.getPlayState()) {
case Paused:
play.setEnabled(false);
pause.setEnabled(true);
stop.setEnabled(false);
break;
case Started:
play.setEnabled(true);
pause.setEnabled(false);
stop.setEnabled(false);
break;
case Stopped:
case Finished:
play.setEnabled(false);
pause.setEnabled(true);
stop.setEnabled(true);
break;
}
}
});
// monitor loading progress and indicate on seekbar
addLoadingProgressHandler(new LoadingProgressHandler() {
@Override
public void onLoadingProgress(LoadingProgressEvent event) {
seekbar.setLoadingProgress(event.getProgress());
}
});
// monitor playing progress & update timer display ...
Timer timer = new Timer() {
@Override
public void run() {
seekbar.setPlayingProgress(getPlayPosition() /
getMediaDuration());
label.setText((getPlayPosition() / 1000) + " / " +
(getMediaDuration() / 1000));
}
};
timer.scheduleRepeating(1000);
}
}It is as simple as that, isn't it? :-)