Listen to playback events

Learn how to observe playback state changes, buffering, seek events, and more using the PlaybackListener interface.

All callbacks are invoked on the main thread.

Attach a playback listener

1val listener = object : PlaybackListener {
2 override fun onPlay() {
3 // Playback started or resumed
4 }
5 override fun onPause() {
6 // Playback paused (not called for ended/idle transitions)
7 }
8 override fun onPlaybackStateChanged(isPlaying: Boolean) {
9 // Unified play/pause state change
10 }
11 override fun onPlayerReady(durationMs: Long) {
12 // Called once per media item when the player reaches READY the first time
13 }
14 override fun onTimeUpdate(currentPositionMs: Long, durationMs: Long, bufferedPositionMs: Long) {
15 // Periodic time updates during active playback (default ~500ms)
16 }
17 override fun onSeekStart(currentPositionMs: Long) {
18 // Fired when a seek begins (user scrub or programmatic seekTo)
19 }
20 override fun onSeekEnd(fromPositionMs: Long, toPositionMs: Long, durationMs: Long) {
21 // Fired when seek completes
22 }
23 override fun onBufferingStart() {
24 // Transition to buffering state
25 }
26 override fun onBufferingEnd() {
27 // Transition from buffering to ready
28 }
29 override fun onVolumeChanged(volumeLevel: Float) {
30 // Device volume changed (0.0..1.0)
31 }
32 override fun onMuteStateChanged(isMuted: Boolean) {
33 // Mute state changed
34 }
35 override fun onPlaybackRateChanged(rate: Float) {
36 // Playback speed updated
37 }
38 override fun onCompleted() {
39 // Reached end of media (still called even if loop=true, before repeating)
40 }
41 override fun onError(error: PlaybackException) {
42 // Playback or validation error
43 }
44}
45player.addPlaybackListener(listener)

Callback details

  • onPlayerReady(durationMs) fires once per media item when the player reaches READY for the first time—not on every rebuffer or seek.
  • onTimeUpdate(...) fires periodically during active playback (default ~500ms) and stops automatically when paused, ended, or when no listeners remain.
  • onSeekStart / onSeekEnd triggers for both user scrubs and programmatic seekTo calls.
  • onBufferingStart / onBufferingEnd fires on buffering transitions. Use these to show or hide a loading spinner.
  • onCompleted() fires when reaching the end of media. If loop = true, this callback still fires before the video repeats.

Remove the listener

Remove the listener when it’s no longer needed to avoid leaks:

1player.removePlaybackListener(listener)