diff --git a/src/Main.kt b/src/Main.kt
index cf2673f..02f618a 100644
--- a/src/Main.kt
+++ b/src/Main.kt
@@ -5,6 +5,7 @@ import zello.ZelloEvent
//TIP To Run code, press or
// click the icon in the gutter.
fun main() {
+
val z = ZelloClient.fromConsumerZello()
z.Start(object : ZelloEvent {
override fun onChannelStatus(
diff --git a/src/somecodes/Codes.kt b/src/somecodes/Codes.kt
index 2040bc2..715a027 100644
--- a/src/somecodes/Codes.kt
+++ b/src/somecodes/Codes.kt
@@ -1,10 +1,35 @@
package somecodes
+@Suppress("unused")
class Codes {
companion object{
fun ValidString(s : String?) : Boolean {
return s != null && s.isNotEmpty() && s.isNotBlank()
}
+
+ /**
+ * Codec header for Zello audio packet is base64 encoded string from {samplingrate (16 Little Endian), frames_per_packet, frame_size_ms}
+ * @param samplingrate Sampling rate in Hz (e.g., 8000, 16000, 32000, etc.)
+ * @param frames_per_packet Number of frames per packet (usually 1 or 2)
+ * @param frame_size_ms Size of each frame in milliseconds (e.g., 20, 30, 40, etc.)
+ */
+ fun toCodecHeader(samplingrate: Int, frames_per_packet: Byte, frame_size_ms: Byte) : String{
+ val xx = ByteArray(4)
+ xx[0] = (samplingrate and 0xFF).toByte() // Little Endian
+ xx[1] = ((samplingrate shr 8) and 0xFF).toByte()
+ xx[2] = frames_per_packet
+ xx[3] = frame_size_ms
+ return java.util.Base64.getEncoder().encodeToString(xx)
+ }
+
+ fun fromCodecHeader(header: String) : Triple? {
+ val decoded = java.util.Base64.getDecoder().decode(header)
+ if (decoded.size != 4) return null
+ val samplingrate = (decoded[0].toInt() and 0xFF) or ((decoded[1].toInt() and 0xFF) shl 8)
+ val frames_per_packet = decoded[2]
+ val frame_size_ms = decoded[3]
+ return Triple(samplingrate, frames_per_packet, frame_size_ms)
+ }
}
}
\ No newline at end of file
diff --git a/src/zello/Event_OnStreamStart.kt b/src/zello/Event_OnStreamStart.kt
index 6455729..39c9a1f 100644
--- a/src/zello/Event_OnStreamStart.kt
+++ b/src/zello/Event_OnStreamStart.kt
@@ -1,6 +1,8 @@
package zello
import com.fasterxml.jackson.annotation.JsonPropertyOrder
+import somecodes.Codes.Companion.ValidString
+import somecodes.Codes.Companion.fromCodecHeader
@Suppress("unused")
@JsonPropertyOrder(value = ["command", "type", "codec", "codec_header", "packet_duration", "stream_id", "channel", "from", "for"])
@@ -14,4 +16,46 @@ class Event_OnStreamStart {
var channel: String=""
var from: String = "" // the user who started the stream
var For: String = "" // the user who is receiving the stream, should be "for" not "For"
+
+ /**
+ * Get Sampling Rate from codec_header.
+ * @return sampling rate in Hz, or 0 if codec_header is not valid.
+ */
+ fun getSamplingRate() : Int{
+ if (ValidString(codec_header)){
+ val triple = fromCodecHeader(codec_header)
+ if (triple!=null){
+ return triple.first
+ }
+ }
+ return 0
+ }
+
+ /**
+ * Get number of frames per packet, either 1 or 2
+ * @return number of frames per packet, or 0 if codec_header is not valid.
+ */
+ fun getFramesPerSecond() : Byte{
+ if (ValidString(codec_header)){
+ val triple = fromCodecHeader(codec_header)
+ if (triple!=null){
+ return triple.second
+ }
+ }
+ return 0
+ }
+
+ /**
+ * Get audio frame size in miliseconds
+ * @return audio frame size in milliseconds, or 0 if codec_header is not valid.
+ */
+ fun getFrameSizePerMs() : Byte{
+ if (ValidString(codec_header)){
+ val triple = fromCodecHeader(codec_header)
+ if (triple!=null){
+ return triple.third
+ }
+ }
+ return 0
+ }
}
\ No newline at end of file