dev → main: Android UPnP/Sonos transport parity + server stream URL extension #79
@@ -206,6 +206,13 @@ class MinstrelForwardingPlayer(
|
||||
pollJob?.cancel()
|
||||
if (active != null) {
|
||||
Timber.w("UPnP active: %s -- pollLoop starting", active.routeName)
|
||||
// Pause the wrapped ExoPlayer so we are not playing local audio
|
||||
// simultaneously with the remote renderer. handler.post targets the
|
||||
// application looper, so this runs on the same thread that processes
|
||||
// our override calls -- no race with the pause() override branching
|
||||
// to SOAP (holder.active is already non-null by the time this post
|
||||
// fires, but delegate.pause() bypasses the override entirely).
|
||||
handler.post { delegate.pause() }
|
||||
pollJob = scope.launch { pollLoop(active) }
|
||||
// Do NOT pre-queue here: selectUpnp's SetAV+Play SOAP may not have
|
||||
// landed yet. Initial pre-queue fires from pollLoop once the first
|
||||
@@ -225,6 +232,14 @@ class MinstrelForwardingPlayer(
|
||||
// SetAV+Play from selectUpnp (trackUri lands in the first
|
||||
// successful poll). Firing from onActiveChanged would race
|
||||
// with selectUpnp's SOAP calls.
|
||||
if (!initialPreQueueDone) {
|
||||
Timber.w(
|
||||
"UPnP poll OK: route=%s trackUri=%s posMs=%d",
|
||||
active.routeName,
|
||||
remoteState.currentTrackUri,
|
||||
remoteState.positionMs,
|
||||
)
|
||||
}
|
||||
if (!initialPreQueueDone && remoteState.currentTrackUri.isNotBlank()) {
|
||||
Timber.w("UPnP initial pre-queue for %s", active.routeName)
|
||||
preQueueNext(active)
|
||||
|
||||
+7
-6
@@ -258,12 +258,13 @@ class OutputPickerController @Inject constructor(
|
||||
return@withLock
|
||||
}
|
||||
val rendering = renderingClientFor(effectiveRoute.id)
|
||||
// Pause local FIRST while holder.active is still null so the pause()
|
||||
// call routes to ExoPlayer, not SOAP. After holder.set() below,
|
||||
// ForwardingPlayer.pause() would translate this into AVTransport.Pause()
|
||||
// -- the opposite of what we want, since we are about to tell Sonos
|
||||
// to start playing.
|
||||
playerController.pause()
|
||||
// Local pause is handled by MinstrelForwardingPlayer.onActiveChanged
|
||||
// via handler.post { delegate.pause() } -- called immediately after
|
||||
// holder.set() fires. That path bypasses the SOAP-routing override, so
|
||||
// there is no race between pausing ExoPlayer and starting the remote
|
||||
// renderer. Do NOT call playerController.pause() here: it dispatches
|
||||
// through Handler.post on the application looper, meaning it runs after
|
||||
// holder.active is non-null and the override would route it to SOAP.
|
||||
selectedUpnpRouteIdInternal.value = effectiveRoute.id
|
||||
activeUpnpHolder.set(
|
||||
ActiveUpnp(
|
||||
|
||||
Reference in New Issue
Block a user