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