diff --git a/.gitignore b/.gitignore
index 3ddbf4c..882b89c 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,5 +1,6 @@
### IntelliJ IDEA ###
out/
+audiofile/
!**/src/main/**/out/
!**/src/test/**/out/
diff --git a/EWS_POC.iml b/EWS_POC.iml
index 0896530..1fbf6a0 100644
--- a/EWS_POC.iml
+++ b/EWS_POC.iml
@@ -9,6 +9,7 @@
+
diff --git a/html/assets/js/pocreceiver.js b/html/assets/js/pocreceiver.js
index d1915e5..ec4ceb2 100644
--- a/html/assets/js/pocreceiver.js
+++ b/html/assets/js/pocreceiver.js
@@ -1,20 +1,20 @@
$(document).ready(function() {
// Your code here
- console.log('pocreceiver.js is ready!');
+ //console.log('pocreceiver.js is ready!');
const path = window.location.pathname;
const ws = new WebSocket('ws://' + window.location.host + path + '/ws');
ws.onopen = function() {
- console.log('WebSocket connection opened');
+ //console.log('WebSocket connection opened');
$('#indicatorDisconnected').addClass('visually-hidden');
$('#indicatorConnected').removeClass('visually-hidden');
setInterval(function() {
sendCommand({ command: "getZelloStatus" });
- }, 5000);
+ }, 1000);
};
ws.onmessage = function(event) {
- console.log('WebSocket message received:', event.data);
+ //console.log('WebSocket message received:', event.data);
let msg = {};
try {
msg = JSON.parse(event.data);
@@ -25,13 +25,13 @@ $(document).ready(function() {
}
if (msg.reply === "getZelloStatus" && msg.data !== undefined && msg.data.length > 0) {
const zelloData = msg.data;
- console.log('Zello Status Data:', zelloData);
- $('#zelloStatus').text(zelloData.status);
+ //console.log('Zello Status Data:', zelloData);
+ $('#zelloStatus').text(zelloData);
}
};
ws.onclose = function() {
- console.log('WebSocket connection closed');
+ //console.log('WebSocket connection closed');
$('#indicatorDisconnected').removeClass('visually-hidden');
$('#indicatorConnected').addClass('visually-hidden');
};
diff --git a/html/pocreceiver.html b/html/pocreceiver.html
index c063d53..7d65085 100644
--- a/html/pocreceiver.html
+++ b/html/pocreceiver.html
@@ -35,7 +35,7 @@
Zello Status
diff --git a/src/Main.kt b/src/Main.kt
index 0b29c27..ebcc15e 100644
--- a/src/Main.kt
+++ b/src/Main.kt
@@ -10,12 +10,14 @@ import web.webApp
import zello.ZelloClient
import zello.ZelloEvent
import javafx.util.Pair
+import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.Dispatchers
+import kotlinx.coroutines.delay
+import kotlinx.coroutines.launch
import org.slf4j.LoggerFactory
import somecodes.Codes
import web.WsCommand
import java.util.function.BiFunction
-import kotlin.io.path.isRegularFile
-import kotlin.io.path.pathString
//TIP To Run code, press or
// click the icon in the gutter.
@@ -25,23 +27,140 @@ fun main() {
val cfg = configFile()
cfg.Load()
- val au = AudioUtility()
var audioID = 0
val preferedAudioDevice = "Speakers"
- au.DetectPlaybackDevices().forEach { pair ->
- println("Device ID: ${pair.first}, Name: ${pair.second}")
+
+ AudioUtility.DetectPlaybackDevices().forEach { pair ->
+ logger.info("Device ID: ${pair.first}, Name: ${pair.second}")
if (pair.second.contains(preferedAudioDevice)) {
audioID = pair.first
}
}
if (audioID!=0){
- val initsuccess = au.InitDevice(audioID,44100)
- println("Audio Device $audioID initialized: $initsuccess")
+ val initsuccess = AudioUtility.InitDevice(audioID,44100)
+ logger.info("Audio Device $audioID initialized: $initsuccess")
}
+ // for Zello Client
val o = OpusStreamReceiver(audioID)
+ // for AudioFilePlayer
var afp: AudioFilePlayer? = null
+ /**
+ * Creates a ZelloClient instance based on the configuration.
+ */
+ fun CreateZelloFromConfig(): ZelloClient {
+ return when (cfg.ZelloServer) {
+ "work" -> {
+ ZelloClient.fromZelloWork(
+ cfg.ZelloUsername ?: "",
+ cfg.ZelloPassword ?: "",
+ cfg.ZelloChannel ?: "",
+ cfg.ZelloWorkNetworkName ?: ""
+ )
+ }
+ "enterprise" -> {
+ ZelloClient.fromZelloEnterpriseServer(
+ cfg.ZelloUsername ?: "",
+ cfg.ZelloPassword ?: "",
+ cfg.ZelloChannel ?: "",
+ cfg.ZelloEnterpriseServerDomain ?: ""
+ )
+ }
+ else -> {
+ ZelloClient.fromConsumerZello(cfg.ZelloUsername ?: "", cfg.ZelloPassword ?: "", cfg.ZelloChannel ?: "")
+ }
+ }
+ }
+
+ // Create Zello client from configuration and start it
+ var z = CreateZelloFromConfig()
+
+ // Create ZelloEvent implementation to handle events
+ val z_event = object : ZelloEvent{
+ override fun onChannelStatus(
+ channel: String,
+ status: String,
+ userOnline: Int,
+ error: String?,
+ errorType: String?
+ ) {
+ logger.info("Channel Status: $channel is $status with $userOnline users online.")
+ if (ValidString(error) && ValidString(errorType)) {
+ logger.info("Error: $error, Type: $errorType")
+ }
+ }
+
+ override fun onAudioData(streamID: Int, from: String, For: String, channel: String, data: ByteArray) {
+ logger.info("Audio Data received from $from for $For on channel $channel with streamID $streamID ")
+ }
+
+ override fun onThumbnailImage(imageID: Int, from: String, For: String, channel: String, data: ByteArray, timestamp: Long) {
+ logger.info("Thumbnail Image received from $from for $For on channel $channel with imageID $imageID at timestamp $timestamp")
+ }
+
+ override fun onFullImage(imageID: Int, from: String, For: String, channel: String, data: ByteArray, timestamp: Long) {
+ logger.info("Full Image received from $from for $For on channel $channel with imageID $imageID at timestamp $timestamp")
+ }
+
+ override fun onTextMessage(messageID: Int, from: String, For: String, channel: String, text: String, timestamp: Long) {
+ logger.info("Text Message received from $from for $For on channel $channel with messageID $messageID at timestamp $timestamp. Text: $text")
+ }
+
+ override fun onLocation(messageID: Int, from: String, For: String, channel: String, latitude: Double, longitude: Double, address: String, accuracy: Double, timestamp: Long) {
+ logger.info("Location received from $from for $For on channel $channel with messageID $messageID at timestamp $timestamp. Location($latitude,$longitude), Address:$address, Accuracy:$accuracy")
+ }
+
+ override fun onConnected() {
+ logger.info("Connected to Zello server.")
+ }
+
+ override fun onDisconnected(reason: String) {
+ logger.info("Disconnected from Zello Server, reason: $reason")
+ logger.info("Reconnecting after 10 seconds...")
+ z.Stop()
+ val e = this
+ CoroutineScope(Dispatchers.Default).launch {
+
+ delay(10000) // Wait for 10 seconds before trying to reconnect
+ z = CreateZelloFromConfig()
+ z.Start(e)
+ }
+ }
+
+ override fun onError(errorMessage: String) {
+ logger.info("Error occurred in Zello client: $errorMessage")
+ }
+
+ override fun onStartStreaming(from: String, For: String, channel: String) {
+ // stop any previous playback
+ afp?.Stop()
+ afp = null
+
+ if (o.Start()){
+ logger.info("Opus Receiver ready for streaming from $from for $For on channel $channel")
+ } else {
+ logger.info("Failed to start Opus Receiver for streaming from $from for $For on channel $channel")
+ }
+ }
+
+ override fun onStopStreaming(from: String, For: String, channel: String) {
+ o.Stop()
+ logger.info("Opus Receiver stopped streaming from $from for $For on channel $channel")
+ }
+
+ override fun onStreamingData(
+ from: String,
+ For: String,
+ channel: String,
+ data: ByteArray
+ ) {
+ if (o.isPlaying) o.PushData(data)
+ }
+ }
+ z.Start(z_event)
+
+ // Start the web application with WebSocket support
val w = webApp("0.0.0.0",3030, BiFunction {
source: String, cmd: WsCommand ->
when (source) {
@@ -70,14 +189,39 @@ fun main() {
"setZelloConfig" -> {
try{
val xx = objectMapper.readValue(cmd.data, object: TypeReference