feat(android): RenderingControl get/set volume
android / Build + lint + test (push) Failing after 1m33s
android / Build + lint + test (push) Failing after 1m33s
This commit is contained in:
+44
@@ -0,0 +1,44 @@
|
||||
package com.fabledsword.minstrel.player.output.upnp
|
||||
|
||||
import okhttp3.HttpUrl
|
||||
|
||||
/**
|
||||
* RenderingControl service wrapper for hardware-volume routing while a
|
||||
* UPnP route is active. GetVolume seeds an in-memory cache; SetVolume
|
||||
* is invoked by NowPlayingScreen's volume-key interceptor. Clamps to
|
||||
* the UPnP-standard 0..100 range.
|
||||
*/
|
||||
class RenderingControlClient(
|
||||
private val soap: SoapClient,
|
||||
private val controlUrl: HttpUrl,
|
||||
) {
|
||||
suspend fun getVolume(channel: String = "Master"): Int {
|
||||
val args = soap.call(
|
||||
controlUrl = controlUrl,
|
||||
serviceType = SERVICE_TYPE,
|
||||
action = "GetVolume",
|
||||
args = mapOf("InstanceID" to "0", "Channel" to channel),
|
||||
)
|
||||
return args["CurrentVolume"]?.toIntOrNull() ?: 0
|
||||
}
|
||||
|
||||
suspend fun setVolume(volume: Int, channel: String = "Master") {
|
||||
val clamped = volume.coerceIn(VOLUME_MIN, VOLUME_MAX)
|
||||
soap.call(
|
||||
controlUrl = controlUrl,
|
||||
serviceType = SERVICE_TYPE,
|
||||
action = "SetVolume",
|
||||
args = mapOf(
|
||||
"InstanceID" to "0",
|
||||
"Channel" to channel,
|
||||
"DesiredVolume" to clamped.toString(),
|
||||
),
|
||||
)
|
||||
}
|
||||
|
||||
private companion object {
|
||||
const val SERVICE_TYPE = "urn:schemas-upnp-org:service:RenderingControl:1"
|
||||
const val VOLUME_MIN = 0
|
||||
const val VOLUME_MAX = 100
|
||||
}
|
||||
}
|
||||
+56
@@ -0,0 +1,56 @@
|
||||
package com.fabledsword.minstrel.player.output.upnp
|
||||
|
||||
import kotlinx.coroutines.test.runTest
|
||||
import okhttp3.OkHttpClient
|
||||
import okhttp3.mockwebserver.MockResponse
|
||||
import okhttp3.mockwebserver.MockWebServer
|
||||
import org.junit.jupiter.api.AfterEach
|
||||
import org.junit.jupiter.api.BeforeEach
|
||||
import org.junit.jupiter.api.Test
|
||||
import kotlin.test.assertEquals
|
||||
import kotlin.test.assertTrue
|
||||
|
||||
class RenderingControlClientTest {
|
||||
|
||||
private lateinit var server: MockWebServer
|
||||
private lateinit var client: RenderingControlClient
|
||||
|
||||
@BeforeEach
|
||||
fun setUp() {
|
||||
server = MockWebServer()
|
||||
server.start()
|
||||
client = RenderingControlClient(SoapClient(OkHttpClient()), server.url("/RC"))
|
||||
}
|
||||
|
||||
@AfterEach
|
||||
fun tearDown() { server.shutdown() }
|
||||
|
||||
@Test
|
||||
fun `getVolume parses CurrentVolume`() = runTest {
|
||||
server.enqueue(MockResponse().setBody(
|
||||
"""<?xml version="1.0"?>
|
||||
<s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/">
|
||||
<s:Body>
|
||||
<u:GetVolumeResponse xmlns:u="urn:schemas-upnp-org:service:RenderingControl:1">
|
||||
<CurrentVolume>42</CurrentVolume>
|
||||
</u:GetVolumeResponse>
|
||||
</s:Body>
|
||||
</s:Envelope>""".trimIndent()))
|
||||
assertEquals(42, client.getVolume())
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `setVolume clamps and sends DesiredVolume`() = runTest {
|
||||
server.enqueue(MockResponse().setBody(
|
||||
"""<?xml version="1.0"?>
|
||||
<s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/">
|
||||
<s:Body>
|
||||
<u:SetVolumeResponse
|
||||
xmlns:u="urn:schemas-upnp-org:service:RenderingControl:1"/>
|
||||
</s:Body>
|
||||
</s:Envelope>""".trimIndent()))
|
||||
client.setVolume(150)
|
||||
val body = server.takeRequest().body.readUtf8()
|
||||
assertTrue(body.contains("<DesiredVolume>100</DesiredVolume>")) { body }
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user