Voice Broadcast - use internal playback timer instead of relying on the media player position
This commit is contained in:
parent
af67705778
commit
a06104534b
|
@ -206,7 +206,7 @@ class VoiceBroadcastPlayerImpl @Inject constructor(
|
|||
}
|
||||
}
|
||||
State.Buffering -> {
|
||||
val savedPosition = currentVoiceBroadcast?.voiceBroadcastId?.let { playbackTracker.getPlaybackTime(it) }
|
||||
val savedPosition = currentVoiceBroadcast?.let { playbackTracker.getPlaybackTime(it.voiceBroadcastId) }
|
||||
when {
|
||||
// resume playback from the next sequence item
|
||||
playlist.currentSequence != null -> playlist.getNextItem()?.let { startPlayback(it.startTime) }
|
||||
|
@ -226,18 +226,21 @@ class VoiceBroadcastPlayerImpl @Inject constructor(
|
|||
private fun startPlayback(position: Int) {
|
||||
stopPlayer()
|
||||
|
||||
val playlistItem = playlist.findByPosition(position)
|
||||
val content = playlistItem?.audioEvent?.content ?: run { Timber.w("## Voice Broadcast | No content to play at position $position"); return }
|
||||
val playlistItem = playlist.findByPosition(position) ?: run { Timber.w("## Voice Broadcast | No content to play at position $position"); return }
|
||||
val sequence = playlistItem.sequence ?: run { Timber.w("## Voice Broadcast | Playlist item has no sequence"); return }
|
||||
val sequencePosition = position - playlistItem.startTime
|
||||
|
||||
prepareCurrentPlayerJob = sessionScope.launch {
|
||||
try {
|
||||
val mp = prepareMediaPlayer(content)
|
||||
val mp = prepareMediaPlayer(playlistItem.audioEvent.content)
|
||||
playlist.currentSequence = sequence - 1 // will be incremented in onNextMediaPlayerStarted
|
||||
|
||||
mp.start()
|
||||
if (sequencePosition > 0) {
|
||||
mp.seekTo(sequencePosition)
|
||||
}
|
||||
|
||||
currentVoiceBroadcast?.let { playbackTicker.startPlaybackTicker(it.voiceBroadcastId) }
|
||||
onNextMediaPlayerStarted(mp)
|
||||
} catch (failure: VoiceBroadcastFailure.ListeningError) {
|
||||
playingState = State.Error(failure)
|
||||
|
@ -259,7 +262,7 @@ class VoiceBroadcastPlayerImpl @Inject constructor(
|
|||
playingState = State.Playing
|
||||
currentMediaPlayer?.start()
|
||||
} else {
|
||||
val savedPosition = currentVoiceBroadcast?.voiceBroadcastId?.let { playbackTracker.getPlaybackTime(it) } ?: 0
|
||||
val savedPosition = currentVoiceBroadcast?.let { playbackTracker.getPlaybackTime(it.voiceBroadcastId) } ?: 0
|
||||
startPlayback(savedPosition)
|
||||
}
|
||||
}
|
||||
|
@ -270,6 +273,8 @@ class VoiceBroadcastPlayerImpl @Inject constructor(
|
|||
playbackTracker.updatePausedAtPlaybackTime(voiceBroadcast.voiceBroadcastId, positionMillis, positionMillis.toFloat() / duration)
|
||||
}
|
||||
playingState == State.Playing || playingState == State.Buffering -> {
|
||||
stopPlayer()
|
||||
playbackTracker.updatePlayingAtPlaybackTime(voiceBroadcast.voiceBroadcastId, positionMillis, positionMillis.toFloat() / duration)
|
||||
startPlayback(positionMillis)
|
||||
}
|
||||
playingState == State.Idle || playingState == State.Paused -> {
|
||||
|
@ -355,6 +360,8 @@ class VoiceBroadcastPlayerImpl @Inject constructor(
|
|||
|
||||
private fun stopPlayer() {
|
||||
tryOrNull { currentMediaPlayer?.stop() }
|
||||
playbackTicker.stopPlaybackTicker()
|
||||
|
||||
currentMediaPlayer?.release()
|
||||
currentMediaPlayer = null
|
||||
|
||||
|
@ -376,7 +383,7 @@ class VoiceBroadcastPlayerImpl @Inject constructor(
|
|||
State.Paused,
|
||||
State.Buffering,
|
||||
is State.Error,
|
||||
State.Idle -> playbackTicker.stopPlaybackTicker(voiceBroadcastId)
|
||||
State.Idle -> playbackTicker.stopPlaybackTicker()
|
||||
}
|
||||
|
||||
// Notify playback tracker about error
|
||||
|
@ -416,22 +423,6 @@ class VoiceBroadcastPlayerImpl @Inject constructor(
|
|||
prepareNextMediaPlayer()
|
||||
}
|
||||
|
||||
private fun getCurrentPlaybackPosition(): Int? {
|
||||
val voiceBroadcastId = currentVoiceBroadcast?.voiceBroadcastId ?: return null
|
||||
val computedPosition = tryOrNull { currentMediaPlayer?.currentPosition }?.let { playlist.currentItem?.startTime?.plus(it) }
|
||||
val savedPosition = playbackTracker.getPlaybackTime(voiceBroadcastId)
|
||||
return computedPosition ?: savedPosition
|
||||
}
|
||||
|
||||
private fun getCurrentPlaybackPercentage(): Float? {
|
||||
val playlistPosition = playlist.currentItem?.startTime
|
||||
val computedPosition = tryOrNull { currentMediaPlayer?.currentPosition }?.let { playlistPosition?.plus(it) } ?: playlistPosition
|
||||
val duration = playlist.duration
|
||||
val computedPercentage = if (computedPosition != null && duration > 0) computedPosition.toFloat() / duration else null
|
||||
val savedPercentage = currentVoiceBroadcast?.voiceBroadcastId?.let { playbackTracker.getPercentage(it) }
|
||||
return computedPercentage ?: savedPercentage
|
||||
}
|
||||
|
||||
private inner class MediaPlayerListener :
|
||||
MediaPlayer.OnInfoListener,
|
||||
MediaPlayer.OnCompletionListener,
|
||||
|
@ -492,39 +483,37 @@ class VoiceBroadcastPlayerImpl @Inject constructor(
|
|||
initialTime = playbackTracker.getPlaybackTime(id)?.toLong() ?: 0L,
|
||||
intervalInMs = 50L
|
||||
).apply {
|
||||
tickListener = CountUpTimer.TickListener { onPlaybackTick(id) }
|
||||
tickListener = CountUpTimer.TickListener { onPlaybackTick(id, it.toInt()) }
|
||||
resume()
|
||||
}
|
||||
onPlaybackTick(id)
|
||||
}
|
||||
|
||||
fun stopPlaybackTicker(id: String) {
|
||||
fun stopPlaybackTicker() {
|
||||
playbackTicker?.stop()
|
||||
playbackTicker?.tickListener = null
|
||||
playbackTicker = null
|
||||
onPlaybackTick(id)
|
||||
}
|
||||
|
||||
private fun onPlaybackTick(id: String) {
|
||||
val playbackTime = getCurrentPlaybackPosition()
|
||||
val percentage = getCurrentPlaybackPercentage()
|
||||
private fun onPlaybackTick(id: String, position: Int) {
|
||||
val percentage = tryOrNull { position.toFloat() / playlist.duration }
|
||||
when (playingState) {
|
||||
State.Playing -> {
|
||||
if (playbackTime != null && percentage != null) {
|
||||
playbackTracker.updatePlayingAtPlaybackTime(id, playbackTime, percentage)
|
||||
if (percentage != null) {
|
||||
playbackTracker.updatePlayingAtPlaybackTime(id, position, percentage)
|
||||
}
|
||||
}
|
||||
State.Paused,
|
||||
State.Buffering -> {
|
||||
if (playbackTime != null && percentage != null) {
|
||||
playbackTracker.updatePausedAtPlaybackTime(id, playbackTime, percentage)
|
||||
if (percentage != null) {
|
||||
playbackTracker.updatePausedAtPlaybackTime(id, position, percentage)
|
||||
}
|
||||
}
|
||||
State.Idle -> {
|
||||
// restart the playback time if player completed with less than 250 ms remaining time
|
||||
if (playbackTime == null || percentage == null || (playlist.duration - playbackTime) < 250) {
|
||||
// restart the playback time if player completed with less than 1s remaining time
|
||||
if (percentage == null || (playlist.duration - position) < 1000) {
|
||||
playbackTracker.stopPlayback(id)
|
||||
} else {
|
||||
playbackTracker.updatePausedAtPlaybackTime(id, playbackTime, percentage)
|
||||
playbackTracker.updatePausedAtPlaybackTime(id, position, percentage)
|
||||
}
|
||||
}
|
||||
is State.Error -> Unit
|
||||
|
|
Loading…
Reference in New Issue