42

I searched two days for this question in github but i can't find true answer . I want example for detecting pause / resume in ExoPlayer > 2.x . Any one can give me an example ? I checked onPlayerStateChanged and problem not solved .

onPlayerStateChanged   :   STATE_BUFFERING 
onPlayerStateChanged   :   STATE_READY 

I just got this log from onPlayerStateChanged and this is not called in all times !

MrNadimi
  • 1,424
  • 4
  • 18
  • 33

11 Answers11

81

EDIT---

Please refer to the Player.isPlaying() method which provides this as an API.

"Rather than having to check these properties individually, Player.isPlaying can be called."

https://exoplayer.dev/listening-to-player-events.html#playback-state-changes

--- EDIT END

You need to check playWhenReady with a Player.EventListener. The Playback states of ExoPlayer are independent from the player being paused or not:

player.addListener(new Player.DefaultEventListener() {
  @Override
  public void onPlayerStateChanged(boolean playWhenReady, int playbackState) {
    if (playWhenReady && playbackState == Player.STATE_READY) {
      // media actually playing
    } else if (playWhenReady) {
      // might be idle (plays after prepare()), 
      // buffering (plays when data available) 
      // or ended (plays when seek away from end)
    } else {
      // player paused in any state
    }
  }
});

To play/pause the player ExoPlayer provides

player.setPlayWhenReady(boolean)

The sequence of playback states with ExoPlayer with a media file which never stalls to rebuffer is once in each of the four states and does not express play/paused:

Player.STATE_IDLE;
Player.STATE_BUFFERING;
Player.STATE_READY;
Player.STATE_ENDED;

Each time the player needs to buffer it goes:

Player.STATE_READY;
Player.STATE_BUFFERING;
Player.STATE_READY;

Setting playWhenReady does not affect the state.

All together your media is actually playing when

playWhenReady && playbackState == Player.STATE_READY

It plays when ready. :)

marcbaechinger
  • 2,759
  • 18
  • 21
  • The mentioned constants are marked deprecated now, but they are still working, which is useful for debugging. – Ben Mar 22 '18 at 19:27
  • On the dev-2 branch (prerelease) the STATE_XYZ constants are not deprecated. Why do you think this is the case? – marcbaechinger Mar 23 '18 at 22:20
  • I'm using Exo Player 2.7.0 and Android Studio tells me so (targeting API 27 and down to 16) - I just wanted to leave some info that they are still working. I'm not sure about the "dev-2 branch". – Ben Mar 24 '18 at 16:53
  • This logic fails when we pause video in landscape mode and change to portrait mode. Any solution for that? – Sandeep Nov 26 '18 at 07:43
16

You can use this function:

public boolean isPlaying() {
    return exoPlayer.getPlaybackState() == Player.STATE_READY && exoPlayer.getPlayWhenReady();
}
Pavel Chuchuva
  • 22,633
  • 10
  • 99
  • 115
Payam Roozbahani
  • 1,225
  • 15
  • 27
16

It must be that since the other answers were posted, a new method has been provided in Player.EventListener. [EDIT: Now it is Player.Listener, as Player.EventListener has been deprecated]. This works well for me:

override fun onIsPlayingChanged(isPlaying: Boolean) {
    // your code here
}

If isPlaying is false, it is paused, otherwise playing.

Casey Perkins
  • 1,853
  • 2
  • 23
  • 41
6

I had the same requirement to detect the click event of exoplayer play/pause button. Above answers were mainly talking about the state not about the button click event.

This is what I did to detect the Play/Pause button click, works perfect.

Step 1: Create custom control dispatcher class and override the method dispatchSetPlayWhenReady

class PlayerControlDispatcher : DefaultControlDispatcher() {
    override fun dispatchSetPlayWhenReady(player: Player?, playWhenReady: Boolean): Boolean {
        if(playWhenReady) {
           // Play button clicked
        } else {
          // Paused button clicked
        }
        return super.dispatchSetPlayWhenReady(player, playWhenReady)
    }
}

Step 2: Set the custom control dispatcher class PlayerControlDispatcher into the the player view.

playerView.setControlDispatcher(PlayerControlDispatcher())

Where playerView is an instance of com.google.android.exoplayer2.ui.PlayerView which we declare in our layout file.

