Commit 06/08/2025
This commit is contained in:
1
.idea/inspectionProfiles/Project_Default.xml
generated
1
.idea/inspectionProfiles/Project_Default.xml
generated
@@ -2,6 +2,7 @@
|
|||||||
<profile version="1.0">
|
<profile version="1.0">
|
||||||
<option name="myName" value="Project Default" />
|
<option name="myName" value="Project Default" />
|
||||||
<inspection_tool class="AiaStyle" enabled="false" level="TYPO" enabled_by_default="false" />
|
<inspection_tool class="AiaStyle" enabled="false" level="TYPO" enabled_by_default="false" />
|
||||||
|
<inspection_tool class="AssignedValueIsNeverRead" enabled="false" level="WARNING" enabled_by_default="false" />
|
||||||
<inspection_tool class="ClassName" enabled="false" level="WEAK WARNING" enabled_by_default="false" />
|
<inspection_tool class="ClassName" enabled="false" level="WEAK WARNING" enabled_by_default="false" />
|
||||||
<inspection_tool class="DuplicatedCode" enabled="false" level="WEAK WARNING" enabled_by_default="false" />
|
<inspection_tool class="DuplicatedCode" enabled="false" level="WEAK WARNING" enabled_by_default="false" />
|
||||||
<inspection_tool class="FunctionName" enabled="false" level="WEAK WARNING" enabled_by_default="false" />
|
<inspection_tool class="FunctionName" enabled="false" level="WEAK WARNING" enabled_by_default="false" />
|
||||||
|
|||||||
13
.idea/libraries/jetbrains_kotlinx_coroutines_core.xml
generated
Normal file
13
.idea/libraries/jetbrains_kotlinx_coroutines_core.xml
generated
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
<component name="libraryTable">
|
||||||
|
<library name="jetbrains.kotlinx.coroutines.core" type="repository">
|
||||||
|
<properties maven-id="org.jetbrains.kotlinx:kotlinx-coroutines-core:1.10.2" />
|
||||||
|
<CLASSES>
|
||||||
|
<root url="jar://$MAVEN_REPOSITORY$/org/jetbrains/kotlinx/kotlinx-coroutines-core/1.10.2/kotlinx-coroutines-core-1.10.2.jar!/" />
|
||||||
|
<root url="jar://$MAVEN_REPOSITORY$/org/jetbrains/kotlinx/kotlinx-coroutines-core-jvm/1.10.2/kotlinx-coroutines-core-jvm-1.10.2.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.1.0/kotlin-stdlib-2.1.0.jar!/" />
|
||||||
|
</CLASSES>
|
||||||
|
<JAVADOC />
|
||||||
|
<SOURCES />
|
||||||
|
</library>
|
||||||
|
</component>
|
||||||
@@ -16,5 +16,6 @@
|
|||||||
<orderEntry type="library" name="net.java.dev.jna" level="project" />
|
<orderEntry type="library" name="net.java.dev.jna" level="project" />
|
||||||
<orderEntry type="library" name="java.websocket.Java.WebSocket" level="project" />
|
<orderEntry type="library" name="java.websocket.Java.WebSocket" level="project" />
|
||||||
<orderEntry type="library" name="io.javalin.bundle" level="project" />
|
<orderEntry type="library" name="io.javalin.bundle" level="project" />
|
||||||
|
<orderEntry type="library" name="jetbrains.kotlinx.coroutines.core" level="project" />
|
||||||
</component>
|
</component>
|
||||||
</module>
|
</module>
|
||||||
@@ -123,7 +123,7 @@ fun main() {
|
|||||||
if (ValidFile(filename)){
|
if (ValidFile(filename)){
|
||||||
try{
|
try{
|
||||||
val player= AudioFilePlayer(audioID, filename)
|
val player= AudioFilePlayer(audioID, filename)
|
||||||
player.Play { cb -> afp = null}
|
player.Play { _ -> afp = null}
|
||||||
afp = player
|
afp = player
|
||||||
WsReply(cmd.command,"success")
|
WsReply(cmd.command,"success")
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,9 @@
|
|||||||
package audio
|
package audio
|
||||||
|
|
||||||
|
import kotlinx.coroutines.CoroutineScope
|
||||||
|
import kotlinx.coroutines.Dispatchers
|
||||||
|
import kotlinx.coroutines.delay
|
||||||
|
import kotlinx.coroutines.launch
|
||||||
import java.util.function.Consumer
|
import java.util.function.Consumer
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -31,10 +35,10 @@ class AudioFilePlayer(deviceID: Int, val filename: String?, device_samplingrate:
|
|||||||
fun Play(finished: Consumer<Any> ) : Boolean{
|
fun Play(finished: Consumer<Any> ) : Boolean{
|
||||||
if (bass.BASS_ChannelPlay(filehandle, false)){
|
if (bass.BASS_ChannelPlay(filehandle, false)){
|
||||||
|
|
||||||
val thread = Thread{
|
CoroutineScope(Dispatchers.Default).launch {
|
||||||
isPlaying = true
|
isPlaying = true
|
||||||
while(true){
|
while(true){
|
||||||
Thread.sleep(1000)
|
delay(1000)
|
||||||
|
|
||||||
if (bass.BASS_ChannelIsActive(filehandle)!= Bass.BASS_ACTIVE_PLAYING){
|
if (bass.BASS_ChannelIsActive(filehandle)!= Bass.BASS_ACTIVE_PLAYING){
|
||||||
// finished playing
|
// finished playing
|
||||||
@@ -46,9 +50,25 @@ class AudioFilePlayer(deviceID: Int, val filename: String?, device_samplingrate:
|
|||||||
filehandle = 0
|
filehandle = 0
|
||||||
finished.accept(true)
|
finished.accept(true)
|
||||||
}
|
}
|
||||||
thread.name = "AudioFilePlayer $filename"
|
// Revisi 06/08/2025 Ganti thread dengan Coroutine
|
||||||
thread.isDaemon = true
|
// val thread = Thread{
|
||||||
thread.start()
|
// isPlaying = true
|
||||||
|
// while(true){
|
||||||
|
// Thread.sleep(1000)
|
||||||
|
//
|
||||||
|
// if (bass.BASS_ChannelIsActive(filehandle)!= Bass.BASS_ACTIVE_PLAYING){
|
||||||
|
// // finished playing
|
||||||
|
// break
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// isPlaying = false
|
||||||
|
// bass.BASS_StreamFree(filehandle)
|
||||||
|
// filehandle = 0
|
||||||
|
// finished.accept(true)
|
||||||
|
// }
|
||||||
|
// thread.name = "AudioFilePlayer $filename"
|
||||||
|
// thread.isDaemon = true
|
||||||
|
// thread.start()
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
return false
|
return false
|
||||||
|
|||||||
@@ -2,6 +2,10 @@ package zello
|
|||||||
|
|
||||||
import com.fasterxml.jackson.module.kotlin.contains
|
import com.fasterxml.jackson.module.kotlin.contains
|
||||||
import com.fasterxml.jackson.module.kotlin.jacksonObjectMapper
|
import com.fasterxml.jackson.module.kotlin.jacksonObjectMapper
|
||||||
|
import kotlinx.coroutines.CoroutineScope
|
||||||
|
import kotlinx.coroutines.Dispatchers
|
||||||
|
import kotlinx.coroutines.delay
|
||||||
|
import kotlinx.coroutines.launch
|
||||||
import org.java_websocket.client.WebSocketClient
|
import org.java_websocket.client.WebSocketClient
|
||||||
import org.java_websocket.handshake.ServerHandshake
|
import org.java_websocket.handshake.ServerHandshake
|
||||||
import org.slf4j.Logger
|
import org.slf4j.Logger
|
||||||
@@ -70,7 +74,7 @@ class ZelloClient(val address : URI, val username: String, val password: String)
|
|||||||
// audio stream
|
// audio stream
|
||||||
// format {type(8) = 0x01, stream_id(32), packet_id(32), data[]}
|
// format {type(8) = 0x01, stream_id(32), packet_id(32), data[]}
|
||||||
val str_id = bytes.getInt(1)
|
val str_id = bytes.getInt(1)
|
||||||
val packet_id = bytes.getInt(5)
|
//val packet_id = bytes.getInt(5)
|
||||||
val data = ByteArray(receivedbytes - 9)
|
val data = ByteArray(receivedbytes - 9)
|
||||||
bytes.get(9,data )
|
bytes.get(9,data )
|
||||||
val job = streamJob[str_id]
|
val job = streamJob[str_id]
|
||||||
@@ -113,13 +117,12 @@ class ZelloClient(val address : URI, val username: String, val password: String)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Suppress("UNCHECKED_CAST")
|
||||||
override fun onMessage(message: String?) {
|
override fun onMessage(message: String?) {
|
||||||
logger.info("Message received: $message")
|
logger.info("Message received: $message")
|
||||||
val jsnode = mapper.readTree(message)
|
val jsnode = mapper.readTree(message)
|
||||||
if (jsnode["seq"] != null) {
|
if (jsnode["seq"] != null) {
|
||||||
val seq = jsnode.get("seq").asInt()
|
when(val seq = jsnode.get("seq").asInt()){
|
||||||
when(seq){
|
|
||||||
1 ->{
|
1 ->{
|
||||||
//logon reply
|
//logon reply
|
||||||
val lgreply = mapper.treeToValue(jsnode, LogonReply::class.java)
|
val lgreply = mapper.treeToValue(jsnode, LogonReply::class.java)
|
||||||
@@ -168,7 +171,7 @@ class ZelloClient(val address : URI, val username: String, val password: String)
|
|||||||
"on_stream_start" ->{
|
"on_stream_start" ->{
|
||||||
val streamstart = mapper.treeToValue(jsnode, Event_OnStreamStart::class.java)
|
val streamstart = mapper.treeToValue(jsnode, Event_OnStreamStart::class.java)
|
||||||
logger.info("Stream started on channel ${streamstart.channel} from ${streamstart.from} for ${streamstart.For}")
|
logger.info("Stream started on channel ${streamstart.channel} from ${streamstart.from} for ${streamstart.For}")
|
||||||
streamJob.put(streamstart.stream_id, ZelloAudioJob.fromEventOnStreamStart(streamstart))
|
streamJob[streamstart.stream_id] = ZelloAudioJob.fromEventOnStreamStart(streamstart)
|
||||||
event.onStartStreaming(streamstart.from, streamstart.For, streamstart.channel)
|
event.onStartStreaming(streamstart.from, streamstart.For, streamstart.channel)
|
||||||
}
|
}
|
||||||
"on_stream_stop" -> {
|
"on_stream_stop" -> {
|
||||||
@@ -185,7 +188,7 @@ class ZelloClient(val address : URI, val username: String, val password: String)
|
|||||||
"on_image" ->{
|
"on_image" ->{
|
||||||
val image = mapper.treeToValue(jsnode, Event_OnImage::class.java)
|
val image = mapper.treeToValue(jsnode, Event_OnImage::class.java)
|
||||||
logger.info("Image received, image_id=${image.message_id}, from=${image.from}, For=${image.For}, channel=${image.channel}")
|
logger.info("Image received, image_id=${image.message_id}, from=${image.from}, For=${image.For}, channel=${image.channel}")
|
||||||
imageJob.put(image.message_id, ZelloImageJob(image.channel,image.message_id,image.height,image.width,image.source,image.from,image.For))
|
imageJob[image.message_id] = ZelloImageJob(image.channel,image.message_id,image.height,image.width,image.source,image.from,image.For)
|
||||||
}
|
}
|
||||||
"on_text_message" ->{
|
"on_text_message" ->{
|
||||||
val textmessage = mapper.treeToValue(jsnode, Event_OnTextMessage::class.java)
|
val textmessage = mapper.treeToValue(jsnode, Event_OnTextMessage::class.java)
|
||||||
@@ -208,17 +211,23 @@ class ZelloClient(val address : URI, val username: String, val password: String)
|
|||||||
logger.info("Closed from ${if (remote) "Remote side" else "Local side"}, Code=$code, Reason=$reason")
|
logger.info("Closed from ${if (remote) "Remote side" else "Local side"}, Code=$code, Reason=$reason")
|
||||||
event.onDisconnected()
|
event.onDisconnected()
|
||||||
// try reconnecting after 10 seconds
|
// try reconnecting after 10 seconds
|
||||||
val thread = Thread {
|
CoroutineScope(Dispatchers.Default).launch {
|
||||||
try {
|
delay(10000)
|
||||||
Thread.sleep(10000)
|
|
||||||
connect()
|
connect()
|
||||||
} catch (e: InterruptedException) {
|
|
||||||
logger.error("Reconnection interrupted: ${e.message}")
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
thread.name= "ZelloClient-ReconnectThread"
|
//Revisi 06/08/2025 : Change to Coroutines
|
||||||
thread.isDaemon = true
|
// val thread = Thread {
|
||||||
thread.start()
|
// try {
|
||||||
|
// Thread.sleep(10000)
|
||||||
|
// connect()
|
||||||
|
// } catch (e: InterruptedException) {
|
||||||
|
// logger.error("Reconnection interrupted: ${e.message}")
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// thread.name= "ZelloClient-ReconnectThread"
|
||||||
|
// thread.isDaemon = true
|
||||||
|
// thread.start()
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onError(ex: Exception?) {
|
override fun onError(ex: Exception?) {
|
||||||
@@ -254,7 +263,7 @@ class ZelloClient(val address : URI, val username: String, val password: String)
|
|||||||
For)
|
For)
|
||||||
client?.send(mapper.writeValueAsString(x))
|
client?.send(mapper.writeValueAsString(x))
|
||||||
// put here, because require a response in onMessage
|
// put here, because require a response in onMessage
|
||||||
commandJob.put(seqID, callback)
|
commandJob[seqID] = callback
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
Reference in New Issue
Block a user