refactor(android): UPnP discovery cleanup -- bareUdn helper, Timber, suppress, kdoc
android / Build + lint + test (push) Has been cancelled
android / Build + lint + test (push) Has been cancelled
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
+15
-8
@@ -1,3 +1,4 @@
|
||||
@file:Suppress("TooManyFunctions") // discovery + Sonos topology + transport-lookup density
|
||||
package com.fabledsword.minstrel.player.output.upnp
|
||||
|
||||
import android.content.Context
|
||||
@@ -15,6 +16,7 @@ import okhttp3.HttpUrl
|
||||
import okhttp3.HttpUrl.Companion.toHttpUrlOrNull
|
||||
import okhttp3.OkHttpClient
|
||||
import okhttp3.Request
|
||||
import timber.log.Timber
|
||||
import javax.inject.Inject
|
||||
import javax.inject.Singleton
|
||||
|
||||
@@ -113,7 +115,9 @@ class UpnpDiscoveryController @Inject constructor(
|
||||
val zgtUrl = anySonos.zoneGroupTopologyControlUrl ?: return
|
||||
val groups = runCatching {
|
||||
ZoneGroupTopologyClient(SoapClient(okHttp), zgtUrl).getZoneGroupState()
|
||||
}.getOrNull() ?: return
|
||||
}
|
||||
.onFailure { Timber.w(it, "refreshSonosTopology failed for %s", anySonos.id) }
|
||||
.getOrNull() ?: return
|
||||
sonosTopologyInternal.value = groups
|
||||
}
|
||||
|
||||
@@ -124,13 +128,11 @@ class UpnpDiscoveryController @Inject constructor(
|
||||
* <UDN> carries it but Sonos's ZoneGroupState Coordinator attr does not.
|
||||
*/
|
||||
fun coordinatorRouteFor(udn: String): UpnpRoute? {
|
||||
val bare = udn.removePrefix("uuid:")
|
||||
val bare = udn.bareUdn()
|
||||
val coord = sonosTopologyInternal.value
|
||||
.firstOrNull { g -> g.members.any { it.udn.removePrefix("uuid:") == bare } }
|
||||
.firstOrNull { g -> g.members.any { it.udn.bareUdn() == bare } }
|
||||
?.coordinatorUdn ?: return null
|
||||
return routesInternal.value.firstOrNull {
|
||||
it.id.removePrefix("uuid:") == coord.removePrefix("uuid:")
|
||||
}
|
||||
return routesInternal.value.firstOrNull { it.id.bareUdn() == coord.bareUdn() }
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -139,8 +141,8 @@ class UpnpDiscoveryController @Inject constructor(
|
||||
*/
|
||||
fun nonCoordinatorMemberUdns(): Set<String> {
|
||||
return sonosTopologyInternal.value.flatMap { g ->
|
||||
g.members.map { it.udn.removePrefix("uuid:") }
|
||||
.filter { it != g.coordinatorUdn.removePrefix("uuid:") }
|
||||
g.members.map { it.udn.bareUdn() }
|
||||
.filter { it != g.coordinatorUdn.bareUdn() }
|
||||
}.toSet()
|
||||
}
|
||||
|
||||
@@ -208,3 +210,8 @@ class UpnpDiscoveryController @Inject constructor(
|
||||
val IP_SUFFIX_REGEX = Regex("""\s*\(\d+\.\d+\.\d+\.\d+\)$""")
|
||||
}
|
||||
}
|
||||
|
||||
// uuid: prefix normalization — DeviceDescription <UDN> carries it; Sonos
|
||||
// ZoneGroupState Coordinator/UUID attrs don't. Helper centralizes the strip
|
||||
// so a future change to the convention isn't a silent compare-always-false bug.
|
||||
private fun String.bareUdn(): String = removePrefix("uuid:")
|
||||
|
||||
@@ -7,10 +7,10 @@ import okhttp3.HttpUrl
|
||||
* Bose SoundTouch, generic DLNA renderers). Lifted out of the SOAP /
|
||||
* SSDP details so the picker UI consumes a narrow domain shape.
|
||||
*
|
||||
* Generic UPnP only for THIS slice — Sonos-specific grouping value-adds
|
||||
* (group join/leave, zone topology) live in a separate Sonos extension
|
||||
* scoped in
|
||||
* docs/superpowers/specs/2026-06-03-android-output-picker-upnp-scope.md.
|
||||
* Sonos devices additionally populate [zoneGroupTopologyControlUrl] from the
|
||||
* ZoneGroupTopology service in their device description; non-Sonos devices
|
||||
* leave it null. The discovery controller uses that URL to aggregate stereo
|
||||
* pairs and multi-speaker groups into single picker rows.
|
||||
*
|
||||
* [id] is the device UDN (e.g. `uuid:RINCON_ABC...`). [name] is the
|
||||
* raw `<friendlyName>` straight from the device description — callers
|
||||
|
||||
+1
@@ -58,6 +58,7 @@ class DeviceDescriptionTest {
|
||||
"http://192.168.1.50:1400/MediaRenderer/RenderingControl/Control",
|
||||
desc.renderingControlUrl?.toString(),
|
||||
)
|
||||
assertNull(desc.zoneGroupTopologyControlUrl)
|
||||
}
|
||||
|
||||
@Test
|
||||
|
||||
Reference in New Issue
Block a user