From a06104534b763b8f94c2255ab0e4c46f717d80c9 Mon Sep 17 00:00:00 2001 From: Florian Renaud Date: Wed, 25 Jan 2023 18:07:16 +0100 Subject: [PATCH] Voice Broadcast - use internal playback timer instead of relying on the media player position --- .../listening/VoiceBroadcastPlayerImpl.kt | 61 ++++++++----------- 1 file changed, 25 insertions(+), 36 deletions(-) diff --git a/vector/src/main/java/im/vector/app/features/voicebroadcast/listening/VoiceBroadcastPlayerImpl.kt b/vector/src/main/java/im/vector/app/features/voicebroadcast/listening/VoiceBroadcastPlayerImpl.kt index c356ed5500..bcc8d0605e 100644 --- a/vector/src/main/java/im/vector/app/features/voicebroadcast/listening/VoiceBroadcastPlayerImpl.kt +++ b/vector/src/main/java/im/vector/app/features/voicebroadcast/listening/VoiceBroadcastPlayerImpl.kt @@ -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