diff --git a/src/Main.kt b/src/Main.kt index bc986a1..de6fb91 100644 --- a/src/Main.kt +++ b/src/Main.kt @@ -18,6 +18,7 @@ import web.WebApp import java.time.DayOfWeek import java.time.LocalDate import java.time.LocalTime +import kotlin.concurrent.fixedRateTimer fun main() { @@ -141,7 +142,7 @@ fun main() { listOf( Pair("admin", "password"), Pair("user", "password") - ), db + ), db, StreamerOutputs ) web.Start() @@ -154,7 +155,7 @@ fun main() { // belum create BarixConnection untuk ipaddress ini Logger.info{"New Streamer Output connection from ${cmd.ipaddress}"} if (_sc!=null){ - val _bc = BarixConnection(_sc.channel,cmd.ipaddress) + val _bc = BarixConnection(_sc.index,_sc.channel,cmd.ipaddress) _bc.vu = cmd.vu _bc.bufferRemain = cmd.buffremain _bc.statusData = cmd.statusdata @@ -163,7 +164,7 @@ fun main() { } else { // sudah ada, update data - if (_sc !=null && !_sc.channel.equals(_streamer.channel)) { + if (_sc !=null && _sc.channel != _streamer.channel) { _streamer.channel = _sc.channel } _streamer.vu = cmd.vu @@ -173,5 +174,23 @@ fun main() { } + val onlinechecker = fixedRateTimer(name="onlinecheck", initialDelay = 1000, period = 1000) { + // cek setiap 1 detik, decrement online counter semua BarixConnection + StreamerOutputs.values.forEach { + it.decrementOnlineCounter() + } + } + + // shutdown hook + Runtime.getRuntime().addShutdownHook(Thread { + Logger.info{"Shutdown hook called, stopping services..."} + barixserver.StopTcpCommand() + onlinechecker.cancel() + web.Stop() + audioPlayer.Close() + db.close() + Logger.info{"All services stopped, exiting application."} + } ) + } diff --git a/src/audio/AudioPlayer.kt b/src/audio/AudioPlayer.kt index 985e957..a70d3fe 100644 --- a/src/audio/AudioPlayer.kt +++ b/src/audio/AudioPlayer.kt @@ -75,7 +75,7 @@ class AudioPlayer (var samplingrate: Int) { /** * Uninitializes the audio system if it was previously initialized. */ - fun UnInitAudio(){ + fun Close(){ if (initedDevice != -1) { bass.BASS_SetDevice(initedDevice) if (bass.BASS_Free()) { diff --git a/src/barix/BarixConnection.kt b/src/barix/BarixConnection.kt index ad0b02d..31036fe 100644 --- a/src/barix/BarixConnection.kt +++ b/src/barix/BarixConnection.kt @@ -1,26 +1,74 @@ package barix +import codes.Somecodes +import com.fasterxml.jackson.databind.JsonNode import org.tinylog.Logger import java.net.DatagramPacket import java.net.DatagramSocket import java.net.InetSocketAddress @Suppress("unused") -class BarixConnection(var channel: String, val ipaddress: String, val port: Int = 5002) { - var bufferRemain: Int = 0 - var statusData: Int = 0 - var vu: Int = 0 +class BarixConnection(val index: UInt, var channel: String, val ipaddress: String, val port: Int = 5002) { + private var _bR: Int = 0 + private var _sd: Int = 0 + private var _vu: Int = 0 + private var _onlinecounter = 0 private val udp = DatagramSocket(0) private val inet = InetSocketAddress(ipaddress, port) + + + /** + * Buffer remain in bytes + */ + var bufferRemain: Int + get() = _bR + set(value) { + _bR = value + _onlinecounter = 5 + } + + /** + * Status data, 0 = playback idle, 1 = playback running + */ + var statusData: Int + get() = _sd + set(value) { + _sd = if (value < 0) 0 else if (value > 1) 1 else value + _onlinecounter = 5 + } + + /** + * VU level 0-100 + */ + var vu: Int + get() = _vu + set(value) { + _vu = if (value < 0) 0 else if (value > 100) 100 else value + _onlinecounter = 5 + } + + /** + * Decrement online counter, if counter reaches 0, the device is considered offline + */ + fun decrementOnlineCounter() { + if (_onlinecounter > 0) { + _onlinecounter-- + } + } + + fun isOnline(): Boolean { + return _onlinecounter > 0 + } + /** * Send data to Barix device via UDP * @param data The data to send * @return true if successful */ fun SendData(data: ByteArray): Boolean { - if (data.isNotEmpty()){ - try{ + if (data.isNotEmpty()) { + try { udp.send(DatagramPacket(data, data.size, inet)) return true } catch (e: Exception) { @@ -30,4 +78,30 @@ class BarixConnection(var channel: String, val ipaddress: String, val port: Int return false } + + /** + * Convert BarixConnection to JsonNode + * @return JsonNode representation of BarixConnection + */ + fun toJsonNode(): JsonNode { + // make json node from index, channel, ipaddress, port, bufferRemain, statusData, vu + return Somecodes.objectmapper.createObjectNode().apply { + put("index", index.toInt()) + put("channel", channel) + put("ipaddress", ipaddress) + put("port", port) + put("bufferRemain", bufferRemain) + put("statusData", statusData) + put("vu", vu) + put("isOnline", isOnline()) + } + } + + /** + * Convert BarixConnection to JSON string + * @return JSON string representation of BarixConnection + */ + fun toJsonString(): String { + return Somecodes.toJsonString(toJsonNode()) + } } \ No newline at end of file diff --git a/src/barix/TCP_Barix_Command_Server.kt b/src/barix/TCP_Barix_Command_Server.kt index 7e04029..1a692c6 100644 --- a/src/barix/TCP_Barix_Command_Server.kt +++ b/src/barix/TCP_Barix_Command_Server.kt @@ -13,8 +13,9 @@ class TCP_Barix_Command_Server { private var job: Job? = null private val socketMap = mutableMapOf() - private val regex: String = "\\$\\\"STATUSBARIX;(\\d+);(\\d+);?(\\d)?\\\"\\$" + private val regex = """\$\\"STATUSBARIX;(\d+);(\d+);?(\d)?\\"$""" private val pattern = Regex(regex) + /** * Start TCP Command Server * @param port The port number to listen on (default is 5001) diff --git a/src/codes/Somecodes.kt b/src/codes/Somecodes.kt index 1e2a645..fbb5399 100644 --- a/src/codes/Somecodes.kt +++ b/src/codes/Somecodes.kt @@ -1,5 +1,7 @@ package codes +import com.fasterxml.jackson.databind.JsonNode +import com.fasterxml.jackson.module.kotlin.jacksonObjectMapper import content.ScheduleDay import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Dispatchers @@ -31,6 +33,47 @@ class Somecodes { const val MB_threshold = KB_threshold * 1024.0 const val GB_threshold = MB_threshold * 1024.0 const val TB_threshold = GB_threshold * 1024.0 + val objectmapper = jacksonObjectMapper() + + /** + * Convert an object to a JSON string. + * @param data The object to convert. + * @return A JSON string representation of the object, or "{}" if conversion fails. + */ + fun toJsonString(data: Any) : String { + return try { + objectmapper.writeValueAsString(data) + } catch (e: Exception){ + "{}" + } + } + + /** + * Convert a JSON string to an object of the specified class. + * @param json The JSON string to convert. + * @param clazz The class of the object to convert to. + * @return An object of the specified class, or null if conversion fails. + */ + fun fromJsonString(json: String, clazz: Class) : T? { + return try { + objectmapper.readValue(json, clazz) + } catch (e: Exception){ + null + } + } + + /** + * Convert a JSON string to a JsonNode. + * @param data The JSON string to convert. + * @return A JsonNode representation of the JSON string, or empty JsonNode if conversion fails. + */ + fun toJsonNode(data: String) : JsonNode { + return try { + objectmapper.readTree(data) + } catch (e: Exception){ + objectmapper.createObjectNode() + } + } /** * List all audio files (.mp3 and .wav) in the specified directory and its subdirectories. diff --git a/src/database/MariaDB.kt b/src/database/MariaDB.kt index 600a0c7..a40d208 100644 --- a/src/database/MariaDB.kt +++ b/src/database/MariaDB.kt @@ -1,7 +1,7 @@ package database import codes.Somecodes.Companion.ValiDateForLogHtml -import com.fasterxml.jackson.module.kotlin.jacksonObjectMapper +import codes.Somecodes.Companion.toJsonString import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.runBlocking import kotlinx.coroutines.withContext @@ -50,7 +50,6 @@ class MariaDB( return regex.matches(time) } - private val objectMapper = jacksonObjectMapper() /** * Convert SoundbankList, MessagebankList, LanguageLinkList, or SchedulebankList to a JSON String. @@ -59,7 +58,7 @@ class MariaDB( */ fun ArrayListtoString(list: ArrayList): String { return try { - objectMapper.writeValueAsString(list) + toJsonString(list) } catch (e: Exception) { Logger.error("Error converting list to JSON: ${e.message}" as Any) "[]" diff --git a/src/web/WebApp.kt b/src/web/WebApp.kt index 9553a44..cad3c8c 100644 --- a/src/web/WebApp.kt +++ b/src/web/WebApp.kt @@ -1,5 +1,6 @@ package web +import barix.BarixConnection import codes.Somecodes import codes.Somecodes.Companion.ListAudioFiles import codes.Somecodes.Companion.ValiDateForLogHtml @@ -35,7 +36,7 @@ import org.apache.poi.xssf.usermodel.XSSFWorkbook import java.time.LocalDateTime @Suppress("unused") -class WebApp(val listenPort: Int, val userlist: List>, val db: MariaDB) { +class WebApp(val listenPort: Int, val userlist: List>, val db: MariaDB, val StreamerOutputs : MutableMap ) { var app: Javalin? = null val objectmapper = jacksonObjectMapper() @@ -134,6 +135,10 @@ class WebApp(val listenPort: Int, val userlist: List>, val SendReply(wsMessageContext, cmd.command, objectmapper.writeValueAsString(db.Read_Queue_Table())) } + "getStreamerOutputs" -> { + SendReply(wsMessageContext, cmd.command, objectmapper.writeValueAsString(StreamerOutputs.values.toList())) + } + else -> { SendReply(wsMessageContext, cmd.command, "Unknown command") }