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)
// prioritas 1 , habisin queue paging
subcode01.Read_Queue_Paging()
// prioritas 2, habisin queue table
subcode01.Read_Queue_Table()
// prioritas 2, habisin queue shalat
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

View File

@@ -1,4 +1,5 @@
import audio.AudioFileInfo
import codes.Result_GetSoundbankFiles
import codes.Somecodes.Companion.Get_ANN_ID
import codes.Somecodes.Companion.IsAlphabethic
import codes.Somecodes.Companion.IsNumber
@@ -22,7 +23,6 @@ import java.time.DayOfWeek
import java.time.LocalDate
import java.time.LocalDateTime
import java.time.LocalTime
import java.util.function.Consumer
/**
* 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
* @param mb Messagebank object
* @param variables Map of variables to replace in tags.
* @param cbOK Callback function if success, returns List of soundbank file names
* @param cbFail Callback function if failed, returns error message
* @return Result_GetSoundbankFiles object containing success status, message, and list of soundbank file paths.
*/
fun Get_Soundbank_Files(
mb: Messagebank,
variables: Map<String, String>,
cbOK: Consumer<List<String>>,
cbFail: Consumer<String>
) {
variables: Map<String, String>
) : Result_GetSoundbankFiles {
val tags = mb.Message_TAGS.split(" ")
if (tags.isEmpty()) {
cbFail.accept("No tags found in messagebank id ${mb.ANN_ID}")
return
return Result_GetSoundbankFiles(false, "No tags found in messagebank id ${mb.ANN_ID}")
}
// dapatkan soundbank array berdasarkan VoiceType dan Language
val sb = db.soundDB.List
.filter { it.VoiceType.equals(mb.Voice_Type, true) }
.filter { it.Language.equals(mb.Language, true) }
if (sb.isEmpty()) {
cbFail.accept("No soundbank found for voice type ${mb.Voice_Type} and language ${mb.Language}")
return
return Result_GetSoundbankFiles(false, "No soundbank found for voice type ${mb.Voice_Type} and language ${mb.Language}")
}
val files = mutableListOf<String>()
@@ -244,16 +242,16 @@ class MainExtension01 {
if (ValidFile(airplane.Path)) {
files.add(airplane.Path)
} else {
cbFail.accept("Invalid soundbank file ${airplane.Path} for tag=$_tag voicetype=${mb.Voice_Type} language=${mb.Language} ANN_ID=${mb.ANN_ID}")
return
return Result_GetSoundbankFiles(false, "Invalid soundbank file ${airplane.Path} for tag=$_tag voicetype=${mb.Voice_Type} language=${mb.Language} ANN_ID=${mb.ANN_ID}")
}
} else {
cbFail.accept("No Airplane_Name found for tag=$_tag voicetype=${mb.Voice_Type} language=${mb.Language} ANN_ID=${mb.ANN_ID}")
return
return Result_GetSoundbankFiles(false, "No Airplane_Name found for tag=$_tag voicetype=${mb.Voice_Type} language=${mb.Language} ANN_ID=${mb.ANN_ID}")
}
} else {
cbFail.accept("AIRPLANE_NAME variable is missing or empty for tag $_tag in messagebank id ${mb.ANN_ID}")
return
return Result_GetSoundbankFiles(false, "AIRPLANE_NAME variable is missing or empty for tag $_tag in messagebank id ${mb.ANN_ID}")
}
}
@@ -268,23 +266,23 @@ class MainExtension01 {
if (ValidFile(val1.Path)) {
files.add(val1.Path)
} else {
cbFail.accept("Invalid soundbank file ${val1.Path} for tag=$_tag voicetype=${mb.Voice_Type} language=${mb.Language} ANN_ID=${mb.ANN_ID}")
return
return Result_GetSoundbankFiles(false, "Invalid soundbank file ${val1.Path} for tag=$_tag voicetype=${mb.Voice_Type} language=${mb.Language} ANN_ID=${mb.ANN_ID}")
}
} 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()) {
files.addAll(val2)
} 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
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}")
}
} else {
cbFail.accept("AIRPLANE_NAME or FLIGHT_NUMBER variable is missing or empty for tag $_tag in messagebank id ${mb.ANN_ID}")
return
return Result_GetSoundbankFiles(false, "FLIGHT_NUMBER or AIRLINE_CODE variable is missing or empty for tag $_tag in messagebank id ${mb.ANN_ID}")
}
}
@@ -321,12 +319,12 @@ class MainExtension01 {
}
}
} else {
cbFail.accept("PLATNOMOR variable has invalid format for value '$value' in messagebank id ${mb.ANN_ID}")
return
return Result_GetSoundbankFiles(false, "PLATNOMOR variable has invalid format for value '$value' in messagebank id ${mb.ANN_ID}")
}
} else {
cbFail.accept("PLATNOMOR variable is missing or empty for tag $_tag in messagebank id ${mb.ANN_ID}")
return
return Result_GetSoundbankFiles(false, "PLATNOMOR variable is missing or empty for tag $_tag in messagebank id ${mb.ANN_ID}")
}
}
@@ -339,17 +337,17 @@ class MainExtension01 {
if (ValidFile(city.Path)) {
files.add(city.Path)
} else {
cbFail.accept("Invalid soundbank file ${city.Path} for tag=$_tag voicetype=${mb.Voice_Type} language=${mb.Language} ANN_ID=${mb.ANN_ID}")
return
return Result_GetSoundbankFiles(false, "Invalid soundbank file ${city.Path} for tag=$_tag voicetype=${mb.Voice_Type} language=${mb.Language} ANN_ID=${mb.ANN_ID}")
}
} else {
cbFail.accept("No City found for tag=$_tag voicetype=${mb.Voice_Type} language=${mb.Language} ANN_ID=${mb.ANN_ID}")
return
return Result_GetSoundbankFiles(false, "No City found for tag=$_tag voicetype=${mb.Voice_Type} language=${mb.Language} ANN_ID=${mb.ANN_ID}")
}
}
} else {
cbFail.accept("CITY variable is missing or empty for tag $_tag in messagebank id ${mb.ANN_ID}")
return
return Result_GetSoundbankFiles(false, "CITY variable is missing or empty for tag $_tag in messagebank id ${mb.ANN_ID}")
}
}
@@ -361,16 +359,16 @@ class MainExtension01 {
if (ValidFile(places.Path)) {
files.add(places.Path)
} else {
cbFail.accept("Invalid soundbank file ${places.Path} for tag=$_tag voicetype=${mb.Voice_Type} language=${mb.Language} ANN_ID=${mb.ANN_ID}")
return
return Result_GetSoundbankFiles(false, "Invalid soundbank file ${places.Path} for tag=$_tag voicetype=${mb.Voice_Type} language=${mb.Language} ANN_ID=${mb.ANN_ID}")
}
} else {
cbFail.accept("No Places found for tag=$_tag voicetype=${mb.Voice_Type} language=${mb.Language} ANN_ID=${mb.ANN_ID}")
return
return Result_GetSoundbankFiles(false, "No Places found for tag=$_tag voicetype=${mb.Voice_Type} language=${mb.Language} ANN_ID=${mb.ANN_ID}")
}
} else {
cbFail.accept("PLACES variable is missing or empty for tag $_tag in messagebank id ${mb.ANN_ID}")
return
return Result_GetSoundbankFiles(false, "PLACES variable is missing or empty for tag $_tag in messagebank id ${mb.ANN_ID}")
}
}
@@ -390,19 +388,19 @@ class MainExtension01 {
files.add(hh)
files.add(mm)
} else {
cbFail.accept("ETAD variable has invalid soundbank for hour or minute for tag $_tag in messagebank id ${mb.ANN_ID}")
return
return Result_GetSoundbankFiles(false, "ETAD variable has invalid soundbank for hour or minute for tag $_tag in messagebank id ${mb.ANN_ID}")
}
} 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
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")
}
}
} else {
cbFail.accept("ETAD variable has invalid format for tag $_tag in messagebank id ${mb.ANN_ID}, expected format HH:MM")
return
return Result_GetSoundbankFiles(false, "ETAD variable has invalid format for tag $_tag in messagebank id ${mb.ANN_ID}, expected format HH:MM")
}
}
@@ -415,16 +413,16 @@ class MainExtension01 {
if (ValidFile(shalat.Path)) {
files.add(shalat.Path)
} else {
cbFail.accept("Invalid soundbank file ${shalat.Path} for tag=$_tag voicetype=${mb.Voice_Type} language=${mb.Language} ANN_ID=${mb.ANN_ID}")
return
return Result_GetSoundbankFiles(false, "Invalid soundbank file ${shalat.Path} for tag=$_tag voicetype=${mb.Voice_Type} language=${mb.Language} ANN_ID=${mb.ANN_ID}")
}
} else {
cbFail.accept("No Shalat found for tag=$_tag voicetype=${mb.Voice_Type} language=${mb.Language} ANN_ID=${mb.ANN_ID}")
return
return Result_GetSoundbankFiles(false, "No Shalat found for tag=$_tag voicetype=${mb.Voice_Type} language=${mb.Language} ANN_ID=${mb.ANN_ID}")
}
} else {
cbFail.accept("SHALAT variable is missing or empty for tag $_tag in messagebank id ${mb.ANN_ID}")
return
return Result_GetSoundbankFiles(false, "SHALAT variable is missing or empty for tag $_tag in messagebank id ${mb.ANN_ID}")
}
}
@@ -437,8 +435,8 @@ class MainExtension01 {
if (path != null) {
files.addAll(path)
} else {
cbFail.accept("BCB variable is missing, empty, or doesn't have valid soundbank for value '$value' in messagebank id ${mb.ANN_ID}")
return
return Result_GetSoundbankFiles(false, "BCB variable doesn't have valid soundbank for value '$value' in messagebank id ${mb.ANN_ID}")
}
}
@@ -454,17 +452,17 @@ class MainExtension01 {
if (path != null) {
files.addAll(path)
} else {
cbFail.accept("GATENUMBER variable doesn't have valid soundbank for value '$vv' in messagebank id ${mb.ANN_ID}")
return
return Result_GetSoundbankFiles(false, "GATENUMBER variable doesn't have valid soundbank for value '$vv' in messagebank id ${mb.ANN_ID}")
}
}
} else {
cbFail.accept("GATENUMBER variable is empty after split for tag $_tag in messagebank id ${mb.ANN_ID}")
return
return Result_GetSoundbankFiles(false, "GATENUMBER variable is empty after split for tag $_tag in messagebank id ${mb.ANN_ID}")
}
} else {
cbFail.accept("GATENUMBER variable is missing or empty for tag $_tag in messagebank id ${mb.ANN_ID}")
return
return Result_GetSoundbankFiles(false, "GATENUMBER variable is missing or empty for tag $_tag in messagebank id ${mb.ANN_ID}")
}
}
@@ -477,16 +475,16 @@ class MainExtension01 {
if (ValidFile(reason.Path)) {
files.add(reason.Path)
} else {
cbFail.accept("Invalid soundbank file ${reason.Path} for tag=$_tag voicetype=${mb.Voice_Type} language=${mb.Language} ANN_ID=${mb.ANN_ID}")
return
return Result_GetSoundbankFiles(false, "Invalid soundbank file ${reason.Path} for tag=$_tag voicetype=${mb.Voice_Type} language=${mb.Language} ANN_ID=${mb.ANN_ID}")
}
} else {
cbFail.accept("No Reason found for tag=$_tag voicetype=${mb.Voice_Type} language=${mb.Language} ANN_ID=${mb.ANN_ID}")
return
return Result_GetSoundbankFiles(false, "No Reason found for tag=$_tag voicetype=${mb.Voice_Type} language=${mb.Language} ANN_ID=${mb.ANN_ID}")
}
} else {
cbFail.accept("REASON variable is missing or empty for tag $_tag in messagebank id ${mb.ANN_ID}")
return
return Result_GetSoundbankFiles(false, "REASON variable is missing or empty for tag $_tag in messagebank id ${mb.ANN_ID}")
}
}
@@ -499,16 +497,16 @@ class MainExtension01 {
if (ValidFile(procedure.Path)) {
files.add(procedure.Path)
} else {
cbFail.accept("Invalid soundbank file ${procedure.Path} for tag=$_tag voicetype=${mb.Voice_Type} language=${mb.Language} ANN_ID=${mb.ANN_ID}")
return
return Result_GetSoundbankFiles(false, "Invalid soundbank file ${procedure.Path} for tag=$_tag voicetype=${mb.Voice_Type} language=${mb.Language} ANN_ID=${mb.ANN_ID}")
}
} else {
cbFail.accept("No Procedure found for tag=$_tag voicetype=${mb.Voice_Type} language=${mb.Language} ANN_ID=${mb.ANN_ID}")
return
return Result_GetSoundbankFiles(false, "No Procedure found for tag=$_tag voicetype=${mb.Voice_Type} language=${mb.Language} ANN_ID=${mb.ANN_ID}")
}
} else {
cbFail.accept("PROCEDURE variable is missing or empty for tag $_tag in messagebank id ${mb.ANN_ID}")
return
return Result_GetSoundbankFiles(false,"PROCEDURE variable is missing or empty for tag $_tag in messagebank id ${mb.ANN_ID}")
}
}
@@ -520,12 +518,12 @@ class MainExtension01 {
if (ValidFile(phrase.Path)) {
files.add(phrase.Path)
} else {
cbFail.accept("Invalid soundbank file ${phrase.Path} for tag=$_tag voicetype=${mb.Voice_Type} language=${mb.Language} ANN_ID=${mb.ANN_ID}")
return
return Result_GetSoundbankFiles(false, "Invalid soundbank file ${phrase.Path} for tag=$_tag voicetype=${mb.Voice_Type} language=${mb.Language} ANN_ID=${mb.ANN_ID}")
}
} else {
cbFail.accept("No Phrase found for tag=$_tag voicetype=${mb.Voice_Type} language=${mb.Language} ANN_ID=${mb.ANN_ID}")
return
return Result_GetSoundbankFiles(false, "No Phrase found for tag=$_tag voicetype=${mb.Voice_Type} language=${mb.Language} ANN_ID=${mb.ANN_ID}")
}
}
@@ -533,51 +531,34 @@ class MainExtension01 {
}
}
// all tags processed, return files
cbOK.accept(files)
return Result_GetSoundbankFiles(true, "Success", files)
}
/**
* Read and process Queue_Paging table.
*/
fun Read_Queue_Paging(){
fun Read_Queue_Paging() : Boolean{
db.queuepagingDB.Get()
for (qp in db.queuepagingDB.List) {
val list = db.queuepagingDB.List
.filter { it.Source=="PAGING" }
list.forEach { qp ->
println("Processing $qp")
if (qp.BroadcastZones.isNotBlank()) {
val zz = qp.BroadcastZones.split(";")
if (AllBroadcastZonesValid(zz)) {
val ips = BroadcastZones_to_SoundChannel_IP(zz)
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)
if (afi.isValid()){
// file bisa di load, kirim ke masing masing Streamer Output by IP address
ips.forEach {
ip ->
val br = StreamerOutputs[ip]
br?.SendData(afi.bytes, { db.Add_Log("AAS", it) }, { db.Add_Log("AAS", it) })
}
if (qp.BroadcastZones.isNotBlank()){
if (ValidFile(qp.Message)){
val zz = qp.BroadcastZones.split(";")
if (AllBroadcastZonesValid(zz)){
val ips = BroadcastZones_to_SoundChannel_IP(zz)
if (AllStreamerOutputIdle(ips)){
val afi = audioPlayer.LoadAudioFile(qp.Message)
if (afi.isValid()){
// file bisa di load, kirim ke masing masing Streamer Output by IP address
ips.forEach { ip -> StreamerOutputs[ip]?.SendData(afi.bytes, { db.Add_Log("AAS", it) }, { db.Add_Log("AAS", it) }) }
val logmessage =
"Broadcast started PAGING with Filename '${qp.Message}' to zones: ${qp.BroadcastZones}"
Logger.info { logmessage }
db.Add_Log("AAS", logmessage)
db.queuepagingDB.DeleteByIndex(qp.index.toInt())
return
} 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"
)
}
val logmessage =
"Broadcast started PAGING with Filename '${qp.Message}' to zones: ${qp.BroadcastZones}"
Logger.info { logmessage }
db.Add_Log("AAS", logmessage)
db.queuepagingDB.DeleteByIndex(qp.index.toInt())
return true
} else {
// file tidak valid, delete from queue paging
db.queuepagingDB.DeleteByIndex(qp.index.toInt())
@@ -586,101 +567,18 @@ class MainExtension01 {
"Cancelled paging message with index ${qp.index} due to invalid audio file"
)
}
} else if (qp.Source == "SHALAT") {
val ann_id = Get_ANN_ID(qp.Message)
if (ann_id > 0) {
// shalat, ambil messagebank berdasarkan ann_id dengan bahasa Indonesia saja
Get_MessageBank_by_id(ann_id, listOf(Language.INDONESIA.name)).let { mblist ->
if (mblist.isNotEmpty()) {
Get_Soundbank_Files(
mblist[0],
emptyMap(),
{
// dapat list dari files dan sudah dicek valid path
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(
"Shalat",
""
)
).toString()
audioPlayer.WavWriter(
listafi,
targetfile, true,
) { success, message ->
db.Add_Log("AAS", 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 SHALAT message with generated file '$targetfile' to zones: ${qp.BroadcastZones}"
Logger.info { logmsg }
db.Add_Log("AAS", logmsg)
db.queuepagingDB.DeleteByIndex(qp.index.toInt())
} else {
db.Add_Log(
"AAS",
"Failed to load generated Shalat WAV file $targetfile"
)
}
}
}
},
{ err ->
db.queuepagingDB.DeleteByIndex(qp.index.toInt())
db.Add_Log("AAS", err)
}
)
} else {
// tidak ada messagebank dengan ann_id ini, delete from queue paging
db.queuepagingDB.DeleteByIndex(qp.index.toInt())
db.Add_Log(
"AAS",
"Cancelled Shalat message with index ${qp.index} due to ANN_ID $ann_id not found in Messagebank"
)
}
}
} else {
// invalid ann_id, delete from queue paging
db.queuepagingDB.DeleteByIndex(qp.index.toInt())
db.Add_Log(
"AAS",
"Cancelled Shalat message with index ${qp.index} due to invalid ANN_ID"
)
}
}
} // 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 {
// ada broadcast zone yang tidak valid, delete from queue paging
// 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 broadcast zone"
"Cancelled paging message with index ${qp.index} due to invalid audio file"
)
}
} else {
@@ -689,66 +587,129 @@ class MainExtension01 {
db.Add_Log("AAS", "Cancelled paging message with index ${qp.index} due to empty broadcast zone")
}
}
return false
}
/**
* Read and process Queue_Table table.
*/
fun Read_Queue_Table(){
db.queuetableDB.Get()
db.queuetableDB.List.forEach { qa ->
println("Processing $qa")
if (qa.BroadcastZones.isNotEmpty()) {
val zz = qa.BroadcastZones.split(";")
fun Read_Queue_Shalat() : Boolean{
db.queuepagingDB.Get()
val list = db.queuepagingDB.List
.filter { it.Source=="SHALAT" }
list.forEach { qp ->
println("Processing $qp")
if (qp.BroadcastZones.isNotBlank()){
val zz = qp.BroadcastZones.split(";")
if (AllBroadcastZonesValid(zz)){
val ann_id = Get_ANN_ID(qp.Message)
if (ann_id>0){
val ips = BroadcastZones_to_SoundChannel_IP(zz)
if (AllStreamerOutputIdle(ips)){
val mblist = Get_MessageBank_by_id(ann_id, listOf(Language.INDONESIA.name))
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)
}
}
if (AllBroadcastZonesValid(zz)) {
val ips = BroadcastZones_to_SoundChannel_IP(zz)
if (AllStreamerOutputIdle(ips)) {
if (qa.Type == "SOUNDBANK") {
val variables = Get_Soundbank_Data(qa.SB_TAGS)
val languages = qa.Language.split(";")
// cek apakah ANN_ID ada di SB_TAGS
val ann_id = variables?.get("ANN_ID")?.toIntOrNull() ?: 0
if (ann_id==0){
// not available from variables, try to get from Message column
// ada ini, karena protokol FIS dulu tidak ada ANN_ID tapi pake Remark
val remark = variables?.get("REMARK").orEmpty()
when(remark){
"GOP" -> {
//TODO Combobox First_Call_Message_Chooser
}
"GBD" ->{
// TODO Combobox Second_Call_Message_Chooser
}
"GFC" ->{
// TODO Combobox Final_Call_Message_Chooser
}
"FLD" ->{
// TODO Combobox Landed_Message_Chooser
}
val targetfile = SoundbankResult_directory.resolve(
Make_WAV_FileName(
"Shalat",
""
)
).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 SHALAT message with generated file '$targetfile' to zones: ${qp.BroadcastZones}"
Logger.info { logmsg }
db.Add_Log("AAS", logmsg)
db.queuepagingDB.DeleteByIndex(qp.index.toInt())
return true
} else {
db.Add_Log(
"AAS",
"Failed to load generated Shalat WAV file $targetfile"
)
}
}
} else{
db.queuepagingDB.DeleteByIndex(qp.index.toInt())
db.Add_Log("AAS", result.message)
}
}
}
// recheck again
if (ann_id == 0) {
} else {
// tidak ada messagebank dengan ann_id ini, delete from queue paging
db.queuepagingDB.DeleteByIndex(qp.index.toInt())
db.Add_Log(
"AAS",
"Cancelled SOUNDBANK message with index ${qa.index} due to missing or invalid ANN_ID in SB_TAGS"
"Cancelled Shalat message with index ${qp.index} due to ANN_ID $ann_id not found in Messagebank"
)
db.queuetableDB.DeleteByIndex(qa.index.toInt())
return@forEach
}
// sampe sini punya ann_id valid
} // kalau enggak semua streamer idle, skip dulu
val mblist = Get_MessageBank_by_id(ann_id, languages)
} else {
// invalid ann_id, delete from queue paging
db.queuepagingDB.DeleteByIndex(qp.index.toInt())
db.Add_Log("AAS", "Cancelled shalat message with index ${qp.index} due to invalid ANN_ID")
}
} else {
// ada broadcast zone yang tidak valid, delete from queue paging
db.queuepagingDB.DeleteByIndex(qp.index.toInt())
db.Add_Log("AAS", "Cancelled shalat message with index ${qp.index} due to invalid broadcast zone")
}
} else {
// invalid broadcast zone, delete from queue paging
db.queuepagingDB.DeleteByIndex(qp.index.toInt())
db.Add_Log("AAS", "Cancelled shalat message with index ${qp.index} due to empty broadcast zone")
}
}
return false
}
fun Read_Queue_Timer() : Boolean{
db.queuetableDB.Get()
val list = db.queuetableDB.List.filter { it.Type=="TIMER" }
list.forEach { qa ->
println("Processing $qa")
if (qa.BroadcastZones.isNotEmpty()){
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()) {
val listafi = mutableListOf<AudioFileInfo>()
mblist.forEach { mb ->
Get_Soundbank_Files(mb, variables ?: emptyMap(), {
listfile ->
listfile.forEach { filenya ->
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)
@@ -761,144 +722,190 @@ class MainExtension01 {
}
}
},
{
err ->
db.Add_Log("AAS", err)
db.queuetableDB.DeleteByIndex(qa.index.toInt())
})
}
if (listafi.isNotEmpty()){
db.queuetableDB.DeleteByIndex(qa.index.toInt())
val targetfile = SoundbankResult_directory.resolve(Make_WAV_FileName("Soundbank","")).toString()
println("Writing to target WAV file: $targetfile")
audioPlayer.WavWriter(listafi, targetfile, true,
) { success, message ->
if (success) {
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
println("Successfully wrote WAV file: $targetfile")
val targetafi = audioPlayer.LoadAudioFile(targetfile)
if (targetafi.isValid()) {
ips.forEach { ip ->
StreamerOutputs[ip].let{ sc ->
sc?.SendData(targetafi.bytes,
{ db.Add_Log("AAS", it) },
{ db.Add_Log("AAS", it) } )
}
}
ips.forEach { ip -> StreamerOutputs[ip]?.SendData(targetafi.bytes, { db.Add_Log("AAS", it) }, { db.Add_Log("AAS", it) }) }
val logmsg =
"Broadcast started SOUNDBANK message with generated file '$targetfile' to zones: ${qa.BroadcastZones}"
"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 {
println("Failed to write WAV file: $message")
} else{
db.queuetableDB.DeleteByIndex(qa.index.toInt())
db.Add_Log("AAS", message)
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 SOUNDBANK message with index ${qa.index} due to ANN_ID $ann_id not found in Messagebank"
"Cancelled TIMER 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)
}
}
} // kalau enggak semua streamer idle, skip dulu
}
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 {
// 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 table message with index ${qa.index} due to invalid broadcast zone"
)
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 table message with index ${qa.index} due to empty broadcast zone")
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)){
val ips = BroadcastZones_to_SoundChannel_IP(zz)
if (AllStreamerOutputIdle(ips)) {
val variables = Get_Soundbank_Data(qa.SB_TAGS)
val languages = qa.Language.split(";")
// cek apakah ANN_ID ada di SB_TAGS
val ann_id = variables?.get("ANN_ID")?.toIntOrNull() ?: 0
if (ann_id==0){
// not available from variables, try to get from Message column
// ada ini, karena protokol FIS dulu tidak ada ANN_ID tapi pake Remark
val remark = variables?.get("REMARK").orEmpty()
when(remark){
"GOP" -> {
//TODO Combobox First_Call_Message_Chooser
}
"GBD" ->{
// TODO Combobox Second_Call_Message_Chooser
}
"GFC" ->{
// TODO Combobox Final_Call_Message_Chooser
}
"FLD" ->{
// TODO Combobox Landed_Message_Chooser
}
}
}
// recheck again
if (ann_id == 0) {
db.Add_Log(
"AAS",
"Cancelled SOUNDBANK message with index ${qa.index} due to missing or invalid ANN_ID in SB_TAGS"
)
db.queuetableDB.DeleteByIndex(qa.index.toInt())
return@forEach
}
// sampe sini punya ann_id valid
val mblist = Get_MessageBank_by_id(ann_id, languages)
if (mblist.isNotEmpty()) {
val listafi = mutableListOf<AudioFileInfo>()
mblist.forEach { mb ->
val result = Get_Soundbank_Files(mb, variables ?: emptyMap())
if (result.success){
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)
}
}
}
} else {
db.Add_Log("AAS", result.message)
db.queuetableDB.DeleteByIndex(qa.index.toInt())
}
}
if (listafi.isNotEmpty()){
db.queuetableDB.DeleteByIndex(qa.index.toInt())
val targetfile = SoundbankResult_directory.resolve(Make_WAV_FileName("Soundbank","")).toString()
println("Writing to target WAV file: $targetfile")
val result = audioPlayer.WavWriter(listafi, targetfile, true)
if (result.success){
// file siap broadcast
println("Successfully wrote WAV file: $targetfile")
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 SOUNDBANK message with generated file '$targetfile' to zones: ${qa.BroadcastZones}"
Logger.info { logmsg }
db.Add_Log("AAS", logmsg)
return true
}
} else {
println("Failed to write WAV file: ${result.message}")
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 SOUNDBANK message with index ${qa.index} due to ANN_ID $ann_id not found in Messagebank"
)
}
}
} else {
// ada broadcast zone yang tidak valid, delete from queue table
db.queuetableDB.DeleteByIndex(qa.index.toInt())
db.Add_Log("AAS", "Cancelled SOUNDBANK 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 SOUNDBANK message with index ${qa.index} due to empty broadcast zone")
}
}
return false
}
/**
* Read and process Schedule_Table table.
* 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_SAMPLE_MONO
import audio.BassEnc.BASS_ENCODE_PCM
import codes.Result_Boolean_String
import codes.Somecodes.Companion.ValidFile
import codes.Somecodes.Companion.ValidString
import com.sun.jna.Memory
import com.sun.jna.Pointer
import contentCache
import kotlinx.coroutines.CoroutineName
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.launch
import org.tinylog.Logger
import java.util.function.BiConsumer
@Suppress("unused")
class AudioPlayer (var samplingrate: Int) {
@@ -131,84 +128,87 @@ class AudioPlayer (var samplingrate: Int) {
* @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.
* @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>) {
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)
fun WavWriter(data: ByteArray, target: String, withChime: Boolean = true) : Result_Boolean_String {
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){
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")
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")
}
return pushresult != -1
}
} else println("Chime Up not valid")
}
var all_success = true
if (pushData(data)){
println("Data pushed")
} else {
all_success = false
println("Data push failed")
}
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
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")
}
} while (read > 0)
println("Finished reading stream data, total $totalread bytes read")
} else println("Chime Down not valid")
}
if (all_success){
callback.accept(true, "WAV file written successfully: $target")
} else {
callback.accept(false, "Failed to write some data to WAV file: $target")
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
}
bassenc.BASS_Encode_Stop(encodehandle)
} else callback.accept(false, "Failed to start encoding: ${bass.BASS_ErrorGetCode()}")
} while (read > 0)
println("Finished reading stream data, total $totalread bytes read")
bassenc.BASS_Encode_Stop(encodehandle)
bass.BASS_StreamFree(streamhandle)
return if (all_success){
Result_Boolean_String(true, "WAV file written successfully: $target")
} else {
Result_Boolean_String(false, "Failed to write some data to WAV file: $target")
}
} else {
callback.accept(false, "Failed to create stream: ${bass.BASS_ErrorGetCode()}")
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,107 +220,102 @@ class AudioPlayer (var samplingrate: Int) {
* @param sources List of AudioFileInfo objects containing the audio data to write.
* @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.
* @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()) {
callback.accept(false, " Invalid sources")
return
return Result_Boolean_String(false,"Invalid Source")
}
if (!ValidString(target)) {
callback.accept(false, " Invalid target file name")
return
return Result_Boolean_String(false, " Invalid target file name")
}
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){
return Result_Boolean_String(false, "Failed to create stream: ${bass.BASS_ErrorGetCode()}")
}
val encodehandle = bassenc.BASS_Encode_Start(streamhandle, target, BASS_ENCODE_PCM, null, null)
if (encodehandle==0){
bass.BASS_StreamFree(streamhandle)
return Result_Boolean_String(false, "Failed to start encoding: ${bass.BASS_ErrorGetCode()}")
}
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
}
CoroutineScope(Dispatchers.IO).launch(CoroutineName("WavWriter $target")) {
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){
callback.accept(false, "Failed to create stream: ${bass.BASS_ErrorGetCode()}")
return@launch
}
val encodehandle = bassenc.BASS_Encode_Start(streamhandle, target, BASS_ENCODE_PCM, null, null)
if (encodehandle==0){
bass.BASS_StreamFree(streamhandle)
callback.accept(false, "Failed to start encoding: ${bass.BASS_ErrorGetCode()}")
return@launch
}
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 allsuccess = true
if (withChime){
val chup = contentCache.getAudioFile("chimeup")
if (chup!=null && chup.isValid()){
if (pushData(chup.bytes)){
println("Chime up pushed")
} else {
allsuccess = false
println("Chime up failed")
}
} else println("Chime Up not valid")
}
sources.forEach { source ->
if (source.isValid()) {
// write the bytes to the stream
if (pushData(source.bytes)){
println("Source ${source.fileName} pushed")
} else {
allsuccess = false
println("Source ${source.fileName} push failed")
}
var allsuccess = true
if (withChime){
val chup = contentCache.getAudioFile("chimeup")
if (chup!=null && chup.isValid()){
if (pushData(chup.bytes)){
println("Chime up pushed")
} else {
allsuccess = false
println("Source ${source.fileName} is not valid")
println("Chime up failed")
}
}
if (withChime){
val chdn = contentCache.getAudioFile("chimedown")
if (chdn!=null && chdn.isValid()){
if (pushData(chdn.bytes)){
println("Chime down pushed")
} else {
allsuccess = 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")
// close the encoding handle
bassenc.BASS_Encode_Stop(encodehandle)
bass.BASS_ChannelFree(streamhandle)
if (allsuccess){
callback.accept(true, "WAV file written successfully: $target")
} else {
callback.accept(false, "Failed to write some data to WAV file: $target")
}
} else println("Chime Up not valid")
}
sources.forEach { source ->
if (source.isValid()) {
// write the bytes to the stream
if (pushData(source.bytes)){
println("Source ${source.fileName} pushed")
} else {
allsuccess = false
println("Source ${source.fileName} push failed")
}
} else {
allsuccess = false
println("Source ${source.fileName} is not valid")
}
}
if (withChime){
val chdn = contentCache.getAudioFile("chimedown")
if (chdn!=null && chdn.isValid()){
if (pushData(chdn.bytes)){
println("Chime down pushed")
} else {
allsuccess = 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")
// close the encoding handle
bassenc.BASS_Encode_Stop(encodehandle)
bass.BASS_ChannelFree(streamhandle)
return if (allsuccess){
Result_Boolean_String(true, "WAV file written successfully: $target")
} else {
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,25 +60,32 @@ class TCP_Android_Command_Server {
Logger.info { "Start communicating with IPMT/IPM with IP $key" }
val din = socket.getInputStream()
val dout = socket.getOutputStream()
while (isActive) {
if (din.available() > 0) {
val bb = ByteArray(din.available())
din.read(bb)
// B4A format, 4 bytes di depan adalah size
val str = String(bb, 4, bb.size - 4)
str.split("@").map { it.trim() }.filter { ValidString(it) }
.forEach {
process_command(key,it) { reply ->
try {
dout.write(String_to_Byte_Android(reply))
} catch (e: Exception) {
logcb.accept("Failed to send reply to $key, Message : $e")
try{
while (isActive) {
if (din.available() > 0) {
val bb = ByteArray(din.available())
din.read(bb)
// B4A format, 4 bytes di depan adalah size
val str = String(bb, 4, bb.size - 4)
println("Received command from $key : $str")
str.split("@").map { it.trim() }.filter { ValidString(it) }
.forEach {
process_command(key,it) { reply ->
try {
dout.write(String_to_Byte_Android(reply))
} catch (e: Exception) {
logcb.accept("Failed to send reply to $key, Message : $e")
}
}
}
}
}
}
} catch (e : Exception){
logcb.accept("Exception in communication with $key, Message : ${e.message}")
}
logcb.accept("Finished communicatiing with $key")
CloseSocket(socket)
socketMap.remove(key)
}
@@ -98,6 +105,14 @@ class TCP_Android_Command_Server {
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
* @param str The input string
@@ -184,33 +199,30 @@ class TCP_Android_Command_Server {
val data = pj.GetData()
pj.Close()
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),
"PAGING",
"NORMAL",
pj.filePath.absolutePathString(),
pj.broadcastzones
)
if (db.queuepagingDB.Add(qp)){
logcb.accept("Paging audio inserted to queue paging table from Android $key, file ${pj.filePath.absolutePathString()}")
cb.accept(parts[0]+";OK@")
} else {
logcb.accept("Failed to insert paging audio to queue paging table from Android $key, file ${pj.filePath.absolutePathString()}")
cb.accept(parts[0]+";NG@")
}
val result = audioPlayer.WavWriter(data, pj.filePath.absolutePathString(), true)
if (result.success){
val qp = QueuePaging(
0u,
LocalDateTime.now().format(datetimeformat1),
"PAGING",
"NORMAL",
pj.filePath.absolutePathString(),
pj.broadcastzones
)
if (db.queuepagingDB.Add(qp)){
logcb.accept("Paging audio inserted to queue paging table from Android $key, file ${pj.filePath.absolutePathString()}")
cb.accept(parts[0]+";OK@")
} else {
logcb.accept("Failed to write paging audio to file ${pj.filePath.absolutePathString()}, Message : $message")
logcb.accept("Failed to insert paging audio to queue paging table from Android $key, file ${pj.filePath.absolutePathString()}")
cb.accept(parts[0]+";NG@")
}
} else {
logcb.accept("Failed to write paging audio to file ${pj.filePath.absolutePathString()}, Message : ${result.message}")
cb.accept(parts[0]+";NG@")
return
}
} else {
logcb.accept("Paging stop from Android $key failed, no ongoing paging")
cb.accept(parts[0]+";NG@")