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? :-)