Handling Exoplayer events
Hello every one! In our pervious exoplayer tutorials we have created our own media player and also customized their UI components. In this tutorial we will look at the Exoplayer events and implement these events in our project.
Let’s get started…
For event handling in exoplayer lets see the Eventlistener interface methods.
@Override
public void onTimelineChanged(Timeline timeline, Object manifest) {
}
@Override
public void onTracksChanged(TrackGroupArray trackGroups, TrackSelectionArray trackSelections) {
}
@Override
public void onLoadingChanged(boolean isLoading) {
}
@Override
public void onPlayerStateChanged(boolean playWhenReady, int playbackState) {
}
@Override
public void onRepeatModeChanged(int repeatMode) {
}
@Override
public void onPlayerError(ExoPlaybackException error) {
}
@Override
public void onPositionDiscontinuity() {
}
@Override
public void onPlaybackParametersChanged(PlaybackParameters playbackParameters) {
}
Here we can see that the player state can be found from onPlayerStateChanged(boolean playWhenReady,int playbackState). The playbackState variable gives us the state like buffering,ready,idle,start and end. Similarly with onPlayerError(ExoPlaybackException error) function we can find the error that occurs while the media is being played. In the same way onTracksChanged(TrackGroupArray trackGroups,TrackSelectionArray trackSelections) function gives us information when new track is switched. Now let us setup our goals.Our goals are:
- To show the currently playing track.
- To show buffering and playing.
- To show error if error occures while playing.
Now lets change activity_main.xml as:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
tools:context="player.abhijet.dynamicplayer.MainActivity">
<Button
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Add Media"
android:id="@+id/add_media"/>
<com.google.android.exoplayer2.ui.SimpleExoPlayerView android:id="@+id/player_view"
android:layout_width="match_parent"
android:layout_height="300dp"
app:controller_layout_id="@layout/playback_control_view">
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="@+id/state_holder"
android:visibility="gone"
android:background="#CCDEDEDE">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerInParent="true"
android:textSize="15dp"
android:id="@+id/state_text"/>
</RelativeLayout>
</com.google.android.exoplayer2.ui.SimpleExoPlayerView>
</LinearLayout>
Lets see what we have done. If we look at SimpleExoplayerView class we can see that it extends FrameLayout. Hence if we add a RelativeLayout under it we can give space to show different player states like buffering and errors. We have added a TextView to center of that RelativeLayout. This TextView will show the player states.
Finalizing..
Once we have done this much there is very little left to do. Lets go to Player.java and change the code as :
public class Player implements com.google.android.exoplayer2.Player.EventListener {
private Context context;
private DynamicConcatenatingMediaSource dynamicConcatenatingMediaSource;
private SimpleExoPlayerView playerView;
private SimpleExoPlayer player;
private RelativeLayout state_holder;
private TextView state_text;
private TextView song_name;
private static String LOG_TAG="PLAYER";
public Player(Context context, SimpleExoPlayerView playerView) {
this.context = context;
this.dynamicConcatenatingMediaSource = new DynamicConcatenatingMediaSource();
this.playerView = playerView;
init_player();
}
private void init_player() {
/**GET the reqired view to show in you player
* In our case as we know the the simpleExoplayerView is a FrameLayout
* Thus we have made a relative layout underneath it
* By this we can get the relative layout from the simpleExoplayerView
* The song name text view is the playback_control_view.xml
*/
state_holder = (RelativeLayout) playerView.findViewById(R.id.state_holder);
state_text = (TextView) playerView.findViewById(R.id.state_text);
song_name = (TextView) playerView.findViewById(R.id.song_name);
BandwidthMeter bandwidthMeter = new DefaultBandwidthMeter();
TrackSelection.Factory videoTrackSelectionFactory =
new AdaptiveTrackSelection.Factory(bandwidthMeter);
TrackSelector trackSelector =
new DefaultTrackSelector(videoTrackSelectionFactory);
player = ExoPlayerFactory.newSimpleInstance(context, trackSelector);
player.addListener(this);//initiate the event listener
playerView.setPlayer(player);
}
/*
add media urls dynamically at run time
Here we have added urls that are compatible with ExtractorMediaSource
If you need other media source then pass media source as arguement not the url
*/
public void addMedia(String url) {
DefaultBandwidthMeter bandwidthMeterA = new DefaultBandwidthMeter();
DefaultDataSourceFactory dataSourceFactory = new DefaultDataSourceFactory(context, Util.getUserAgent(context, "NepTechSansaar"), bandwidthMeterA);
ExtractorsFactory extractorsFactory = new DefaultExtractorsFactory();
MediaSource mediaSource = new ExtractorMediaSource(Uri.parse(url),
dataSourceFactory, extractorsFactory, null, null);
if (dynamicConcatenatingMediaSource.getSize() == 0) {
dynamicConcatenatingMediaSource.addMediaSource(mediaSource);
player.prepare(dynamicConcatenatingMediaSource);
player.setPlayWhenReady(true);
} else {
dynamicConcatenatingMediaSource.addMediaSource(mediaSource);
}
}
private void show_buffering() {
state_holder.setVisibility(View.VISIBLE);
state_text.setTextColor(Color.YELLOW);
state_text.setText("BUFFERING...");
}
private void show_error() {
state_holder.setVisibility(View.VISIBLE);
state_text.setTextColor(Color.RED);
state_text.setText("CANNOT PLAY....");
}
private void show_ready() {
state_holder.setVisibility(View.GONE);
}
private void update_track(int index) {
song_name.setText("Playing track "+index);
}
@Override
public void onTimelineChanged(Timeline timeline, Object manifest) {
}
@Override
public void onTracksChanged(TrackGroupArray trackGroups, TrackSelectionArray trackSelections) {
update_track(player.getCurrentPeriodIndex());
}
@Override
public void onLoadingChanged(boolean isLoading) {
}
@Override
public void onPlayerStateChanged(boolean playWhenReady,
int playbackState) {
switch (playbackState) {
case com.google.android.exoplayer2.Player.STATE_IDLE:
Log.e(LOG_TAG,"IDLE state");
break;
case com.google.android.exoplayer2.Player.STATE_BUFFERING:
Log.e(LOG_TAG,"BUFFERING state");
show_buffering();
break;
case com.google.android.exoplayer2.Player.STATE_READY:
Log.e(LOG_TAG,"READY state");
show_ready();
break;
case com.google.android.exoplayer2.Player.STATE_ENDED:
Log.e(LOG_TAG,"ENDED state");
break;
}
}
@Override
public void onRepeatModeChanged(int repeatMode) {
}
@Override
public void onPlayerError(ExoPlaybackException error) {
Log.e(LOG_TAG,"ERROR state");
show_error();
}
@Override
public void onPositionDiscontinuity() {
}
@Override
public void onPlaybackParametersChanged(PlaybackParameters playbackParameters) {
}
}
Finally! run the program.