Refactor io.bartek.ttsserver.sonos package
This commit is contained in:
@@ -7,7 +7,7 @@ import androidx.preference.PreferenceManager
|
|||||||
import dagger.Module
|
import dagger.Module
|
||||||
import dagger.Provides
|
import dagger.Provides
|
||||||
import io.bartek.ttsserver.service.ForegroundNotificationFactory
|
import io.bartek.ttsserver.service.ForegroundNotificationFactory
|
||||||
import io.bartek.ttsserver.sonos.SonosQueue
|
import io.bartek.ttsserver.sonos.queue.SonosQueue
|
||||||
import io.bartek.ttsserver.tts.engine.TTSEngine
|
import io.bartek.ttsserver.tts.engine.TTSEngine
|
||||||
import io.bartek.ttsserver.tts.status.TTSStatusHolder
|
import io.bartek.ttsserver.tts.status.TTSStatusHolder
|
||||||
import io.bartek.ttsserver.util.NetworkUtil
|
import io.bartek.ttsserver.util.NetworkUtil
|
||||||
|
|||||||
@@ -1,66 +0,0 @@
|
|||||||
package io.bartek.ttsserver.sonos
|
|
||||||
|
|
||||||
import android.content.SharedPreferences
|
|
||||||
import com.vmichalak.sonoscontroller.SonosDiscovery
|
|
||||||
import io.bartek.ttsserver.preference.PreferenceKey
|
|
||||||
import io.bartek.ttsserver.service.ForegroundService
|
|
||||||
import io.bartek.ttsserver.service.ServiceState
|
|
||||||
import io.bartek.ttsserver.tts.engine.TTSEngine
|
|
||||||
import io.bartek.ttsserver.util.NetworkUtil
|
|
||||||
import io.bartek.ttsserver.web.dto.BaseDTO
|
|
||||||
import java.util.concurrent.BlockingQueue
|
|
||||||
import java.util.concurrent.LinkedBlockingQueue
|
|
||||||
|
|
||||||
private class Consumer(
|
|
||||||
private val tts: TTSEngine,
|
|
||||||
private val host: String,
|
|
||||||
private val port: Int,
|
|
||||||
private val queue: BlockingQueue<BaseDTO>
|
|
||||||
) : Runnable {
|
|
||||||
|
|
||||||
override fun run() = try {
|
|
||||||
while (ForegroundService.state == ServiceState.RUNNING) {
|
|
||||||
consume(queue.take())
|
|
||||||
}
|
|
||||||
} catch (e: InterruptedException) {
|
|
||||||
Thread.currentThread().interrupt()
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
private fun consume(data: BaseDTO) =
|
|
||||||
SonosDiscovery.discover().firstOrNull { it.zoneGroupState.name == data.zone }?.let {
|
|
||||||
val file = tts.createTTSFile(data.text, data.language)
|
|
||||||
val filename = file.name
|
|
||||||
val url = "http://$host:$port/sonos/$filename"
|
|
||||||
val currentVolume = it.volume
|
|
||||||
it.volume = data.volume
|
|
||||||
it.clip(url, "")
|
|
||||||
it.volume = currentVolume
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class SonosQueue(
|
|
||||||
private val tts: TTSEngine,
|
|
||||||
private val networkUtil: NetworkUtil,
|
|
||||||
private val preferences: SharedPreferences
|
|
||||||
) {
|
|
||||||
private val queue: BlockingQueue<BaseDTO> = LinkedBlockingQueue()
|
|
||||||
private val host: String
|
|
||||||
get() = networkUtil.getIpAddress()
|
|
||||||
private val port: Int
|
|
||||||
get() = preferences.getInt(PreferenceKey.PORT, 8080)
|
|
||||||
private var consumer: Thread? = null
|
|
||||||
|
|
||||||
fun run() {
|
|
||||||
consumer?.interrupt()
|
|
||||||
consumer = Thread(Consumer(tts, host, port, queue)).also { it.name = "SonosQueue" }
|
|
||||||
consumer?.start()
|
|
||||||
}
|
|
||||||
|
|
||||||
fun stop() {
|
|
||||||
consumer?.interrupt()
|
|
||||||
consumer = null
|
|
||||||
}
|
|
||||||
|
|
||||||
fun push(data: BaseDTO) = queue.add(data)
|
|
||||||
}
|
|
||||||
@@ -1,2 +0,0 @@
|
|||||||
package io.bartek.ttsserver.sonos
|
|
||||||
|
|
||||||
@@ -0,0 +1,43 @@
|
|||||||
|
package io.bartek.ttsserver.sonos.queue
|
||||||
|
|
||||||
|
import android.content.SharedPreferences
|
||||||
|
import io.bartek.ttsserver.preference.PreferenceKey
|
||||||
|
import io.bartek.ttsserver.sonos.worker.SonosWorker
|
||||||
|
import io.bartek.ttsserver.tts.engine.TTSEngine
|
||||||
|
import io.bartek.ttsserver.util.NetworkUtil
|
||||||
|
import io.bartek.ttsserver.web.dto.SonosDTO
|
||||||
|
import java.util.concurrent.BlockingQueue
|
||||||
|
import java.util.concurrent.LinkedBlockingQueue
|
||||||
|
|
||||||
|
class SonosQueue(
|
||||||
|
private val tts: TTSEngine,
|
||||||
|
private val networkUtil: NetworkUtil,
|
||||||
|
private val preferences: SharedPreferences
|
||||||
|
) {
|
||||||
|
private val queue: BlockingQueue<SonosDTO> = LinkedBlockingQueue()
|
||||||
|
private var consumer: Thread? = null
|
||||||
|
private val host: String
|
||||||
|
get() = networkUtil.getIpAddress()
|
||||||
|
private val port: Int
|
||||||
|
get() = preferences.getInt(PreferenceKey.PORT, 8080)
|
||||||
|
|
||||||
|
fun run() {
|
||||||
|
consumer?.interrupt()
|
||||||
|
consumer = Thread(
|
||||||
|
SonosWorker(
|
||||||
|
tts,
|
||||||
|
host,
|
||||||
|
port,
|
||||||
|
queue
|
||||||
|
)
|
||||||
|
).also { it.name = "SonosQueue" }
|
||||||
|
consumer?.start()
|
||||||
|
}
|
||||||
|
|
||||||
|
fun stop() {
|
||||||
|
consumer?.interrupt()
|
||||||
|
consumer = null
|
||||||
|
}
|
||||||
|
|
||||||
|
fun push(data: SonosDTO) = queue.add(data)
|
||||||
|
}
|
||||||
@@ -0,0 +1,49 @@
|
|||||||
|
package io.bartek.ttsserver.sonos.worker
|
||||||
|
|
||||||
|
import com.vmichalak.sonoscontroller.SonosDevice
|
||||||
|
import com.vmichalak.sonoscontroller.SonosDiscovery
|
||||||
|
import com.vmichalak.sonoscontroller.model.PlayState
|
||||||
|
import io.bartek.ttsserver.service.ForegroundService
|
||||||
|
import io.bartek.ttsserver.service.ServiceState
|
||||||
|
import io.bartek.ttsserver.tts.engine.TTSEngine
|
||||||
|
import io.bartek.ttsserver.web.dto.SonosDTO
|
||||||
|
import java.util.concurrent.BlockingQueue
|
||||||
|
|
||||||
|
class SonosWorker(
|
||||||
|
private val tts: TTSEngine,
|
||||||
|
private val host: String,
|
||||||
|
private val port: Int,
|
||||||
|
private val queue: BlockingQueue<SonosDTO>
|
||||||
|
) : Runnable {
|
||||||
|
|
||||||
|
override fun run() = try {
|
||||||
|
while (ForegroundService.state == ServiceState.RUNNING) {
|
||||||
|
consume(queue.take())
|
||||||
|
}
|
||||||
|
} catch (e: InterruptedException) {
|
||||||
|
Thread.currentThread().interrupt()
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun consume(data: SonosDTO) =
|
||||||
|
SonosDiscovery.discover().firstOrNull { it.zoneGroupState.name == data.zone }?.let {
|
||||||
|
val file = tts.createTTSFile(data.text, data.language)
|
||||||
|
val filename = file.name
|
||||||
|
val url = "http://$host:$port/sonos/$filename"
|
||||||
|
it.announce(url, data.volume)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun SonosDevice.announce(url: String, volume: Int) {
|
||||||
|
val currentPlayState = this.playState
|
||||||
|
val currentVolume = this.volume
|
||||||
|
|
||||||
|
this.stop()
|
||||||
|
this.volume = volume
|
||||||
|
this.clip(url, "")
|
||||||
|
|
||||||
|
this.volume = currentVolume
|
||||||
|
when(currentPlayState) {
|
||||||
|
PlayState.PLAYING -> this.play()
|
||||||
|
else -> this.stop()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,35 +1,15 @@
|
|||||||
package io.bartek.ttsserver.web.dto
|
package io.bartek.ttsserver.web.dto
|
||||||
|
|
||||||
import fi.iki.elonen.NanoHTTPD
|
|
||||||
import fi.iki.elonen.NanoHTTPD.ResponseException
|
|
||||||
import org.json.JSONObject
|
import org.json.JSONObject
|
||||||
import java.util.*
|
import java.util.*
|
||||||
|
|
||||||
data class BaseDTO(val text: String, val language: Locale, val zone: String, val volume: Int) {
|
data class BaseDTO(val text: String, val language: Locale) : DTO() {
|
||||||
companion object {
|
companion object {
|
||||||
fun fromJSON(json: String): BaseDTO {
|
fun fromJSON(json: String) = JSONObject(json).let {root ->
|
||||||
val root = JSONObject(json)
|
val language = root.nullableString("language") ?.let { Locale(it) } ?: Locale.US
|
||||||
|
val text = root.requiredString("text")
|
||||||
|
|
||||||
val language = root.optString("language")
|
BaseDTO(text, language)
|
||||||
.takeIf { it.isNotBlank() }
|
|
||||||
?.let { Locale(it) }
|
|
||||||
?: Locale.US
|
|
||||||
val text = root.optString("text") ?: throw ResponseException(
|
|
||||||
NanoHTTPD.Response.Status.BAD_REQUEST,
|
|
||||||
""
|
|
||||||
)
|
|
||||||
val zone = root.optString("zone") ?: throw ResponseException(
|
|
||||||
NanoHTTPD.Response.Status.BAD_REQUEST,
|
|
||||||
""
|
|
||||||
)
|
|
||||||
val volume = root.optInt("volume", 50)
|
|
||||||
|
|
||||||
return BaseDTO(
|
|
||||||
text,
|
|
||||||
language,
|
|
||||||
zone,
|
|
||||||
volume
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
16
app/src/main/java/io/bartek/ttsserver/web/dto/DTO.kt
Normal file
16
app/src/main/java/io/bartek/ttsserver/web/dto/DTO.kt
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
package io.bartek.ttsserver.web.dto
|
||||||
|
|
||||||
|
import fi.iki.elonen.NanoHTTPD.Response
|
||||||
|
import fi.iki.elonen.NanoHTTPD.ResponseException
|
||||||
|
import org.json.JSONObject
|
||||||
|
|
||||||
|
abstract class DTO {
|
||||||
|
companion object {
|
||||||
|
fun JSONObject.requiredString(key: String) = this.nullableString(key)
|
||||||
|
?: throw ResponseException(Response.Status.BAD_REQUEST, "")
|
||||||
|
|
||||||
|
|
||||||
|
fun JSONObject.nullableString(key: String) = this.optString(key)
|
||||||
|
.takeIf { it.isNotBlank() }
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,25 +1,18 @@
|
|||||||
package io.bartek.ttsserver.web.dto
|
package io.bartek.ttsserver.web.dto
|
||||||
|
|
||||||
import fi.iki.elonen.NanoHTTPD
|
|
||||||
import fi.iki.elonen.NanoHTTPD.ResponseException
|
|
||||||
import org.json.JSONObject
|
import org.json.JSONObject
|
||||||
import java.util.*
|
import java.util.*
|
||||||
|
|
||||||
data class SonosDTO(val text: String, val language: Locale) {
|
data class SonosDTO(val text: String, val language: Locale, val zone: String, val volume: Int) :
|
||||||
|
DTO() {
|
||||||
companion object {
|
companion object {
|
||||||
fun fromJSON(json: String): SonosDTO {
|
fun fromJSON(json: String) = JSONObject(json).let { root ->
|
||||||
val root = JSONObject(json)
|
val language = root.nullableString("language") ?.let { Locale(it) } ?: Locale.US
|
||||||
|
val text = root.requiredString("text")
|
||||||
|
val zone = root.requiredString("zone")
|
||||||
|
val volume = root.optInt("volume", 50)
|
||||||
|
|
||||||
val language = root.optString("language")
|
SonosDTO(text, language, zone, volume)
|
||||||
.takeIf { it.isNotBlank() }
|
|
||||||
?.let { Locale(it) }
|
|
||||||
?: Locale.US
|
|
||||||
val text = root.optString("text") ?: throw ResponseException(
|
|
||||||
NanoHTTPD.Response.Status.BAD_REQUEST,
|
|
||||||
""
|
|
||||||
)
|
|
||||||
|
|
||||||
return SonosDTO(text, language)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -10,7 +10,7 @@ import fi.iki.elonen.NanoHTTPD.Response.Status.*
|
|||||||
import io.bartek.ttsserver.preference.PreferenceKey
|
import io.bartek.ttsserver.preference.PreferenceKey
|
||||||
import io.bartek.ttsserver.service.ForegroundService
|
import io.bartek.ttsserver.service.ForegroundService
|
||||||
import io.bartek.ttsserver.service.ServiceState
|
import io.bartek.ttsserver.service.ServiceState
|
||||||
import io.bartek.ttsserver.sonos.SonosQueue
|
import io.bartek.ttsserver.sonos.queue.SonosQueue
|
||||||
import io.bartek.ttsserver.tts.engine.TTSEngine
|
import io.bartek.ttsserver.tts.engine.TTSEngine
|
||||||
import io.bartek.ttsserver.tts.status.TTSStatus
|
import io.bartek.ttsserver.tts.status.TTSStatus
|
||||||
import io.bartek.ttsserver.web.dto.BaseDTO
|
import io.bartek.ttsserver.web.dto.BaseDTO
|
||||||
@@ -73,7 +73,7 @@ class WebServer(
|
|||||||
}
|
}
|
||||||
|
|
||||||
val (text, language) = extractBody(session) {
|
val (text, language) = extractBody(session) {
|
||||||
SonosDTO.fromJSON(
|
BaseDTO.fromJSON(
|
||||||
it
|
it
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@@ -103,7 +103,7 @@ class WebServer(
|
|||||||
}
|
}
|
||||||
|
|
||||||
val (text, language) = extractBody(session) {
|
val (text, language) = extractBody(session) {
|
||||||
SonosDTO.fromJSON(
|
BaseDTO.fromJSON(
|
||||||
it
|
it
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@@ -127,7 +127,7 @@ class WebServer(
|
|||||||
}
|
}
|
||||||
|
|
||||||
val data = extractBody(session) {
|
val data = extractBody(session) {
|
||||||
BaseDTO.fromJSON(
|
SonosDTO.fromJSON(
|
||||||
it
|
it
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ package io.bartek.ttsserver.web.server
|
|||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.content.SharedPreferences
|
import android.content.SharedPreferences
|
||||||
import io.bartek.ttsserver.preference.PreferenceKey
|
import io.bartek.ttsserver.preference.PreferenceKey
|
||||||
import io.bartek.ttsserver.sonos.SonosQueue
|
import io.bartek.ttsserver.sonos.queue.SonosQueue
|
||||||
import io.bartek.ttsserver.tts.engine.TTSEngine
|
import io.bartek.ttsserver.tts.engine.TTSEngine
|
||||||
|
|
||||||
class WebServerFactory(
|
class WebServerFactory(
|
||||||
|
|||||||
Reference in New Issue
Block a user