diff --git a/src/MainExtension01.kt b/src/MainExtension01.kt index fbe8bef..14a627a 100644 --- a/src/MainExtension01.kt +++ b/src/MainExtension01.kt @@ -548,7 +548,6 @@ class MainExtension01 { val zz = qp.BroadcastZones.split(";") if (AllBroadcastZonesValid(zz)) { val ips = BroadcastZones_to_SoundChannel_IP(zz) - println("Broadcast zones $zz converted to SoundChannel IPs: $ips") if (AllStreamerOutputIdle(ips)) { if (qp.Source == "PAGING") { // nama file ada di Message diff --git a/src/audio/AudioPlayer.kt b/src/audio/AudioPlayer.kt index a777f6f..e6ea5ff 100644 --- a/src/audio/AudioPlayer.kt +++ b/src/audio/AudioPlayer.kt @@ -130,14 +130,89 @@ class AudioPlayer (var samplingrate: Int) { * Writes the audio data from a byte array to a WAV file. * @param data The byte array containing the audio data. * @param target The target file name for the WAV file. + * @param withChime If true, adds a chime sound at the beginning and end of the audio. * @param callback A BiConsumer that accepts a Boolean indicating success or failure and a String message. */ - fun WavWriter(data: ByteArray, target: String, callback: BiConsumer) { - val source = AudioFileInfo() - source.bytes = data - source.fileName = "In-Memory Data" - val sources = listOf(source) - WavWriter(sources, target, false, callback) + fun WavWriter(data: ByteArray, target: String, withChime: Boolean = true, callback: BiConsumer) { + CoroutineScope(Dispatchers.IO).launch { + bass.BASS_SetDevice(0) // Set to No Sound device for writing + val streamhandle = bass.BASS_StreamCreate(samplingrate, 1, BASS_STREAM_DECODE, Pointer(-1), null) + + if (streamhandle!=0){ + val encodehandle = bassenc.BASS_Encode_Start(streamhandle, target, BASS_ENCODE_PCM, null, null) + if (encodehandle!=0){ + + fun pushData(data: ByteArray): Boolean { + val mem = Memory(data.size.toLong()) + mem.write(0, data, 0, data.size) + val pushresult = bass.BASS_StreamPutData(streamhandle, mem, data.size) + if (pushresult==-1){ + val errcode = bass.BASS_ErrorGetCode() + println("BASS_StreamPutData failed: $errcode") + } + return pushresult != -1 + } + + var all_success = true + + if (withChime){ + val chup = contentCache.getAudioFile("chimeup") + if (chup!=null && chup.isValid()){ + if (pushData(chup.bytes)){ + println("Chime up pushed") + } else { + all_success = false + println("Chime up failed") + } + } else println("Chime Up not valid") + } + + if (pushData(data)){ + println("Data pushed") + } else { + all_success = false + println("Data push failed") + } + + if (withChime){ + val chdn = contentCache.getAudioFile("chimedown") + if (chdn!=null && chdn.isValid()){ + if (pushData(chdn.bytes)){ + println("Chime down pushed") + } else { + all_success = false + println("Chime down failed") + } + } else println("Chime Down not valid") + } + + val readsize: Long = 1024 * 1024 // read 1 MB at a time + var totalread: Long = 0 + do{ + val p = Memory(readsize) + val read = bass.BASS_ChannelGetData(streamhandle, p, 4096) + if (read > 0) { + totalread += read + } + } while (read > 0) + println("Finished reading stream data, total $totalread bytes read") + + if (all_success){ + callback.accept(true, "WAV file written successfully: $target") + } else { + callback.accept(false, "Failed to write some data to WAV file: $target") + } + + bassenc.BASS_Encode_Stop(encodehandle) + } else callback.accept(false, "Failed to start encoding: ${bass.BASS_ErrorGetCode()}") + bass.BASS_StreamFree(streamhandle) + } else { + callback.accept(false, "Failed to create stream: ${bass.BASS_ErrorGetCode()}") + } + } + + + } /** @@ -147,7 +222,7 @@ class AudioPlayer (var samplingrate: Int) { * @param withChime If true, adds a chime sound at the beginning and end of the audio. * @param callback A BiConsumer that accepts a Boolean indicating success or failure and a String message. */ - fun WavWriter(sources: List, target: String, withChime: Boolean, callback: BiConsumer) { + fun WavWriter(sources: List, target: String, withChime: Boolean = true, callback: BiConsumer) { if (sources.isEmpty()) { callback.accept(false, " Invalid sources") return diff --git a/src/commandServer/PagingJob.kt b/src/commandServer/PagingJob.kt index 3a39a84..4d8b483 100644 --- a/src/commandServer/PagingJob.kt +++ b/src/commandServer/PagingJob.kt @@ -13,7 +13,7 @@ import java.time.LocalDateTime * @param broadcastzones The zones to which the paging is broadcasted, is a semicolon-separated string. */ class PagingJob(val fromIP: String, val broadcastzones: String) { - val filePath : Path = PagingResult_directory.resolve(LocalDateTime.now().format(filenameformat)+"_RAW.wav") + val filePath : Path = PagingResult_directory.resolve("PAGING_"+fromIP+"_"+LocalDateTime.now().format(filenameformat)+".wav") private val bos : ByteArrayOutputStream = ByteArrayOutputStream() var totalBytesReceived = 0; private set var isRunning = true; private set @@ -25,7 +25,6 @@ class PagingJob(val fromIP: String, val broadcastzones: String) { * @param length The number of bytes to write from the data array. */ fun addData(data: ByteArray, length: Int) { - Logger.info{"PagingJob from $fromIP, zones: $broadcastzones, received $length bytes"} bos.write(data, 0, length) totalBytesReceived += length } diff --git a/src/commandServer/TCP_Android_Command_Server.kt b/src/commandServer/TCP_Android_Command_Server.kt index 2329f31..b8df24b 100644 --- a/src/commandServer/TCP_Android_Command_Server.kt +++ b/src/commandServer/TCP_Android_Command_Server.kt @@ -66,12 +66,10 @@ class TCP_Android_Command_Server { din.read(bb) // B4A format, 4 bytes di depan adalah size val str = String(bb, 4, bb.size - 4) - println("Received from $key : $str") str.split("@").map { it.trim() }.filter { ValidString(it) } .forEach { process_command(key,it) { reply -> try { - println("Reply to $key : ${reply.length} bytes") dout.write(String_to_Byte_Android(reply)) } catch (e: Exception) { logcb.accept("Failed to send reply to $key, Message : $e") @@ -155,12 +153,13 @@ class TCP_Android_Command_Server { } "PCMFILE_START","STARTPAGINGAND" -> { - val zones = parts.getOrElse(3) { "" }.replace(",",";") + val zones = parts.getOrElse(1) { "" }.replace(",",";") if (ValidString(zones)){ // create pagingjob val pj = PagingJob(key, zones) // masukin ke list listOnGoingPaging[key] = pj + Logger.info{"PagingJob created for Android $key, zones: $zones, file: ${pj.filePath.absolutePathString()}"} // start minta data dari udpreceiver udpreceiver.RequestDataFrom(key){ @@ -184,10 +183,12 @@ class TCP_Android_Command_Server { // get remaining data val data = pj.GetData() pj.Close() - audioPlayer.WavWriter(data, pj.filePath.absolutePathString()){ + Logger.info{"Paging job closed from Android $key, total bytes received ${data.size}, writing to file ${pj.filePath.absolutePathString()}"} + audioPlayer.WavWriter(data, pj.filePath.absolutePathString(), true){ success, message -> if (success){ // insert to paging queue + val qp = QueuePaging( 0u, LocalDateTime.now().format(datetimeformat1), @@ -235,14 +236,10 @@ class TCP_Android_Command_Server { // pengiriman variabel ke Android val username = parts.getOrElse(1) { "" } if (ValidString(username)){ - println("Initialize request from $key with username $username") val userlogin = listUserLogin.find { it.username == username } if (userlogin != null){ - println("User $username found in listUserLogin") val userdb = db.userDB.List.find { it.username == username } if (userdb != null){ - println("User $username found in userDB") - println(userdb) val result = StringBuilder() result.append("ZONE") userdb.broadcastzones.split(";").map { it.trim() }.filter { it.isNotBlank() }.forEach { @@ -322,8 +319,6 @@ class TCP_Android_Command_Server { // send to sender cb.accept(result.toString()) - println("Result so far: $result") - println("Result size: ${result.length} bytes") result.clear() //Append MSG, for Android only Indonesia and English @@ -365,11 +360,8 @@ class TCP_Android_Command_Server { result.append("VARPROCEDURE;").append(index).append(";").append(soundbank.TAG).append(";").append(soundbank.Description).append("@") } // send to sender - println("Final Result: $result") - println("Final Result size: ${result.length} bytes") cb.accept(result.toString()) logcb.accept("All variables sent to $key with username $username") - return } else logcb.accept("STARTINITIALIZE failed from $key with username $username not found in userDB") } else logcb.accept("STARTINITIALIZE failed from $key with unregistered username $username") diff --git a/src/database/MariaDB.kt b/src/database/MariaDB.kt index 34a66cb..8c252dd 100644 --- a/src/database/MariaDB.kt +++ b/src/database/MariaDB.kt @@ -1145,7 +1145,7 @@ class MariaDB( "SB_TAGS VARCHAR(1024)," + // Comma-separated soundbank tags "BroadcastZones VARCHAR(1024) NOT NULL," + // Comma-separated broadcast zones "`Repeat` INT NOT NULL," + // Number of repeats - "Language VARCHAR(45) NOT NULL" + // Language of the message + "Language VARCHAR(100) NOT NULL" + // Language of the message ")" super.Create(tabledefinition) } @@ -1311,7 +1311,7 @@ class MariaDB( "Date_Time VARCHAR(45) NOT NULL," + // Date and time of the entry "Source VARCHAR(45) NOT NULL," + // Source of the entry "Type VARCHAR(45) NOT NULL," + // Type of the entry - "Message VARCHAR(512) NOT NULL," + // Message content + "Message VARCHAR(1024) NOT NULL," + // Message content "BroadcastZones VARCHAR(1024)" + // Comma-separated soundbank tags ")" super.Create(tabledefinition) @@ -1330,7 +1330,7 @@ class MariaDB( resultSet.getString("Source"), resultSet.getString("Type"), resultSet.getString("Message"), - resultSet.getString("SB_TAGS"), + resultSet.getString("BroadcastZones"), ) queueList.add(queuePaging) List.add(queuePaging) @@ -1730,7 +1730,6 @@ class MariaDB( statement?.setString(4, data.description) val rowsAffected = statement?.executeUpdate() if (rowsAffected != null && rowsAffected > 0) { - Logger.info{"Log added : $data"} return true } else { Logger.warn{"Failed to add log entry : $data"}