Enable gong for /sonos endpoint
This commit is contained in:
@@ -1,5 +1,6 @@
|
|||||||
package com.bartlomiejpluta.ttsserver.core.sonos.queue
|
package com.bartlomiejpluta.ttsserver.core.sonos.queue
|
||||||
|
|
||||||
|
import android.content.SharedPreferences
|
||||||
import com.bartlomiejpluta.ttsserver.core.sonos.worker.SonosWorker
|
import com.bartlomiejpluta.ttsserver.core.sonos.worker.SonosWorker
|
||||||
import com.bartlomiejpluta.ttsserver.core.tts.engine.TTSEngine
|
import com.bartlomiejpluta.ttsserver.core.tts.engine.TTSEngine
|
||||||
import com.bartlomiejpluta.ttsserver.core.util.NetworkUtil
|
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.BlockingQueue
|
||||||
import java.util.concurrent.LinkedBlockingQueue
|
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<SonosDTO> = LinkedBlockingQueue()
|
private val queue: BlockingQueue<SonosDTO> = LinkedBlockingQueue()
|
||||||
private var consumer: Thread? = null
|
private var consumer: Thread? = null
|
||||||
|
|
||||||
fun run() {
|
fun run() {
|
||||||
consumer?.interrupt()
|
consumer?.interrupt()
|
||||||
consumer = Thread(SonosWorker(tts, networkUtil.serverAddress, queue))
|
consumer = createWorkerThread()
|
||||||
.also { it.name = "SonosQueue" }
|
|
||||||
consumer?.start()
|
consumer?.start()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun createWorkerThread(): Thread {
|
||||||
|
val worker = SonosWorker(tts, networkUtil.serverAddress, preferences, queue)
|
||||||
|
return Thread(worker).also { it.name = "SonosQueue" }
|
||||||
|
}
|
||||||
|
|
||||||
fun stop() {
|
fun stop() {
|
||||||
consumer?.interrupt()
|
consumer?.interrupt()
|
||||||
consumer = null
|
consumer = null
|
||||||
|
|||||||
@@ -1,9 +1,12 @@
|
|||||||
package com.bartlomiejpluta.ttsserver.core.sonos.worker
|
package com.bartlomiejpluta.ttsserver.core.sonos.worker
|
||||||
|
|
||||||
|
import android.content.SharedPreferences
|
||||||
import com.bartlomiejpluta.ttsserver.core.tts.engine.TTSEngine
|
import com.bartlomiejpluta.ttsserver.core.tts.engine.TTSEngine
|
||||||
import com.bartlomiejpluta.ttsserver.core.web.dto.SonosDTO
|
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.foreground.ForegroundService
|
||||||
import com.bartlomiejpluta.ttsserver.service.state.ServiceState
|
import com.bartlomiejpluta.ttsserver.service.state.ServiceState
|
||||||
|
import com.bartlomiejpluta.ttsserver.ui.preference.PreferenceKey
|
||||||
import com.vmichalak.sonoscontroller.Snapshot
|
import com.vmichalak.sonoscontroller.Snapshot
|
||||||
import com.vmichalak.sonoscontroller.SonosDevice
|
import com.vmichalak.sonoscontroller.SonosDevice
|
||||||
import com.vmichalak.sonoscontroller.SonosDiscovery
|
import com.vmichalak.sonoscontroller.SonosDiscovery
|
||||||
@@ -13,8 +16,11 @@ import java.util.concurrent.BlockingQueue
|
|||||||
class SonosWorker(
|
class SonosWorker(
|
||||||
private val tts: TTSEngine,
|
private val tts: TTSEngine,
|
||||||
private val address: String,
|
private val address: String,
|
||||||
|
private val preferences: SharedPreferences,
|
||||||
private val queue: BlockingQueue<SonosDTO>
|
private val queue: BlockingQueue<SonosDTO>
|
||||||
) : Runnable {
|
) : 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
|
private var snapshot: Snapshot? = null
|
||||||
|
|
||||||
override fun run() = try {
|
override fun run() = try {
|
||||||
@@ -27,21 +33,30 @@ class SonosWorker(
|
|||||||
|
|
||||||
private fun consume(data: SonosDTO) =
|
private fun consume(data: SonosDTO) =
|
||||||
SonosDiscovery.discover().firstOrNull { it.zoneGroupState.name == data.zone }?.let {
|
SonosDiscovery.discover().firstOrNull { it.zoneGroupState.name == data.zone }?.let {
|
||||||
updateSnapshotIfFirst(it)
|
|
||||||
val url = prepareTTSFile(data)
|
val url = prepareTTSFile(data)
|
||||||
|
updateSnapshotIfFirst(it)
|
||||||
announce(it, data, url)
|
announce(it, data, url)
|
||||||
restoreSnapshotIfLast()
|
restoreSnapshotIfLast()
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun prepareTTSFile(data: SonosDTO): String {
|
private fun prepareTTSFile(data: SonosDTO): String {
|
||||||
val filename = tts.createTTSFile(data.text, data.language).name
|
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) {
|
private fun announce(device: SonosDevice, data: SonosDTO, url: String) {
|
||||||
device.stop()
|
device.stop()
|
||||||
device.volume = data.volume
|
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) {
|
while (device.playState != PlayState.STOPPED) {
|
||||||
Thread.sleep(500)
|
Thread.sleep(500)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,7 +5,11 @@ enum class Endpoint(val uri: String, val id: Int) {
|
|||||||
SAY("/say", 2),
|
SAY("/say", 2),
|
||||||
WAVE("/wave", 3),
|
WAVE("/wave", 3),
|
||||||
SONOS("/sonos", 4),
|
SONOS("/sonos", 4),
|
||||||
SONOS_CACHE("/sonos/*", 5);
|
SONOS_CACHE("/sonos/*", 5),
|
||||||
|
GONG("/gong.wav", 6);
|
||||||
|
|
||||||
|
val trimmedUri: String
|
||||||
|
get() = uri.replace("*", "")
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
fun of(id: Int) = values().firstOrNull { it.id == id } ?: UNKNOWN
|
fun of(id: Int) = values().firstOrNull { it.id == id } ?: UNKNOWN
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ import android.net.Uri
|
|||||||
import androidx.localbroadcastmanager.content.LocalBroadcastManager
|
import androidx.localbroadcastmanager.content.LocalBroadcastManager
|
||||||
import com.bartlomiejpluta.ttsserver.core.sonos.queue.SonosQueue
|
import com.bartlomiejpluta.ttsserver.core.sonos.queue.SonosQueue
|
||||||
import com.bartlomiejpluta.ttsserver.core.tts.engine.TTSEngine
|
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.tts.status.TTSStatus
|
||||||
import com.bartlomiejpluta.ttsserver.core.web.dto.BaseDTO
|
import com.bartlomiejpluta.ttsserver.core.web.dto.BaseDTO
|
||||||
import com.bartlomiejpluta.ttsserver.core.web.dto.SonosDTO
|
import com.bartlomiejpluta.ttsserver.core.web.dto.SonosDTO
|
||||||
@@ -59,6 +60,7 @@ class WebServer(
|
|||||||
Endpoint.WAVE -> wave(it)
|
Endpoint.WAVE -> wave(it)
|
||||||
Endpoint.SONOS -> sonos(it)
|
Endpoint.SONOS -> sonos(it)
|
||||||
Endpoint.SONOS_CACHE -> sonosCache(it)
|
Endpoint.SONOS_CACHE -> sonosCache(it)
|
||||||
|
Endpoint.GONG -> gong(it)
|
||||||
Endpoint.UNKNOWN -> throw WebException(NOT_FOUND)
|
Endpoint.UNKNOWN -> throw WebException(NOT_FOUND)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -161,6 +163,29 @@ class WebServer(
|
|||||||
return newFixedLengthResponse(OK, MIME_WAVE, stream, size)
|
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() {
|
override fun start() {
|
||||||
super.start()
|
super.start()
|
||||||
sonos.run()
|
sonos.run()
|
||||||
|
|||||||
@@ -60,7 +60,8 @@ class TTSModule {
|
|||||||
|
|
||||||
@Provides
|
@Provides
|
||||||
@Singleton
|
@Singleton
|
||||||
fun sonosQueue(tts: TTSEngine, networkUtil: NetworkUtil) = SonosQueue(tts, networkUtil)
|
fun sonosQueue(tts: TTSEngine, preferences: SharedPreferences, networkUtil: NetworkUtil) =
|
||||||
|
SonosQueue(tts, preferences, networkUtil)
|
||||||
|
|
||||||
@Provides
|
@Provides
|
||||||
@Singleton
|
@Singleton
|
||||||
|
|||||||
Reference in New Issue
Block a user