fix(android player): seek broke after seamless track transitions (durationMs stuck at 0)
After skipping through already-buffered tracks the player stays READY, so onPlaybackStateChanged never fires and syncState() isn't re-called; ctrl.duration was TIME_UNSET(→0) at the transition, leaving state.durationMs stuck at 0. The seek bar then computed fraction*0 = 0 and snapped playback to the start every time (or to a stale value → "only 10s"). Restarting the app re-read the real duration, which is why it recovered. Fix: durationMs now self-heals — the 500ms ticker refreshes it too, and resolveDurationMs() falls back to the current song's known duration while ctrl.duration is still unset. Also record the Erkunden swipe-between-tabs idea. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
1 parent
803331e807
commit
87ee8cd097
2 files changed
+17
-2
No files matched your search
@@ -227,11 +227,25 @@ class PlayerController(private val context: Context, private val repo: MusicRepo
|
||||
while (isActive) {
|
||||
delay(500)
|
||||
val ctrl = controller ?: break
|
||||
_state.update { it.copy(positionMs = ctrl.currentPosition) }
|
||||
// Refresh durationMs too — after a SEAMLESS track transition (skipping through
|
||||
// already-buffered tracks) the player stays READY, so onPlaybackStateChanged never
|
||||
// fires and syncState() isn't re-called; ctrl.duration was TIME_UNSET(→0) at the
|
||||
// transition, leaving durationMs stuck at 0. Seek then computes fraction*0 = 0 and
|
||||
// snaps to the start every time. Re-reading here lets it self-heal within 500ms.
|
||||
_state.update { it.copy(positionMs = ctrl.currentPosition, durationMs = resolveDurationMs(ctrl)) }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** Player duration, falling back to the current song's known duration while ctrl.duration is
|
||||
* still TIME_UNSET (right after a media transition). Prevents a 0-duration seek → snap-to-0. */
|
||||
private fun resolveDurationMs(ctrl: MediaController): Long {
|
||||
val d = ctrl.duration
|
||||
if (d > 0) return d
|
||||
val songDurSecs = queue.getOrNull(ctrl.currentMediaItemIndex)?.duration?.toLong() ?: 0L
|
||||
return songDurSecs * 1000L
|
||||
}
|
||||
|
||||
private fun stopTicker() {
|
||||
tickerJob?.cancel()
|
||||
tickerJob = null
|
||||
@@ -271,7 +285,7 @@ class PlayerController(private val context: Context, private val repo: MusicRepo
|
||||
currentSong = queue.getOrNull(idx),
|
||||
currentIndex = idx,
|
||||
positionMs = ctrl.currentPosition,
|
||||
durationMs = ctrl.duration.coerceAtLeast(0),
|
||||
durationMs = resolveDurationMs(ctrl),
|
||||
queue = queue,
|
||||
repeatMode = ctrl.repeatMode,
|
||||
shuffled = isManuallyShuffled,
|
||||
|
||||
Reference in new issue
Block a user