From 65883917b023882842a0d71067dbe5598080fed9 Mon Sep 17 00:00:00 2001 From: Liam Warfield Date: Mon, 19 Jan 2026 22:07:06 +0000 Subject: [PATCH] Add a default noise floor. (#13) (Turns out not) Pretty simple, if the average amplitude is under a certain value clear out the buffer! The value I chose (.001) was an arbitrary value I got from printf debugging. I was able to show that this worked pretty well on the desktop session. Hopefully we'll add this to the settings page at some point. Once the app has been under that threshold for more than 200ms, we stop transmitting and send a terminator packet. Reviewed-on: https://git.ohea.xyz/mumble/mumble-web2/pulls/13 Reviewed-by: restitux --- Cargo.lock | 525 +++++++++--------------------------- gui/src/effects.rs | 60 ++++- gui/src/imp/native_audio.rs | 45 ++-- gui/src/imp/web.rs | 47 +++- gui/src/lib.rs | 4 +- 5 files changed, 249 insertions(+), 432 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 1a6f340..e273680 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -188,50 +188,6 @@ version = "0.7.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7c02d123df017efcdfbd739ef81735b36c5ba83ec3c59c80a9d7ecc718f92e50" -[[package]] -name = "ashpd" -version = "0.11.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6cbdf310d77fd3aaee6ea2093db7011dc2d35d2eb3481e5607f1f8d942ed99df" -dependencies = [ - "enumflags2", - "futures-channel", - "futures-util", - "rand 0.9.2", - "raw-window-handle 0.6.2", - "serde", - "serde_repr", - "tokio", - "url", - "wayland-backend", - "wayland-client", - "wayland-protocols", - "zbus", -] - -[[package]] -name = "async-broadcast" -version = "0.7.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "435a87a52755b8f27fcf321ac4f04b2802e337c8c4872923137471ec39c37532" -dependencies = [ - "event-listener", - "event-listener-strategy", - "futures-core", - "pin-project-lite", -] - -[[package]] -name = "async-recursion" -version = "1.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3b43422f69d8ff38f95f1b2bb76517c91589a924d1559a0e935d7c8ce0274c11" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.108", -] - [[package]] name = "async-stream" version = "0.3.6" @@ -898,15 +854,6 @@ dependencies = [ "static_assertions", ] -[[package]] -name = "concurrent-queue" -version = "2.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4ca0197aee26d1ae37445ee532fefce43251d24cc7c166799f4d46817f1d3973" -dependencies = [ - "crossbeam-utils", -] - [[package]] name = "console_error_panic_hook" version = "0.1.7" @@ -949,7 +896,17 @@ version = "0.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ad7154afa56de2f290e3c82c2c6dc4f5b282b6870903f56ef3509aba95866edc" dependencies = [ - "const-serialize-macro", + "const-serialize-macro 0.7.2", +] + +[[package]] +name = "const-serialize" +version = "0.8.0-alpha.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9e42cd5aabba86f128b3763da1fec1491c0f728ce99245062cd49b6f9e6d235b" +dependencies = [ + "const-serialize 0.7.2", + "const-serialize-macro 0.8.0-alpha.0", "serde", ] @@ -964,6 +921,17 @@ dependencies = [ "syn 2.0.108", ] +[[package]] +name = "const-serialize-macro" +version = "0.8.0-alpha.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "42571ed01eb46d2e1adcf99c8ca576f081e46f2623d13500eba70d1d99a4c439" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.108", +] + [[package]] name = "const-str" version = "0.7.0" @@ -1510,9 +1478,9 @@ dependencies = [ [[package]] name = "dioxus" -version = "0.7.2" +version = "0.7.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3a115f9dbe5900c6044ee6a791e1b160c29989c6a8721eec099e01a964e5dae4" +checksum = "92b583b48ac77158495e6678fe3a2b5954fc8866fc04cb9695dd146e88bc329d" dependencies = [ "dioxus-asset-resolver", "dioxus-cli-config", @@ -1538,9 +1506,9 @@ dependencies = [ [[package]] name = "dioxus-asset-resolver" -version = "0.7.2" +version = "0.7.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6851ae49ba3988f1b77f6ef826eb142e811602129841c24bf5a4e103708d9844" +checksum = "c0161af1d3cfc8ff31503ff1b7ee0068c97771fc38d0cc6566e23483142ddf4f" dependencies = [ "dioxus-cli-config", "http", @@ -1559,18 +1527,18 @@ dependencies = [ [[package]] name = "dioxus-cli-config" -version = "0.7.2" +version = "0.7.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c59e9d9da2e7334fdae5d77e3989207aa549062f74ff1ca2171393bbdd7fda90" +checksum = "ccd67ab405e1915a47df9769cd5408545d1b559d5c01ce7a0f442caef520d1f3" dependencies = [ "wasm-bindgen", ] [[package]] name = "dioxus-config-macro" -version = "0.7.2" +version = "0.7.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9bd56be5ea6c9f416b25e9e3adc910c02127be75b6d1ecd567661f31920b27ba" +checksum = "f040ec7c41aa5428283f56bb0670afba9631bfe3ffd885f4814807f12c8c9d91" dependencies = [ "proc-macro2", "quote", @@ -1578,15 +1546,15 @@ dependencies = [ [[package]] name = "dioxus-config-macros" -version = "0.7.2" +version = "0.7.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c49327465c2d434d00fb4c86bd35ae72155b479622e09352b950d9ab4807bf23" +checksum = "10c41b47b55a433b61f7c12327c85ba650572bacbcc42c342ba2e87a57975264" [[package]] name = "dioxus-core" -version = "0.7.2" +version = "0.7.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7400cbd21a98e585a13f8c29574da9b8afb2fd343f712618042b6c71761f0933" +checksum = "b389b0e3cc01c7da292ad9b884b088835fdd1671d45fbd2f737506152b22eef0" dependencies = [ "anyhow", "const_format", @@ -1606,9 +1574,9 @@ dependencies = [ [[package]] name = "dioxus-core-macro" -version = "0.7.2" +version = "0.7.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e51c0eb7eb76dd5a0b9a116d94d29ca78924a1ed1fcb7ea072eda5045d3ac056" +checksum = "6a82d65f0024fc86f01911a16156d280eea583be5a82a3bed85e7e8e4194302d" dependencies = [ "convert_case 0.8.0", "dioxus-rsx", @@ -1619,15 +1587,15 @@ dependencies = [ [[package]] name = "dioxus-core-types" -version = "0.7.2" +version = "0.7.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0652ab5f9c2c32261d44a3155debbfd909ed03d03434d7f70f5a796bf255c519" +checksum = "bfc4b8cdc440a55c17355542fc2089d97949bba674255d84cac77805e1db8c9f" [[package]] name = "dioxus-desktop" -version = "0.7.2" +version = "0.7.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b24aa7e4aa87fce202c5e67d560cddd9ed67ad533f16b7d922916c04993766ff" +checksum = "7e6ec66749d1556636c5b4f661495565c155a7f78a46d4d007d7478c6bdc288c" dependencies = [ "async-trait", "base64", @@ -1661,7 +1629,7 @@ dependencies = [ "objc_id", "percent-encoding", "rand 0.9.2", - "rfd 0.15.4", + "rfd 0.17.2", "rustc-hash 2.1.1", "serde", "serde_json", @@ -1680,9 +1648,9 @@ dependencies = [ [[package]] name = "dioxus-devtools" -version = "0.7.2" +version = "0.7.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9748128bcd102b10e58c765939807053ccab542206a939b8bab228077455c259" +checksum = "dcf89488bad8fb0f18b9086ee2db01f95f709801c10c68be42691a36378a0f2d" dependencies = [ "dioxus-cli-config", "dioxus-core", @@ -1698,9 +1666,9 @@ dependencies = [ [[package]] name = "dioxus-devtools-types" -version = "0.7.2" +version = "0.7.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "48540ca8a0ab1ec81cd4db35f0c9713d43b158647fc1dcb0d79965fc3b41d96c" +checksum = "6e7381d9d7d0a0f66b9d5082d584853c3d53be21d34007073daca98ddf26fc4d" dependencies = [ "dioxus-core", "serde", @@ -1709,9 +1677,9 @@ dependencies = [ [[package]] name = "dioxus-document" -version = "0.7.2" +version = "0.7.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "501a189b391d091c9aa02c05f5b25f5d0d17fa0e1016e000b0fdbb073d77cd6a" +checksum = "6ba0aeeff26d9d06441f59fd8d7f4f76098ba30ca9728e047c94486161185ceb" dependencies = [ "dioxus-core", "dioxus-core-macro", @@ -1728,9 +1696,9 @@ dependencies = [ [[package]] name = "dioxus-fullstack" -version = "0.7.2" +version = "0.7.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "54150804265defdb21a6f2d8914a45316a1e7fb70ab22c30cf836e8fe2f8081b" +checksum = "7db1f8b70338072ec408b48d09c96559cf071f87847465d8161294197504c498" dependencies = [ "anyhow", "async-stream", @@ -1785,9 +1753,9 @@ dependencies = [ [[package]] name = "dioxus-fullstack-core" -version = "0.7.2" +version = "0.7.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d0a9be2ef4d701520eefef284d218fb35b159dccd6bccc02b5bad42945e2599d" +checksum = "cda8b152e85121243741b9d5f2a3d8cb3c47a7b2299e902f98b6a7719915b0a2" dependencies = [ "anyhow", "axum-core", @@ -1813,9 +1781,9 @@ dependencies = [ [[package]] name = "dioxus-fullstack-macro" -version = "0.7.2" +version = "0.7.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a31ea4451fe8c9d2af24fb718a94966d5fd7e11325777e5b5a59085c5c85e5fb" +checksum = "255104d4a4f278f1a8482fa30536c91d22260c561c954b753e72987df8d65b2e" dependencies = [ "const_format", "convert_case 0.8.0", @@ -1827,9 +1795,9 @@ dependencies = [ [[package]] name = "dioxus-history" -version = "0.7.2" +version = "0.7.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "55d704b3ba9504cb3c9cde49499b75546d1faaff2736f4c368aca6c061c48ac3" +checksum = "8d00ba43bfe6e5ca226fef6128f240ca970bea73cac0462416188026360ccdcf" dependencies = [ "dioxus-core", "tracing", @@ -1837,9 +1805,9 @@ dependencies = [ [[package]] name = "dioxus-hooks" -version = "0.7.2" +version = "0.7.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "79c6d68be372eca8186a1c57ec49be67a6ea46022150b5e85ab6a6acde52d272" +checksum = "dab2da4f038c33cb38caa37ffc3f5d6dfbc018f05da35b238210a533bb075823" dependencies = [ "dioxus-core", "dioxus-signals", @@ -1853,9 +1821,9 @@ dependencies = [ [[package]] name = "dioxus-html" -version = "0.7.2" +version = "0.7.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3aa87ecfa0f38ec286be25789a7f2d6c30778111f1fbff563da4bae41d171496" +checksum = "eded5fa6d2e677b7442a93f4228bf3c0ad2597a8bd3292cae50c869d015f3a99" dependencies = [ "async-trait", "bytes", @@ -1880,9 +1848,9 @@ dependencies = [ [[package]] name = "dioxus-html-internal-macro" -version = "0.7.2" +version = "0.7.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49301d0e389378e8070b8b704110339a0d3358efad9f5ad483ffab3a8d406dae" +checksum = "45462ab85fe059a36841508d40545109fd0e25855012d22583a61908eb5cd02a" dependencies = [ "convert_case 0.8.0", "proc-macro2", @@ -1892,9 +1860,9 @@ dependencies = [ [[package]] name = "dioxus-interpreter-js" -version = "0.7.2" +version = "0.7.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f5437a89d3ef7edfebc0f10acb065f1709cb7ffb678e3a4bb1416706d71f7c67" +checksum = "a42a7f73ad32a5054bd8c1014f4ac78cca3b7f6889210ee2b57ea31b33b6d32f" dependencies = [ "dioxus-core", "dioxus-core-types", @@ -1912,9 +1880,9 @@ dependencies = [ [[package]] name = "dioxus-logger" -version = "0.7.2" +version = "0.7.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2b25ebfbc193cebcf5af5e19b8ee7c6adee486fbd1c12f11aea058b464da16f9" +checksum = "f1eeab114cb009d9e6b85ea10639a18cfc54bb342f3b837770b004c4daeb89c2" dependencies = [ "dioxus-cli-config", "tracing", @@ -1924,9 +1892,9 @@ dependencies = [ [[package]] name = "dioxus-rsx" -version = "0.7.2" +version = "0.7.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "19d97c02689beff55767ba5f6e185ffd204c6a193e372f0fead8a3722c6f7eea" +checksum = "53128858f0ccca9de54292a4d48409fda1df75fd5012c6243f664042f0225d68" dependencies = [ "proc-macro2", "proc-macro2-diagnostics", @@ -1937,9 +1905,9 @@ dependencies = [ [[package]] name = "dioxus-signals" -version = "0.7.2" +version = "0.7.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "27fc4df7a31a7f02e5a0b40884bb66ee165226a05d75fce03baa44029e438762" +checksum = "2f48020bc23bc9766e7cce986c0fd6de9af0b8cbfd432652ec6b1094439c1ec6" dependencies = [ "dioxus-core", "futures-channel", @@ -1953,9 +1921,9 @@ dependencies = [ [[package]] name = "dioxus-stores" -version = "0.7.2" +version = "0.7.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e2dec3cd677078824a733de25ddbe8e987cfc8d98aec29b7d199e1fdb8452b96" +checksum = "77aaa9ac56d781bb506cf3c0d23bea96b768064b89fe50d3b4d4659cc6bd8058" dependencies = [ "dioxus-core", "dioxus-signals", @@ -1965,9 +1933,9 @@ dependencies = [ [[package]] name = "dioxus-stores-macro" -version = "0.7.2" +version = "0.7.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c9b7f085e374aaaa78403227b9bd83675c4078388d41a41b67dfbe4aa0bb64d5" +checksum = "5b1a728622e7b63db45774f75e71504335dd4e6115b235bbcff272980499493a" dependencies = [ "convert_case 0.8.0", "proc-macro2", @@ -1977,9 +1945,9 @@ dependencies = [ [[package]] name = "dioxus-web" -version = "0.7.2" +version = "0.7.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "315009f3a77c3c813415b3b8a8ea62a4d7a32dde9a666664b30862d4386e8456" +checksum = "3b33fe739fed4e8143dac222a9153593f8e2451662ce8fc4c9d167a9d6ec0923" dependencies = [ "dioxus-cli-config", "dioxus-core", @@ -2058,15 +2026,6 @@ dependencies = [ "syn 2.0.108", ] -[[package]] -name = "dlib" -version = "0.5.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "330c60081dcc4c72131f8eb70510f1ac07223e5d4163db481a04a0befcffa412" -dependencies = [ - "libloading 0.8.9", -] - [[package]] name = "dlopen2" version = "0.8.0" @@ -2227,12 +2186,6 @@ dependencies = [ "cfg-if", ] -[[package]] -name = "endi" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a3d8a32ae18130a3c84dd492d4215c3d913c3b07c6b63c2eb3eb7ff1101ab7bf" - [[package]] name = "enumflags2" version = "0.7.12" @@ -2240,7 +2193,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1027f7680c853e056ebcec683615fb6fbbc07dbaa13b4d5d9442b146ded4ecef" dependencies = [ "enumflags2_derive", - "serde", ] [[package]] @@ -2332,27 +2284,6 @@ dependencies = [ "serde", ] -[[package]] -name = "event-listener" -version = "5.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e13b66accf52311f30a0db42147dadea9850cb48cd070028831ae5f5d4b856ab" -dependencies = [ - "concurrent-queue", - "parking", - "pin-project-lite", -] - -[[package]] -name = "event-listener-strategy" -version = "0.5.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8be9f3dfaaffdae2972880079a491a1a8bb7cbed0b8dd7a347f668b4150a3b93" -dependencies = [ - "event-listener", - "pin-project-lite", -] - [[package]] name = "eyre" version = "0.6.12" @@ -2565,19 +2496,6 @@ version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9e5c1b78ca4aae1ac06c48a526a655760685149f0d465d21f37abfe57ce075c6" -[[package]] -name = "futures-lite" -version = "2.6.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f78e10609fe0e0b3f4157ffab1876319b5b0db102a2c60dc4626306dc46b44ad" -dependencies = [ - "fastrand", - "futures-core", - "futures-io", - "parking", - "pin-project-lite", -] - [[package]] name = "futures-macro" version = "0.3.31" @@ -2715,9 +2633,9 @@ dependencies = [ [[package]] name = "generational-box" -version = "0.7.2" +version = "0.7.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e658d10252a15200ca4a1c67c7180fc0baffa3f92869bbd903025daf6f70fd65" +checksum = "cc4ed190b9de8e734d47a70be59b1e7588b9e8e0d0036e332f4c014e8aed1bc5" dependencies = [ "parking_lot", "tracing", @@ -3729,9 +3647,9 @@ dependencies = [ [[package]] name = "lazy-js-bundle" -version = "0.7.2" +version = "0.7.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "21972afec4627b7ba0de60b5269585b5ac2f56d559b0696f57eee6daf8a51b68" +checksum = "c7b88b715ab1496c6e6b8f5e927be961c4235196121b6ae59bcb51077a21dd36" [[package]] name = "lazy_static" @@ -4034,32 +3952,35 @@ dependencies = [ [[package]] name = "manganis" -version = "0.7.2" +version = "0.7.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "97c63ae68d25457a579b7714806088c5cb44c536cf624a53a17184878f9f0bcd" +checksum = "6cce7d688848bf9d034168513b9a2ffbfe5f61df2ff14ae15e6cfc866efdd344" dependencies = [ - "const-serialize", + "const-serialize 0.7.2", + "const-serialize 0.8.0-alpha.0", "manganis-core", "manganis-macro", ] [[package]] name = "manganis-core" -version = "0.7.2" +version = "0.7.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "88d071660b149f985cbab8b23f2004ea6dd5cf947b63a0843f0e2f46e6af7229" +checksum = "84ce917b978268fe8a7db49e216343ec7c8f471f7e686feb70940d67293f19d4" dependencies = [ - "const-serialize", + "const-serialize 0.7.2", + "const-serialize 0.8.0-alpha.0", "dioxus-cli-config", "dioxus-core-types", "serde", + "winnow 0.7.14", ] [[package]] name = "manganis-macro" -version = "0.7.2" +version = "0.7.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9793d1d33778245b4240c330a8f575d208ce077c7e7bab1c79064252ddd4a162" +checksum = "ad513e990f7c0bca86aa68659a7a3dc4c705572ed4c22fd6af32ccf261334cc2" dependencies = [ "dunce", "macro-string", @@ -4481,7 +4402,6 @@ dependencies = [ "cfg-if", "cfg_aliases", "libc", - "memoffset", ] [[package]] @@ -4862,16 +4782,6 @@ dependencies = [ "hashbrown 0.14.5", ] -[[package]] -name = "ordered-stream" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9aa2b01e1d916879f73a53d01d1d6cee68adbb31d6d9177a8cfce093cced1d50" -dependencies = [ - "futures-core", - "pin-project-lite", -] - [[package]] name = "ordermap" version = "0.5.12" @@ -4936,12 +4846,6 @@ dependencies = [ "system-deps", ] -[[package]] -name = "parking" -version = "2.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f38d5652c16fde515bb1ecef450ab0f6a219d619a7274976324d5e377f7dceba" - [[package]] name = "parking_lot" version = "0.12.5" @@ -5514,15 +5418,6 @@ dependencies = [ "psl-types", ] -[[package]] -name = "quick-xml" -version = "0.37.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "331e97a1af0bf59823e6eadffe373d7b27f485be8748f71471c662c1f269b7fb" -dependencies = [ - "memchr", -] - [[package]] name = "quinn" version = "0.11.9" @@ -5878,30 +5773,6 @@ dependencies = [ "subtle", ] -[[package]] -name = "rfd" -version = "0.15.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ef2bee61e6cffa4635c72d7d81a84294e28f0930db0ddcb0f66d10244674ebed" -dependencies = [ - "ashpd", - "block2", - "dispatch2", - "js-sys", - "log", - "objc2", - "objc2-app-kit", - "objc2-core-foundation", - "objc2-foundation", - "pollster", - "raw-window-handle 0.6.2", - "urlencoding", - "wasm-bindgen", - "wasm-bindgen-futures", - "web-sys", - "windows-sys 0.59.0", -] - [[package]] name = "rfd" version = "0.16.0" @@ -5924,6 +5795,30 @@ dependencies = [ "windows-sys 0.61.2", ] +[[package]] +name = "rfd" +version = "0.17.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "20dafead71c16a34e1ff357ddefc8afc11e7d51d6d2b9fbd07eaa48e3e540220" +dependencies = [ + "block2", + "dispatch2", + "js-sys", + "libc", + "log", + "objc2", + "objc2-app-kit", + "objc2-core-foundation", + "objc2-foundation", + "percent-encoding", + "pollster", + "raw-window-handle 0.6.2", + "wasm-bindgen", + "wasm-bindgen-futures", + "web-sys", + "windows-sys 0.61.2", +] + [[package]] name = "ring" version = "0.17.14" @@ -7059,9 +6954,9 @@ dependencies = [ [[package]] name = "subsecond" -version = "0.7.2" +version = "0.7.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c09bc2c9ef0381b403ab8b58122961cb83266d16b1f55f9486d5857ba4a9ae26" +checksum = "8438668e545834d795d04c4335aafc332ce046106521a29f0a5c6501de34187c" dependencies = [ "js-sys", "libc", @@ -7078,9 +6973,9 @@ dependencies = [ [[package]] name = "subsecond-types" -version = "0.7.2" +version = "0.7.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d07aa455c66ddfdbb51507537402b961e027846468954ef8d974bce65dff9eb0" +checksum = "1e72f747606fc19fe81d6c59e491af93ed7dcbcb6aad9d1d18b05129914ec298" dependencies = [ "serde", ] @@ -7400,7 +7295,6 @@ dependencies = [ "signal-hook-registry", "socket2", "tokio-macros", - "tracing", "windows-sys 0.61.2", ] @@ -7524,7 +7418,7 @@ dependencies = [ "indexmap", "toml_datetime 0.7.3", "toml_parser", - "winnow 0.7.13", + "winnow 0.7.14", ] [[package]] @@ -7533,7 +7427,7 @@ version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c0cbe268d35bdb4bb5a56a2de88d0ad0eb70af5384a99d648cd4b3d04039800e" dependencies = [ - "winnow 0.7.13", + "winnow 0.7.14", ] [[package]] @@ -7910,17 +7804,6 @@ version = "0.1.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2896d95c02a80c6d6a5d6e953d479f5ddf2dfdb6a244441010e373ac0fb88971" -[[package]] -name = "uds_windows" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "89daebc3e6fd160ac4aa9fc8b3bf71e1f74fbf92367ae71fb83a037e8bf164b9" -dependencies = [ - "memoffset", - "tempfile", - "winapi", -] - [[package]] name = "ulid" version = "1.2.1" @@ -7998,12 +7881,6 @@ dependencies = [ "serde", ] -[[package]] -name = "urlencoding" -version = "2.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "daf8dba3b7eb870caf1ddeed7bc9d2a049f3cfdfae7cb521b087cc33ae4c49da" - [[package]] name = "utf-8" version = "0.7.6" @@ -8023,7 +7900,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2f87b8aa10b915a06587d0dec516c282ff295b475d94abf425d62b57710070a2" dependencies = [ "js-sys", - "serde", "wasm-bindgen", ] @@ -8184,66 +8060,6 @@ dependencies = [ "web-sys", ] -[[package]] -name = "wayland-backend" -version = "0.3.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "673a33c33048a5ade91a6b139580fa174e19fb0d23f396dca9fa15f2e1e49b35" -dependencies = [ - "cc", - "downcast-rs", - "rustix", - "scoped-tls", - "smallvec", - "wayland-sys", -] - -[[package]] -name = "wayland-client" -version = "0.31.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c66a47e840dc20793f2264eb4b3e4ecb4b75d91c0dd4af04b456128e0bdd449d" -dependencies = [ - "bitflags 2.10.0", - "rustix", - "wayland-backend", - "wayland-scanner", -] - -[[package]] -name = "wayland-protocols" -version = "0.32.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "efa790ed75fbfd71283bd2521a1cfdc022aabcc28bdcff00851f9e4ae88d9901" -dependencies = [ - "bitflags 2.10.0", - "wayland-backend", - "wayland-client", - "wayland-scanner", -] - -[[package]] -name = "wayland-scanner" -version = "0.31.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "54cb1e9dc49da91950bdfd8b848c49330536d9d1fb03d4bfec8cae50caa50ae3" -dependencies = [ - "proc-macro2", - "quick-xml", - "quote", -] - -[[package]] -name = "wayland-sys" -version = "0.31.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "34949b42822155826b41db8e5d0c1be3a2bd296c747577a43a3e6daefc296142" -dependencies = [ - "dlib", - "log", - "pkg-config", -] - [[package]] name = "web-sys" version = "0.3.82" @@ -8808,9 +8624,9 @@ dependencies = [ [[package]] name = "winnow" -version = "0.7.13" +version = "0.7.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "21a0236b59786fed61e2a80582dd500fe61f18b5dca67a4a067d0bc9039339cf" +checksum = "5a5364e9d77fcdeeaa6062ced926ee3381faa2ee02d3eb83a5c27a8825540829" dependencies = [ "memchr", ] @@ -8984,62 +8800,6 @@ dependencies = [ "synstructure", ] -[[package]] -name = "zbus" -version = "5.12.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b622b18155f7a93d1cd2dc8c01d2d6a44e08fb9ebb7b3f9e6ed101488bad6c91" -dependencies = [ - "async-broadcast", - "async-recursion", - "async-trait", - "enumflags2", - "event-listener", - "futures-core", - "futures-lite", - "hex", - "nix", - "ordered-stream", - "serde", - "serde_repr", - "tokio", - "tracing", - "uds_windows", - "uuid", - "windows-sys 0.61.2", - "winnow 0.7.13", - "zbus_macros", - "zbus_names", - "zvariant", -] - -[[package]] -name = "zbus_macros" -version = "5.12.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1cdb94821ca8a87ca9c298b5d1cbd80e2a8b67115d99f6e4551ac49e42b6a314" -dependencies = [ - "proc-macro-crate 3.4.0", - "proc-macro2", - "quote", - "syn 2.0.108", - "zbus_names", - "zvariant", - "zvariant_utils", -] - -[[package]] -name = "zbus_names" -version = "4.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7be68e64bf6ce8db94f63e72f0c7eb9a60d733f7e0499e628dfab0f84d6bcb97" -dependencies = [ - "serde", - "static_assertions", - "winnow 0.7.13", - "zvariant", -] - [[package]] name = "zerocopy" version = "0.8.27" @@ -9147,44 +8907,3 @@ dependencies = [ "cc", "pkg-config", ] - -[[package]] -name = "zvariant" -version = "5.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2be61892e4f2b1772727be11630a62664a1826b62efa43a6fe7449521cb8744c" -dependencies = [ - "endi", - "enumflags2", - "serde", - "url", - "winnow 0.7.13", - "zvariant_derive", - "zvariant_utils", -] - -[[package]] -name = "zvariant_derive" -version = "5.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "da58575a1b2b20766513b1ec59d8e2e68db2745379f961f86650655e862d2006" -dependencies = [ - "proc-macro-crate 3.4.0", - "proc-macro2", - "quote", - "syn 2.0.108", - "zvariant_utils", -] - -[[package]] -name = "zvariant_utils" -version = "3.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c6949d142f89f6916deca2232cf26a8afacf2b9fdc35ce766105e104478be599" -dependencies = [ - "proc-macro2", - "quote", - "serde", - "syn 2.0.108", - "winnow 0.7.13", -] diff --git a/gui/src/effects.rs b/gui/src/effects.rs index b1aa12e..ef87bcd 100644 --- a/gui/src/effects.rs +++ b/gui/src/effects.rs @@ -10,6 +10,21 @@ use tracing::{error, info}; use crate::imp; static DF_MODEL: Asset = asset!("/assets/DeepFilterNet3_ll_onnx.tar.gz"); +// TODO: make this user configurable. +static DEFAULT_NOISE_FLOOR: f32 = 0.001; +// 200ms hold at 48kHz sample rate +static HOLD_SAMPLES_MAX: usize = 48000 / 5; // 9600 samples = 200ms + +/// Indicates the transmission state after processing audio. +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub enum TransmitState { + /// Audio is above threshold, or below but within hold period - transmit normally + Transmitting, + /// Hold period expired - send this frame as terminator (end_bit = true) + Terminator, + /// Silent and not transmitting - don't send anything + Silent, +} enum DenoisingModelState { Nothing, @@ -76,6 +91,11 @@ pub struct AudioProcessor { denoise: bool, spawn: imp::SpawnHandle, buffer: Vec, + noise_floor: f32, + /// Whether we were transmitting in the previous frame + was_transmitting: bool, + /// Number of samples we've been below threshold (for hold period) + hold_samples: usize, } impl AudioProcessor { @@ -84,6 +104,9 @@ impl AudioProcessor { denoise: false, spawn: imp::SpawnHandle::current(), buffer: Vec::new(), + noise_floor: DEFAULT_NOISE_FLOOR, + was_transmitting: false, + hold_samples: 0, } } @@ -92,12 +115,15 @@ impl AudioProcessor { denoise: true, spawn: imp::SpawnHandle::current(), buffer: Vec::new(), + noise_floor: DEFAULT_NOISE_FLOOR, + was_transmitting: false, + hold_samples: 0, } } } impl AudioProcessor { - pub fn process(&mut self, audio: &[f32], channels: usize, output: &mut Vec) { + pub fn process(&mut self, audio: &[f32], channels: usize, output: &mut Vec) -> TransmitState { let mut include_raw = true; if self.denoise { with_denoising_model(&self.spawn, |df| { @@ -132,6 +158,38 @@ impl AudioProcessor { if include_raw { output.extend(audio.iter().step_by(channels).copied()); } + + // Calculate average amplitude for VAD + let avg: f32 = if output.is_empty() { + 0.0 + } else { + output.iter().map(|x| x.abs()).sum::() / output.len() as f32 + }; + + let above_threshold = avg >= self.noise_floor; + let samples_in_frame = output.len(); + + let state = if above_threshold { + // Above threshold - reset hold counter and transmit + self.hold_samples = 0; + self.was_transmitting = true; + TransmitState::Transmitting + } else if self.was_transmitting && self.hold_samples < HOLD_SAMPLES_MAX { + // Below threshold but in hold period - keep transmitting + self.hold_samples += samples_in_frame; + TransmitState::Transmitting + } else if self.was_transmitting { + // Hold period expired - send terminator + self.was_transmitting = false; + self.hold_samples = 0; + TransmitState::Terminator + } else { + // Not transmitting and below threshold - stay silent + output.clear(); // Don't accumulate stale audio during silence + TransmitState::Silent + }; + + state } } diff --git a/gui/src/imp/native_audio.rs b/gui/src/imp/native_audio.rs index dda5c3a..3867bd6 100644 --- a/gui/src/imp/native_audio.rs +++ b/gui/src/imp/native_audio.rs @@ -1,4 +1,4 @@ -use crate::effects::{AudioProcessor, AudioProcessorSender}; +use crate::effects::{AudioProcessor, AudioProcessorSender, TransmitState}; use color_eyre::eyre::{eyre, Error}; use cpal::traits::{DeviceTrait, HostTrait, StreamTrait as _}; use futures::io::{AsyncRead, AsyncWrite}; @@ -23,6 +23,31 @@ pub struct AudioSystem { const SAMPLE_RATE: u32 = 48_000; const PACKET_SAMPLES: u32 = 960; +fn encode_and_send( + state: TransmitState, + output_buffer: &mut Vec, + encoder: &mut opus::Encoder, + each: &mut impl FnMut(Vec, bool), +) { + let (is_terminator, should_encode) = match state { + TransmitState::Silent => return, + TransmitState::Transmitting => (false, output_buffer.len() >= PACKET_SAMPLES as usize), + TransmitState::Terminator => { + output_buffer.resize(PACKET_SAMPLES as usize, 0.0); + (true, true) + } + }; + + if should_encode { + let remainder = output_buffer.split_off(PACKET_SAMPLES as usize); + let frame = replace(output_buffer, remainder); + match encoder.encode_vec_float(&frame, frame.len() * 2) { + Ok(encoded) => each(encoded, is_terminator), + Err(e) => error!("error encoding {} samples: {e:?}", frame.len()), + } + } +} + type Buffer = Arc>>>; impl AudioSystem { @@ -79,7 +104,7 @@ impl AudioSystem { pub fn start_recording( &mut self, - mut each: impl FnMut(Vec) + Send + 'static, + mut each: impl FnMut(Vec, bool) + Send + 'static, ) -> Result<(), Error> { let config = self.choose_config(self.input.supported_input_configs()?)?; info!( @@ -97,20 +122,8 @@ impl AudioSystem { if let Some(new_processor) = processors.take() { current_processor = new_processor; } - current_processor.process(frame, config.channels as usize, &mut output_buffer); - if output_buffer.len() < PACKET_SAMPLES as usize { - return; - } - let remainder = output_buffer.split_off(PACKET_SAMPLES as usize); - let frame = replace(&mut output_buffer, remainder); - match encoder.encode_vec_float(&frame, frame.len() * 2) { - Ok(buf) => { - each(buf); - } - Err(e) => { - error!("error encoding {} samples: {e:?}", frame.len()); - } - } + let state = current_processor.process(frame, config.channels as usize, &mut output_buffer); + encode_and_send(state, &mut output_buffer, &mut encoder, &mut each); }; match self diff --git a/gui/src/imp/web.rs b/gui/src/imp/web.rs index 5d8980a..4a6339c 100644 --- a/gui/src/imp/web.rs +++ b/gui/src/imp/web.rs @@ -1,6 +1,7 @@ use crate::app::Command; -use crate::effects::{AudioProcessor, AudioProcessorSender}; +use crate::effects::{AudioProcessor, AudioProcessorSender, TransmitState}; use color_eyre::eyre::{bail, eyre, Error}; +use crossbeam::atomic::AtomicCell; use dioxus::prelude::*; use futures::{AsyncRead, AsyncWrite}; use gloo_timers::future::TimeoutFuture; @@ -9,6 +10,7 @@ use mumble_protocol::control::ClientControlCodec; use mumble_web2_common::{ClientConfig, ServerStatus}; use reqwest::Url; use std::future::Future; +use std::sync::Arc; use std::time::Duration; use tracing::level_filters::LevelFilter; use tracing::{debug, error, info, instrument}; @@ -118,7 +120,10 @@ impl AudioSystem { self.processors.store(Some(processor)) } - pub fn start_recording(&mut self, each: impl FnMut(Vec) + 'static) -> Result<(), Error> { + pub fn start_recording( + &mut self, + each: impl FnMut(Vec, bool) + 'static, + ) -> Result<(), Error> { let audio_context_worklet = self.webctx.clone(); let processors = self.processors.clone(); spawn(async move { @@ -222,22 +227,26 @@ impl PromiseExt for Promise { } } -fn process_audio(frame: &JsValue, processor: &mut AudioProcessor) { +fn process_audio(frame: &JsValue, processor: &mut AudioProcessor) -> TransmitState { let Ok(samples) = Reflect::get(&frame, &"data".into()) else { - return; + return TransmitState::Silent; }; let Ok(samples) = samples.dyn_into::() else { - return; + return TransmitState::Silent; }; let input = samples.to_vec(); let mut output = Vec::with_capacity(input.len()); - processor.process(&input, 1, &mut output); - samples.copy_from(&output); + let state = processor.process(&input, 1, &mut output); + if !output.is_empty() { + samples.copy_from(&output); + } + + state } async fn run_encoder_worklet( audio_context: &AudioContext, - mut each: impl FnMut(Vec) + 'static, + mut each: impl FnMut(Vec, bool) + 'static, processors: AudioProcessorSender, ) -> Result { let constraints = MediaStreamConstraints::new(); @@ -262,12 +271,19 @@ async fn run_encoder_worklet( let encoder_error: Closure = Closure::new(|e| error!("error encoding audio {:?}", e)); + // Shared state to signal terminator between onmessage and output closures + // The output closure runs asynchronously after encoding completes + let pending_terminator = Arc::new(AtomicCell::new(false)); + let pending_terminator_output = pending_terminator.clone(); + // This knows what MediaStreamTrackGenerator to use as it closes around it let output: Closure = Closure::new(move |audio_data: EncodedAudioChunk| { let mut array = vec![0u8; audio_data.byte_length() as usize]; audio_data.copy_to_with_u8_slice(&mut array); - each(array); + // Check if this frame was marked as a terminator + let is_terminator = pending_terminator_output.swap(false); + each(array, is_terminator); }); let audio_encoder = AudioEncoder::new(&AudioEncoderInit::new( @@ -294,8 +310,19 @@ async fn run_encoder_worklet( } let frame = event.data(); - process_audio(&frame, &mut current_processor); + let state = process_audio(&frame, &mut current_processor); + match state { + TransmitState::Silent => { + // Don't encode or send anything + return; + } + TransmitState::Transmitting => (), // Normal transmission + TransmitState::Terminator => { + // Mark this as a terminator before encoding + pending_terminator.store(true); + } + } match AudioData::new(frame.unchecked_ref()) { Ok(data) => { let _ = audio_encoder.encode(&data); diff --git a/gui/src/lib.rs b/gui/src/lib.rs index 41a971d..d21a432 100644 --- a/gui/src/lib.rs +++ b/gui/src/lib.rs @@ -114,14 +114,14 @@ pub async fn network_loop( { let send_chan = send_chan.clone(); let mut sequence_num = 0; - audio.start_recording(move |opus_frame| { + audio.start_recording(move |opus_frame, is_terminator| { let _ = send_chan.unbounded_send(ControlPacket::UDPTunnel(Box::new(VoicePacket::Audio { _dst: std::marker::PhantomData, target: 0, session_id: (), seq_num: sequence_num, - payload: VoicePacketPayload::Opus(opus_frame.into(), false), + payload: VoicePacketPayload::Opus(opus_frame.into(), is_terminator), position_info: None, }))); sequence_num = sequence_num.wrapping_add(2);