perf(android): fail-fast connect timeout for UPnP transport SOAP
android / Build + lint + test (push) Failing after 1m8s
android / Build + lint + test (push) Failing after 1m8s
This commit is contained in:
+16
-1
@@ -17,6 +17,7 @@ import okhttp3.HttpUrl.Companion.toHttpUrlOrNull
|
|||||||
import okhttp3.OkHttpClient
|
import okhttp3.OkHttpClient
|
||||||
import okhttp3.Request
|
import okhttp3.Request
|
||||||
import timber.log.Timber
|
import timber.log.Timber
|
||||||
|
import java.util.concurrent.TimeUnit
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
import javax.inject.Singleton
|
import javax.inject.Singleton
|
||||||
|
|
||||||
@@ -45,6 +46,15 @@ class UpnpDiscoveryController @Inject constructor(
|
|||||||
) {
|
) {
|
||||||
private val ssdp = SsdpDiscovery(context)
|
private val ssdp = SsdpDiscovery(context)
|
||||||
|
|
||||||
|
// Transport commands (play/pause/seek/next) and the 1 Hz poll go through
|
||||||
|
// this client. A dead renderer should fail fast so OutputPickerController's
|
||||||
|
// drop-recovery reverts to the phone in ~2 s instead of the shared client's
|
||||||
|
// 10 s connect timeout. Derived via newBuilder() so the connection pool +
|
||||||
|
// dispatcher stay shared with the app client.
|
||||||
|
private val controlHttp: OkHttpClient = okHttp.newBuilder()
|
||||||
|
.connectTimeout(CONTROL_CONNECT_TIMEOUT_SECONDS, TimeUnit.SECONDS)
|
||||||
|
.build()
|
||||||
|
|
||||||
private val routesInternal = MutableStateFlow<List<UpnpRoute>>(emptyList())
|
private val routesInternal = MutableStateFlow<List<UpnpRoute>>(emptyList())
|
||||||
val routes: StateFlow<List<UpnpRoute>> = routesInternal.asStateFlow()
|
val routes: StateFlow<List<UpnpRoute>> = routesInternal.asStateFlow()
|
||||||
|
|
||||||
@@ -91,7 +101,7 @@ class UpnpDiscoveryController @Inject constructor(
|
|||||||
fun transportFor(routeId: String): AVTransportClient? {
|
fun transportFor(routeId: String): AVTransportClient? {
|
||||||
val route = routesInternal.value.firstOrNull { it.id == routeId } ?: return null
|
val route = routesInternal.value.firstOrNull { it.id == routeId } ?: return null
|
||||||
return AVTransportClient(
|
return AVTransportClient(
|
||||||
loggingSoapClient(okHttp, route.name),
|
loggingSoapClient(controlHttp, route.name),
|
||||||
route.avTransportControlUrl,
|
route.avTransportControlUrl,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@@ -225,6 +235,11 @@ class UpnpDiscoveryController @Inject constructor(
|
|||||||
// devices append. Anchored to end-of-string so it never eats
|
// devices append. Anchored to end-of-string so it never eats
|
||||||
// a legitimate parenthetical inside a name.
|
// a legitimate parenthetical inside a name.
|
||||||
val IP_SUFFIX_REGEX = Regex("""\s*\(\d+\.\d+\.\d+\.\d+\)$""")
|
val IP_SUFFIX_REGEX = Regex("""\s*\(\d+\.\d+\.\d+\.\d+\)$""")
|
||||||
|
|
||||||
|
// Aggressive connect timeout for transport SOAP so a dead renderer
|
||||||
|
// trips the drop-recovery quickly. Conservative enough not to false-drop
|
||||||
|
// a slow-but-alive LAN; read timeout still inherits the shared client.
|
||||||
|
const val CONTROL_CONNECT_TIMEOUT_SECONDS = 2L
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user