fix(android): UPnP forwarding -- route mint failures through drop, no double drop
android / Build + lint + test (push) Failing after 1m25s
android / Build + lint + test (push) Failing after 1m25s
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
+20
-7
@@ -101,18 +101,30 @@ class MinstrelForwardingPlayer(
|
||||
|
||||
override fun seekToNextMediaItem() {
|
||||
val active = holder.active.value
|
||||
super.seekToNextMediaItem()
|
||||
if (active != null) {
|
||||
scope.launch { syncCurrentItemToRemote(active) }
|
||||
if (active == null) {
|
||||
super.seekToNextMediaItem()
|
||||
return
|
||||
}
|
||||
// Advance the local cursor first so syncCurrentItemToRemote can read
|
||||
// the new currentMediaItem on the application looper. ExoPlayer stays
|
||||
// paused while UPnP is active (playWhenReady=false invariant), so this
|
||||
// does not produce local audio.
|
||||
super.seekToNextMediaItem()
|
||||
scope.launch { syncCurrentItemToRemote(active) }
|
||||
}
|
||||
|
||||
override fun seekToPreviousMediaItem() {
|
||||
val active = holder.active.value
|
||||
super.seekToPreviousMediaItem()
|
||||
if (active != null) {
|
||||
scope.launch { syncCurrentItemToRemote(active) }
|
||||
if (active == null) {
|
||||
super.seekToPreviousMediaItem()
|
||||
return
|
||||
}
|
||||
// Advance the local cursor first so syncCurrentItemToRemote can read
|
||||
// the new currentMediaItem on the application looper. ExoPlayer stays
|
||||
// paused while UPnP is active (playWhenReady=false invariant), so this
|
||||
// does not produce local audio.
|
||||
super.seekToPreviousMediaItem()
|
||||
scope.launch { syncCurrentItemToRemote(active) }
|
||||
}
|
||||
|
||||
override fun getCurrentPosition(): Long =
|
||||
@@ -135,8 +147,8 @@ class MinstrelForwardingPlayer(
|
||||
|
||||
private suspend fun syncCurrentItemToRemote(active: ActiveUpnp) {
|
||||
val mediaId = handlerEvaluate { delegate.currentMediaItem?.mediaId } ?: return
|
||||
val token = runCatching { tokens.mint(mediaId) }.getOrNull() ?: return
|
||||
runCatching {
|
||||
val token = tokens.mint(mediaId)
|
||||
active.avTransport.setAVTransportURIWithMetadata(
|
||||
uri = token.url,
|
||||
mime = token.mime,
|
||||
@@ -148,6 +160,7 @@ class MinstrelForwardingPlayer(
|
||||
}
|
||||
|
||||
private fun handleSoapFailure(active: ActiveUpnp, t: Throwable) {
|
||||
pollJob?.cancel()
|
||||
Timber.w(t, "UPnP transport call failed on %s", active.routeName)
|
||||
remoteState.applyError(t)
|
||||
handler.post { onDrop(active.routeName) }
|
||||
|
||||
@@ -22,7 +22,7 @@ class RemotePlayerState {
|
||||
@Volatile var currentTrackUri: String = ""; private set
|
||||
@Volatile var lastError: Throwable? = null; private set
|
||||
|
||||
private var consecutivePollFailures: Int = 0
|
||||
@Volatile private var consecutivePollFailures: Int = 0
|
||||
|
||||
fun applyPositionInfo(positionMs: Long, durationMs: Long, trackUri: String) {
|
||||
this.positionMs = positionMs
|
||||
|
||||
+1
-1
@@ -45,7 +45,7 @@ data class RouteSnapshot(
|
||||
* - [OutputRoute.Protocol.SYSTEM] — MediaRouter.selectRoute (built-in,
|
||||
* wired, Bluetooth)
|
||||
* - [OutputRoute.Protocol.UPNP] — mint a signed stream token via
|
||||
* [CastApi.streamToken], drive the discovered renderer with
|
||||
* [StreamTokenProvider.mint], drive the discovered renderer with
|
||||
* AVTransport.SetAVTransportURI + Play, pause local playback so
|
||||
* audio yields to the network speaker
|
||||
* - [OutputRoute.Protocol.CAST] / [OutputRoute.Protocol.SONOS] —
|
||||
|
||||
Reference in New Issue
Block a user