From 5f3905f2c7f13624a6e4b7a57698b7562e334bba Mon Sep 17 00:00:00 2001 From: Bryan Van Deusen Date: Wed, 3 Jun 2026 11:51:11 -0400 Subject: [PATCH] feat(android): UPnP picker foundation (UPnP slice 3/6) UpnpRoute - narrow domain model for a discovered UPnP / DLNA renderer. Carries the AVTransport + RenderingControl control URLs the SOAP client uses. CastApi - Retrofit interface for the new POST /api/cast/stream-token endpoint (UPnP slice 2/6). Returns {token, exp, url} for the selection path. OutputRoute.fromUpnpRoute - companion factory that tags the route with Protocol.UPNP. Subtitle is 'Manufacturer Model' or falls back to 'Network speaker' when description fields are blank. CHANGE_WIFI_MULTICAST_STATE manifest permission - install-time on all API levels, no runtime prompt. Required for SSDP multicast discovery. Discovery + SOAP + integration land in follow-up commits. Co-Authored-By: Claude Opus 4.7 --- android/app/src/main/AndroidManifest.xml | 1 + .../minstrel/api/endpoints/CastApi.kt | 49 +++++++++++++++++++ .../minstrel/player/output/OutputRoute.kt | 31 ++++++++++++ .../minstrel/player/output/upnp/UpnpRoute.kt | 27 ++++++++++ 4 files changed, 108 insertions(+) create mode 100644 android/app/src/main/java/com/fabledsword/minstrel/api/endpoints/CastApi.kt create mode 100644 android/app/src/main/java/com/fabledsword/minstrel/player/output/upnp/UpnpRoute.kt diff --git a/android/app/src/main/AndroidManifest.xml b/android/app/src/main/AndroidManifest.xml index 2315ed80..15066c95 100644 --- a/android/app/src/main/AndroidManifest.xml +++ b/android/app/src/main/AndroidManifest.xml @@ -10,6 +10,7 @@ + ` straight from the device description — callers + * fall back to "Network speaker" upstream when it's blank; this class + * does not perform that substitution itself. + */ +data class UpnpRoute( + val id: String, + val name: String, + val manufacturer: String, + val modelName: String, + val avTransportControlUrl: HttpUrl, + val renderingControlUrl: HttpUrl?, +)