Created
June 6, 2023 20:48
-
-
Save whitipet/058e7901aeadff4a1a982c102329018b to your computer and use it in GitHub Desktop.
Position tracker for android media3 Player
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
private const val MIN_UPDATE_INTERVAL_MS: Long = 200 | |
private const val MAX_UPDATE_INTERVAL_MS: Long = 1000 | |
class PlayerPositionTracker { | |
private val handlerUpdatePosition = Handler() | |
private val runnableUpdatePosition = Runnable { updatePosition() } | |
var player: Player? = null | |
set(value) { | |
field = value | |
updatePlayerEventListenerRegistration() | |
updatePosition() | |
} | |
var playerPositionListener: PlayerPositionListener? = null | |
set(value) { | |
field = value | |
updatePlayerEventListenerRegistration() | |
updatePosition() | |
} | |
private val playerEventListener = object : Player.Listener { | |
override fun onEvents(player: Player, events: Player.Events) { | |
if (events.containsAny( | |
Player.EVENT_PLAYBACK_STATE_CHANGED, | |
Player.EVENT_PLAY_WHEN_READY_CHANGED, | |
Player.EVENT_IS_PLAYING_CHANGED, | |
Player.EVENT_AVAILABLE_COMMANDS_CHANGED, | |
Player.EVENT_POSITION_DISCONTINUITY, | |
Player.EVENT_TIMELINE_CHANGED, | |
Player.EVENT_AVAILABLE_COMMANDS_CHANGED | |
) | |
) updatePosition(player) | |
} | |
} | |
private fun updatePlayerEventListenerRegistration() = player?.let { | |
if (playerPositionListener != null) it.addListener(playerEventListener) | |
else it.removeListener(playerEventListener) | |
} | |
private fun updatePosition(player: Player? = this.player) { | |
handlerUpdatePosition.removeCallbacks(runnableUpdatePosition) | |
if (player == null) return | |
val position = player.currentPosition | |
playerPositionListener?.onPlayerPositionChanged(position) | |
val playbackState = player.playbackState | |
if (player.isPlaying) | |
handlerUpdatePosition.postDelayed( | |
runnableUpdatePosition, | |
player.playbackParameters.speed.let { playbackSpeed -> | |
if (playbackSpeed > 0) ((1000 - position % 1000) / playbackSpeed).toLong() | |
else MAX_UPDATE_INTERVAL_MS | |
}.coerceIn(MIN_UPDATE_INTERVAL_MS, MAX_UPDATE_INTERVAL_MS) | |
) | |
else if (playbackState != Player.STATE_ENDED && playbackState != Player.STATE_IDLE) | |
handlerUpdatePosition.postDelayed(runnableUpdatePosition, MAX_UPDATE_INTERVAL_MS) | |
} | |
fun release() { | |
handlerUpdatePosition.removeCallbacks(runnableUpdatePosition) | |
player?.removeListener(playerEventListener) | |
player = null | |
playerPositionListener = null | |
} | |
} | |
fun interface PlayerPositionListener { | |
fun onPlayerPositionChanged(position: Long) | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment