From 763e386bec971dfe17fbb8f97468ebaa1b7c7a70 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Przemys=C5=82aw=20Pluta?= Date: Sat, 16 May 2020 10:54:11 +0200 Subject: [PATCH] Refactor io.bartek.ttsserver.sonos package --- .../java/io/bartek/ttsserver/di/TTSModule.kt | 2 +- .../io/bartek/ttsserver/sonos/SonosQueue.kt | 66 ------------------- .../bartek/ttsserver/sonos/SonosTTSRequest.kt | 2 - .../ttsserver/sonos/queue/SonosQueue.kt | 43 ++++++++++++ .../ttsserver/sonos/worker/SonosWorker.kt | 49 ++++++++++++++ .../io/bartek/ttsserver/web/dto/BaseDTO.kt | 30 ++------- .../java/io/bartek/ttsserver/web/dto/DTO.kt | 16 +++++ .../io/bartek/ttsserver/web/dto/SonosDTO.kt | 23 +++---- .../bartek/ttsserver/web/server/WebServer.kt | 8 +-- .../ttsserver/web/server/WebServerFactory.kt | 2 +- 10 files changed, 127 insertions(+), 114 deletions(-) delete mode 100644 app/src/main/java/io/bartek/ttsserver/sonos/SonosQueue.kt delete mode 100644 app/src/main/java/io/bartek/ttsserver/sonos/SonosTTSRequest.kt create mode 100644 app/src/main/java/io/bartek/ttsserver/sonos/queue/SonosQueue.kt create mode 100644 app/src/main/java/io/bartek/ttsserver/sonos/worker/SonosWorker.kt create mode 100644 app/src/main/java/io/bartek/ttsserver/web/dto/DTO.kt diff --git a/app/src/main/java/io/bartek/ttsserver/di/TTSModule.kt b/app/src/main/java/io/bartek/ttsserver/di/TTSModule.kt index 7a66331..cb7b370 100644 --- a/app/src/main/java/io/bartek/ttsserver/di/TTSModule.kt +++ b/app/src/main/java/io/bartek/ttsserver/di/TTSModule.kt @@ -7,7 +7,7 @@ import androidx.preference.PreferenceManager import dagger.Module import dagger.Provides 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.status.TTSStatusHolder import io.bartek.ttsserver.util.NetworkUtil diff --git a/app/src/main/java/io/bartek/ttsserver/sonos/SonosQueue.kt b/app/src/main/java/io/bartek/ttsserver/sonos/SonosQueue.kt deleted file mode 100644 index 610ce75..0000000 --- a/app/src/main/java/io/bartek/ttsserver/sonos/SonosQueue.kt +++ /dev/null @@ -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 -) : 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 = 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) -} \ No newline at end of file diff --git a/app/src/main/java/io/bartek/ttsserver/sonos/SonosTTSRequest.kt b/app/src/main/java/io/bartek/ttsserver/sonos/SonosTTSRequest.kt deleted file mode 100644 index b6aa139..0000000 --- a/app/src/main/java/io/bartek/ttsserver/sonos/SonosTTSRequest.kt +++ /dev/null @@ -1,2 +0,0 @@ -package io.bartek.ttsserver.sonos - diff --git a/app/src/main/java/io/bartek/ttsserver/sonos/queue/SonosQueue.kt b/app/src/main/java/io/bartek/ttsserver/sonos/queue/SonosQueue.kt new file mode 100644 index 0000000..41a4321 --- /dev/null +++ b/app/src/main/java/io/bartek/ttsserver/sonos/queue/SonosQueue.kt @@ -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 = 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) +} \ No newline at end of file diff --git a/app/src/main/java/io/bartek/ttsserver/sonos/worker/SonosWorker.kt b/app/src/main/java/io/bartek/ttsserver/sonos/worker/SonosWorker.kt new file mode 100644 index 0000000..b03cd6b --- /dev/null +++ b/app/src/main/java/io/bartek/ttsserver/sonos/worker/SonosWorker.kt @@ -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 +) : 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() + } + } +} \ No newline at end of file diff --git a/app/src/main/java/io/bartek/ttsserver/web/dto/BaseDTO.kt b/app/src/main/java/io/bartek/ttsserver/web/dto/BaseDTO.kt index 80461c8..f3c58d9 100644 --- a/app/src/main/java/io/bartek/ttsserver/web/dto/BaseDTO.kt +++ b/app/src/main/java/io/bartek/ttsserver/web/dto/BaseDTO.kt @@ -1,35 +1,15 @@ package io.bartek.ttsserver.web.dto -import fi.iki.elonen.NanoHTTPD -import fi.iki.elonen.NanoHTTPD.ResponseException import org.json.JSONObject 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 { - fun fromJSON(json: String): BaseDTO { - val root = JSONObject(json) + fun fromJSON(json: String) = JSONObject(json).let {root -> + val language = root.nullableString("language") ?.let { Locale(it) } ?: Locale.US + val text = root.requiredString("text") - val language = root.optString("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 - ) + BaseDTO(text, language) } } } \ No newline at end of file diff --git a/app/src/main/java/io/bartek/ttsserver/web/dto/DTO.kt b/app/src/main/java/io/bartek/ttsserver/web/dto/DTO.kt new file mode 100644 index 0000000..a35443d --- /dev/null +++ b/app/src/main/java/io/bartek/ttsserver/web/dto/DTO.kt @@ -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() } + } +} \ No newline at end of file diff --git a/app/src/main/java/io/bartek/ttsserver/web/dto/SonosDTO.kt b/app/src/main/java/io/bartek/ttsserver/web/dto/SonosDTO.kt index a23e1c3..9fe3d53 100644 --- a/app/src/main/java/io/bartek/ttsserver/web/dto/SonosDTO.kt +++ b/app/src/main/java/io/bartek/ttsserver/web/dto/SonosDTO.kt @@ -1,25 +1,18 @@ package io.bartek.ttsserver.web.dto -import fi.iki.elonen.NanoHTTPD -import fi.iki.elonen.NanoHTTPD.ResponseException import org.json.JSONObject 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 { - fun fromJSON(json: String): SonosDTO { - val root = JSONObject(json) + fun fromJSON(json: String) = JSONObject(json).let { root -> + 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") - .takeIf { it.isNotBlank() } - ?.let { Locale(it) } - ?: Locale.US - val text = root.optString("text") ?: throw ResponseException( - NanoHTTPD.Response.Status.BAD_REQUEST, - "" - ) - - return SonosDTO(text, language) + SonosDTO(text, language, zone, volume) } } } \ No newline at end of file diff --git a/app/src/main/java/io/bartek/ttsserver/web/server/WebServer.kt b/app/src/main/java/io/bartek/ttsserver/web/server/WebServer.kt index 7768ca5..1f54ec2 100644 --- a/app/src/main/java/io/bartek/ttsserver/web/server/WebServer.kt +++ b/app/src/main/java/io/bartek/ttsserver/web/server/WebServer.kt @@ -10,7 +10,7 @@ import fi.iki.elonen.NanoHTTPD.Response.Status.* import io.bartek.ttsserver.preference.PreferenceKey import io.bartek.ttsserver.service.ForegroundService 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.status.TTSStatus import io.bartek.ttsserver.web.dto.BaseDTO @@ -73,7 +73,7 @@ class WebServer( } val (text, language) = extractBody(session) { - SonosDTO.fromJSON( + BaseDTO.fromJSON( it ) } @@ -103,7 +103,7 @@ class WebServer( } val (text, language) = extractBody(session) { - SonosDTO.fromJSON( + BaseDTO.fromJSON( it ) } @@ -127,7 +127,7 @@ class WebServer( } val data = extractBody(session) { - BaseDTO.fromJSON( + SonosDTO.fromJSON( it ) } diff --git a/app/src/main/java/io/bartek/ttsserver/web/server/WebServerFactory.kt b/app/src/main/java/io/bartek/ttsserver/web/server/WebServerFactory.kt index 243f13a..efe0f07 100644 --- a/app/src/main/java/io/bartek/ttsserver/web/server/WebServerFactory.kt +++ b/app/src/main/java/io/bartek/ttsserver/web/server/WebServerFactory.kt @@ -3,7 +3,7 @@ package io.bartek.ttsserver.web.server import android.content.Context import android.content.SharedPreferences 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 class WebServerFactory(