From 49e82aae0eb63e3aed60b738ccb0340e2a099cd5 Mon Sep 17 00:00:00 2001 From: rdkartono Date: Mon, 28 Jul 2025 15:49:53 +0700 Subject: [PATCH] commit 28/07/2025 --- .idea/libraries/kotlinx_coroutines_core.xml | 22 +++++ AAS_NewGen.iml | 1 + src/audio/UDPReceiverToFile.kt | 25 +++--- src/audio/UDPSenderFromFile.kt | 99 +++++++++++++++++++++ 4 files changed, 136 insertions(+), 11 deletions(-) create mode 100644 .idea/libraries/kotlinx_coroutines_core.xml create mode 100644 src/audio/UDPSenderFromFile.kt diff --git a/.idea/libraries/kotlinx_coroutines_core.xml b/.idea/libraries/kotlinx_coroutines_core.xml new file mode 100644 index 0000000..ecaecc9 --- /dev/null +++ b/.idea/libraries/kotlinx_coroutines_core.xml @@ -0,0 +1,22 @@ + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/AAS_NewGen.iml b/AAS_NewGen.iml index c1b8382..8bf29d4 100644 --- a/AAS_NewGen.iml +++ b/AAS_NewGen.iml @@ -16,5 +16,6 @@ + \ No newline at end of file diff --git a/src/audio/UDPReceiverToFile.kt b/src/audio/UDPReceiverToFile.kt index 4360e27..9ee3b56 100644 --- a/src/audio/UDPReceiverToFile.kt +++ b/src/audio/UDPReceiverToFile.kt @@ -2,6 +2,11 @@ package audio import audio.Bass.BASS_STREAMPROC_END import audio.BassEnc.BASS_ENCODE_PCM +import kotlinx.coroutines.CoroutineName +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.launch +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.delay import org.tinylog.Logger import java.io.PipedInputStream import java.io.PipedOutputStream @@ -76,7 +81,8 @@ class UDPReceiverToFile(listeningAddress: String, listeningPort: Int, val sampli var isReceiving = false if (isReady){ - val thread1 = Thread{ + val scope = CoroutineScope(Dispatchers.Default) + scope.launch(CoroutineName("UDPReceiverToFile UDP $senderIP $outputFilePath")) { Logger.info { "UDPReceiverToFile started, listening on ${socket?.localSocketAddress} , saving to $outputFilePath" } PipedOutputStream(pipeIn).use { pipeOut -> @@ -100,11 +106,9 @@ class UDPReceiverToFile(listeningAddress: String, listeningPort: Int, val sampli } Logger.info { "UDPReceiverToFile ended" } } - thread1.name = "UDPReceiverToFile Thread1 $senderIP $outputFilePath" - thread1.isDaemon = true - thread1.start() - val thread2 = Thread{ + + scope.launch(CoroutineName("UDPReceiverToFile BASS $senderIP $outputFilePath")) { bass.BASS_SetDevice(0) // Set to No Sound device, we are not playing audio val streamhandle = bass.BASS_StreamCreate(samplingrate, channel, 0, streamProc, null) if (streamhandle!=0){ @@ -115,7 +119,7 @@ class UDPReceiverToFile(listeningAddress: String, listeningPort: Int, val sampli callback.accept(true, "UDPReceiverToFile started successfully, writing to $outputFilePath") while (isReceiving) { try { - Thread.sleep(1000) // Sleep to avoid busy waiting + delay(1000) } catch (e: InterruptedException) { Logger.error { "UDPReceiverToFile thread interrupted: ${e.message}" } break @@ -125,19 +129,18 @@ class UDPReceiverToFile(listeningAddress: String, listeningPort: Int, val sampli bass.BASS_StreamFree(streamhandle) Logger.info { "UDPReceiverToFile stopped writing to $outputFilePath" } callback.accept(false, "UDPReceiverToFile stopped successfully, written bytes: $bytesWritten") + } else { callback.accept(false, "Failed to start encoding: ${bass.BASS_ErrorGetCode()}") - return@Thread } } else { callback.accept(false, "Failed to create stream: ${bass.BASS_ErrorGetCode()}") - return@Thread } } - thread2.name = "UDPReceiverToFile Thread2 $senderIP $outputFilePath" - thread2.isDaemon = true - thread2.start() + + + diff --git a/src/audio/UDPSenderFromFile.kt b/src/audio/UDPSenderFromFile.kt new file mode 100644 index 0000000..97e10d6 --- /dev/null +++ b/src/audio/UDPSenderFromFile.kt @@ -0,0 +1,99 @@ +package audio + +import audio.Bass.BASS_STREAM_DECODE +import codes.Somecodes.Companion.ValidFile +import com.sun.jna.Memory +import java.net.DatagramPacket +import java.net.DatagramSocket +import java.net.InetSocketAddress +import java.net.SocketAddress +import java.util.function.BiConsumer +import kotlinx.coroutines.CoroutineName +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.launch + +@Suppress("unused") +class UDPSenderFromFile(val fileName: String, val bytesPerPackage: Int=1024, targetIP: Array, targetPort: Int ) { + val bass: Bass = Bass.Instance + var filehandle: Int = 0 + var listSocketAddress = ArrayList() + + var initialized: Boolean = false; private set + var isRunning: Boolean = false; private set + var bytesSent: Int = 0; private set + + init { + if (ValidFile(fileName)){ + bass.BASS_SetDevice(0) + val handle = bass.BASS_StreamCreateFile(false, fileName, 0,0, BASS_STREAM_DECODE) + if (handle!=0){ + // test buka file berhasil, tutup lagi + bass.BASS_StreamFree(handle) + if (targetPort>0 && targetPort<65535){ + if (targetIP.isNotEmpty()){ + var validIPs = true + for(ip in targetIP){ + try{ + var so = InetSocketAddress(ip, targetPort) + listSocketAddress.add(so) + } catch (e : Exception){ + validIPs = false + } + } + + if (validIPs){ + initialized = true + } + + } + } + } + + } + } + + fun Start(callback: BiConsumer){ + if (initialized){ + + val scope = CoroutineScope(Dispatchers.Default) + scope.launch(CoroutineName("UDPSenderFromFile $fileName")) { + try { + val socket = DatagramSocket() + bass.BASS_SetDevice(0) // Set to No Sound Device + val handle = bass.BASS_StreamCreateFile(false, fileName, 0, 0, BASS_STREAM_DECODE) + if (handle!=0){ + isRunning = true + bytesSent = 0 + callback.accept(true,"UDPSenderFromFile started, sending $fileName to ${listSocketAddress.size} targets") + while(isRunning){ + val buffer = Memory(bytesPerPackage.toLong()) + val bytesRead = bass.BASS_ChannelGetData(handle, buffer, bytesPerPackage) + if (bytesRead > 0) { + for(so in listSocketAddress){ + val bytes = buffer.getByteArray(0, bytesRead) + socket.send(DatagramPacket(bytes, bytes.size, so)) + bytesSent += bytes.size + } + + } else isRunning = false + } + callback.accept(false,"UDPSenderFromFile finished sending $fileName") + bass.BASS_StreamFree(handle) + socket.close() + } else callback.accept(false, "Failed to open file $fileName for reading") + } catch (e : Exception){ + callback.accept(false, "Error in UDPSenderFromFile: ${e.message}") + isRunning = false + } + } + + + } else callback.accept(false, "UDP Sender not initialized, check file and target IP/Port") + + } + + fun Stop(){ + isRunning = false + } +} \ No newline at end of file