feat: new protocol client implementation

This commit is contained in:
Ahmet Kaan Gümüş 2025-06-14 06:04:48 +03:00
parent 51c29f7921
commit 5ad6184f13
9 changed files with 497 additions and 267 deletions

360
Cargo.lock generated
View file

@ -97,7 +97,7 @@ dependencies = [
"jni-sys", "jni-sys",
"libc", "libc",
"log", "log",
"ndk 0.9.0", "ndk",
"ndk-context", "ndk-context",
"ndk-sys 0.6.0+11769913", "ndk-sys 0.6.0+11769913",
"num_enum", "num_enum",
@ -406,7 +406,7 @@ version = "0.29.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "61b1d86e7705efe1be1b569bab41d4fa1e14e220b60a160f78de2db687add079" checksum = "61b1d86e7705efe1be1b569bab41d4fa1e14e220b60a160f78de2db687add079"
dependencies = [ dependencies = [
"bindgen 0.69.5", "bindgen",
"cc", "cc",
"cmake", "cmake",
"dunce", "dunce",
@ -457,7 +457,7 @@ dependencies = [
"bitflags 2.9.0", "bitflags 2.9.0",
"cexpr", "cexpr",
"clang-sys", "clang-sys",
"itertools 0.12.1", "itertools",
"lazy_static", "lazy_static",
"lazycell", "lazycell",
"log", "log",
@ -471,24 +471,6 @@ dependencies = [
"which", "which",
] ]
[[package]]
name = "bindgen"
version = "0.70.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f49d8fed880d473ea71efb9bf597651e77201bdd4893efe54c9e5d65ae04ce6f"
dependencies = [
"bitflags 2.9.0",
"cexpr",
"clang-sys",
"itertools 0.13.0",
"proc-macro2",
"quote",
"regex",
"rustc-hash 1.1.0",
"shlex",
"syn",
]
[[package]] [[package]]
name = "bit-set" name = "bit-set"
version = "0.8.0" version = "0.8.0"
@ -531,7 +513,7 @@ version = "0.5.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2c132eebf10f5cad5289222520a4a058514204aed6d791f1cf4fe8088b82d15f" checksum = "2c132eebf10f5cad5289222520a4a058514204aed6d791f1cf4fe8088b82d15f"
dependencies = [ dependencies = [
"objc2", "objc2 0.5.2",
] ]
[[package]] [[package]]
@ -675,6 +657,12 @@ dependencies = [
"libloading", "libloading",
] ]
[[package]]
name = "claxon"
version = "0.4.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4bfbf56724aa9eca8afa4fcfadeb479e722935bb2a0900c2d37e0cc477af0688"
[[package]] [[package]]
name = "client" name = "client"
version = "0.1.0" version = "0.1.0"
@ -684,6 +672,7 @@ dependencies = [
"fixed-resample", "fixed-resample",
"iced", "iced",
"protocol", "protocol",
"rodio",
"s2n-quic", "s2n-quic",
"tokio", "tokio",
] ]
@ -703,9 +692,9 @@ version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9b7f4aaa047ba3c3630b080bb9860894732ff23e2aee290a418909aa6d5df38f" checksum = "9b7f4aaa047ba3c3630b080bb9860894732ff23e2aee290a418909aa6d5df38f"
dependencies = [ dependencies = [
"objc2", "objc2 0.5.2",
"objc2-app-kit", "objc2-app-kit",
"objc2-foundation", "objc2-foundation 0.2.2",
] ]
[[package]] [[package]]
@ -841,22 +830,16 @@ dependencies = [
[[package]] [[package]]
name = "coreaudio-rs" name = "coreaudio-rs"
version = "0.11.3" version = "0.13.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "321077172d79c662f64f5071a03120748d5bb652f5231570141be24cfcd2bace" checksum = "1aae284fbaf7d27aa0e292f7677dfbe26503b0d555026f702940805a630eac17"
dependencies = [ dependencies = [
"bitflags 1.3.2", "bitflags 1.3.2",
"core-foundation-sys", "libc",
"coreaudio-sys", "objc2-audio-toolbox",
] "objc2-core-audio",
"objc2-core-audio-types",
[[package]] "objc2-core-foundation",
name = "coreaudio-sys"
version = "0.2.16"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2ce857aa0b77d77287acc1ac3e37a05a8c95a2af3647d23b15f263bdaeb7562b"
dependencies = [
"bindgen 0.70.1",
] ]
[[package]] [[package]]
@ -884,21 +867,24 @@ dependencies = [
[[package]] [[package]]
name = "cpal" name = "cpal"
version = "0.15.3" version = "0.16.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "873dab07c8f743075e57f524c583985fbaf745602acbe916a01539364369a779" checksum = "cbd307f43cc2a697e2d1f8bc7a1d824b5269e052209e28883e5bc04d095aaa3f"
dependencies = [ dependencies = [
"alsa", "alsa",
"core-foundation-sys",
"coreaudio-rs", "coreaudio-rs",
"dasp_sample", "dasp_sample",
"jni", "jni",
"js-sys", "js-sys",
"libc", "libc",
"mach2", "mach2",
"ndk 0.8.0", "ndk",
"ndk-context", "ndk-context",
"oboe", "num-derive",
"num-traits",
"objc2-audio-toolbox",
"objc2-core-audio",
"objc2-core-audio-types",
"wasm-bindgen", "wasm-bindgen",
"wasm-bindgen-futures", "wasm-bindgen-futures",
"web-sys", "web-sys",
@ -969,8 +955,8 @@ checksum = "18e1a09f280e29a8b00bc7e81eca5ac87dca0575639c9422a5fa25a07bb884b8"
dependencies = [ dependencies = [
"ashpd", "ashpd",
"async-std", "async-std",
"objc2", "objc2 0.5.2",
"objc2-foundation", "objc2-foundation 0.2.2",
"web-sys", "web-sys",
"winreg", "winreg",
] ]
@ -987,6 +973,16 @@ version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bd0c93bb4b0c6d9b77f4435b0ae98c24d17f1c45b2ff844c6151a07256ca923b" checksum = "bd0c93bb4b0c6d9b77f4435b0ae98c24d17f1c45b2ff844c6151a07256ca923b"
[[package]]
name = "dispatch2"
version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "89a09f22a6c6069a18470eb92d2298acf25463f14256d24778e1230d789a2aec"
dependencies = [
"bitflags 2.9.0",
"objc2 0.6.1",
]
[[package]] [[package]]
name = "displaydoc" name = "displaydoc"
version = "0.2.5" version = "0.2.5"
@ -1078,6 +1074,15 @@ version = "1.15.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "48c757948c5ede0e46177b7add2e67155f70e33c07fea8284df6576da70b3719" checksum = "48c757948c5ede0e46177b7add2e67155f70e33c07fea8284df6576da70b3719"
[[package]]
name = "encoding_rs"
version = "0.8.35"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "75030f3c4f45dafd7586dd6780965a8c7e8e285a5ecb86713e63a79c5b2766f3"
dependencies = [
"cfg-if",
]
[[package]] [[package]]
name = "endi" name = "endi"
version = "1.1.0" version = "1.1.0"
@ -1644,6 +1649,12 @@ dependencies = [
"windows-sys 0.59.0", "windows-sys 0.59.0",
] ]
[[package]]
name = "hound"
version = "3.5.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "62adaabb884c94955b19907d60019f4e145d091c75345379e70d1ee696f7854f"
[[package]] [[package]]
name = "iana-time-zone" name = "iana-time-zone"
version = "0.1.63" version = "0.1.63"
@ -1978,15 +1989,6 @@ dependencies = [
"either", "either",
] ]
[[package]]
name = "itertools"
version = "0.13.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "413ee7dfc52ee1a4949ceeb7dbc8a33f2d6c088194d9f922fb8318faf1f01186"
dependencies = [
"either",
]
[[package]] [[package]]
name = "jni" name = "jni"
version = "0.21.1" version = "0.21.1"
@ -2077,6 +2079,17 @@ version = "1.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "830d08ce1d1d941e6b30645f1a0eb5643013d835ce3779a5fc208261dbe10f55" checksum = "830d08ce1d1d941e6b30645f1a0eb5643013d835ce3779a5fc208261dbe10f55"
[[package]]
name = "lewton"
version = "0.10.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "777b48df9aaab155475a83a7df3070395ea1ac6902f5cd062b8f2b028075c030"
dependencies = [
"byteorder",
"ogg",
"tinyvec",
]
[[package]] [[package]]
name = "libc" name = "libc"
version = "0.2.172" version = "0.2.172"
@ -2280,20 +2293,6 @@ dependencies = [
"unicode-xid", "unicode-xid",
] ]
[[package]]
name = "ndk"
version = "0.8.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2076a31b7010b17a38c01907c45b945e8f11495ee4dd588309718901b1f7a5b7"
dependencies = [
"bitflags 2.9.0",
"jni-sys",
"log",
"ndk-sys 0.5.0+25.2.9519653",
"num_enum",
"thiserror 1.0.69",
]
[[package]] [[package]]
name = "ndk" name = "ndk"
version = "0.9.0" version = "0.9.0"
@ -2356,6 +2355,16 @@ dependencies = [
"minimal-lexical", "minimal-lexical",
] ]
[[package]]
name = "num-bigint"
version = "0.4.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a5e44f723f1133c9deac646763579fdb3ac745e418f2a7af9cd0c431da1f20b9"
dependencies = [
"num-integer",
"num-traits",
]
[[package]] [[package]]
name = "num-complex" name = "num-complex"
version = "0.4.6" version = "0.4.6"
@ -2391,6 +2400,7 @@ version = "0.4.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f83d14da390562dca69fc84082e73e548e1ad308d24accdedd2720017cb37824" checksum = "f83d14da390562dca69fc84082e73e548e1ad308d24accdedd2720017cb37824"
dependencies = [ dependencies = [
"num-bigint",
"num-integer", "num-integer",
"num-traits", "num-traits",
] ]
@ -2461,6 +2471,15 @@ dependencies = [
"objc2-encode", "objc2-encode",
] ]
[[package]]
name = "objc2"
version = "0.6.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "88c6597e14493ab2e44ce58f2fdecf095a51f12ca57bec060a11c57332520551"
dependencies = [
"objc2-encode",
]
[[package]] [[package]]
name = "objc2-app-kit" name = "objc2-app-kit"
version = "0.2.2" version = "0.2.2"
@ -2470,13 +2489,28 @@ dependencies = [
"bitflags 2.9.0", "bitflags 2.9.0",
"block2", "block2",
"libc", "libc",
"objc2", "objc2 0.5.2",
"objc2-core-data", "objc2-core-data",
"objc2-core-image", "objc2-core-image",
"objc2-foundation", "objc2-foundation 0.2.2",
"objc2-quartz-core", "objc2-quartz-core",
] ]
[[package]]
name = "objc2-audio-toolbox"
version = "0.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "10cbe18d879e20a4aea544f8befe38bcf52255eb63d3f23eca2842f3319e4c07"
dependencies = [
"bitflags 2.9.0",
"libc",
"objc2 0.6.1",
"objc2-core-audio",
"objc2-core-audio-types",
"objc2-core-foundation",
"objc2-foundation 0.3.1",
]
[[package]] [[package]]
name = "objc2-cloud-kit" name = "objc2-cloud-kit"
version = "0.2.2" version = "0.2.2"
@ -2485,9 +2519,9 @@ checksum = "74dd3b56391c7a0596a295029734d3c1c5e7e510a4cb30245f8221ccea96b009"
dependencies = [ dependencies = [
"bitflags 2.9.0", "bitflags 2.9.0",
"block2", "block2",
"objc2", "objc2 0.5.2",
"objc2-core-location", "objc2-core-location",
"objc2-foundation", "objc2-foundation 0.2.2",
] ]
[[package]] [[package]]
@ -2497,8 +2531,30 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a5ff520e9c33812fd374d8deecef01d4a840e7b41862d849513de77e44aa4889" checksum = "a5ff520e9c33812fd374d8deecef01d4a840e7b41862d849513de77e44aa4889"
dependencies = [ dependencies = [
"block2", "block2",
"objc2", "objc2 0.5.2",
"objc2-foundation", "objc2-foundation 0.2.2",
]
[[package]]
name = "objc2-core-audio"
version = "0.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ca44961e888e19313b808f23497073e3f6b3c22bb485056674c8b49f3b025c82"
dependencies = [
"dispatch2",
"objc2 0.6.1",
"objc2-core-audio-types",
"objc2-core-foundation",
]
[[package]]
name = "objc2-core-audio-types"
version = "0.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c0f1cc99bb07ad2ddb6527ddf83db6a15271bb036b3eb94b801cd44fdc666ee1"
dependencies = [
"bitflags 2.9.0",
"objc2 0.6.1",
] ]
[[package]] [[package]]
@ -2509,8 +2565,19 @@ checksum = "617fbf49e071c178c0b24c080767db52958f716d9eabdf0890523aeae54773ef"
dependencies = [ dependencies = [
"bitflags 2.9.0", "bitflags 2.9.0",
"block2", "block2",
"objc2", "objc2 0.5.2",
"objc2-foundation", "objc2-foundation 0.2.2",
]
[[package]]
name = "objc2-core-foundation"
version = "0.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1c10c2894a6fed806ade6027bcd50662746363a9589d3ec9d9bef30a4e4bc166"
dependencies = [
"bitflags 2.9.0",
"dispatch2",
"objc2 0.6.1",
] ]
[[package]] [[package]]
@ -2520,8 +2587,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "55260963a527c99f1819c4f8e3b47fe04f9650694ef348ffd2227e8196d34c80" checksum = "55260963a527c99f1819c4f8e3b47fe04f9650694ef348ffd2227e8196d34c80"
dependencies = [ dependencies = [
"block2", "block2",
"objc2", "objc2 0.5.2",
"objc2-foundation", "objc2-foundation 0.2.2",
"objc2-metal", "objc2-metal",
] ]
@ -2532,9 +2599,9 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "000cfee34e683244f284252ee206a27953279d370e309649dc3ee317b37e5781" checksum = "000cfee34e683244f284252ee206a27953279d370e309649dc3ee317b37e5781"
dependencies = [ dependencies = [
"block2", "block2",
"objc2", "objc2 0.5.2",
"objc2-contacts", "objc2-contacts",
"objc2-foundation", "objc2-foundation 0.2.2",
] ]
[[package]] [[package]]
@ -2553,7 +2620,16 @@ dependencies = [
"block2", "block2",
"dispatch", "dispatch",
"libc", "libc",
"objc2", "objc2 0.5.2",
]
[[package]]
name = "objc2-foundation"
version = "0.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "900831247d2fe1a09a683278e5384cfb8c80c79fe6b166f9d14bfdde0ea1b03c"
dependencies = [
"objc2 0.6.1",
] ]
[[package]] [[package]]
@ -2563,9 +2639,9 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a1a1ae721c5e35be65f01a03b6d2ac13a54cb4fa70d8a5da293d7b0020261398" checksum = "a1a1ae721c5e35be65f01a03b6d2ac13a54cb4fa70d8a5da293d7b0020261398"
dependencies = [ dependencies = [
"block2", "block2",
"objc2", "objc2 0.5.2",
"objc2-app-kit", "objc2-app-kit",
"objc2-foundation", "objc2-foundation 0.2.2",
] ]
[[package]] [[package]]
@ -2576,8 +2652,8 @@ checksum = "dd0cba1276f6023976a406a14ffa85e1fdd19df6b0f737b063b95f6c8c7aadd6"
dependencies = [ dependencies = [
"bitflags 2.9.0", "bitflags 2.9.0",
"block2", "block2",
"objc2", "objc2 0.5.2",
"objc2-foundation", "objc2-foundation 0.2.2",
] ]
[[package]] [[package]]
@ -2588,8 +2664,8 @@ checksum = "e42bee7bff906b14b167da2bac5efe6b6a07e6f7c0a21a7308d40c960242dc7a"
dependencies = [ dependencies = [
"bitflags 2.9.0", "bitflags 2.9.0",
"block2", "block2",
"objc2", "objc2 0.5.2",
"objc2-foundation", "objc2-foundation 0.2.2",
"objc2-metal", "objc2-metal",
] ]
@ -2599,8 +2675,8 @@ version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0a684efe3dec1b305badae1a28f6555f6ddd3bb2c2267896782858d5a78404dc" checksum = "0a684efe3dec1b305badae1a28f6555f6ddd3bb2c2267896782858d5a78404dc"
dependencies = [ dependencies = [
"objc2", "objc2 0.5.2",
"objc2-foundation", "objc2-foundation 0.2.2",
] ]
[[package]] [[package]]
@ -2611,12 +2687,12 @@ checksum = "b8bb46798b20cd6b91cbd113524c490f1686f4c4e8f49502431415f3512e2b6f"
dependencies = [ dependencies = [
"bitflags 2.9.0", "bitflags 2.9.0",
"block2", "block2",
"objc2", "objc2 0.5.2",
"objc2-cloud-kit", "objc2-cloud-kit",
"objc2-core-data", "objc2-core-data",
"objc2-core-image", "objc2-core-image",
"objc2-core-location", "objc2-core-location",
"objc2-foundation", "objc2-foundation 0.2.2",
"objc2-link-presentation", "objc2-link-presentation",
"objc2-quartz-core", "objc2-quartz-core",
"objc2-symbols", "objc2-symbols",
@ -2631,8 +2707,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "44fa5f9748dbfe1ca6c0b79ad20725a11eca7c2218bceb4b005cb1be26273bfe" checksum = "44fa5f9748dbfe1ca6c0b79ad20725a11eca7c2218bceb4b005cb1be26273bfe"
dependencies = [ dependencies = [
"block2", "block2",
"objc2", "objc2 0.5.2",
"objc2-foundation", "objc2-foundation 0.2.2",
] ]
[[package]] [[package]]
@ -2643,9 +2719,9 @@ checksum = "76cfcbf642358e8689af64cee815d139339f3ed8ad05103ed5eaf73db8d84cb3"
dependencies = [ dependencies = [
"bitflags 2.9.0", "bitflags 2.9.0",
"block2", "block2",
"objc2", "objc2 0.5.2",
"objc2-core-location", "objc2-core-location",
"objc2-foundation", "objc2-foundation 0.2.2",
] ]
[[package]] [[package]]
@ -2658,26 +2734,12 @@ dependencies = [
] ]
[[package]] [[package]]
name = "oboe" name = "ogg"
version = "0.6.1" version = "0.8.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e8b61bebd49e5d43f5f8cc7ee2891c16e0f41ec7954d36bcb6c14c5e0de867fb" checksum = "6951b4e8bf21c8193da321bcce9c9dd2e13c858fe078bf9054a288b419ae5d6e"
dependencies = [ dependencies = [
"jni", "byteorder",
"ndk 0.8.0",
"ndk-context",
"num-derive",
"num-traits",
"oboe-sys",
]
[[package]]
name = "oboe-sys"
version = "0.6.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6c8bb09a4a2b1d668170cfe0a7d5bc103f8999fb316c98099b6a9939c9f2e79d"
dependencies = [
"cc",
] ]
[[package]] [[package]]
@ -2929,6 +2991,7 @@ version = "0.1.0"
dependencies = [ dependencies = [
"bincode", "bincode",
"chrono", "chrono",
"tokio",
] ]
[[package]] [[package]]
@ -3170,6 +3233,20 @@ dependencies = [
"portable-atomic-util", "portable-atomic-util",
] ]
[[package]]
name = "rodio"
version = "0.20.1"
source = "git+https://github.com/RustAudio/rodio?rev=071db6df2adfccfe1032be43dd87e5681e34292c#071db6df2adfccfe1032be43dd87e5681e34292c"
dependencies = [
"claxon",
"cpal",
"dasp_sample",
"hound",
"lewton",
"num-rational",
"symphonia",
]
[[package]] [[package]]
name = "roxmltree" name = "roxmltree"
version = "0.20.0" version = "0.20.0"
@ -3694,8 +3771,8 @@ dependencies = [
"js-sys", "js-sys",
"log", "log",
"memmap2", "memmap2",
"objc2", "objc2 0.5.2",
"objc2-foundation", "objc2-foundation 0.2.2",
"objc2-quartz-core", "objc2-quartz-core",
"raw-window-handle", "raw-window-handle",
"redox_syscall 0.5.12", "redox_syscall 0.5.12",
@ -3788,6 +3865,55 @@ dependencies = [
"zeno", "zeno",
] ]
[[package]]
name = "symphonia"
version = "0.5.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "815c942ae7ee74737bb00f965fa5b5a2ac2ce7b6c01c0cc169bbeaf7abd5f5a9"
dependencies = [
"lazy_static",
"symphonia-bundle-mp3",
"symphonia-core",
"symphonia-metadata",
]
[[package]]
name = "symphonia-bundle-mp3"
version = "0.5.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c01c2aae70f0f1fb096b6f0ff112a930b1fb3626178fba3ae68b09dce71706d4"
dependencies = [
"lazy_static",
"log",
"symphonia-core",
"symphonia-metadata",
]
[[package]]
name = "symphonia-core"
version = "0.5.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "798306779e3dc7d5231bd5691f5a813496dc79d3f56bf82e25789f2094e022c3"
dependencies = [
"arrayvec",
"bitflags 1.3.2",
"bytemuck",
"lazy_static",
"log",
]
[[package]]
name = "symphonia-metadata"
version = "0.5.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bc622b9841a10089c5b18e99eb904f4341615d5aa55bbf4eedde1be721a4023c"
dependencies = [
"encoding_rs",
"lazy_static",
"log",
"symphonia-core",
]
[[package]] [[package]]
name = "syn" name = "syn"
version = "2.0.101" version = "2.0.101"
@ -5037,10 +5163,10 @@ dependencies = [
"js-sys", "js-sys",
"libc", "libc",
"memmap2", "memmap2",
"ndk 0.9.0", "ndk",
"objc2", "objc2 0.5.2",
"objc2-app-kit", "objc2-app-kit",
"objc2-foundation", "objc2-foundation 0.2.2",
"objc2-ui-kit", "objc2-ui-kit",
"orbclient", "orbclient",
"percent-encoding", "percent-encoding",

View file

@ -8,6 +8,7 @@ protocol = { path = "../protocol" }
chrono = { workspace = true } chrono = { workspace = true }
tokio = { workspace = true } tokio = { workspace = true }
s2n-quic = { workspace = true } s2n-quic = { workspace = true }
cpal = "0.15.3" cpal = "0.16.0"
iced = { features = ["tokio"], git = "https://github.com/iced-rs/iced", rev = "d39022432c778a8cda455f40b9c12245db86ce45" } iced = { features = ["tokio"], git = "https://github.com/iced-rs/iced", rev = "d39022432c778a8cda455f40b9c12245db86ce45" }
fixed-resample = "0.8.0" fixed-resample = "0.8.0"
rodio = {git = "https://github.com/RustAudio/rodio", rev = "071db6df2adfccfe1032be43dd87e5681e34292c"}

View file

@ -18,13 +18,13 @@ use crate::{
}; };
#[derive(Debug)] #[derive(Debug)]
struct Signal { struct Controller {
record_control: mpsc::Sender<State>, record_control: mpsc::Sender<State>,
play_control: mpsc::Sender<State>, play_control: mpsc::Sender<State>,
connection_stop_sender: RwLock<Option<oneshot::Sender<bool>>>, connection_stop_sender: RwLock<Option<oneshot::Sender<bool>>>,
} }
impl Signal { impl Controller {
fn reset_connection(&self) -> Result<(), Error> { fn reset_connection(&self) -> Result<(), Error> {
let connection_stop_sender = self.connection_stop_sender.write().unwrap().take(); let connection_stop_sender = self.connection_stop_sender.write().unwrap().take();
match connection_stop_sender { match connection_stop_sender {
@ -43,7 +43,7 @@ impl Signal {
#[derive(Debug)] #[derive(Debug)]
struct Channel { struct Channel {
microphone: Arc<broadcast::Sender<f32>>, microphone: Arc<broadcast::Sender<f32>>,
speaker: Arc<broadcast::Sender<f32>>, speaker: Arc<broadcast::Sender<protocol::protocol::Signal>>,
} }
#[derive(Debug, Clone, Copy)] #[derive(Debug, Clone, Copy)]
@ -90,12 +90,12 @@ pub struct App {
client_config: Arc<ClientConfig>, client_config: Arc<ClientConfig>,
gui_status: Arc<RwLock<GUIStatus>>, gui_status: Arc<RwLock<GUIStatus>>,
channel: Channel, channel: Channel,
signal: Arc<Signal>, controller: Arc<Controller>,
} }
impl App { impl App {
fn reset_connection(&mut self) -> Result<(), Error> { fn reset_connection(&mut self) -> Result<(), Error> {
self.signal.reset_connection()?; self.controller.reset_connection()?;
self.gui_status.write().unwrap().room = State::Passive; self.gui_status.write().unwrap().room = State::Passive;
Ok(()) Ok(())
} }
@ -122,7 +122,7 @@ impl App {
microphone: record_sender, microphone: record_sender,
speaker: play_sender, speaker: play_sender,
}, },
signal: Signal { controller: Controller {
record_control: record_control.0, record_control: record_control.0,
play_control: play_control.0, play_control: play_control.0,
connection_stop_sender: None.into(), connection_stop_sender: None.into(),
@ -168,7 +168,7 @@ impl App {
let speaker_sender = self.channel.speaker.clone(); let speaker_sender = self.channel.speaker.clone();
let (connection_stop_sender, connection_stop_receiver) = oneshot::channel(); let (connection_stop_sender, connection_stop_receiver) = oneshot::channel();
*self.signal.connection_stop_sender.write().unwrap() = Some(connection_stop_sender); *self.controller.connection_stop_sender.write().unwrap() = Some(connection_stop_sender);
Task::perform( Task::perform(
async move { async move {
@ -211,7 +211,7 @@ impl App {
self.gui_status.write().unwrap().microphone = State::Loading; self.gui_status.write().unwrap().microphone = State::Loading;
let gui_status = self.gui_status.clone(); let gui_status = self.gui_status.clone();
let signal = self.signal.clone(); let signal = self.controller.clone();
Task::perform( Task::perform(
async move { signal.record_control.send(State::Active).await }, async move { signal.record_control.send(State::Active).await },
move |result| { move |result| {
@ -232,7 +232,7 @@ impl App {
self.gui_status.write().unwrap().microphone = State::Loading; self.gui_status.write().unwrap().microphone = State::Loading;
let gui_status = self.gui_status.clone(); let gui_status = self.gui_status.clone();
let signal = self.signal.clone(); let signal = self.controller.clone();
Task::perform( Task::perform(
async move { signal.record_control.send(State::Passive).await }, async move { signal.record_control.send(State::Passive).await },
move |result| { move |result| {
@ -253,7 +253,7 @@ impl App {
self.gui_status.write().unwrap().speaker = State::Loading; self.gui_status.write().unwrap().speaker = State::Loading;
let gui_status = self.gui_status.clone(); let gui_status = self.gui_status.clone();
let signal = self.signal.clone(); let signal = self.controller.clone();
Task::perform( Task::perform(
async move { signal.play_control.send(State::Active).await }, async move { signal.play_control.send(State::Active).await },
move |result| { move |result| {
@ -274,7 +274,7 @@ impl App {
self.gui_status.write().unwrap().speaker = State::Loading; self.gui_status.write().unwrap().speaker = State::Loading;
let gui_status = self.gui_status.clone(); let gui_status = self.gui_status.clone();
let signal = self.signal.clone(); let signal = self.controller.clone();
Task::perform( Task::perform(
async move { signal.play_control.send(State::Passive).await }, async move { signal.play_control.send(State::Passive).await },
move |result| { move |result| {

View file

@ -1,3 +1,6 @@
use protocol::protocol::Speaker;
use tokio::sync::broadcast;
pub mod gui; pub mod gui;
pub mod stream; pub mod stream;
pub mod voice; pub mod voice;
@ -5,6 +8,21 @@ pub mod voice;
const MICROPHONE_BUFFER_LENGHT: usize = 1024 * 4; const MICROPHONE_BUFFER_LENGHT: usize = 1024 * 4;
const SPEAKER_BUFFER_LENGHT: usize = 1024 * 16 * 16; const SPEAKER_BUFFER_LENGHT: usize = 1024 * 16 * 16;
#[derive(Debug, Clone)]
pub struct SpeakerWithData {
speaker: Speaker,
audio_sender: broadcast::Sender<f32>,
}
impl SpeakerWithData {
pub fn get_speaker_id(&self) -> u8 {
self.speaker.get_id()
}
pub fn subscribe(&self) -> broadcast::Receiver<f32> {
self.audio_sender.subscribe()
}
}
#[derive(Debug)] #[derive(Debug)]
pub struct ClientConfig { pub struct ClientConfig {
certificate_path: String, certificate_path: String,

View file

@ -1,6 +1,9 @@
use std::{net::SocketAddr, path::Path, sync::Arc}; use std::{net::SocketAddr, path::Path, sync::Arc};
use protocol::{Error, NETWORK_BUFFER_LENGTH, Signal, SignalType, SignedAudioDatum}; use protocol::{
Error,
protocol::{NETWORK_DATA_LENGTH, Signal},
};
use s2n_quic::{ use s2n_quic::{
Client, Client,
client::Connect, client::Connect,
@ -22,7 +25,7 @@ pub struct ConnectReturn {
pub async fn connect( pub async fn connect(
microphone_receiver: broadcast::Receiver<f32>, microphone_receiver: broadcast::Receiver<f32>,
speaker_sender: Arc<broadcast::Sender<f32>>, speaker_sender: Arc<broadcast::Sender<Signal>>,
client_config: Arc<ClientConfig>, client_config: Arc<ClientConfig>,
) -> Result<ConnectReturn, Error> { ) -> Result<ConnectReturn, Error> {
let client = Client::builder() let client = Client::builder()
@ -58,10 +61,8 @@ pub async fn connect(
.map_err(|err_val| Error::ConnectionSetup(err_val.to_string()))?; .map_err(|err_val| Error::ConnectionSetup(err_val.to_string()))?;
let (receive_stream, send_stream) = stream.split(); let (receive_stream, send_stream) = stream.split();
let ready_signal = broadcast::channel(3);
let send_signals_task = tokio::spawn(send_signals(send_stream, microphone_receiver)); let send_signals_task = tokio::spawn(send_signals(send_stream, microphone_receiver));
let speaker_clone = speaker_sender.clone();
let receive_signals_task = tokio::spawn(receive_signals(receive_stream, speaker_sender)); let receive_signals_task = tokio::spawn(receive_signals(receive_stream, speaker_sender));
Ok(ConnectReturn { Ok(ConnectReturn {
@ -111,25 +112,15 @@ async fn send_signals(
async fn receive_signals( async fn receive_signals(
mut receive_stream: ReceiveStream, mut receive_stream: ReceiveStream,
speaker_sender: Arc<broadcast::Sender<SignedAudioDatum>>, speaker_sender: Arc<broadcast::Sender<Signal>>,
) { ) {
let mut network_buffer = [0; NETWORK_BUFFER_LENGTH]; let mut network_buffer = [0; NETWORK_DATA_LENGTH];
loop { loop {
match receive_stream.read_exact(&mut network_buffer).await { match receive_stream.read_exact(&mut network_buffer).await {
Ok(_) => match Signal::unpack_signal(&network_buffer) { Ok(_) => match Signal::unpack(network_buffer) {
Ok(received_signal) => match received_signal.signal_type { Ok(signal) => {
SignalType::AudioDatum => match received_signal.unpack_audio() { let _ = speaker_sender.send(signal);
Ok(signed_audio_datum) => {
let _ = speaker_sender.send(signed_audio_datum);
} }
Err(err_val) => {
eprintln!("Error: Unpack Audio | {}", err_val);
println!("Warning: Illegal Operation");
return;
}
},
SignalType::SpeakerLeft => todo!(),
},
Err(err_val) => { Err(err_val) => {
eprintln!("Error: Unpack Signal | {}", err_val); eprintln!("Error: Unpack Signal | {}", err_val);
} }

View file

@ -1,11 +1,30 @@
use std::sync::Arc; use std::sync::{
Arc,
atomic::{AtomicBool, Ordering},
};
use cpal::traits::{DeviceTrait, HostTrait, StreamTrait}; use cpal::traits::{DeviceTrait, HostTrait, StreamTrait};
use protocol::Error; use protocol::{
Error,
protocol::{DEFAULT_SAMPLE_RATE, Signal, SignalType},
};
use rodio::{OutputStream, OutputStreamBuilder, Sink, buffer::SamplesBuffer, mixer::Mixer};
use tokio::sync::{broadcast, mpsc}; use tokio::sync::{broadcast, mpsc};
use crate::gui::State; use crate::gui::State;
struct SpeakerSink {
speaker_id: u8,
sink: Sink,
}
impl SpeakerSink {
fn new(speaker_id: u8, mixer: &Mixer) -> Self {
let sink = Sink::connect_new(mixer);
Self { speaker_id, sink }
}
}
pub async fn record( pub async fn record(
mut record_control: mpsc::Receiver<State>, mut record_control: mpsc::Receiver<State>,
record_sender: Arc<broadcast::Sender<f32>>, record_sender: Arc<broadcast::Sender<f32>>,
@ -61,66 +80,85 @@ pub async fn record(
}) })
} }
pub async fn play( async fn signal_handler(
mut play_control: mpsc::Receiver<State>, output_stream: OutputStream,
mut play_receiver: broadcast::Receiver<f32>, mut play_receiver: broadcast::Receiver<Signal>,
) -> Result<(), Error> { play_pause: Arc<AtomicBool>,
let host = cpal::default_host(); ) {
let output_device = host.default_output_device().unwrap(); let mut speaker_list = vec![];
let config = output_device.default_output_config().unwrap().into();
println!("Speaker Stream Config = {:#?}", config);
let output = move |data: &mut [f32], _: &cpal::OutputCallbackInfo| { while let Ok(signal) = play_receiver.recv().await {
for sample in data { match signal.get_signal_type() {
match play_receiver.try_recv() { SignalType::AudioDatum => {
Ok(received_sample) => *sample = received_sample, let data = if play_pause.load(std::sync::atomic::Ordering::Relaxed) {
Err(err_val) => match err_val { [signal.get_audio_datum()]
broadcast::error::TryRecvError::Empty => *sample = 0.0, } else {
broadcast::error::TryRecvError::Closed => { [0.0]
eprintln!("Error: Speaker Receive | Local Channel | Channel Closed");
return;
}
broadcast::error::TryRecvError::Lagged(lag_amount) => {
eprintln!(
"Error: Speaker Receive | Local Channel | Lagging by -> {}",
lag_amount
);
play_receiver = play_receiver.resubscribe();
}
},
}
}
}; };
let output_stream = output_device let source = SamplesBuffer::new(2, DEFAULT_SAMPLE_RATE, data);
.build_output_stream(&config, output, voice_error, None)
.unwrap();
output_stream match speaker_list.binary_search_by(|speaker_sink: &SpeakerSink| {
.play() speaker_sink.speaker_id.cmp(&signal.get_speaker_id())
.map_err(|inner| Error::Play(inner.to_string()))?; }) {
Ok(speaker_sink_index) => {
let speaker_sink = speaker_list.get(speaker_sink_index).expect("Never");
speaker_sink.sink.append(source);
}
Err(_) => {
let speaker_sink =
SpeakerSink::new(signal.get_speaker_id(), output_stream.mixer());
speaker_sink.sink.append(source);
speaker_list.push(speaker_sink);
speaker_list.sort_by(|x, y| x.speaker_id.cmp(&y.speaker_id));
}
}
}
SignalType::SpeakerLeft => {
speaker_list
.retain(|speaker_sink| speaker_sink.speaker_id != signal.get_speaker_id());
}
}
}
}
pub async fn play(
mut play_control: mpsc::Receiver<State>,
play_receiver: broadcast::Receiver<Signal>,
) {
let output_stream = OutputStreamBuilder::open_default_stream().unwrap();
let play_pause = Arc::new(AtomicBool::new(true));
let signal_handler = tokio::spawn(signal_handler(
output_stream,
play_receiver,
play_pause.clone(),
));
tokio::task::block_in_place(|| { tokio::task::block_in_place(|| {
loop { loop {
match play_control.blocking_recv() { match play_control.blocking_recv() {
Some(message) => match message { Some(requested_state) => match requested_state {
State::Active => output_stream State::Active => {
.play() play_pause.store(true, Ordering::Relaxed);
.map_err(|inner| Error::Play(inner.to_string()))?, }
State::Passive => output_stream State::Passive => {
.pause() play_pause.store(false, Ordering::Relaxed);
.map_err(|inner| Error::Play(inner.to_string()))?, }
State::Loading => {} State::Loading => {}
}, },
None => { None => {
output_stream signal_handler.abort();
.pause() return;
.map_err(|inner| Error::Play(inner.to_string()))?;
return Ok(());
} }
} }
} }
}) });
signal_handler.abort();
} }
fn voice_error(err_val: cpal::StreamError) { fn voice_error(err_val: cpal::StreamError) {

View file

@ -6,5 +6,6 @@ edition = "2024"
[dependencies] [dependencies]
# serde = { workspace = true } # serde = { workspace = true }
# serde_json = { workspace = true } # serde_json = { workspace = true }
tokio = { workspace = true }
chrono = { workspace = true } chrono = { workspace = true }
bincode = { workspace = true } bincode = { workspace = true }

View file

@ -1,10 +1,17 @@
use std::sync::Arc;
use bincode::{Decode, Encode}; use bincode::{Decode, Encode};
use tokio::sync::broadcast;
use crate::Error; use crate::Error;
const SIGNAL_DATA_LENGTH: usize = 4; const SIGNAL_DATA_LENGTH: usize = 4;
const NETWORK_DATA_LENGTH: usize = 6; pub const NETWORK_DATA_LENGTH: usize = 6;
pub const SPEAKER_ACTION_CHANNEL_LENGTH: usize = 1024;
pub const AUDIO_DATA_SENDER_CHANNEL_LENGTH: usize = 1024 * 16 * 4;
pub const DEFAULT_SAMPLE_RATE: u32 = 44100;
pub type SpeakerWithDataAndAction = (SpeakerWithData, SpeakerAction);
type SignalBufferReturn = [u8; SIGNAL_DATA_LENGTH]; type SignalBufferReturn = [u8; SIGNAL_DATA_LENGTH];
type NetworkBufferReturn = [u8; NETWORK_DATA_LENGTH]; type NetworkBufferReturn = [u8; NETWORK_DATA_LENGTH];
@ -26,20 +33,88 @@ impl Speaker {
} }
} }
#[derive(Debug, Encode, Decode)] #[derive(Debug, Clone, Copy)]
pub enum SpeakerAction {
Join,
Left,
}
#[derive(Debug, Clone)]
pub struct SpeakerWithData {
speaker: Speaker,
speaker_action_sender: Arc<broadcast::Sender<(SpeakerWithData, SpeakerAction)>>,
audio_data_sender: Arc<broadcast::Sender<f32>>,
}
impl SpeakerWithData {
pub fn new(speaker: Speaker) -> Self {
let speaker_action_sender = broadcast::channel(SPEAKER_ACTION_CHANNEL_LENGTH).0.into();
let audio_data_sender = broadcast::channel(AUDIO_DATA_SENDER_CHANNEL_LENGTH)
.0
.into();
Self {
speaker,
speaker_action_sender,
audio_data_sender,
}
}
pub fn get_speaker_id(&self) -> u8 {
self.speaker.get_id()
}
pub fn get_speaker(&self) -> Speaker {
self.speaker
}
pub fn send_speaker_action(&self, speaker_with_data_and_action: SpeakerWithDataAndAction) {
let _ = self
.speaker_action_sender
.send(speaker_with_data_and_action);
}
pub fn clone_audio_data_sender(&self) -> Arc<broadcast::Sender<f32>> {
self.audio_data_sender.clone()
}
pub fn subscribe_speaker_action_channel(
&self,
) -> broadcast::Receiver<(SpeakerWithData, SpeakerAction)> {
self.speaker_action_sender.subscribe()
}
pub fn subscribe_audio_data_channel(&self) -> broadcast::Receiver<f32> {
self.audio_data_sender.subscribe()
}
}
#[derive(Debug, Clone, Copy, Encode, Decode)]
pub enum SignalType { pub enum SignalType {
AudioDatum, AudioDatum,
SpeakerLeft, SpeakerLeft,
} }
#[derive(Debug, Encode, Decode)] #[derive(Debug, Clone, Copy, Encode, Decode)]
pub struct Signal { pub struct Signal {
signal_type: SignalType, signal_type: SignalType,
speaker: Speaker, speaker: Speaker,
data: [u8; SIGNAL_DATA_LENGTH], data: SignalBufferReturn,
} }
impl Signal { impl Signal {
pub fn get_signal_type(&self) -> SignalType {
self.signal_type
}
pub fn get_speaker_id(&self) -> u8 {
self.speaker.get_id()
}
pub fn get_audio_datum(&self) -> f32 {
f32::from_be_bytes(self.data)
}
pub fn unpack(data: NetworkBufferReturn) -> Result<Self, Error> { pub fn unpack(data: NetworkBufferReturn) -> Result<Self, Error> {
Ok(bincode::decode_from_slice::<Self, _>(&data, BINCODE_CONFIG) Ok(bincode::decode_from_slice::<Self, _>(&data, BINCODE_CONFIG)
.map_err(|inner| Error::Deserialization(inner.to_string()))? .map_err(|inner| Error::Deserialization(inner.to_string()))?

View file

@ -3,7 +3,9 @@ use std::{
sync::{Arc, LazyLock}, sync::{Arc, LazyLock},
}; };
use protocol::protocol::{Signal, Speaker}; use protocol::protocol::{
Signal, Speaker, SpeakerAction, SpeakerWithData, SpeakerWithDataAndAction,
};
use s2n_quic::{ use s2n_quic::{
Connection, Server, Connection, Server,
stream::{ReceiveStream, SendStream}, stream::{ReceiveStream, SendStream},
@ -15,74 +17,46 @@ use tokio::{
use crate::ServerConfig; use crate::ServerConfig;
const NEW_SPEAKER_LENGTH: usize = u8::MAX as usize; async fn add_speaker(
const AUDIO_BUFFER_LENGTH: usize = 1024 * 16 * 16; speaker_with_data: SpeakerWithData,
) -> (
#[derive(Debug, Clone, Copy)] broadcast::Receiver<SpeakerWithDataAndAction>,
enum SpeakerAction { Arc<broadcast::Sender<f32>>,
Join, ) {
Left, // Do this first so receiver can keep track of later insertions, otherwise they just wastes
} let speaker_action_receiver = speaker_with_data.subscribe_speaker_action_channel();
#[derive(Debug, Clone)]
struct SpeakerWithData {
speaker: Speaker,
speaker_action_sender: broadcast::Sender<(SpeakerWithData, SpeakerAction)>,
audio_data_sender: broadcast::Sender<f32>,
}
impl SpeakerWithData {
async fn new(
speaker: Speaker,
) -> (
broadcast::Receiver<(SpeakerWithData, SpeakerAction)>,
broadcast::Sender<f32>,
) {
let speaker_action_channel = broadcast::channel(NEW_SPEAKER_LENGTH);
let audio_data_sender = broadcast::channel(AUDIO_BUFFER_LENGTH).0;
let speaker_with_data = Self {
speaker,
speaker_action_sender: speaker_action_channel.0,
audio_data_sender: audio_data_sender.clone(),
};
let mut online_speakers = ONLINE_SPEAKERS.write().await; let mut online_speakers = ONLINE_SPEAKERS.write().await;
for online_speaker in online_speakers.iter() { for online_speaker in online_speakers.iter() {
let _ = speaker_with_data speaker_with_data.send_speaker_action((online_speaker.clone(), SpeakerAction::Join));
.speaker_action_sender online_speaker.send_speaker_action((speaker_with_data.clone(), SpeakerAction::Join));
.send((online_speaker.clone(), SpeakerAction::Join));
let _ = online_speaker
.speaker_action_sender
.send((speaker_with_data.clone(), SpeakerAction::Join));
} }
let audio_data_sender = speaker_with_data.clone_audio_data_sender();
online_speakers.push(speaker_with_data); online_speakers.push(speaker_with_data);
online_speakers.sort_by_key(|speaker| speaker.speaker.get_id()); online_speakers.sort_by_key(|speaker| speaker.get_speaker_id());
drop(online_speakers); drop(online_speakers);
(speaker_action_channel.1, audio_data_sender) (speaker_action_receiver, audio_data_sender)
} }
async fn remove(speaker_id: u8) { async fn remove_speaker(speaker_id: u8) {
let mut online_speakers = ONLINE_SPEAKERS.write().await; let mut online_speakers = ONLINE_SPEAKERS.write().await;
let speaker_index = let speaker_index =
online_speakers.binary_search_by_key(&speaker_id, |speaker| speaker.speaker.get_id()); online_speakers.binary_search_by_key(&speaker_id, |speaker| speaker.get_speaker_id());
match speaker_index { match speaker_index {
Ok(speaker_index) => { Ok(speaker_index) => {
let speaker = online_speakers.remove(speaker_index); let speaker = online_speakers.remove(speaker_index);
for online_speaker in online_speakers.iter() { for online_speaker in online_speakers.iter() {
let _ = online_speaker online_speaker.send_speaker_action((speaker.clone(), SpeakerAction::Left));
.speaker_action_sender
.send((speaker.clone(), SpeakerAction::Left));
} }
} }
Err(_) => return, Err(_) => return,
} }
}
} }
static ONLINE_SPEAKERS: LazyLock<RwLock<Vec<SpeakerWithData>>> = LazyLock::new(|| vec![].into()); static ONLINE_SPEAKERS: LazyLock<RwLock<Vec<SpeakerWithData>>> = LazyLock::new(|| vec![].into());
@ -133,7 +107,9 @@ async fn handle_client(speaker: Speaker, mut connection: Connection) {
let (receive_stream, send_stream) = stream.split(); let (receive_stream, send_stream) = stream.split();
let speaker_id = speaker.get_id(); let speaker_id = speaker.get_id();
let (speaker_action_receiver, audio_data_sender) = SpeakerWithData::new(speaker).await;
let speaker_with_data = SpeakerWithData::new(speaker);
let (speaker_action_receiver, audio_data_sender) = add_speaker(speaker_with_data).await;
tokio::spawn(receive_audio_data( tokio::spawn(receive_audio_data(
receive_stream, receive_stream,
@ -158,22 +134,25 @@ async fn send_audio_data(
SpeakerAction::Join => { SpeakerAction::Join => {
let send_stream = send_stream.clone(); let send_stream = send_stream.clone();
tokio::spawn(async move { tokio::spawn(async move {
let mut audio_data_receiver = speaker_with_data.audio_data_sender.subscribe(); let mut audio_data_receiver = speaker_with_data.subscribe_audio_data_channel();
while let Ok(audio_datum) = audio_data_receiver.recv().await { while let Ok(audio_datum) = audio_data_receiver.recv().await {
let data = Signal::pack_audio_datum(speaker_with_data.speaker, audio_datum); let data =
Signal::pack_audio_datum(speaker_with_data.get_speaker(), audio_datum);
if let Err(err_val) = send_stream.write().await.write_all(&data).await { if let Err(err_val) = send_stream.write().await.write_all(&data).await {
eprintln!("Error: Send Audio Data | Remote | {}", err_val); eprintln!("Error: Send Audio Data | Remote | {}", err_val);
SpeakerWithData::remove(speaker_id).await; remove_speaker(speaker_id).await;
return;
}; };
} }
}); });
} }
SpeakerAction::Left => { SpeakerAction::Left => {
let data = Signal::pack_speaker_left(speaker_with_data.speaker); let data = Signal::pack_speaker_left(speaker_with_data.get_speaker());
if let Err(err_val) = send_stream.write().await.write_all(&data).await { if let Err(err_val) = send_stream.write().await.write_all(&data).await {
eprintln!("Error: Send Speaker Left | Remote | {}", err_val); eprintln!("Error: Send Speaker Left | Remote | {}", err_val);
SpeakerWithData::remove(speaker_id).await; remove_speaker(speaker_id).await;
return;
} }
} }
} }
@ -183,7 +162,7 @@ async fn send_audio_data(
async fn receive_audio_data( async fn receive_audio_data(
mut receive_stream: ReceiveStream, mut receive_stream: ReceiveStream,
speaker_id: u8, speaker_id: u8,
audio_data_sender: broadcast::Sender<f32>, audio_data_sender: Arc<broadcast::Sender<f32>>,
) { ) {
loop { loop {
match receive_stream.read_f32().await { match receive_stream.read_f32().await {
@ -192,7 +171,8 @@ async fn receive_audio_data(
} }
Err(err_val) => { Err(err_val) => {
eprintln!("Error: Receive Audio Data | Remote | {}", err_val); eprintln!("Error: Receive Audio Data | Remote | {}", err_val);
SpeakerWithData::remove(speaker_id).await; remove_speaker(speaker_id).await;
return;
} }
} }
} }