Refactor io.bartek.ttsserver.tts package

This commit is contained in:
2020-05-15 21:45:15 +02:00
parent e756d28b45
commit 6eaf27359d
11 changed files with 97 additions and 67 deletions

View File

@@ -8,8 +8,8 @@ import dagger.Module
import dagger.Provides
import io.bartek.ttsserver.service.ForegroundNotificationFactory
import io.bartek.ttsserver.sonos.SonosQueue
import io.bartek.ttsserver.tts.TTS
import io.bartek.ttsserver.tts.TTSStatusHolder
import io.bartek.ttsserver.tts.engine.TTSEngine
import io.bartek.ttsserver.tts.status.TTSStatusHolder
import io.bartek.ttsserver.util.NetworkUtil
import io.bartek.ttsserver.web.server.WebServerFactory
import javax.inject.Singleton
@@ -29,14 +29,14 @@ class TTSModule {
@Provides
@Singleton
fun tts(context: Context, textToSpeech: TextToSpeech, ttsStatusHolder: TTSStatusHolder) =
TTS(context, textToSpeech, ttsStatusHolder)
TTSEngine(context, textToSpeech, ttsStatusHolder)
@Provides
@Singleton
fun webServerFactory(
preferences: SharedPreferences,
context: Context,
tts: TTS,
tts: TTSEngine,
sonos: SonosQueue
) =
WebServerFactory(
@@ -56,7 +56,7 @@ class TTSModule {
@Provides
@Singleton
fun sonosQueue(tts: TTS, networkUtil: NetworkUtil, preferences: SharedPreferences) =
fun sonosQueue(tts: TTSEngine, networkUtil: NetworkUtil, preferences: SharedPreferences) =
SonosQueue(tts, networkUtil, preferences)
@Provides

View File

@@ -5,14 +5,14 @@ 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.TTS
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: TTS,
private val tts: TTSEngine,
private val host: String,
private val port: Int,
private val queue: BlockingQueue<BaseDTO>
@@ -40,7 +40,7 @@ private class Consumer(
}
class SonosQueue(
private val tts: TTS,
private val tts: TTSEngine,
private val networkUtil: NetworkUtil,
private val preferences: SharedPreferences
) {

View File

@@ -1,27 +1,28 @@
package io.bartek.ttsserver.tts
package io.bartek.ttsserver.tts.engine
import android.content.Context
import android.speech.tts.TextToSpeech
import android.speech.tts.UtteranceProgressListener
import io.bartek.ttsserver.exception.TTSException
import io.bartek.ttsserver.tts.exception.TTSException
import io.bartek.ttsserver.tts.listener.Lock
import io.bartek.ttsserver.tts.listener.TTSProcessListener
import io.bartek.ttsserver.tts.model.TTSStream
import io.bartek.ttsserver.tts.status.TTSStatus
import io.bartek.ttsserver.tts.status.TTSStatusHolder
import java.io.BufferedInputStream
import java.io.File
import java.io.FileInputStream
import java.io.InputStream
import java.security.MessageDigest
import java.util.*
data class SpeechData(val stream: InputStream, val size: Long)
class TTS(
class TTSEngine(
private val context: Context,
private val tts: TextToSpeech,
private val ttsStausHolder: TTSStatusHolder
private val ttsStatusHolder: TTSStatusHolder
) {
private val messageDigest = MessageDigest.getInstance("SHA-256")
val status: TTSStatus
get() = ttsStausHolder.status
get() = ttsStatusHolder.status
fun createTTSFile(text: String, language: Locale): File {
val digest = hash(text, language)
@@ -32,7 +33,12 @@ class TTS(
val uuid = UUID.randomUUID().toString()
val lock = Lock()
tts.setOnUtteranceProgressListener(TTSProcessListener(uuid, lock))
tts.setOnUtteranceProgressListener(
TTSProcessListener(
uuid,
lock
)
)
synchronized(lock) {
tts.language = language
@@ -53,12 +59,17 @@ class TTS(
return digest.fold("", { str, it -> str + "%02x".format(it) })
}
fun fetchTTSStream(text: String, language: Locale): SpeechData {
fun fetchTTSStream(text: String, language: Locale): TTSStream {
val file = createTempFile("tmp_tts_server", ".wav")
val uuid = UUID.randomUUID().toString()
val lock = Lock()
tts.setOnUtteranceProgressListener(TTSProcessListener(uuid, lock))
tts.setOnUtteranceProgressListener(
TTSProcessListener(
uuid,
lock
)
)
synchronized(lock) {
tts.language = language
@@ -75,13 +86,18 @@ class TTS(
file.delete()
return SpeechData(stream, length)
return TTSStream(stream, length)
}
fun performTTS(text: String, language: Locale) {
val uuid = UUID.randomUUID().toString()
val lock = Lock()
tts.setOnUtteranceProgressListener(TTSProcessListener(uuid, lock))
tts.setOnUtteranceProgressListener(
TTSProcessListener(
uuid,
lock
)
)
synchronized(lock) {
tts.language = language
@@ -95,32 +111,3 @@ class TTS(
}
}
@Suppress("PLATFORM_CLASS_MAPPED_TO_KOTLIN")
// TODO: Investigate the Kotlin way to achieve the same
private data class Lock(var success: Boolean = false) : Object()
private class TTSProcessListener(
private val uuid: String,
private val lock: Lock
) : UtteranceProgressListener() {
override fun onDone(utteranceId: String?) {
if (utteranceId == uuid) {
synchronized(lock) {
lock.success = true
lock.notifyAll()
}
}
}
override fun onError(utteranceId: String?) {
if (utteranceId == uuid) {
synchronized(lock) {
lock.success = false
lock.notifyAll()
}
}
}
override fun onStart(utteranceId: String?) {}
}

View File

@@ -1,3 +1,3 @@
package io.bartek.ttsserver.exception
package io.bartek.ttsserver.tts.exception
class TTSException : Exception("TTS process failed")

View File

@@ -0,0 +1,5 @@
package io.bartek.ttsserver.tts.listener
@Suppress("PLATFORM_CLASS_MAPPED_TO_KOTLIN")
// TODO: Investigate the Kotlin way to achieve the same
data class Lock(var success: Boolean = false) : Object()

View File

@@ -0,0 +1,29 @@
package io.bartek.ttsserver.tts.listener
import android.speech.tts.UtteranceProgressListener
class TTSProcessListener(
private val uuid: String,
private val lock: Lock
) : UtteranceProgressListener() {
override fun onDone(utteranceId: String?) {
if (utteranceId == uuid) {
synchronized(lock) {
lock.success = true
lock.notifyAll()
}
}
}
override fun onError(utteranceId: String?) {
if (utteranceId == uuid) {
synchronized(lock) {
lock.success = false
lock.notifyAll()
}
}
}
override fun onStart(utteranceId: String?) {}
}

View File

@@ -0,0 +1,5 @@
package io.bartek.ttsserver.tts.model
import java.io.InputStream
data class TTSStream(val stream: InputStream, val length: Long)

View File

@@ -1,4 +1,4 @@
package io.bartek.ttsserver.tts
package io.bartek.ttsserver.tts.status
import android.speech.tts.TextToSpeech
@@ -10,13 +10,4 @@ enum class TTSStatus(private val status: Int) {
companion object {
fun of(status: Int) = values().firstOrNull { it.status == status } ?: UNLOADED
}
}
class TTSStatusHolder : TextToSpeech.OnInitListener {
var status = TTSStatus.UNLOADED
private set
override fun onInit(status: Int) {
this.status = TTSStatus.of(status)
}
}

View File

@@ -0,0 +1,13 @@
package io.bartek.ttsserver.tts.status
import android.speech.tts.TextToSpeech
import io.bartek.ttsserver.tts.status.TTSStatus
class TTSStatusHolder : TextToSpeech.OnInitListener {
var status = TTSStatus.UNLOADED
private set
override fun onInit(status: Int) {
this.status = TTSStatus.of(status)
}
}

View File

@@ -11,8 +11,8 @@ 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.tts.TTS
import io.bartek.ttsserver.tts.TTSStatus
import io.bartek.ttsserver.tts.engine.TTSEngine
import io.bartek.ttsserver.tts.status.TTSStatus
import io.bartek.ttsserver.web.dto.BaseDTO
import io.bartek.ttsserver.web.dto.SonosDTO
import io.bartek.ttsserver.web.endpoint.Endpoint
@@ -26,7 +26,7 @@ class WebServer(
port: Int,
private val context: Context,
private val preferences: SharedPreferences,
private val tts: TTS,
private val tts: TTSEngine,
private val sonos: SonosQueue
) : NanoHTTPD(port) {
override fun serve(session: IHTTPSession?): Response {

View File

@@ -4,12 +4,12 @@ import android.content.Context
import android.content.SharedPreferences
import io.bartek.ttsserver.preference.PreferenceKey
import io.bartek.ttsserver.sonos.SonosQueue
import io.bartek.ttsserver.tts.TTS
import io.bartek.ttsserver.tts.engine.TTSEngine
class WebServerFactory(
private val preferences: SharedPreferences,
private val context: Context,
private val tts: TTS,
private val tts: TTSEngine,
private val sonos: SonosQueue
) {
fun createWebServer() =