fix(android): hold UI patch until cursor sync lands; reanchor on track flip
android / Build + lint + test (push) Failing after 1m21s
android / Build + lint + test (push) Failing after 1m21s
This commit is contained in:
@@ -411,6 +411,11 @@ class PlayerController @Inject constructor(
|
|||||||
// Reset the per-item evaluation guard so the new
|
// Reset the per-item evaluation guard so the new
|
||||||
// item's STATE_READY transition gets a fresh check.
|
// item's STATE_READY transition gets a fresh check.
|
||||||
lastEvaluatedItemIndex = -1
|
lastEvaluatedItemIndex = -1
|
||||||
|
// The track flipped -- re-anchor the position interpolator
|
||||||
|
// so the next polling tick treats the new track's
|
||||||
|
// remoteState.positionMs as fresh rather than carrying the
|
||||||
|
// old anchor + elapsed forward.
|
||||||
|
lastSeenRemotePositionMs = -1L
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onPlaybackStateChanged(playbackState: Int) {
|
override fun onPlaybackStateChanged(playbackState: Int) {
|
||||||
@@ -493,6 +498,14 @@ class PlayerController @Inject constructor(
|
|||||||
while (isActive) {
|
while (isActive) {
|
||||||
delay(POSITION_POLL_INTERVAL_MS)
|
delay(POSITION_POLL_INTERVAL_MS)
|
||||||
val upnpActive = activeUpnpHolder.active.value != null
|
val upnpActive = activeUpnpHolder.active.value != null
|
||||||
|
// Track-alignment gate: if Sonos's reported Track is past the
|
||||||
|
// wrapped player's currentMediaItemIndex, a forward cursor sync
|
||||||
|
// is in flight (pollOnce wrote new remoteState, handler.post'd
|
||||||
|
// delegate.seekTo; the seek hasn't run yet). Skipping the tick
|
||||||
|
// here lets onMediaItemTransition rebuild the full uiState
|
||||||
|
// atomically rather than patching position+duration while
|
||||||
|
// currentTrack/queueIndex still point at the old track.
|
||||||
|
if (upnpActive && isForwardCursorSyncPending(controller)) continue
|
||||||
val effectiveIsPlaying =
|
val effectiveIsPlaying =
|
||||||
if (upnpActive) remoteState.isPlaying else controller.isPlaying
|
if (upnpActive) remoteState.isPlaying else controller.isPlaying
|
||||||
val effectivePosition = if (upnpActive) {
|
val effectivePosition = if (upnpActive) {
|
||||||
@@ -533,6 +546,12 @@ class PlayerController @Inject constructor(
|
|||||||
@Volatile private var positionAnchorMs: Long = 0L
|
@Volatile private var positionAnchorMs: Long = 0L
|
||||||
@Volatile private var positionAnchorAtRealtimeMs: Long = 0L
|
@Volatile private var positionAnchorAtRealtimeMs: Long = 0L
|
||||||
|
|
||||||
|
private fun isForwardCursorSyncPending(controller: MediaController): Boolean {
|
||||||
|
val sonosTrack = remoteState.trackNumber
|
||||||
|
if (sonosTrack <= 0) return false
|
||||||
|
return (sonosTrack - 1) > controller.currentMediaItemIndex
|
||||||
|
}
|
||||||
|
|
||||||
private fun interpolatedRemotePosition(isPlaying: Boolean): Long {
|
private fun interpolatedRemotePosition(isPlaying: Boolean): Long {
|
||||||
val raw = remoteState.positionMs
|
val raw = remoteState.positionMs
|
||||||
val now = SystemClock.elapsedRealtime()
|
val now = SystemClock.elapsedRealtime()
|
||||||
|
|||||||
Reference in New Issue
Block a user