commit 28/07/2025

This commit is contained in:
2025-07-28 15:49:53 +07:00
parent 901d553da9
commit 49e82aae0e
4 changed files with 136 additions and 11 deletions

View File

@@ -0,0 +1,22 @@
<component name="libraryTable">
<library name="kotlinx-coroutines-core" type="repository">
<properties maven-id="org.jetbrains.kotlinx:kotlinx-coroutines-core:1.9.0" />
<CLASSES>
<root url="jar://$MAVEN_REPOSITORY$/org/jetbrains/kotlinx/kotlinx-coroutines-core/1.9.0/kotlinx-coroutines-core-1.9.0.jar!/" />
<root url="jar://$MAVEN_REPOSITORY$/org/jetbrains/kotlinx/kotlinx-coroutines-core-jvm/1.9.0/kotlinx-coroutines-core-jvm-1.9.0.jar!/" />
<root url="jar://$MAVEN_REPOSITORY$/org/jetbrains/annotations/23.0.0/annotations-23.0.0.jar!/" />
<root url="jar://$MAVEN_REPOSITORY$/org/jetbrains/kotlin/kotlin-stdlib/2.0.0/kotlin-stdlib-2.0.0.jar!/" />
</CLASSES>
<JAVADOC>
<root url="jar://$MAVEN_REPOSITORY$/org/jetbrains/kotlinx/kotlinx-coroutines-core-jvm/1.9.0/kotlinx-coroutines-core-jvm-1.9.0-javadoc.jar!/" />
<root url="jar://$MAVEN_REPOSITORY$/org/jetbrains/annotations/23.0.0/annotations-23.0.0-javadoc.jar!/" />
<root url="jar://$MAVEN_REPOSITORY$/org/jetbrains/kotlin/kotlin-stdlib/2.0.0/kotlin-stdlib-2.0.0-javadoc.jar!/" />
</JAVADOC>
<SOURCES>
<root url="jar://$MAVEN_REPOSITORY$/org/jetbrains/kotlinx/kotlinx-coroutines-core/1.9.0/kotlinx-coroutines-core-1.9.0-sources.jar!/" />
<root url="jar://$MAVEN_REPOSITORY$/org/jetbrains/kotlinx/kotlinx-coroutines-core-jvm/1.9.0/kotlinx-coroutines-core-jvm-1.9.0-sources.jar!/" />
<root url="jar://$MAVEN_REPOSITORY$/org/jetbrains/annotations/23.0.0/annotations-23.0.0-sources.jar!/" />
<root url="jar://$MAVEN_REPOSITORY$/org/jetbrains/kotlin/kotlin-stdlib/2.0.0/kotlin-stdlib-2.0.0-sources.jar!/" />
</SOURCES>
</library>
</component>

View File

@@ -16,5 +16,6 @@
<orderEntry type="library" name="net.java.dev.jna" level="project" />
<orderEntry type="library" name="io.javalin" level="project" />
<orderEntry type="library" name="mariadb.jdbc.java.client" level="project" />
<orderEntry type="library" name="kotlinx-coroutines-core" level="project" />
</component>
</module>

View File

@@ -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()

View File

@@ -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<String>, targetPort: Int ) {
val bass: Bass = Bass.Instance
var filehandle: Int = 0
var listSocketAddress = ArrayList<SocketAddress>()
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<Boolean, String>){
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
}
}