From 96f12d6aacd733bb0ed78bedfef095a2d07b1b6e Mon Sep 17 00:00:00 2001 From: Bryan Van Deusen Date: Wed, 3 Jun 2026 14:59:57 -0400 Subject: [PATCH] fix(android): UPnP select - loud logs on every code path MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Two silent early returns in selectUpnp were swallowing the most likely failure modes: - currentTrack null (nothing playing locally → can't cast a track) - transportFor() returns null (route disappeared or id mismatch) On-device verification reported 'tap collapses the sheet but no audio routes', with logcat empty - one of these was firing without any signal. Each early-return now Timber.w's why; the runCatching block adds Timber.i breadcrumbs at every step (mint token, SetAVTransportURI, Play, done) so the next failure shows exactly how far we got. --- .../player/output/OutputPickerController.kt | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) diff --git a/android/app/src/main/java/com/fabledsword/minstrel/player/output/OutputPickerController.kt b/android/app/src/main/java/com/fabledsword/minstrel/player/output/OutputPickerController.kt index 76ee9b9b..1f6a178b 100644 --- a/android/app/src/main/java/com/fabledsword/minstrel/player/output/OutputPickerController.kt +++ b/android/app/src/main/java/com/fabledsword/minstrel/player/output/OutputPickerController.kt @@ -178,13 +178,28 @@ class OutputPickerController @Inject constructor( * deserialize / SOAP-parse code paths). */ private suspend fun selectUpnp(route: OutputRoute) { - val trackId = playerController.uiState.value.currentTrack?.id ?: return - val transport = upnpDiscovery.transportFor(route.id) ?: return + val trackId = playerController.uiState.value.currentTrack?.id + if (trackId == null) { + Timber.w("UPnP select skipped: no currentTrack (start playback first)") + return + } + val transport = upnpDiscovery.transportFor(route.id) + if (transport == null) { + Timber.w( + "UPnP select skipped: no transport for route id=${route.id} " + + "(route disappeared or id mismatch with discovery list)", + ) + return + } runCatching { + Timber.i("UPnP select: mint token for track=$trackId, route=${route.name}") val token = castApi.streamToken(StreamTokenRequest(trackId = trackId)) + Timber.i("UPnP select: SetAVTransportURI to ${token.url}") transport.setAVTransportURI(token.url) + Timber.i("UPnP select: Play") transport.play() playerController.pause() + Timber.i("UPnP select: done") }.onFailure { e -> Timber.w(e, "UPnP select failed for route ${route.id}") }