diff --git a/app/src/main/java/com/bartlomiejpluta/ttsserver/core/sonos/queue/SonosQueue.kt b/app/src/main/java/com/bartlomiejpluta/ttsserver/core/sonos/queue/SonosQueue.kt index c8da08d..7a4f456 100644 --- a/app/src/main/java/com/bartlomiejpluta/ttsserver/core/sonos/queue/SonosQueue.kt +++ b/app/src/main/java/com/bartlomiejpluta/ttsserver/core/sonos/queue/SonosQueue.kt @@ -1,5 +1,6 @@ package com.bartlomiejpluta.ttsserver.core.sonos.queue +import android.content.SharedPreferences import com.bartlomiejpluta.ttsserver.core.sonos.worker.SonosWorker import com.bartlomiejpluta.ttsserver.core.tts.engine.TTSEngine import com.bartlomiejpluta.ttsserver.core.util.NetworkUtil @@ -7,17 +8,25 @@ import com.bartlomiejpluta.ttsserver.core.web.dto.SonosDTO import java.util.concurrent.BlockingQueue import java.util.concurrent.LinkedBlockingQueue -class SonosQueue(private val tts: TTSEngine, private val networkUtil: NetworkUtil) { +class SonosQueue( + private val tts: TTSEngine, + private val preferences: SharedPreferences, + private val networkUtil: NetworkUtil +) { private val queue: BlockingQueue = LinkedBlockingQueue() private var consumer: Thread? = null fun run() { consumer?.interrupt() - consumer = Thread(SonosWorker(tts, networkUtil.serverAddress, queue)) - .also { it.name = "SonosQueue" } + consumer = createWorkerThread() consumer?.start() } + private fun createWorkerThread(): Thread { + val worker = SonosWorker(tts, networkUtil.serverAddress, preferences, queue) + return Thread(worker).also { it.name = "SonosQueue" } + } + fun stop() { consumer?.interrupt() consumer = null diff --git a/app/src/main/java/com/bartlomiejpluta/ttsserver/core/sonos/worker/SonosWorker.kt b/app/src/main/java/com/bartlomiejpluta/ttsserver/core/sonos/worker/SonosWorker.kt index a379143..62143f1 100644 --- a/app/src/main/java/com/bartlomiejpluta/ttsserver/core/sonos/worker/SonosWorker.kt +++ b/app/src/main/java/com/bartlomiejpluta/ttsserver/core/sonos/worker/SonosWorker.kt @@ -1,9 +1,12 @@ package com.bartlomiejpluta.ttsserver.core.sonos.worker +import android.content.SharedPreferences import com.bartlomiejpluta.ttsserver.core.tts.engine.TTSEngine import com.bartlomiejpluta.ttsserver.core.web.dto.SonosDTO +import com.bartlomiejpluta.ttsserver.core.web.endpoint.Endpoint import com.bartlomiejpluta.ttsserver.service.foreground.ForegroundService import com.bartlomiejpluta.ttsserver.service.state.ServiceState +import com.bartlomiejpluta.ttsserver.ui.preference.PreferenceKey import com.vmichalak.sonoscontroller.Snapshot import com.vmichalak.sonoscontroller.SonosDevice import com.vmichalak.sonoscontroller.SonosDiscovery @@ -13,8 +16,11 @@ import java.util.concurrent.BlockingQueue class SonosWorker( private val tts: TTSEngine, private val address: String, + private val preferences: SharedPreferences, private val queue: BlockingQueue ) : Runnable { + private val gongUrl: String get() = address + Endpoint.GONG.trimmedUri + private val announcementUrl: String get() = address + Endpoint.SONOS_CACHE.trimmedUri private var snapshot: Snapshot? = null override fun run() = try { @@ -27,21 +33,30 @@ class SonosWorker( private fun consume(data: SonosDTO) = SonosDiscovery.discover().firstOrNull { it.zoneGroupState.name == data.zone }?.let { - updateSnapshotIfFirst(it) val url = prepareTTSFile(data) + updateSnapshotIfFirst(it) announce(it, data, url) restoreSnapshotIfLast() } private fun prepareTTSFile(data: SonosDTO): String { val filename = tts.createTTSFile(data.text, data.language).name - return "$address/sonos/$filename" + return "$announcementUrl$filename" } private fun announce(device: SonosDevice, data: SonosDTO, url: String) { device.stop() device.volume = data.volume - device.playUri(url, "") + + if (preferences.getBoolean(PreferenceKey.ENABLE_GONG, false)) { + playUri(device, gongUrl) + } + + playUri(device, url) + } + + private fun playUri(device: SonosDevice, uri: String) { + device.playUri(uri, "") while (device.playState != PlayState.STOPPED) { Thread.sleep(500) } diff --git a/app/src/main/java/com/bartlomiejpluta/ttsserver/core/web/endpoint/Endpoint.kt b/app/src/main/java/com/bartlomiejpluta/ttsserver/core/web/endpoint/Endpoint.kt index 5e1479c..50b92ae 100644 --- a/app/src/main/java/com/bartlomiejpluta/ttsserver/core/web/endpoint/Endpoint.kt +++ b/app/src/main/java/com/bartlomiejpluta/ttsserver/core/web/endpoint/Endpoint.kt @@ -5,7 +5,11 @@ enum class Endpoint(val uri: String, val id: Int) { SAY("/say", 2), WAVE("/wave", 3), SONOS("/sonos", 4), - SONOS_CACHE("/sonos/*", 5); + SONOS_CACHE("/sonos/*", 5), + GONG("/gong.wav", 6); + + val trimmedUri: String + get() = uri.replace("*", "") companion object { fun of(id: Int) = values().firstOrNull { it.id == id } ?: UNKNOWN diff --git a/app/src/main/java/com/bartlomiejpluta/ttsserver/core/web/server/WebServer.kt b/app/src/main/java/com/bartlomiejpluta/ttsserver/core/web/server/WebServer.kt index 2942ede..268c279 100644 --- a/app/src/main/java/com/bartlomiejpluta/ttsserver/core/web/server/WebServer.kt +++ b/app/src/main/java/com/bartlomiejpluta/ttsserver/core/web/server/WebServer.kt @@ -7,6 +7,7 @@ import android.net.Uri import androidx.localbroadcastmanager.content.LocalBroadcastManager import com.bartlomiejpluta.ttsserver.core.sonos.queue.SonosQueue import com.bartlomiejpluta.ttsserver.core.tts.engine.TTSEngine +import com.bartlomiejpluta.ttsserver.core.tts.exception.TTSException import com.bartlomiejpluta.ttsserver.core.tts.status.TTSStatus import com.bartlomiejpluta.ttsserver.core.web.dto.BaseDTO import com.bartlomiejpluta.ttsserver.core.web.dto.SonosDTO @@ -59,6 +60,7 @@ class WebServer( Endpoint.WAVE -> wave(it) Endpoint.SONOS -> sonos(it) Endpoint.SONOS_CACHE -> sonosCache(it) + Endpoint.GONG -> gong(it) Endpoint.UNKNOWN -> throw WebException(NOT_FOUND) } } @@ -161,6 +163,29 @@ class WebServer( return newFixedLengthResponse(OK, MIME_WAVE, stream, size) } + private fun gong(session: IHTTPSession): Response { + if (!preferences.getBoolean(PreferenceKey.ENABLE_GONG, false)) { + throw WebException(NOT_FOUND) + } + + if (session.method != Method.GET) { + throw WebException(METHOD_NOT_ALLOWED, "Only GET methods are allowed") + } + + val uri = Uri.parse( + preferences.getString(PreferenceKey.GONG, null) ?: throw TTSException() + ) + + val size = context.contentResolver.openFileDescriptor(uri, "r")?.statSize + ?: throw TTSException() + + val stream = BufferedInputStream( + context.contentResolver.openInputStream(uri) ?: throw TTSException() + ) + + return newFixedLengthResponse(OK, MIME_WAVE, stream, size) + } + override fun start() { super.start() sonos.run() diff --git a/app/src/main/java/com/bartlomiejpluta/ttsserver/di/module/TTSModule.kt b/app/src/main/java/com/bartlomiejpluta/ttsserver/di/module/TTSModule.kt index 0453cfd..35839de 100644 --- a/app/src/main/java/com/bartlomiejpluta/ttsserver/di/module/TTSModule.kt +++ b/app/src/main/java/com/bartlomiejpluta/ttsserver/di/module/TTSModule.kt @@ -60,7 +60,8 @@ class TTSModule { @Provides @Singleton - fun sonosQueue(tts: TTSEngine, networkUtil: NetworkUtil) = SonosQueue(tts, networkUtil) + fun sonosQueue(tts: TTSEngine, preferences: SharedPreferences, networkUtil: NetworkUtil) = + SonosQueue(tts, preferences, networkUtil) @Provides @Singleton