commit 07/10/2025

This commit is contained in:
2025-10-07 15:57:23 +07:00
parent d04a8bedd1
commit e8695c7a6f
6 changed files with 583 additions and 558 deletions

View File

@@ -109,8 +109,12 @@ fun main() {
delay(1000) delay(1000)
// prioritas 1 , habisin queue paging // prioritas 1 , habisin queue paging
subcode01.Read_Queue_Paging() subcode01.Read_Queue_Paging()
// prioritas 2, habisin queue table // prioritas 2, habisin queue shalat
subcode01.Read_Queue_Table() subcode01.Read_Queue_Shalat()
// prioritas 3, habisin queue timer
subcode01.Read_Queue_Timer()
// prioritas 4, habisin queue soundbank
subcode01.Read_Queue_Soundbank()
} }
} }
// Coroutine untuk cek Schedulebank tiap menit saat detik 00 // Coroutine untuk cek Schedulebank tiap menit saat detik 00

View File

@@ -1,4 +1,5 @@
import audio.AudioFileInfo import audio.AudioFileInfo
import codes.Result_GetSoundbankFiles
import codes.Somecodes.Companion.Get_ANN_ID import codes.Somecodes.Companion.Get_ANN_ID
import codes.Somecodes.Companion.IsAlphabethic import codes.Somecodes.Companion.IsAlphabethic
import codes.Somecodes.Companion.IsNumber import codes.Somecodes.Companion.IsNumber
@@ -22,7 +23,6 @@ import java.time.DayOfWeek
import java.time.LocalDate import java.time.LocalDate
import java.time.LocalDateTime import java.time.LocalDateTime
import java.time.LocalTime import java.time.LocalTime
import java.util.function.Consumer
/** /**
* MainExtension01 contains additional functions for the main application. * MainExtension01 contains additional functions for the main application.
@@ -208,27 +208,25 @@ class MainExtension01 {
* Find soundbank files from messagebank tags, filtered by VoiceType and Language * Find soundbank files from messagebank tags, filtered by VoiceType and Language
* @param mb Messagebank object * @param mb Messagebank object
* @param variables Map of variables to replace in tags. * @param variables Map of variables to replace in tags.
* @param cbOK Callback function if success, returns List of soundbank file names * @return Result_GetSoundbankFiles object containing success status, message, and list of soundbank file paths.
* @param cbFail Callback function if failed, returns error message
*/ */
fun Get_Soundbank_Files( fun Get_Soundbank_Files(
mb: Messagebank, mb: Messagebank,
variables: Map<String, String>, variables: Map<String, String>
cbOK: Consumer<List<String>>,
cbFail: Consumer<String> ) : Result_GetSoundbankFiles {
) {
val tags = mb.Message_TAGS.split(" ") val tags = mb.Message_TAGS.split(" ")
if (tags.isEmpty()) { if (tags.isEmpty()) {
cbFail.accept("No tags found in messagebank id ${mb.ANN_ID}") return Result_GetSoundbankFiles(false, "No tags found in messagebank id ${mb.ANN_ID}")
return
} }
// dapatkan soundbank array berdasarkan VoiceType dan Language // dapatkan soundbank array berdasarkan VoiceType dan Language
val sb = db.soundDB.List val sb = db.soundDB.List
.filter { it.VoiceType.equals(mb.Voice_Type, true) } .filter { it.VoiceType.equals(mb.Voice_Type, true) }
.filter { it.Language.equals(mb.Language, true) } .filter { it.Language.equals(mb.Language, true) }
if (sb.isEmpty()) { if (sb.isEmpty()) {
cbFail.accept("No soundbank found for voice type ${mb.Voice_Type} and language ${mb.Language}") return Result_GetSoundbankFiles(false, "No soundbank found for voice type ${mb.Voice_Type} and language ${mb.Language}")
return
} }
val files = mutableListOf<String>() val files = mutableListOf<String>()
@@ -244,16 +242,16 @@ class MainExtension01 {
if (ValidFile(airplane.Path)) { if (ValidFile(airplane.Path)) {
files.add(airplane.Path) files.add(airplane.Path)
} else { } else {
cbFail.accept("Invalid soundbank file ${airplane.Path} for tag=$_tag voicetype=${mb.Voice_Type} language=${mb.Language} ANN_ID=${mb.ANN_ID}") return Result_GetSoundbankFiles(false, "Invalid soundbank file ${airplane.Path} for tag=$_tag voicetype=${mb.Voice_Type} language=${mb.Language} ANN_ID=${mb.ANN_ID}")
return
} }
} else { } else {
cbFail.accept("No Airplane_Name found for tag=$_tag voicetype=${mb.Voice_Type} language=${mb.Language} ANN_ID=${mb.ANN_ID}") return Result_GetSoundbankFiles(false, "No Airplane_Name found for tag=$_tag voicetype=${mb.Voice_Type} language=${mb.Language} ANN_ID=${mb.ANN_ID}")
return
} }
} else { } else {
cbFail.accept("AIRPLANE_NAME variable is missing or empty for tag $_tag in messagebank id ${mb.ANN_ID}") return Result_GetSoundbankFiles(false, "AIRPLANE_NAME variable is missing or empty for tag $_tag in messagebank id ${mb.ANN_ID}")
return
} }
} }
@@ -268,23 +266,23 @@ class MainExtension01 {
if (ValidFile(val1.Path)) { if (ValidFile(val1.Path)) {
files.add(val1.Path) files.add(val1.Path)
} else { } else {
cbFail.accept("Invalid soundbank file ${val1.Path} for tag=$_tag voicetype=${mb.Voice_Type} language=${mb.Language} ANN_ID=${mb.ANN_ID}") return Result_GetSoundbankFiles(false, "Invalid soundbank file ${val1.Path} for tag=$_tag voicetype=${mb.Voice_Type} language=${mb.Language} ANN_ID=${mb.ANN_ID}")
return
} }
} else { } else {
cbFail.accept("No Airline_Code found for tag=$_tag voicetype=${mb.Voice_Type} language=${mb.Language} ANN_ID=${mb.ANN_ID}")
return return Result_GetSoundbankFiles(false, "No Airline_Code found for tag=$_tag voicetype=${mb.Voice_Type} language=${mb.Language} ANN_ID=${mb.ANN_ID}")
} }
if (val2 != null && val2.isNotEmpty()) { if (val2 != null && val2.isNotEmpty()) {
files.addAll(val2) files.addAll(val2)
} else { } else {
cbFail.accept("No valid soundbank files found for FLIGHT_NUMBER value '$fncode' for tag=$_tag voicetype=${mb.Voice_Type} language=${mb.Language} ANN_ID=${mb.ANN_ID}") return Result_GetSoundbankFiles(false, "No valid soundbank files found for FLIGHT_NUMBER value '$fncode' for tag=$_tag voicetype=${mb.Voice_Type} language=${mb.Language} ANN_ID=${mb.ANN_ID}")
return
} }
} else { } else {
cbFail.accept("AIRPLANE_NAME or FLIGHT_NUMBER variable is missing or empty for tag $_tag in messagebank id ${mb.ANN_ID}") return Result_GetSoundbankFiles(false, "FLIGHT_NUMBER or AIRLINE_CODE variable is missing or empty for tag $_tag in messagebank id ${mb.ANN_ID}")
return
} }
} }
@@ -321,12 +319,12 @@ class MainExtension01 {
} }
} }
} else { } else {
cbFail.accept("PLATNOMOR variable has invalid format for value '$value' in messagebank id ${mb.ANN_ID}") return Result_GetSoundbankFiles(false, "PLATNOMOR variable has invalid format for value '$value' in messagebank id ${mb.ANN_ID}")
return
} }
} else { } else {
cbFail.accept("PLATNOMOR variable is missing or empty for tag $_tag in messagebank id ${mb.ANN_ID}") return Result_GetSoundbankFiles(false, "PLATNOMOR variable is missing or empty for tag $_tag in messagebank id ${mb.ANN_ID}")
return
} }
} }
@@ -339,17 +337,17 @@ class MainExtension01 {
if (ValidFile(city.Path)) { if (ValidFile(city.Path)) {
files.add(city.Path) files.add(city.Path)
} else { } else {
cbFail.accept("Invalid soundbank file ${city.Path} for tag=$_tag voicetype=${mb.Voice_Type} language=${mb.Language} ANN_ID=${mb.ANN_ID}") return Result_GetSoundbankFiles(false, "Invalid soundbank file ${city.Path} for tag=$_tag voicetype=${mb.Voice_Type} language=${mb.Language} ANN_ID=${mb.ANN_ID}")
return
} }
} else { } else {
cbFail.accept("No City found for tag=$_tag voicetype=${mb.Voice_Type} language=${mb.Language} ANN_ID=${mb.ANN_ID}") return Result_GetSoundbankFiles(false, "No City found for tag=$_tag voicetype=${mb.Voice_Type} language=${mb.Language} ANN_ID=${mb.ANN_ID}")
return
} }
} }
} else { } else {
cbFail.accept("CITY variable is missing or empty for tag $_tag in messagebank id ${mb.ANN_ID}") return Result_GetSoundbankFiles(false, "CITY variable is missing or empty for tag $_tag in messagebank id ${mb.ANN_ID}")
return
} }
} }
@@ -361,16 +359,16 @@ class MainExtension01 {
if (ValidFile(places.Path)) { if (ValidFile(places.Path)) {
files.add(places.Path) files.add(places.Path)
} else { } else {
cbFail.accept("Invalid soundbank file ${places.Path} for tag=$_tag voicetype=${mb.Voice_Type} language=${mb.Language} ANN_ID=${mb.ANN_ID}") return Result_GetSoundbankFiles(false, "Invalid soundbank file ${places.Path} for tag=$_tag voicetype=${mb.Voice_Type} language=${mb.Language} ANN_ID=${mb.ANN_ID}")
return
} }
} else { } else {
cbFail.accept("No Places found for tag=$_tag voicetype=${mb.Voice_Type} language=${mb.Language} ANN_ID=${mb.ANN_ID}") return Result_GetSoundbankFiles(false, "No Places found for tag=$_tag voicetype=${mb.Voice_Type} language=${mb.Language} ANN_ID=${mb.ANN_ID}")
return
} }
} else { } else {
cbFail.accept("PLACES variable is missing or empty for tag $_tag in messagebank id ${mb.ANN_ID}") return Result_GetSoundbankFiles(false, "PLACES variable is missing or empty for tag $_tag in messagebank id ${mb.ANN_ID}")
return
} }
} }
@@ -390,19 +388,19 @@ class MainExtension01 {
files.add(hh) files.add(hh)
files.add(mm) files.add(mm)
} else { } else {
cbFail.accept("ETAD variable has invalid soundbank for hour or minute for tag $_tag in messagebank id ${mb.ANN_ID}") return Result_GetSoundbankFiles(false, "ETAD variable has invalid soundbank for hour or minute for tag $_tag in messagebank id ${mb.ANN_ID}")
return
} }
} else { } else {
cbFail.accept("ETAD variable has invalid hour or minute for tag $_tag in messagebank id ${mb.ANN_ID}, hour must be 0-23 and minute must be 0-59") return Result_GetSoundbankFiles(false, "ETAD variable has invalid hour or minute for tag $_tag in messagebank id ${mb.ANN_ID}, hour must be 0-23 and minute must be 0-59")
return
} }
} }
} else { } else {
cbFail.accept("ETAD variable has invalid format for tag $_tag in messagebank id ${mb.ANN_ID}, expected format HH:MM") return Result_GetSoundbankFiles(false, "ETAD variable has invalid format for tag $_tag in messagebank id ${mb.ANN_ID}, expected format HH:MM")
return
} }
} }
@@ -415,16 +413,16 @@ class MainExtension01 {
if (ValidFile(shalat.Path)) { if (ValidFile(shalat.Path)) {
files.add(shalat.Path) files.add(shalat.Path)
} else { } else {
cbFail.accept("Invalid soundbank file ${shalat.Path} for tag=$_tag voicetype=${mb.Voice_Type} language=${mb.Language} ANN_ID=${mb.ANN_ID}") return Result_GetSoundbankFiles(false, "Invalid soundbank file ${shalat.Path} for tag=$_tag voicetype=${mb.Voice_Type} language=${mb.Language} ANN_ID=${mb.ANN_ID}")
return
} }
} else { } else {
cbFail.accept("No Shalat found for tag=$_tag voicetype=${mb.Voice_Type} language=${mb.Language} ANN_ID=${mb.ANN_ID}") return Result_GetSoundbankFiles(false, "No Shalat found for tag=$_tag voicetype=${mb.Voice_Type} language=${mb.Language} ANN_ID=${mb.ANN_ID}")
return
} }
} else { } else {
cbFail.accept("SHALAT variable is missing or empty for tag $_tag in messagebank id ${mb.ANN_ID}") return Result_GetSoundbankFiles(false, "SHALAT variable is missing or empty for tag $_tag in messagebank id ${mb.ANN_ID}")
return
} }
} }
@@ -437,8 +435,8 @@ class MainExtension01 {
if (path != null) { if (path != null) {
files.addAll(path) files.addAll(path)
} else { } else {
cbFail.accept("BCB variable is missing, empty, or doesn't have valid soundbank for value '$value' in messagebank id ${mb.ANN_ID}") return Result_GetSoundbankFiles(false, "BCB variable doesn't have valid soundbank for value '$value' in messagebank id ${mb.ANN_ID}")
return
} }
} }
@@ -454,17 +452,17 @@ class MainExtension01 {
if (path != null) { if (path != null) {
files.addAll(path) files.addAll(path)
} else { } else {
cbFail.accept("GATENUMBER variable doesn't have valid soundbank for value '$vv' in messagebank id ${mb.ANN_ID}") return Result_GetSoundbankFiles(false, "GATENUMBER variable doesn't have valid soundbank for value '$vv' in messagebank id ${mb.ANN_ID}")
return
} }
} }
} else { } else {
cbFail.accept("GATENUMBER variable is empty after split for tag $_tag in messagebank id ${mb.ANN_ID}") return Result_GetSoundbankFiles(false, "GATENUMBER variable is empty after split for tag $_tag in messagebank id ${mb.ANN_ID}")
return
} }
} else { } else {
cbFail.accept("GATENUMBER variable is missing or empty for tag $_tag in messagebank id ${mb.ANN_ID}") return Result_GetSoundbankFiles(false, "GATENUMBER variable is missing or empty for tag $_tag in messagebank id ${mb.ANN_ID}")
return
} }
} }
@@ -477,16 +475,16 @@ class MainExtension01 {
if (ValidFile(reason.Path)) { if (ValidFile(reason.Path)) {
files.add(reason.Path) files.add(reason.Path)
} else { } else {
cbFail.accept("Invalid soundbank file ${reason.Path} for tag=$_tag voicetype=${mb.Voice_Type} language=${mb.Language} ANN_ID=${mb.ANN_ID}") return Result_GetSoundbankFiles(false, "Invalid soundbank file ${reason.Path} for tag=$_tag voicetype=${mb.Voice_Type} language=${mb.Language} ANN_ID=${mb.ANN_ID}")
return
} }
} else { } else {
cbFail.accept("No Reason found for tag=$_tag voicetype=${mb.Voice_Type} language=${mb.Language} ANN_ID=${mb.ANN_ID}") return Result_GetSoundbankFiles(false, "No Reason found for tag=$_tag voicetype=${mb.Voice_Type} language=${mb.Language} ANN_ID=${mb.ANN_ID}")
return
} }
} else { } else {
cbFail.accept("REASON variable is missing or empty for tag $_tag in messagebank id ${mb.ANN_ID}") return Result_GetSoundbankFiles(false, "REASON variable is missing or empty for tag $_tag in messagebank id ${mb.ANN_ID}")
return
} }
} }
@@ -499,16 +497,16 @@ class MainExtension01 {
if (ValidFile(procedure.Path)) { if (ValidFile(procedure.Path)) {
files.add(procedure.Path) files.add(procedure.Path)
} else { } else {
cbFail.accept("Invalid soundbank file ${procedure.Path} for tag=$_tag voicetype=${mb.Voice_Type} language=${mb.Language} ANN_ID=${mb.ANN_ID}") return Result_GetSoundbankFiles(false, "Invalid soundbank file ${procedure.Path} for tag=$_tag voicetype=${mb.Voice_Type} language=${mb.Language} ANN_ID=${mb.ANN_ID}")
return
} }
} else { } else {
cbFail.accept("No Procedure found for tag=$_tag voicetype=${mb.Voice_Type} language=${mb.Language} ANN_ID=${mb.ANN_ID}") return Result_GetSoundbankFiles(false, "No Procedure found for tag=$_tag voicetype=${mb.Voice_Type} language=${mb.Language} ANN_ID=${mb.ANN_ID}")
return
} }
} else { } else {
cbFail.accept("PROCEDURE variable is missing or empty for tag $_tag in messagebank id ${mb.ANN_ID}") return Result_GetSoundbankFiles(false,"PROCEDURE variable is missing or empty for tag $_tag in messagebank id ${mb.ANN_ID}")
return
} }
} }
@@ -520,12 +518,12 @@ class MainExtension01 {
if (ValidFile(phrase.Path)) { if (ValidFile(phrase.Path)) {
files.add(phrase.Path) files.add(phrase.Path)
} else { } else {
cbFail.accept("Invalid soundbank file ${phrase.Path} for tag=$_tag voicetype=${mb.Voice_Type} language=${mb.Language} ANN_ID=${mb.ANN_ID}") return Result_GetSoundbankFiles(false, "Invalid soundbank file ${phrase.Path} for tag=$_tag voicetype=${mb.Voice_Type} language=${mb.Language} ANN_ID=${mb.ANN_ID}")
return
} }
} else { } else {
cbFail.accept("No Phrase found for tag=$_tag voicetype=${mb.Voice_Type} language=${mb.Language} ANN_ID=${mb.ANN_ID}") return Result_GetSoundbankFiles(false, "No Phrase found for tag=$_tag voicetype=${mb.Voice_Type} language=${mb.Language} ANN_ID=${mb.ANN_ID}")
return
} }
} }
@@ -533,34 +531,26 @@ class MainExtension01 {
} }
} }
// all tags processed, return files // all tags processed, return files
cbOK.accept(files) return Result_GetSoundbankFiles(true, "Success", files)
} }
/** fun Read_Queue_Paging() : Boolean{
* Read and process Queue_Paging table.
*/
fun Read_Queue_Paging(){
db.queuepagingDB.Get() db.queuepagingDB.Get()
for (qp in db.queuepagingDB.List) { val list = db.queuepagingDB.List
.filter { it.Source=="PAGING" }
list.forEach { qp ->
println("Processing $qp") println("Processing $qp")
if (qp.BroadcastZones.isNotBlank()){ if (qp.BroadcastZones.isNotBlank()){
if (ValidFile(qp.Message)){
val zz = qp.BroadcastZones.split(";") val zz = qp.BroadcastZones.split(";")
if (AllBroadcastZonesValid(zz)){ if (AllBroadcastZonesValid(zz)){
val ips = BroadcastZones_to_SoundChannel_IP(zz) val ips = BroadcastZones_to_SoundChannel_IP(zz)
if (AllStreamerOutputIdle(ips)){ if (AllStreamerOutputIdle(ips)){
if (qp.Source == "PAGING") {
// nama file ada di Message
if (ValidFile(qp.Message)) {
// file ketemu di path
val afi = audioPlayer.LoadAudioFile(qp.Message) val afi = audioPlayer.LoadAudioFile(qp.Message)
if (afi.isValid()){ if (afi.isValid()){
// file bisa di load, kirim ke masing masing Streamer Output by IP address // file bisa di load, kirim ke masing masing Streamer Output by IP address
ips.forEach { ips.forEach { ip -> StreamerOutputs[ip]?.SendData(afi.bytes, { db.Add_Log("AAS", it) }, { db.Add_Log("AAS", it) }) }
ip ->
val br = StreamerOutputs[ip]
br?.SendData(afi.bytes, { db.Add_Log("AAS", it) }, { db.Add_Log("AAS", it) })
}
val logmessage = val logmessage =
"Broadcast started PAGING with Filename '${qp.Message}' to zones: ${qp.BroadcastZones}" "Broadcast started PAGING with Filename '${qp.Message}' to zones: ${qp.BroadcastZones}"
@@ -568,7 +558,7 @@ class MainExtension01 {
db.Add_Log("AAS", logmessage) db.Add_Log("AAS", logmessage)
db.queuepagingDB.DeleteByIndex(qp.index.toInt()) db.queuepagingDB.DeleteByIndex(qp.index.toInt())
return return true
} else { } else {
// file tidak valid, delete from queue paging // file tidak valid, delete from queue paging
db.queuepagingDB.DeleteByIndex(qp.index.toInt()) db.queuepagingDB.DeleteByIndex(qp.index.toInt())
@@ -577,29 +567,49 @@ class MainExtension01 {
"Cancelled paging message with index ${qp.index} due to invalid audio file" "Cancelled paging message with index ${qp.index} due to invalid audio file"
) )
} }
} // kalau enggak semua streamer idle, skip dulu
} else {
// ada broadcast zone yang tidak valid, delete from queue paging
db.queuepagingDB.DeleteByIndex(qp.index.toInt())
db.Add_Log("AAS", "Cancelled paging message with index ${qp.index} due to invalid broadcast zone")
}
} else {
// file tidak valid, delete from queue paging
db.queuepagingDB.DeleteByIndex(qp.index.toInt())
db.Add_Log(
"AAS",
"Cancelled paging message with index ${qp.index} due to invalid audio file"
)
}
} else {
// invalid broadcast zone, delete from queue paging
db.queuepagingDB.DeleteByIndex(qp.index.toInt())
db.Add_Log("AAS", "Cancelled paging message with index ${qp.index} due to empty broadcast zone")
}
}
return false
}
} else { fun Read_Queue_Shalat() : Boolean{
// file tidak valid, delete from queue paging db.queuepagingDB.Get()
db.queuepagingDB.DeleteByIndex(qp.index.toInt()) val list = db.queuepagingDB.List
db.Add_Log( .filter { it.Source=="SHALAT" }
"AAS", list.forEach { qp ->
"Cancelled paging message with index ${qp.index} due to invalid audio file" println("Processing $qp")
) if (qp.BroadcastZones.isNotBlank()){
} val zz = qp.BroadcastZones.split(";")
} else if (qp.Source == "SHALAT") { if (AllBroadcastZonesValid(zz)){
val ann_id = Get_ANN_ID(qp.Message) val ann_id = Get_ANN_ID(qp.Message)
if (ann_id>0){ if (ann_id>0){
// shalat, ambil messagebank berdasarkan ann_id dengan bahasa Indonesia saja val ips = BroadcastZones_to_SoundChannel_IP(zz)
Get_MessageBank_by_id(ann_id, listOf(Language.INDONESIA.name)).let { mblist -> if (AllStreamerOutputIdle(ips)){
val mblist = Get_MessageBank_by_id(ann_id, listOf(Language.INDONESIA.name))
if (mblist.isNotEmpty()) { if (mblist.isNotEmpty()) {
Get_Soundbank_Files( mblist.forEach { mb ->
mblist[0], val result = Get_Soundbank_Files(mb, emptyMap())
emptyMap(), if (result.success){
{
// dapat list dari files dan sudah dicek valid path
listfile ->
val listafi = mutableListOf<AudioFileInfo>() val listafi = mutableListOf<AudioFileInfo>()
listfile.forEach { filenya -> result.files.forEach { filenya ->
val afi = contentCache.getAudioFile(filenya) val afi = contentCache.getAudioFile(filenya)
if (afi!=null && afi.isValid()){ if (afi!=null && afi.isValid()){
listafi.add(afi) listafi.add(afi)
@@ -619,27 +629,24 @@ class MainExtension01 {
"" ""
) )
).toString() ).toString()
audioPlayer.WavWriter(
val result =audioPlayer.WavWriter(
listafi, listafi,
targetfile, true, targetfile, true,
) { success, message -> )
db.Add_Log("AAS", message) db.Add_Log("AAS", result.message)
if (success) { if (result.success) {
// file siap broadcast // file siap broadcast
val targetafi = audioPlayer.LoadAudioFile(targetfile) val targetafi = audioPlayer.LoadAudioFile(targetfile)
if (targetafi.isValid()) { if (targetafi.isValid()) {
zz.forEach { z1 -> ips.forEach { ip -> StreamerOutputs[ip]?.SendData(targetafi.bytes, { db.Add_Log("AAS", it) }, {db.Add_Log("AAS", it) }) }
StreamerOutputs.values.find { it.channel == z1 }
?.SendData(
targetafi.bytes,
{ db.Add_Log("AAS", it) },
{ db.Add_Log("AAS", it) })
}
val logmsg = val logmsg =
"Broadcast started SHALAT message with generated file '$targetfile' to zones: ${qp.BroadcastZones}" "Broadcast started SHALAT message with generated file '$targetfile' to zones: ${qp.BroadcastZones}"
Logger.info { logmsg } Logger.info { logmsg }
db.Add_Log("AAS", logmsg) db.Add_Log("AAS", logmsg)
db.queuepagingDB.DeleteByIndex(qp.index.toInt()) db.queuepagingDB.DeleteByIndex(qp.index.toInt())
return true
} else { } else {
db.Add_Log( db.Add_Log(
"AAS", "AAS",
@@ -647,15 +654,13 @@ class MainExtension01 {
) )
} }
} }
} } else{
},
{ err ->
db.queuepagingDB.DeleteByIndex(qp.index.toInt()) db.queuepagingDB.DeleteByIndex(qp.index.toInt())
db.Add_Log("AAS", err) db.Add_Log("AAS", result.message)
} }
) }
} else { } else {
// tidak ada messagebank dengan ann_id ini, delete from queue paging // tidak ada messagebank dengan ann_id ini, delete from queue paging
db.queuepagingDB.DeleteByIndex(qp.index.toInt()) db.queuepagingDB.DeleteByIndex(qp.index.toInt())
@@ -664,48 +669,125 @@ class MainExtension01 {
"Cancelled Shalat message with index ${qp.index} due to ANN_ID $ann_id not found in Messagebank" "Cancelled Shalat message with index ${qp.index} due to ANN_ID $ann_id not found in Messagebank"
) )
} }
} } // kalau enggak semua streamer idle, skip dulu
} else { } else {
// invalid ann_id, delete from queue paging // invalid ann_id, delete from queue paging
db.queuepagingDB.DeleteByIndex(qp.index.toInt()) db.queuepagingDB.DeleteByIndex(qp.index.toInt())
db.Add_Log( db.Add_Log("AAS", "Cancelled shalat message with index ${qp.index} due to invalid ANN_ID")
"AAS",
"Cancelled Shalat message with index ${qp.index} due to invalid ANN_ID"
)
}
}
} }
} else { } else {
// ada broadcast zone yang tidak valid, delete from queue paging // ada broadcast zone yang tidak valid, delete from queue paging
db.queuepagingDB.DeleteByIndex(qp.index.toInt()) db.queuepagingDB.DeleteByIndex(qp.index.toInt())
db.Add_Log( db.Add_Log("AAS", "Cancelled shalat message with index ${qp.index} due to invalid broadcast zone")
"AAS",
"Cancelled paging message with index ${qp.index} due to invalid broadcast zone"
)
} }
} else { } else {
// invalid broadcast zone, delete from queue paging // invalid broadcast zone, delete from queue paging
db.queuepagingDB.DeleteByIndex(qp.index.toInt()) db.queuepagingDB.DeleteByIndex(qp.index.toInt())
db.Add_Log("AAS", "Cancelled paging message with index ${qp.index} due to empty broadcast zone") db.Add_Log("AAS", "Cancelled shalat message with index ${qp.index} due to empty broadcast zone")
} }
} }
return false
}
} fun Read_Queue_Timer() : Boolean{
/**
* Read and process Queue_Table table.
*/
fun Read_Queue_Table(){
db.queuetableDB.Get() db.queuetableDB.Get()
db.queuetableDB.List.forEach { qa -> val list = db.queuetableDB.List.filter { it.Type=="TIMER" }
list.forEach { qa ->
println("Processing $qa") println("Processing $qa")
if (qa.BroadcastZones.isNotEmpty()){ if (qa.BroadcastZones.isNotEmpty()){
val zz = qa.BroadcastZones.split(";") val zz = qa.BroadcastZones.split(";")
if (AllBroadcastZonesValid(zz)){
val ips = BroadcastZones_to_SoundChannel_IP(zz)
val ann_id = Get_ANN_ID(qa.Message)
if (ann_id>0){
if (AllStreamerOutputIdle(ips)){
val mblist = Get_MessageBank_by_id(ann_id, qa.Language.split(";"))
if (mblist.isNotEmpty()) {
mblist.forEach {
mb ->
val result = Get_Soundbank_Files(mb, emptyMap())
if (result.success){
val listafi = mutableListOf<AudioFileInfo>()
result.files.forEach { filenya ->
val afi = contentCache.getAudioFile(filenya)
if (afi!=null && afi.isValid()){
listafi.add(afi)
} else {
val afi = audioPlayer.LoadAudioFile(filenya)
if (afi.isValid()) {
listafi.add(afi)
contentCache.addAudioFile(filenya, afi)
}
}
}
val targetfile = SoundbankResult_directory.resolve(Make_WAV_FileName("Timer","")).toString()
val result = audioPlayer.WavWriter(listafi, targetfile, true)
db.Add_Log("AAS", result.message)
if (result.success){
// file siap broadcast
val targetafi = audioPlayer.LoadAudioFile(targetfile)
if (targetafi.isValid()) {
ips.forEach { ip -> StreamerOutputs[ip]?.SendData(targetafi.bytes, { db.Add_Log("AAS", it) }, { db.Add_Log("AAS", it) }) }
val logmsg =
"Broadcast started TIMER message with generated file '$targetfile' to zones: ${qa.BroadcastZones}"
Logger.info { logmsg }
db.Add_Log("AAS", logmsg)
db.queuetableDB.DeleteByIndex(qa.index.toInt())
return true
}
} else{
db.queuetableDB.DeleteByIndex(qa.index.toInt())
db.Add_Log("AAS", result.message)
}
} else {
db.queuetableDB.DeleteByIndex(qa.index.toInt())
db.Add_Log("AAS", result.message)
}
}
} else {
// tidak ada messagebank dengan ann_id ini, delete from queue table
db.queuetableDB.DeleteByIndex(qa.index.toInt())
db.Add_Log(
"AAS",
"Cancelled TIMER with index ${qa.index} due to ANN_ID $ann_id not found in Messagebank"
)
}
} // kalau enggak semua streamer idle, skip dulu
} else {
// invalid ann_id, delete from queue table
db.queuetableDB.DeleteByIndex(qa.index.toInt())
db.Add_Log("AAS", "Cancelled TIMER message with index ${qa.index} due to invalid ANN_ID")
}
} else {
// ada broadcast zone yang tidak valid, delete from queue table
db.queuetableDB.DeleteByIndex(qa.index.toInt())
db.Add_Log("AAS", "Cancelled TIMER message with index ${qa.index} due to invalid broadcast zone")
}
} else {
// invalid broadcast zone, delete from queue table
db.queuetableDB.DeleteByIndex(qa.index.toInt())
db.Add_Log("AAS", "Cancelled TIMER message with index ${qa.index} due to empty broadcast zone")
}
}
return false
}
fun Read_Queue_Soundbank() : Boolean{
db.queuetableDB.Get()
val list = db.queuetableDB.List.filter { it.Type=="SOUNDBANK" }
list.forEach { qa ->
println("Processing $qa")
if (qa.BroadcastZones.isNotEmpty()){
val zz = qa.BroadcastZones.split(";")
if (AllBroadcastZonesValid(zz)){ if (AllBroadcastZonesValid(zz)){
val ips = BroadcastZones_to_SoundChannel_IP(zz) val ips = BroadcastZones_to_SoundChannel_IP(zz)
if (AllStreamerOutputIdle(ips)) { if (AllStreamerOutputIdle(ips)) {
if (qa.Type == "SOUNDBANK") {
val variables = Get_Soundbank_Data(qa.SB_TAGS) val variables = Get_Soundbank_Data(qa.SB_TAGS)
val languages = qa.Language.split(";") val languages = qa.Language.split(";")
// cek apakah ANN_ID ada di SB_TAGS // cek apakah ANN_ID ada di SB_TAGS
@@ -746,9 +828,9 @@ class MainExtension01 {
val listafi = mutableListOf<AudioFileInfo>() val listafi = mutableListOf<AudioFileInfo>()
mblist.forEach { mb -> mblist.forEach { mb ->
Get_Soundbank_Files(mb, variables ?: emptyMap(), { val result = Get_Soundbank_Files(mb, variables ?: emptyMap())
listfile -> if (result.success){
listfile.forEach { filenya -> result.files.forEach { filenya ->
val afi = contentCache.getAudioFile(filenya) val afi = contentCache.getAudioFile(filenya)
if (afi!=null && afi.isValid()){ if (afi!=null && afi.isValid()){
listafi.add(afi) listafi.add(afi)
@@ -761,12 +843,11 @@ class MainExtension01 {
} }
} }
}, } else {
{ db.Add_Log("AAS", result.message)
err ->
db.Add_Log("AAS", err)
db.queuetableDB.DeleteByIndex(qa.index.toInt()) db.queuetableDB.DeleteByIndex(qa.index.toInt())
}) }
} }
if (listafi.isNotEmpty()){ if (listafi.isNotEmpty()){
@@ -774,34 +855,27 @@ class MainExtension01 {
val targetfile = SoundbankResult_directory.resolve(Make_WAV_FileName("Soundbank","")).toString() val targetfile = SoundbankResult_directory.resolve(Make_WAV_FileName("Soundbank","")).toString()
println("Writing to target WAV file: $targetfile") println("Writing to target WAV file: $targetfile")
audioPlayer.WavWriter(listafi, targetfile, true, val result = audioPlayer.WavWriter(listafi, targetfile, true)
) { success, message -> if (result.success){
if (success) {
// file siap broadcast // file siap broadcast
println("Successfully wrote WAV file: $targetfile") println("Successfully wrote WAV file: $targetfile")
val targetafi = audioPlayer.LoadAudioFile(targetfile) val targetafi = audioPlayer.LoadAudioFile(targetfile)
if (targetafi.isValid()) { if (targetafi.isValid()) {
ips.forEach { ip -> ips.forEach { ip -> StreamerOutputs[ip]?.SendData(targetafi.bytes, { db.Add_Log("AAS", it) }, { db.Add_Log("AAS", it) }) }
StreamerOutputs[ip].let{ sc ->
sc?.SendData(targetafi.bytes,
{ db.Add_Log("AAS", it) },
{ db.Add_Log("AAS", it) } )
}
}
val logmsg = val logmsg =
"Broadcast started SOUNDBANK message with generated file '$targetfile' to zones: ${qa.BroadcastZones}" "Broadcast started SOUNDBANK message with generated file '$targetfile' to zones: ${qa.BroadcastZones}"
Logger.info { logmsg } Logger.info { logmsg }
db.Add_Log("AAS", logmsg) db.Add_Log("AAS", logmsg)
return true
} }
} else { } else {
println("Failed to write WAV file: $message") println("Failed to write WAV file: ${result.message}")
db.queuetableDB.DeleteByIndex(qa.index.toInt()) db.queuetableDB.DeleteByIndex(qa.index.toInt())
db.Add_Log("AAS", message) db.Add_Log("AAS", result.message)
}
} }
} }
} else { } else {
// tidak ada messagebank dengan ann_id ini, delete from queue table // tidak ada messagebank dengan ann_id ini, delete from queue table
@@ -811,94 +885,27 @@ class MainExtension01 {
"Cancelled SOUNDBANK message with index ${qa.index} due to ANN_ID $ann_id not found in Messagebank" "Cancelled SOUNDBANK message with index ${qa.index} due to ANN_ID $ann_id not found in Messagebank"
) )
} }
} else if (qa.Type == "TIMER") {
val ann_id = Get_ANN_ID(qa.SB_TAGS)
if (ann_id > 0) {
val mblist = Get_MessageBank_by_id(ann_id, qa.Language.split(";"))
if (mblist.isNotEmpty()) {
mblist.forEach {
mb ->
Get_Soundbank_Files(mb, emptyMap(), {
listfile ->
val listafi = mutableListOf<AudioFileInfo>()
listfile.forEach { filenya ->
val afi = contentCache.getAudioFile(filenya)
if (afi!=null && afi.isValid()){
listafi.add(afi)
} else {
val afi = audioPlayer.LoadAudioFile(filenya)
if (afi.isValid()) {
listafi.add(afi)
contentCache.addAudioFile(filenya, afi)
}
}
} }
val targetfile = SoundbankResult_directory.resolve(Make_WAV_FileName("Timer","")).toString()
audioPlayer.WavWriter(listafi, targetfile, true,
) { success, message ->
if (success) {
// file siap broadcast
val targetafi = audioPlayer.LoadAudioFile(targetfile)
if (targetafi.isValid()) {
zz.forEach { z1 ->
StreamerOutputs.values.find { it.channel == z1 }
?.SendData(
targetafi.bytes,
{ db.Add_Log("AAS", it) },
{ db.Add_Log("AAS", it) })
}
val logmsg =
"Broadcast started TIMER message with generated file '$targetfile' to zones: ${qa.BroadcastZones}"
Logger.info { logmsg }
db.Add_Log("AAS", logmsg)
db.queuetableDB.DeleteByIndex(qa.index.toInt())
}
}
db.Add_Log("AAS", message)
}
},
{
err ->
db.Add_Log("AAS", err)
db.queuetableDB.DeleteByIndex(qa.index.toInt())
})
}
} else {
// tidak ada messagebank dengan ann_id ini, delete from queue table
db.queuetableDB.DeleteByIndex(qa.index.toInt())
db.Add_Log(
"AAS",
"Cancelled TIMER with index ${qa.index} due to ANN_ID $ann_id not found in Messagebank"
)
}
} else {
// invalid ann_id, delete from queue table
db.queuetableDB.DeleteByIndex(qa.index.toInt())
db.Add_Log(
"AAS",
"Cancelled TIMER with index ${qa.index} due to invalid ANN_ID"
)
}
}
}
} else { } else {
// ada broadcast zone yang tidak valid, delete from queue table // ada broadcast zone yang tidak valid, delete from queue table
db.queuetableDB.DeleteByIndex(qa.index.toInt()) db.queuetableDB.DeleteByIndex(qa.index.toInt())
db.Add_Log( db.Add_Log("AAS", "Cancelled SOUNDBANK message with index ${qa.index} due to invalid broadcast zone")
"AAS",
"Cancelled table message with index ${qa.index} due to invalid broadcast zone"
)
} }
} else { } else {
// invalid broadcast zone, delete from queue table // invalid broadcast zone, delete from queue table
db.queuetableDB.DeleteByIndex(qa.index.toInt()) db.queuetableDB.DeleteByIndex(qa.index.toInt())
db.Add_Log("AAS", "Cancelled table message with index ${qa.index} due to empty broadcast zone") db.Add_Log("AAS", "Cancelled SOUNDBANK message with index ${qa.index} due to empty broadcast zone")
} }
} }
return false
} }
/** /**
* Read and process Schedule_Table table. * Read and process Schedule_Table table.
* This function is called every minute when second=00. * This function is called every minute when second=00.

View File

@@ -6,17 +6,14 @@ import audio.Bass.BASS_POS_BYTE
import audio.Bass.BASS_STREAM_DECODE import audio.Bass.BASS_STREAM_DECODE
import audio.Bass.BASS_SAMPLE_MONO import audio.Bass.BASS_SAMPLE_MONO
import audio.BassEnc.BASS_ENCODE_PCM import audio.BassEnc.BASS_ENCODE_PCM
import codes.Result_Boolean_String
import codes.Somecodes.Companion.ValidFile import codes.Somecodes.Companion.ValidFile
import codes.Somecodes.Companion.ValidString import codes.Somecodes.Companion.ValidString
import com.sun.jna.Memory import com.sun.jna.Memory
import com.sun.jna.Pointer import com.sun.jna.Pointer
import contentCache import contentCache
import kotlinx.coroutines.CoroutineName
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.launch
import org.tinylog.Logger import org.tinylog.Logger
import java.util.function.BiConsumer
@Suppress("unused") @Suppress("unused")
class AudioPlayer (var samplingrate: Int) { class AudioPlayer (var samplingrate: Int) {
@@ -131,10 +128,9 @@ class AudioPlayer (var samplingrate: Int) {
* @param data The byte array containing the audio data. * @param data The byte array containing the audio data.
* @param target The target file name for the WAV file. * @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 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. * @return A Result_Boolean_String indicating success or failure and a message.
*/ */
fun WavWriter(data: ByteArray, target: String, withChime: Boolean = true, callback: BiConsumer<Boolean, String>) { fun WavWriter(data: ByteArray, target: String, withChime: Boolean = true) : Result_Boolean_String {
CoroutineScope(Dispatchers.IO).launch {
bass.BASS_SetDevice(0) // Set to No Sound device for writing bass.BASS_SetDevice(0) // Set to No Sound device for writing
val streamhandle = bass.BASS_StreamCreate(samplingrate, 1, BASS_STREAM_DECODE, Pointer(-1), null) val streamhandle = bass.BASS_StreamCreate(samplingrate, 1, BASS_STREAM_DECODE, Pointer(-1), null)
@@ -196,19 +192,23 @@ class AudioPlayer (var samplingrate: Int) {
} }
} while (read > 0) } while (read > 0)
println("Finished reading stream data, total $totalread bytes read") 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) bassenc.BASS_Encode_Stop(encodehandle)
} else callback.accept(false, "Failed to start encoding: ${bass.BASS_ErrorGetCode()}")
bass.BASS_StreamFree(streamhandle) bass.BASS_StreamFree(streamhandle)
return if (all_success){
Result_Boolean_String(true, "WAV file written successfully: $target")
} else { } else {
callback.accept(false, "Failed to create stream: ${bass.BASS_ErrorGetCode()}") Result_Boolean_String(false, "Failed to write some data to WAV file: $target")
} }
} else {
bass.BASS_StreamFree(streamhandle)
return Result_Boolean_String(false, "Failed to start encoding: ${bass.BASS_ErrorGetCode()}")
}
} else {
return Result_Boolean_String(false, "Failed to create stream: ${bass.BASS_ErrorGetCode()}")
} }
@@ -220,31 +220,25 @@ class AudioPlayer (var samplingrate: Int) {
* @param sources List of AudioFileInfo objects containing the audio data to write. * @param sources List of AudioFileInfo objects containing the audio data to write.
* @param target The target file name for the WAV file. * @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 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. * @return A Result_Boolean_String indicating success or failure and a message.
*/ */
fun WavWriter(sources: List<AudioFileInfo>, target: String, withChime: Boolean = true, callback: BiConsumer<Boolean, String>) { fun WavWriter(sources: List<AudioFileInfo>, target: String, withChime: Boolean = true) : Result_Boolean_String {
if (sources.isEmpty()) { if (sources.isEmpty()) {
callback.accept(false, " Invalid sources") return Result_Boolean_String(false,"Invalid Source")
return
} }
if (!ValidString(target)) { if (!ValidString(target)) {
callback.accept(false, " Invalid target file name") return Result_Boolean_String(false, " Invalid target file name")
return
} }
CoroutineScope(Dispatchers.IO).launch(CoroutineName("WavWriter $target")) {
bass.BASS_SetDevice(0) // Set to No Sound device for writing bass.BASS_SetDevice(0) // Set to No Sound device for writing
val streamhandle = bass.BASS_StreamCreate(samplingrate, 1, BASS_STREAM_DECODE, Pointer(-1), null) val streamhandle = bass.BASS_StreamCreate(samplingrate, 1, BASS_STREAM_DECODE, Pointer(-1), null)
if (streamhandle==0){ if (streamhandle==0){
callback.accept(false, "Failed to create stream: ${bass.BASS_ErrorGetCode()}") return Result_Boolean_String(false, "Failed to create stream: ${bass.BASS_ErrorGetCode()}")
return@launch
} }
val encodehandle = bassenc.BASS_Encode_Start(streamhandle, target, BASS_ENCODE_PCM, null, null) val encodehandle = bassenc.BASS_Encode_Start(streamhandle, target, BASS_ENCODE_PCM, null, null)
if (encodehandle==0){ if (encodehandle==0){
bass.BASS_StreamFree(streamhandle) bass.BASS_StreamFree(streamhandle)
callback.accept(false, "Failed to start encoding: ${bass.BASS_ErrorGetCode()}") return Result_Boolean_String(false, "Failed to start encoding: ${bass.BASS_ErrorGetCode()}")
return@launch
} }
fun pushData(data: ByteArray): Boolean { fun pushData(data: ByteArray): Boolean {
@@ -314,14 +308,15 @@ class AudioPlayer (var samplingrate: Int) {
// close the encoding handle // close the encoding handle
bassenc.BASS_Encode_Stop(encodehandle) bassenc.BASS_Encode_Stop(encodehandle)
bass.BASS_ChannelFree(streamhandle) bass.BASS_ChannelFree(streamhandle)
if (allsuccess){ return if (allsuccess){
callback.accept(true, "WAV file written successfully: $target") Result_Boolean_String(true, "WAV file written successfully: $target")
} else { } else {
callback.accept(false, "Failed to write some data to WAV file: $target") Result_Boolean_String(false, "Failed to write some data to WAV file: $target")
}
} }
} }

View File

@@ -0,0 +1,4 @@
package codes
class Result_Boolean_String(val success: Boolean, val message: String) {
}

View File

@@ -0,0 +1,3 @@
package codes
class Result_GetSoundbankFiles(val success: Boolean, val message: String , val files: List<String> = emptyList())

View File

@@ -60,12 +60,14 @@ class TCP_Android_Command_Server {
Logger.info { "Start communicating with IPMT/IPM with IP $key" } Logger.info { "Start communicating with IPMT/IPM with IP $key" }
val din = socket.getInputStream() val din = socket.getInputStream()
val dout = socket.getOutputStream() val dout = socket.getOutputStream()
try{
while (isActive) { while (isActive) {
if (din.available() > 0) { if (din.available() > 0) {
val bb = ByteArray(din.available()) val bb = ByteArray(din.available())
din.read(bb) din.read(bb)
// B4A format, 4 bytes di depan adalah size // B4A format, 4 bytes di depan adalah size
val str = String(bb, 4, bb.size - 4) val str = String(bb, 4, bb.size - 4)
println("Received command from $key : $str")
str.split("@").map { it.trim() }.filter { ValidString(it) } str.split("@").map { it.trim() }.filter { ValidString(it) }
.forEach { .forEach {
process_command(key,it) { reply -> process_command(key,it) { reply ->
@@ -78,7 +80,12 @@ class TCP_Android_Command_Server {
} }
} }
} }
} catch (e : Exception){
logcb.accept("Exception in communication with $key, Message : ${e.message}")
}
logcb.accept("Finished communicatiing with $key") logcb.accept("Finished communicatiing with $key")
CloseSocket(socket)
socketMap.remove(key) socketMap.remove(key)
} }
@@ -98,6 +105,14 @@ class TCP_Android_Command_Server {
return false return false
} }
private fun CloseSocket(socket : Socket) {
try {
socket.close()
} catch (e: Exception) {
Logger.error { "Failed to close socket, Message : ${e.message}" }
}
}
/** /**
* Convert a String to ByteArray in prefix AsyncStream format in B4X * Convert a String to ByteArray in prefix AsyncStream format in B4X
* @param str The input string * @param str The input string
@@ -184,11 +199,8 @@ class TCP_Android_Command_Server {
val data = pj.GetData() val data = pj.GetData()
pj.Close() pj.Close()
Logger.info{"Paging job closed from Android $key, total bytes received ${data.size}, writing to file ${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){ val result = audioPlayer.WavWriter(data, pj.filePath.absolutePathString(), true)
success, message -> if (result.success){
if (success){
// insert to paging queue
val qp = QueuePaging( val qp = QueuePaging(
0u, 0u,
LocalDateTime.now().format(datetimeformat1), LocalDateTime.now().format(datetimeformat1),
@@ -204,12 +216,12 @@ class TCP_Android_Command_Server {
logcb.accept("Failed to insert paging audio to queue paging table from Android $key, file ${pj.filePath.absolutePathString()}") logcb.accept("Failed to insert paging audio to queue paging table from Android $key, file ${pj.filePath.absolutePathString()}")
cb.accept(parts[0]+";NG@") cb.accept(parts[0]+";NG@")
} }
} else { } else {
logcb.accept("Failed to write paging audio to file ${pj.filePath.absolutePathString()}, Message : $message") logcb.accept("Failed to write paging audio to file ${pj.filePath.absolutePathString()}, Message : ${result.message}")
cb.accept(parts[0]+";NG@") cb.accept(parts[0]+";NG@")
return
} }
}
} else { } else {
logcb.accept("Paging stop from Android $key failed, no ongoing paging") logcb.accept("Paging stop from Android $key failed, no ongoing paging")