Krishna Sharma
  • 2,828
  • 1
  • 12
  • 23
  • 1
    This is the correct answer, just works perfectly! Thank you @krishna-sharma! – renatoarg Oct 17 '19 at 20:27
  • Glad to see that it worked for you @renatoarg, it will help others to address this answer now. – Krishna Sharma Oct 17 '19 at 20:30
  • Hi @KrishnaSharma I tried your code but got error. Could you explain where I should put the code location/position? – HiDayurie Dave Apr 22 '20 at 01:47
  • @HiDayurieDave you can put that anywhere, either create separate class or inner class. Important line is playerView.setControlDispatcher(PlayerControlDispatcher()) – Krishna Sharma Jun 02 '21 at 17:51
  • 1
    The ControlDispatcher interface has been removed in 2.16.0, see https://github.com/google/ExoPlayer/releases/tag/r2.16.0. – Thomas McGuire Dec 21 '21 at 16:20
  • 1
    binding.playerView.findViewById(R.id.exo_play_pause).setOnClickListener { } this will also work to detect click events on play/pause button. – Mohd Haseen Oct 28 '22 at 07:12
6

Kotlin 2020 solution approach UPDATE

Events such as changes in state and playback errors are reported to registered Player.EventListener instances.

Player.EventListener has empty default methods, so you only need to implement the methods you’re interested in.

First your class, say your activity, has to conform to the Player.EventListener interface.

Then you override the onIsPlayingChanged method, on the class. Outside onCreate method...

Add the listener to your player instance:

// Adding player listener for tracking events
player?.addListener(this)

You can check if the player is playing (i.e. the position is advancing) with Player.isPlaying:

//Listening to player events
override fun onIsPlayingChanged(isPlaying: Boolean){
    if (isPlaying) {
        // Active playback.
    } else {
        // Not playing because playback is paused, ended, suppressed, or the player
        // is buffering, stopped or failed. Check player.getPlaybackState,
        // player.getPlayWhenReady, player.getPlaybackError and
        // player.getPlaybackSuppressionReason for details.
    }
}

That's it. Very simple.

Neil Turner
  • 2,712
  • 2
  • 18
  • 37
Helen Wood
  • 1,872
  • 2
  • 26
  • 41
2

You can use exoplayer.getPlayWhenReady() to check whether the player is currently in a pause state or playing state.

Rohan Seth
  • 2,010
  • 1
  • 14
  • 13
2

I think the callback:

fun onPlayWhenReadyChanged(playWhenReady: Boolean, reason: Int)

From the Player.Listener

2

With version 2.16.1, I use this code:

exoPlayer.addListener(object : Player.Listener {
    override fun onIsPlayingChanged(isPlaying: Boolean) {
        if (isPlaying){
            videoIsPlaying()
        }
    }
})
Kaaveh Mohamedi
  • 1,399
  • 1
  • 15
  • 36
1

Please try below code snipped. The player listener(onPlayerStateChanged) isn't good to observe play / pause action its called multiple time and also invoke while player configuring.

videoView.setControlDispatcher(object : DefaultControlDispatcher() {
            override fun dispatchSetPlayWhenReady(player: Player, playWhenReady: Boolean): Boolean {
                if (playWhenReady)
                  // Tap on Play button  
                else
                 // Tap on Pause button
                return super.dispatchSetPlayWhenReady(player, playWhenReady)
            }
        })
M.Muzammil
  • 643
  • 9
  • 18
0

for kotlin

private fun ExoPlayer.isPlaying() =
    playbackState == Player.STATE_READY && playWhenReady
William Reed
  • 1,717
  • 1
  • 17
  • 30
0

You must use new version: com.google.android.exoplayer:exoplayer:2.18.6

This function deprecated:

@Deprecated
    default void onPlayerStateChanged(boolean playWhenReady, @State int playbackState) {}

New function is:

 default void onPlaybackStateChanged(@State int playbackState) {}

For example:

exoPlayer?.addListener(object : Player.Listener {
            override fun onPlaybackStateChanged(@Player.State state: Int) {
                when (state) {
                    Player.STATE_READY -> {
                        // The player is able to immediately play from its current position. The player will be playing if getPlayWhenReady() is true, and paused otherwise.
                    }
                    Player.STATE_BUFFERING -> {
                       // The player is not able to immediately play the media, but is doing work toward being able to do so. This state typically occurs when the player needs to buffer more data before playback can start.
                    }
                    Player.STATE_IDLE -> {
                       // The player is idle, meaning it holds only limited resources.The player must be prepared before it will play the media.
                    }
                    Player.STATE_ENDED -> { 
                       // The player has finished playing the media.
                    }
                    else -> {
                      // Other things
                    }
                }
            }
        })
Halil Ozel
  • 2,482
  • 3
  • 17
  • 32