refactored tap core into its own crate to eventually support a gui
This commit is contained in:
11 files changed
+328
-352
No files matched your search
Generated
+1
@@ -3,6 +3,7 @@
|
|||||||
<component name="NewModuleRootManager">
|
<component name="NewModuleRootManager">
|
||||||
<content url="file://$MODULE_DIR$">
|
<content url="file://$MODULE_DIR$">
|
||||||
<sourceFolder url="file://$MODULE_DIR$/src" isTestSource="false" />
|
<sourceFolder url="file://$MODULE_DIR$/src" isTestSource="false" />
|
||||||
|
<sourceFolder url="file://$MODULE_DIR$/tap_core/src" isTestSource="false" />
|
||||||
<excludeFolder url="file://$MODULE_DIR$/target" />
|
<excludeFolder url="file://$MODULE_DIR$/target" />
|
||||||
</content>
|
</content>
|
||||||
<orderEntry type="inheritedJdk" />
|
<orderEntry type="inheritedJdk" />
|
||||||
|
|||||||
Generated
+103
-111
@@ -33,12 +33,6 @@ dependencies = [
|
|||||||
"pkg-config",
|
"pkg-config",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "android-tzdata"
|
|
||||||
version = "0.1.1"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "e999941b234f3131b00bc13c22d06e8c5ff726d1b6318ac7eb276997bbb4fef0"
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "android_system_properties"
|
name = "android_system_properties"
|
||||||
version = "0.1.5"
|
version = "0.1.5"
|
||||||
@@ -161,16 +155,15 @@ checksum = "9555578bc9e57714c812a1f84e4fc5b4d21fcb063490c624de019f7464c91268"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "chrono"
|
name = "chrono"
|
||||||
version = "0.4.41"
|
version = "0.4.45"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "c469d952047f47f91b68d1cba3f10d63c11d73e4636f24f08daf0278abf01c4d"
|
checksum = "1aa79e62e7697b8e29b513a68abacf485adcd1fe8284a4316c5ae868e6633327"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"android-tzdata",
|
|
||||||
"iana-time-zone",
|
"iana-time-zone",
|
||||||
"js-sys",
|
"js-sys",
|
||||||
"num-traits",
|
"num-traits",
|
||||||
"wasm-bindgen",
|
"wasm-bindgen",
|
||||||
"windows-link 0.1.3",
|
"windows-link 0.2.1",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -210,7 +203,7 @@ dependencies = [
|
|||||||
"heck",
|
"heck",
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"syn",
|
"syn 2.0.104",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -327,7 +320,7 @@ checksum = "ba7795da175654fe16979af73f81f26a8ea27638d8d9823d317016888a63dc4c"
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
"num-traits",
|
"num-traits",
|
||||||
"quote",
|
"quote",
|
||||||
"syn",
|
"syn 2.0.104",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -361,9 +354,9 @@ checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "errno"
|
name = "errno"
|
||||||
version = "0.3.13"
|
version = "0.3.14"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "778e2ac28f6c47af28e4907f13ffd1e1ddbd400980a9abd7c8df189bf578a5ad"
|
checksum = "39cab71617ae0d63f51a36d69f866391735b51691dbda63cf6f96d042b63efeb"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"libc",
|
"libc",
|
||||||
"windows-sys 0.60.2",
|
"windows-sys 0.60.2",
|
||||||
@@ -371,9 +364,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "fastrand"
|
name = "fastrand"
|
||||||
version = "2.3.0"
|
version = "2.5.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "37909eebbb50d72f9059c3b6d82c0463f2ff062c9e95845c43a6c9c0355411be"
|
checksum = "da7c62ceae207dd37ea5b845da6a0696c799f85e97da1ab5b7910be3c1c80223"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "find-msvc-tools"
|
name = "find-msvc-tools"
|
||||||
@@ -388,10 +381,16 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||||||
checksum = "1d674e81391d1e1ab681a28d99df07927c6d4aa5b027d7da16ba32d1d21ecd99"
|
checksum = "1d674e81391d1e1ab681a28d99df07927c6d4aa5b027d7da16ba32d1d21ecd99"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "futures"
|
name = "foldhash"
|
||||||
version = "0.3.33"
|
version = "0.1.5"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "a88cf1f829d945f548cf8fec32c61b1f202b6d93b45848602fc02af4b12ad218"
|
checksum = "d9c4f5dac5e15c24eb999c26181a6ca40b39fe946cbe4c263c7209467bc83af2"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "futures"
|
||||||
|
version = "0.3.34"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "9a31d2a3fbaaeb2af2368bbdd904aa8e812d3c04a1ee10d3171f52d556e5d0a3"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"futures-channel",
|
"futures-channel",
|
||||||
"futures-core",
|
"futures-core",
|
||||||
@@ -404,9 +403,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "futures-channel"
|
name = "futures-channel"
|
||||||
version = "0.3.33"
|
version = "0.3.34"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "262590f4fe6afeb0bc83be1daa64e52657fe185690a958af7f3ad0e92085c5ae"
|
checksum = "b1f9e3d69d39e4862ffed03ed071a76f9a13ba1d9109d355b0f0aa6b15e393c4"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"futures-core",
|
"futures-core",
|
||||||
"futures-sink",
|
"futures-sink",
|
||||||
@@ -414,15 +413,15 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "futures-core"
|
name = "futures-core"
|
||||||
version = "0.3.33"
|
version = "0.3.34"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "2cd50c473c80f6d7c3670a752354b8e569b1a7cbfdc0419ec88e5edad85e0dc7"
|
checksum = "92d699e522242e69e3003b94ecc1f960f3a5e015aa7c5d7486e65ad01dd94f5e"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "futures-executor"
|
name = "futures-executor"
|
||||||
version = "0.3.33"
|
version = "0.3.34"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "6754879cc9f2c66f88c6e5c35344bb0bdb0708b0352b1201815667c7eabc7458"
|
checksum = "031b47cf1a3c6cc8bc2fc76cd437f521619387907d469316e7c0bc278f1f5432"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"futures-core",
|
"futures-core",
|
||||||
"futures-task",
|
"futures-task",
|
||||||
@@ -431,38 +430,38 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "futures-io"
|
name = "futures-io"
|
||||||
version = "0.3.33"
|
version = "0.3.34"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "4577ecaa3c4f96589d473f679a71b596316f6641bc350038b962a5daf0085d7a"
|
checksum = "53c0fa8157de1303bfffdaa1cc2a673bfffb60102f76b0ef4441659124373fed"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "futures-macro"
|
name = "futures-macro"
|
||||||
version = "0.3.33"
|
version = "0.3.34"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "2d6d3cde68c518367be28956066ddfef33813991b77a55005a69dae04bf3b10b"
|
checksum = "9fb9654ba8355388abeb8dcb4fc62f511300867002afc858860463bdd9fe0c44"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"syn",
|
"syn 3.0.6",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "futures-sink"
|
name = "futures-sink"
|
||||||
version = "0.3.33"
|
version = "0.3.34"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "e34418ac499d6305c2fb5ad0ed2f6ac998c5f8ca209b4510f7f94242c647e307"
|
checksum = "1944426bf7d03f1d14f708785e4b33efd750b36d48a157b836b3efc15ede8e1d"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "futures-task"
|
name = "futures-task"
|
||||||
version = "0.3.33"
|
version = "0.3.34"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "b231ed28831efb4a61a08580c4bc233ec56bc009f4cd8f52da2c3cb97df0c109"
|
checksum = "cd417de3d1d015fc3bfd2b1ea46dfc7bab72ef86f1cc7cc9c78e728b34a6d1fd"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "futures-util"
|
name = "futures-util"
|
||||||
version = "0.3.33"
|
version = "0.3.34"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "a77a90a256fce34da66415271e30f94ee91c57b04b8a2c042d9cf3220179deaa"
|
checksum = "0d50a92467f8ba5dd6e3ee5d4bd04d73ab2e4e1c44474a0674821dfce14b79bc"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"futures-channel",
|
"futures-channel",
|
||||||
"futures-core",
|
"futures-core",
|
||||||
@@ -475,23 +474,14 @@ dependencies = [
|
|||||||
"slab",
|
"slab",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "getrandom"
|
|
||||||
version = "0.3.3"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "26145e563e54f2cadc477553f1ec5ee650b00862f0a58bcd12cbdc5f0ea2d2f4"
|
|
||||||
dependencies = [
|
|
||||||
"cfg-if",
|
|
||||||
"libc",
|
|
||||||
"r-efi",
|
|
||||||
"wasi 0.14.3+wasi-0.2.4",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "hashbrown"
|
name = "hashbrown"
|
||||||
version = "0.15.5"
|
version = "0.15.5"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "9229cfe53dfd69f0609a49f65461bd93001ea1ef889cd5529dd176593f5338a1"
|
checksum = "9229cfe53dfd69f0609a49f65461bd93001ea1ef889cd5529dd176593f5338a1"
|
||||||
|
dependencies = [
|
||||||
|
"foldhash",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "heck"
|
name = "heck"
|
||||||
@@ -575,7 +565,7 @@ checksum = "03343451ff899767262ec32146f6d559dd759fdadf42ff0e227c7c48f72594b4"
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"syn",
|
"syn 2.0.104",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -590,7 +580,7 @@ dependencies = [
|
|||||||
"jni-sys 0.4.1",
|
"jni-sys 0.4.1",
|
||||||
"log",
|
"log",
|
||||||
"simd_cesu8",
|
"simd_cesu8",
|
||||||
"thiserror 2.0.12",
|
"thiserror 2.0.21",
|
||||||
"walkdir",
|
"walkdir",
|
||||||
"windows-link 0.2.1",
|
"windows-link 0.2.1",
|
||||||
]
|
]
|
||||||
@@ -605,7 +595,7 @@ dependencies = [
|
|||||||
"quote",
|
"quote",
|
||||||
"rustc_version",
|
"rustc_version",
|
||||||
"simd_cesu8",
|
"simd_cesu8",
|
||||||
"syn",
|
"syn 2.0.104",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -630,7 +620,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||||||
checksum = "38c0b942f458fe50cdac086d2f946512305e5631e720728f2a61aabcd47a6264"
|
checksum = "38c0b942f458fe50cdac086d2f946512305e5631e720728f2a61aabcd47a6264"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"quote",
|
"quote",
|
||||||
"syn",
|
"syn 2.0.104",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -651,9 +641,9 @@ checksum = "3eaf3ede3fee6db1a4c2ee091bf8a8b4dccdc6d17f656fb07896ee72867612f2"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "linux-raw-sys"
|
name = "linux-raw-sys"
|
||||||
version = "0.9.4"
|
version = "0.12.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "cd945864f07fe9f5371a27ad7b52a172b4b499999f1d97574c9fa68373937e12"
|
checksum = "32a66949e030da00e8c7d4434b251670a91556f4144941d37452769c25d58a53"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "log"
|
name = "log"
|
||||||
@@ -675,13 +665,13 @@ checksum = "32a282da65faaf38286cf3be983213fcf1d2e2a58700e808f83f4ea9a4804bc0"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "mio"
|
name = "mio"
|
||||||
version = "1.2.2"
|
version = "1.2.3"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "30d65c71f1ce40ab09135ce117d742b9f8a19ff91a41a8b57ed50bc2de59c427"
|
checksum = "4b18443e9c262bfe8fa82f51666e2642c53393f7e5c27b3e1aeab922cff5b9d8"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"libc",
|
"libc",
|
||||||
"log",
|
"log",
|
||||||
"wasi 0.11.1+wasi-snapshot-preview1",
|
"wasi",
|
||||||
"windows-sys 0.61.2",
|
"windows-sys 0.61.2",
|
||||||
]
|
]
|
||||||
|
|
||||||
@@ -728,7 +718,7 @@ checksum = "ed3955f1a9c7c0c15e092f9c887db08b1fc683305fdf6eb6684f22555355e202"
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"syn",
|
"syn 2.0.104",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -759,7 +749,7 @@ dependencies = [
|
|||||||
"proc-macro-crate",
|
"proc-macro-crate",
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"syn",
|
"syn 2.0.104",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -884,11 +874,12 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "petgraph"
|
name = "petgraph"
|
||||||
version = "0.7.1"
|
version = "0.8.3"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "3672b37090dbd86368a4145bc067582552b29c27377cad4e0a306c97f9bd7772"
|
checksum = "8701b58ea97060d5e5b155d383a69952a60943f0e6dfe30b04c287beb0b27455"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"fixedbitset",
|
"fixedbitset",
|
||||||
|
"hashbrown",
|
||||||
"indexmap",
|
"indexmap",
|
||||||
]
|
]
|
||||||
|
|
||||||
@@ -926,7 +917,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||||||
checksum = "ff24dfcda44452b9816fff4cd4227e1bb73ff5a2f1bc1105aa92fb8565ce44d2"
|
checksum = "ff24dfcda44452b9816fff4cd4227e1bb73ff5a2f1bc1105aa92fb8565ce44d2"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"syn",
|
"syn 2.0.104",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -959,21 +950,20 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "prost-build"
|
name = "prost-build"
|
||||||
version = "0.14.1"
|
version = "0.14.4"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "ac6c3320f9abac597dcbc668774ef006702672474aad53c6d596b62e487b40b1"
|
checksum = "03da047801ff44bb6a4d407d4860c05fd70bb81714e6b2f3812603d5b145b042"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"heck",
|
"heck",
|
||||||
"itertools",
|
"itertools",
|
||||||
"log",
|
"log",
|
||||||
"multimap",
|
"multimap",
|
||||||
"once_cell",
|
|
||||||
"petgraph",
|
"petgraph",
|
||||||
"prettyplease",
|
"prettyplease",
|
||||||
"prost",
|
"prost",
|
||||||
"prost-types",
|
"prost-types",
|
||||||
"regex",
|
"regex",
|
||||||
"syn",
|
"syn 2.0.104",
|
||||||
"tempfile",
|
"tempfile",
|
||||||
]
|
]
|
||||||
|
|
||||||
@@ -987,14 +977,14 @@ dependencies = [
|
|||||||
"itertools",
|
"itertools",
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"syn",
|
"syn 2.0.104",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "prost-types"
|
name = "prost-types"
|
||||||
version = "0.14.1"
|
version = "0.14.4"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "b9b4db3d6da204ed77bb26ba83b6122a73aeb2e87e25fbf7ad2e84c4ccbf8f72"
|
checksum = "f94967dc7688f3054c7fac87473ffae4cc4c3904800e2d9f5b857246d8963b0a"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"prost",
|
"prost",
|
||||||
]
|
]
|
||||||
@@ -1024,12 +1014,6 @@ dependencies = [
|
|||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "r-efi"
|
|
||||||
version = "5.3.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "69cdb34c158ceb288df11e18b4bd39de994f6657d83847bdffdbd7f346754b0f"
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "regex"
|
name = "regex"
|
||||||
version = "1.11.1"
|
version = "1.11.1"
|
||||||
@@ -1070,9 +1054,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "rustix"
|
name = "rustix"
|
||||||
version = "1.0.8"
|
version = "1.1.5"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "11181fbabf243db407ef8df94a6ce0b2f9a733bd8be4ad02b4eda9602296cac8"
|
checksum = "891efababe418670775f199f0d233d84843c227a0949a883ce15b37c78d6629d"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bitflags",
|
"bitflags",
|
||||||
"errno",
|
"errno",
|
||||||
@@ -1119,7 +1103,7 @@ checksum = "5b0276cf7f2c73365f7157c8123c21cd9a50fbbd844757af28ca1f5925fc2a00"
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"syn",
|
"syn 2.0.104",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -1167,6 +1151,17 @@ dependencies = [
|
|||||||
"unicode-ident",
|
"unicode-ident",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "syn"
|
||||||
|
version = "3.0.6"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "8593e8e72159ed2257d083c7a454a85cbf854f37a0966d8d483aff8c8a3ebcee"
|
||||||
|
dependencies = [
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"unicode-ident",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "tap"
|
name = "tap"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
@@ -1179,11 +1174,9 @@ dependencies = [
|
|||||||
"env_logger",
|
"env_logger",
|
||||||
"hound",
|
"hound",
|
||||||
"log",
|
"log",
|
||||||
"opus",
|
|
||||||
"opusic-sys",
|
|
||||||
"prost",
|
"prost",
|
||||||
"tap-interface",
|
"tap_core",
|
||||||
"thiserror 2.0.12",
|
"thiserror 2.0.21",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -1197,14 +1190,28 @@ dependencies = [
|
|||||||
"prost-types",
|
"prost-types",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "tap_core"
|
||||||
|
version = "0.1.0"
|
||||||
|
dependencies = [
|
||||||
|
"chrono",
|
||||||
|
"circular-buffer",
|
||||||
|
"cpal",
|
||||||
|
"log",
|
||||||
|
"opus",
|
||||||
|
"opusic-sys",
|
||||||
|
"prost",
|
||||||
|
"tap-interface",
|
||||||
|
"thiserror 2.0.21",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "tempfile"
|
name = "tempfile"
|
||||||
version = "3.21.0"
|
version = "3.27.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "15b61f8f20e3a6f7e0649d825294eaf317edce30f82cf6026e7e4cb9222a7d1e"
|
checksum = "32497e9a4c7b38532efcdebeef879707aa9f794296a4f0244f6f69e9bc8574bd"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"fastrand",
|
"fastrand",
|
||||||
"getrandom",
|
|
||||||
"once_cell",
|
"once_cell",
|
||||||
"rustix",
|
"rustix",
|
||||||
"windows-sys 0.60.2",
|
"windows-sys 0.60.2",
|
||||||
@@ -1221,11 +1228,11 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "thiserror"
|
name = "thiserror"
|
||||||
version = "2.0.12"
|
version = "2.0.21"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "567b8a2dae586314f7be2a752ec7474332959c6460e02bde30d702a66d488708"
|
checksum = "09e52cb86a36cede5cb101bf8908837b3e4c6e5e59fe7fd85c23fb56200d189e"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"thiserror-impl 2.0.12",
|
"thiserror-impl 2.0.21",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -1236,18 +1243,18 @@ checksum = "4fee6c4efc90059e10f81e6d42c60a18f76588c3d74cb83a0b242a2b6c7504c1"
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"syn",
|
"syn 2.0.104",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "thiserror-impl"
|
name = "thiserror-impl"
|
||||||
version = "2.0.12"
|
version = "2.0.21"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "7f7cf42b4507d8ea322120659672cf1b9dbb93f8f2d4ecfd6e51350ff5b17a1d"
|
checksum = "fe5197923287db20a58125f0bc85c062f7f2c892de97b18c356f9efb14b28524"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"syn",
|
"syn 3.0.6",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -1295,15 +1302,6 @@ version = "0.11.1+wasi-snapshot-preview1"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "ccf3ec651a847eb01de73ccad15eb7d99f80485de043efb2f370cd654f4ea44b"
|
checksum = "ccf3ec651a847eb01de73ccad15eb7d99f80485de043efb2f370cd654f4ea44b"
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "wasi"
|
|
||||||
version = "0.14.3+wasi-0.2.4"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "6a51ae83037bdd272a9e28ce236db8c07016dd0d50c27038b3f407533c030c95"
|
|
||||||
dependencies = [
|
|
||||||
"wit-bindgen",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "wasm-bindgen"
|
name = "wasm-bindgen"
|
||||||
version = "0.2.100"
|
version = "0.2.100"
|
||||||
@@ -1326,7 +1324,7 @@ dependencies = [
|
|||||||
"log",
|
"log",
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"syn",
|
"syn 2.0.104",
|
||||||
"wasm-bindgen-shared",
|
"wasm-bindgen-shared",
|
||||||
]
|
]
|
||||||
|
|
||||||
@@ -1348,7 +1346,7 @@ checksum = "8ae87ea40c9f689fc23f209965b6fb8a99ad69aeeb0231408be24920604395de"
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"syn",
|
"syn 2.0.104",
|
||||||
"wasm-bindgen-backend",
|
"wasm-bindgen-backend",
|
||||||
"wasm-bindgen-shared",
|
"wasm-bindgen-shared",
|
||||||
]
|
]
|
||||||
@@ -1447,7 +1445,7 @@ checksum = "053e2e040ab57b9dc951b72c264860db7eb3b0200ba345b4e4c3b14f67855ddf"
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"syn",
|
"syn 2.0.104",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -1458,7 +1456,7 @@ checksum = "3f316c4a2570ba26bbec722032c4099d8c8bc095efccdc15688708623367e358"
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"syn",
|
"syn 2.0.104",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -1692,9 +1690,3 @@ checksum = "f3edebf492c8125044983378ecb5766203ad3b4c2f7a922bd7dd207f6d443e95"
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
"memchr",
|
"memchr",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "wit-bindgen"
|
|
||||||
version = "0.45.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "052283831dbae3d879dc7f51f3d92703a316ca49f91540417d38591826127814"
|
|
||||||
+5
-4
@@ -4,19 +4,20 @@ version = "0.1.0"
|
|||||||
edition = "2024"
|
edition = "2024"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
cpal = { version = "0.18.2", features = ["pulseaudio"] }
|
|
||||||
clap = { version = "4.5.43", features = ["derive"] }
|
clap = { version = "4.5.43", features = ["derive"] }
|
||||||
anyhow = "1.0.98"
|
anyhow = "1.0.98"
|
||||||
log = "0.4.27"
|
log = "0.4.27"
|
||||||
env_logger = "0.11.8"
|
env_logger = "0.11.8"
|
||||||
opus= { version="0.4.0" }
|
|
||||||
thiserror = "2.0.12"
|
thiserror = "2.0.12"
|
||||||
circular-buffer = "2.0.1"
|
circular-buffer = "2.0.1"
|
||||||
chrono = "0.4.41"
|
chrono = "0.4.41"
|
||||||
hound = "3.5.1"
|
hound = "3.5.1"
|
||||||
tap-interface = {version = "0.1.0", registry = "ahines"}
|
|
||||||
prost = "0.14.1"
|
prost = "0.14.1"
|
||||||
opusic-sys = { version = "0.7.5", features = ["bundled", "no-stack-protector", "no-hardening", "no-fortify-source"] }
|
tap_core = {path = "tap_core"}
|
||||||
|
cpal = "0.18.2"
|
||||||
|
|
||||||
|
[workspace]
|
||||||
|
members = ["tap_core"]
|
||||||
|
|
||||||
[workspace.metadata.cross.target.x86_64-pc-windows-gnu]
|
[workspace.metadata.cross.target.x86_64-pc-windows-gnu]
|
||||||
pre-build = [
|
pre-build = [
|
||||||
|
|||||||
@@ -1,82 +0,0 @@
|
|||||||
use crate::udp_connection::OpusUdpConnection;
|
|
||||||
use crate::util::{SAMPLE_RATE, SAMPLE_RATE_RAW, STEREO_FRAME_SIZE, TAP_PACKET_MAX_DATA_LEN};
|
|
||||||
use anyhow::Error;
|
|
||||||
use chrono::Utc;
|
|
||||||
use log::{error, warn};
|
|
||||||
use opus::{Channels, Decoder};
|
|
||||||
use prost::Message;
|
|
||||||
use std::io::{ErrorKind, Read};
|
|
||||||
use std::net::SocketAddr;
|
|
||||||
use std::path::Path;
|
|
||||||
use tap_interface::tap::message::TapMessage;
|
|
||||||
|
|
||||||
pub fn record(addr: SocketAddr, output_path: &Path, duration_ms: u64) -> Result<(), Error> {
|
|
||||||
let mut decoder = Decoder::new(SAMPLE_RATE, Channels::Stereo)?;
|
|
||||||
|
|
||||||
let mut udp_connection = OpusUdpConnection::new(addr, addr)?;
|
|
||||||
|
|
||||||
let spec = hound::WavSpec {
|
|
||||||
channels: 2,
|
|
||||||
sample_rate: SAMPLE_RATE_RAW as u32,
|
|
||||||
bits_per_sample: 32,
|
|
||||||
sample_format: hound::SampleFormat::Float,
|
|
||||||
};
|
|
||||||
|
|
||||||
let mut seq_count = 0;
|
|
||||||
|
|
||||||
let mut writer = hound::WavWriter::create(output_path, spec)?;
|
|
||||||
|
|
||||||
let deadline = std::time::Instant::now() + std::time::Duration::from_millis(duration_ms);
|
|
||||||
|
|
||||||
while std::time::Instant::now() < deadline {
|
|
||||||
let mut packet = vec![0; TAP_PACKET_MAX_DATA_LEN];
|
|
||||||
let mut output_buffer = vec![0.0; STEREO_FRAME_SIZE];
|
|
||||||
|
|
||||||
let new_packet = match udp_connection.read(&mut packet) {
|
|
||||||
Ok(data_len) => Some(&packet[0..data_len]),
|
|
||||||
Err(err) => {
|
|
||||||
if err.kind() == ErrorKind::WouldBlock {
|
|
||||||
None
|
|
||||||
} else {
|
|
||||||
error!("Got error trying to recv from UDP: {err}");
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
let data_size = if let Some(new_packet) = new_packet {
|
|
||||||
let tap_message = TapMessage::decode(new_packet)?;
|
|
||||||
|
|
||||||
if tap_message.timestamp - Utc::now().timestamp() as u64 > 1 {
|
|
||||||
warn!(
|
|
||||||
"Packet outside of tolerance: packet.timestamp={} time={}",
|
|
||||||
tap_message.timestamp,
|
|
||||||
Utc::now().timestamp()
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
if tap_message.seq != seq_count {
|
|
||||||
warn!(
|
|
||||||
"Found sequence mismatch, expected seq={}, {tap_message:?}",
|
|
||||||
seq_count
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
(seq_count, _) = tap_message.seq.overflowing_add(1);
|
|
||||||
|
|
||||||
decoder.decode_float(&packet, &mut output_buffer, false)?
|
|
||||||
} else {
|
|
||||||
decoder.decode_float(&[], &mut output_buffer, false)?
|
|
||||||
} * 2;
|
|
||||||
|
|
||||||
for samples in output_buffer[..data_size].chunks(2) {
|
|
||||||
for sample in samples {
|
|
||||||
writer.write_sample(*sample)?;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
writer.finalize()?;
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
@@ -1,119 +0,0 @@
|
|||||||
use crate::tx_thread::TxThread;
|
|
||||||
use crate::udp_connection::OpusUdpConnection;
|
|
||||||
use crate::util::{SAMPLE_RATE, SAMPLE_RATE_RAW, STEREO_FRAME_SIZE, ThreadMessage};
|
|
||||||
use anyhow::Error;
|
|
||||||
use cpal::traits::{DeviceTrait, HostTrait, StreamTrait};
|
|
||||||
use cpal::{BufferSize, FromSample, Host, Sample, SampleRate, StreamConfig};
|
|
||||||
use log::{error, info};
|
|
||||||
use opus::{Application, Bitrate, Channels, Encoder, Signal};
|
|
||||||
use std::io::{Read, stdin};
|
|
||||||
use std::net::SocketAddr;
|
|
||||||
use std::sync::mpsc::{Sender, channel};
|
|
||||||
use std::thread;
|
|
||||||
|
|
||||||
pub fn tap(
|
|
||||||
device: &str,
|
|
||||||
src_addr: SocketAddr,
|
|
||||||
dest_addr: SocketAddr,
|
|
||||||
host: Host,
|
|
||||||
) -> Result<(), Error> {
|
|
||||||
// Set up the input device and stream with the default input config.
|
|
||||||
let device = if device == "default" {
|
|
||||||
host.default_input_device()
|
|
||||||
} else {
|
|
||||||
let id = &device.parse().expect("failed to parse input device id");
|
|
||||||
host.device_by_id(id)
|
|
||||||
}
|
|
||||||
.expect("failed to find input device");
|
|
||||||
|
|
||||||
for dev in host.input_devices()? {
|
|
||||||
info!("ID: {}", dev.id()?);
|
|
||||||
}
|
|
||||||
info!("Input device: {}", device.id()?);
|
|
||||||
|
|
||||||
let config = device
|
|
||||||
.default_input_config()
|
|
||||||
.expect("Failed to get default input config");
|
|
||||||
|
|
||||||
let mut stream_config = StreamConfig::from(config);
|
|
||||||
let count = stream_config.channels;
|
|
||||||
stream_config.sample_rate = SAMPLE_RATE_RAW as SampleRate;
|
|
||||||
stream_config.buffer_size = BufferSize::Fixed(STEREO_FRAME_SIZE as u32 / count as u32);
|
|
||||||
|
|
||||||
for cfg in device.supported_input_configs()? {
|
|
||||||
info!("{:?}", cfg)
|
|
||||||
}
|
|
||||||
|
|
||||||
info!("Stream config: {stream_config:?}");
|
|
||||||
|
|
||||||
let udp_connection = OpusUdpConnection::new(src_addr, dest_addr)?;
|
|
||||||
let mut encoder = Encoder::new(SAMPLE_RATE, Channels::Stereo, Application::Audio)?;
|
|
||||||
encoder.set_bitrate(Bitrate::Max)?;
|
|
||||||
encoder.set_complexity(10)?;
|
|
||||||
encoder.set_signal(Signal::Music)?;
|
|
||||||
|
|
||||||
let (sender, receiver) = channel();
|
|
||||||
|
|
||||||
let tx_thread = TxThread::new(receiver, encoder, udp_connection);
|
|
||||||
|
|
||||||
thread::spawn(move || tx_thread.thread());
|
|
||||||
|
|
||||||
let err_fn = move |err| {
|
|
||||||
error!("an error occurred on stream: {err}");
|
|
||||||
};
|
|
||||||
|
|
||||||
let stream = match config.sample_format() {
|
|
||||||
cpal::SampleFormat::I8 => device.build_input_stream(
|
|
||||||
stream_config,
|
|
||||||
move |data, _: &_| write_input_data::<i8>(data, &sender),
|
|
||||||
err_fn,
|
|
||||||
None,
|
|
||||||
)?,
|
|
||||||
cpal::SampleFormat::I16 => device.build_input_stream(
|
|
||||||
stream_config,
|
|
||||||
move |data, _: &_| write_input_data::<i16>(data, &sender),
|
|
||||||
err_fn,
|
|
||||||
None,
|
|
||||||
)?,
|
|
||||||
cpal::SampleFormat::I32 => device.build_input_stream(
|
|
||||||
stream_config,
|
|
||||||
move |data, _: &_| write_input_data::<i32>(data, &sender),
|
|
||||||
err_fn,
|
|
||||||
None,
|
|
||||||
)?,
|
|
||||||
cpal::SampleFormat::F32 => device.build_input_stream(
|
|
||||||
stream_config,
|
|
||||||
move |data, _: &_| write_input_data::<f32>(data, &sender),
|
|
||||||
err_fn,
|
|
||||||
None,
|
|
||||||
)?,
|
|
||||||
sample_format => {
|
|
||||||
return Err(anyhow::Error::msg(format!(
|
|
||||||
"Unsupported sample format '{sample_format}'"
|
|
||||||
)));
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
info!("Running tap...");
|
|
||||||
stream.play()?;
|
|
||||||
|
|
||||||
let mut stdin = stdin().lock();
|
|
||||||
|
|
||||||
let mut exit = [0u8; 1];
|
|
||||||
stdin.read_exact(&mut exit)?;
|
|
||||||
|
|
||||||
info!("Exiting...");
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn write_input_data<T>(input: &[T], ctx: &Sender<ThreadMessage>)
|
|
||||||
where
|
|
||||||
T: Sample,
|
|
||||||
f32: FromSample<T>,
|
|
||||||
{
|
|
||||||
let sample: Vec<f32> = input.iter().map(|s| f32::from_sample(*s)).collect();
|
|
||||||
|
|
||||||
if let Err(err) = ctx.send(ThreadMessage::Data(sample)) {
|
|
||||||
error!("Got error when sending data: {err}")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
+23
-24
@@ -1,14 +1,11 @@
|
|||||||
mod audio_record;
|
|
||||||
mod audio_source;
|
|
||||||
mod tx_thread;
|
|
||||||
mod udp_connection;
|
mod udp_connection;
|
||||||
mod util;
|
|
||||||
|
|
||||||
use crate::audio_record::record;
|
use crate::udp_connection::OpusUdpConnection;
|
||||||
use clap::{Parser, Subcommand};
|
use clap::{Parser, Subcommand};
|
||||||
use log::LevelFilter;
|
use log::{LevelFilter, error};
|
||||||
use std::net::SocketAddr;
|
use std::net::SocketAddr;
|
||||||
use std::path::PathBuf;
|
use std::sync::mpsc::channel;
|
||||||
|
use tap_core::audio_source_thread::AudioSourceThread;
|
||||||
|
|
||||||
#[derive(Parser, Debug)]
|
#[derive(Parser, Debug)]
|
||||||
#[command(version, about = "Tap sounds from a audio device and send them over a UDP socket", long_about = None)]
|
#[command(version, about = "Tap sounds from a audio device and send them over a UDP socket", long_about = None)]
|
||||||
@@ -29,18 +26,9 @@ enum Tasks {
|
|||||||
/// UDP socket addr to connect to
|
/// UDP socket addr to connect to
|
||||||
dest: SocketAddr,
|
dest: SocketAddr,
|
||||||
},
|
},
|
||||||
|
|
||||||
Record {
|
|
||||||
/// UDP addr to receive data on
|
|
||||||
addr: SocketAddr,
|
|
||||||
/// Number of MS to record for
|
|
||||||
duration_ms: u64,
|
|
||||||
/// Output file
|
|
||||||
output_file: PathBuf,
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn main() -> Result<(), anyhow::Error> {
|
fn main() {
|
||||||
env_logger::builder()
|
env_logger::builder()
|
||||||
.filter_level(LevelFilter::Info)
|
.filter_level(LevelFilter::Info)
|
||||||
.parse_default_env()
|
.parse_default_env()
|
||||||
@@ -50,11 +38,22 @@ fn main() -> Result<(), anyhow::Error> {
|
|||||||
let host = cpal::default_host();
|
let host = cpal::default_host();
|
||||||
|
|
||||||
match opt.command {
|
match opt.command {
|
||||||
Tasks::Tap { device, src, dest } => audio_source::tap(&device, src, dest, host),
|
Tasks::Tap { device, src, dest } => {
|
||||||
Tasks::Record {
|
let udp_connection = match OpusUdpConnection::new(src, dest) {
|
||||||
addr,
|
Ok(c) => c,
|
||||||
duration_ms,
|
Err(err) => {
|
||||||
output_file,
|
error!("Failed to open udp connection: {err}");
|
||||||
} => record(addr, &output_file, duration_ms),
|
return;
|
||||||
}
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
let (_sender, receiver) = channel();
|
||||||
|
|
||||||
|
let audio_source_thread = AudioSourceThread::new(device, host, receiver);
|
||||||
|
|
||||||
|
if let Err(err) = audio_source_thread.worker(udp_connection) {
|
||||||
|
error!("Error running tap: {err}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,15 @@
|
|||||||
|
[package]
|
||||||
|
name = "tap_core"
|
||||||
|
version = "0.1.0"
|
||||||
|
edition = "2024"
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
cpal = {version = "0.18.2", features = ["pulseaudio"]}
|
||||||
|
chrono = "0.4.45"
|
||||||
|
circular-buffer = "2.0.1"
|
||||||
|
log = "0.4.27"
|
||||||
|
prost = "0.14.4"
|
||||||
|
tap-interface = {version = "0.1.0", registry = "ahines"}
|
||||||
|
thiserror = "2.0.21"
|
||||||
|
opus= { version="0.4.0" }
|
||||||
|
opusic-sys = { version = "0.7.5", features = ["bundled", "no-stack-protector", "no-hardening", "no-fortify-source"] }
|
||||||
@@ -0,0 +1,171 @@
|
|||||||
|
use crate::tx_thread::TxThread;
|
||||||
|
use crate::util::{SAMPLE_RATE, SAMPLE_RATE_RAW, STEREO_FRAME_SIZE, ThreadMessage};
|
||||||
|
use cpal::traits::{DeviceTrait, HostTrait, StreamTrait};
|
||||||
|
use cpal::{BufferSize, FromSample, Host, Sample, SampleRate, Stream, StreamConfig};
|
||||||
|
use log::{debug, error, info};
|
||||||
|
use opus::{Application, Bitrate, Channels, Encoder, Signal};
|
||||||
|
use std::io::{Read, Write};
|
||||||
|
use std::sync::mpsc::{Receiver, Sender, channel};
|
||||||
|
use std::thread;
|
||||||
|
use thiserror::Error;
|
||||||
|
|
||||||
|
#[derive(Debug, Error)]
|
||||||
|
pub enum Error {
|
||||||
|
#[error("CPAL error: {0}")]
|
||||||
|
CpalError(#[from] cpal::Error),
|
||||||
|
#[error("Opus error: {0}")]
|
||||||
|
OpusError(#[from] opus::Error),
|
||||||
|
#[error("Unknown sample error format")]
|
||||||
|
UnknownSampleErrorFormat,
|
||||||
|
#[error("Unknown device")]
|
||||||
|
UnknownDevice,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub enum Commands {
|
||||||
|
SetDevice(String),
|
||||||
|
Pause,
|
||||||
|
Resume,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct AudioSourceThread {
|
||||||
|
device: String,
|
||||||
|
host: Host,
|
||||||
|
cmd_channel: Receiver<Commands>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl AudioSourceThread {
|
||||||
|
pub fn new(device: String, host: Host, cmd_channel: Receiver<Commands>) -> Self {
|
||||||
|
Self {
|
||||||
|
device,
|
||||||
|
host,
|
||||||
|
cmd_channel,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn setup_stream(&mut self, audio_sender: &Sender<ThreadMessage>) -> Result<Stream, Error> {
|
||||||
|
let device = if self.device == "default" {
|
||||||
|
self.host.default_input_device()
|
||||||
|
} else {
|
||||||
|
let id = &self.device.parse()?;
|
||||||
|
self.host.device_by_id(id)
|
||||||
|
};
|
||||||
|
|
||||||
|
let device = device.ok_or(Error::UnknownDevice)?;
|
||||||
|
|
||||||
|
info!("Input device: {}", device.id()?);
|
||||||
|
|
||||||
|
let config = device
|
||||||
|
.default_input_config()
|
||||||
|
.expect("Failed to get default input config");
|
||||||
|
|
||||||
|
let mut stream_config = StreamConfig::from(config);
|
||||||
|
let count = stream_config.channels;
|
||||||
|
stream_config.sample_rate = SAMPLE_RATE_RAW as SampleRate;
|
||||||
|
stream_config.buffer_size = BufferSize::Fixed(STEREO_FRAME_SIZE as u32 / count as u32);
|
||||||
|
|
||||||
|
info!("Stream config: {stream_config:?}");
|
||||||
|
|
||||||
|
for cfg in device.supported_input_configs()? {
|
||||||
|
debug!("{:?}", cfg)
|
||||||
|
}
|
||||||
|
|
||||||
|
let callback_sender = audio_sender.clone();
|
||||||
|
let stream = match config.sample_format() {
|
||||||
|
cpal::SampleFormat::I8 => device.build_input_stream(
|
||||||
|
stream_config,
|
||||||
|
move |data, _: &_| write_input_data::<i8>(data, &callback_sender),
|
||||||
|
err_fn,
|
||||||
|
None,
|
||||||
|
)?,
|
||||||
|
cpal::SampleFormat::I16 => device.build_input_stream(
|
||||||
|
stream_config,
|
||||||
|
move |data, _: &_| write_input_data::<i16>(data, &callback_sender),
|
||||||
|
err_fn,
|
||||||
|
None,
|
||||||
|
)?,
|
||||||
|
cpal::SampleFormat::I32 => device.build_input_stream(
|
||||||
|
stream_config,
|
||||||
|
move |data, _: &_| write_input_data::<i32>(data, &callback_sender),
|
||||||
|
err_fn,
|
||||||
|
None,
|
||||||
|
)?,
|
||||||
|
cpal::SampleFormat::F32 => device.build_input_stream(
|
||||||
|
stream_config,
|
||||||
|
move |data, _: &_| write_input_data::<f32>(data, &callback_sender),
|
||||||
|
err_fn,
|
||||||
|
None,
|
||||||
|
)?,
|
||||||
|
sample_format => {
|
||||||
|
error!("Unknown sample format: '{sample_format}'");
|
||||||
|
return Err(Error::UnknownSampleErrorFormat);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
Ok(stream)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn worker<T: Read + Write + Send + 'static>(mut self, connection: T) -> Result<(), Error> {
|
||||||
|
let encoder = Self::setup_encoder()?;
|
||||||
|
let (sender, receiver) = channel();
|
||||||
|
let tx_thread = TxThread::new(receiver, encoder, connection);
|
||||||
|
let thread = thread::spawn(move || tx_thread.thread());
|
||||||
|
|
||||||
|
let mut stream = self.setup_stream(&sender)?;
|
||||||
|
info!("Running...");
|
||||||
|
stream.play()?;
|
||||||
|
|
||||||
|
loop {
|
||||||
|
let msg = self.cmd_channel.recv();
|
||||||
|
|
||||||
|
if let Ok(msg) = msg {
|
||||||
|
match msg {
|
||||||
|
Commands::SetDevice(dev) => {
|
||||||
|
info!("Setting device to {dev}...");
|
||||||
|
self.device = dev;
|
||||||
|
drop(stream);
|
||||||
|
stream = self.setup_stream(&sender)?;
|
||||||
|
stream.play()?;
|
||||||
|
}
|
||||||
|
Commands::Pause => {
|
||||||
|
info!("Pausing Stream...");
|
||||||
|
stream.pause()?;
|
||||||
|
}
|
||||||
|
Commands::Resume => {
|
||||||
|
info!("Playing stream...");
|
||||||
|
stream.play()?;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
error!("Channel closing, stopping threads");
|
||||||
|
drop(sender);
|
||||||
|
thread.join().unwrap();
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn setup_encoder() -> Result<Encoder, Error> {
|
||||||
|
let mut encoder = Encoder::new(SAMPLE_RATE, Channels::Stereo, Application::Audio)?;
|
||||||
|
encoder.set_bitrate(Bitrate::Max)?;
|
||||||
|
encoder.set_complexity(10)?;
|
||||||
|
encoder.set_signal(Signal::Music)?;
|
||||||
|
Ok(encoder)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn err_fn(error: cpal::Error) {
|
||||||
|
error!("Got an error processing audio data: {error}")
|
||||||
|
}
|
||||||
|
|
||||||
|
fn write_input_data<T>(input: &[T], ctx: &Sender<ThreadMessage>)
|
||||||
|
where
|
||||||
|
T: Sample,
|
||||||
|
f32: FromSample<T>,
|
||||||
|
{
|
||||||
|
let sample: Vec<f32> = input.iter().map(|s| f32::from_sample(*s)).collect();
|
||||||
|
|
||||||
|
if let Err(err) = ctx.send(ThreadMessage::Data(sample)) {
|
||||||
|
error!("Got error when sending data: {err}")
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
pub mod audio_source_thread;
|
||||||
|
pub mod tx_thread;
|
||||||
|
pub mod util;
|
||||||
@@ -1,4 +1,3 @@
|
|||||||
use crate::udp_connection::OpusUdpConnection;
|
|
||||||
use crate::util::STEREO_FRAME_SIZE;
|
use crate::util::STEREO_FRAME_SIZE;
|
||||||
use crate::util::{CIRC_BUFFER_SIZE, TAP_PACKET_MAX_DATA_LEN, ThreadMessage};
|
use crate::util::{CIRC_BUFFER_SIZE, TAP_PACKET_MAX_DATA_LEN, ThreadMessage};
|
||||||
use chrono::Utc;
|
use chrono::Utc;
|
||||||
@@ -6,7 +5,7 @@ use circular_buffer::FixedCircularBuffer;
|
|||||||
use log::{error, info, warn};
|
use log::{error, info, warn};
|
||||||
use opus::Encoder;
|
use opus::Encoder;
|
||||||
use prost::Message;
|
use prost::Message;
|
||||||
use std::io::Write;
|
use std::io::{Read, Write};
|
||||||
use std::sync::mpsc::{Receiver, RecvError};
|
use std::sync::mpsc::{Receiver, RecvError};
|
||||||
use tap_interface::tap::message::TapMessage;
|
use tap_interface::tap::message::TapMessage;
|
||||||
use thiserror::Error;
|
use thiserror::Error;
|
||||||
@@ -21,25 +20,21 @@ pub enum Error {
|
|||||||
EncodeFailure(#[from] opus::Error),
|
EncodeFailure(#[from] opus::Error),
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct TxThread {
|
pub struct TxThread<T: Read + Write> {
|
||||||
receiver: Receiver<ThreadMessage>,
|
receiver: Receiver<ThreadMessage>,
|
||||||
encoder: Encoder,
|
encoder: Encoder,
|
||||||
opus_udp_connection: OpusUdpConnection,
|
opus_connection: T,
|
||||||
circular_buffer: FixedCircularBuffer<f32, CIRC_BUFFER_SIZE>,
|
circular_buffer: FixedCircularBuffer<f32, CIRC_BUFFER_SIZE>,
|
||||||
seq_count: u32,
|
seq_count: u32,
|
||||||
exit: bool,
|
exit: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl TxThread {
|
impl<T: Read + Write> TxThread<T> {
|
||||||
pub fn new(
|
pub fn new(receiver: Receiver<ThreadMessage>, encoder: Encoder, opus_connection: T) -> Self {
|
||||||
receiver: Receiver<ThreadMessage>,
|
|
||||||
encoder: Encoder,
|
|
||||||
opus_udp_connection: OpusUdpConnection,
|
|
||||||
) -> Self {
|
|
||||||
Self {
|
Self {
|
||||||
receiver,
|
receiver,
|
||||||
encoder,
|
encoder,
|
||||||
opus_udp_connection,
|
opus_connection,
|
||||||
circular_buffer: Default::default(),
|
circular_buffer: Default::default(),
|
||||||
seq_count: 0,
|
seq_count: 0,
|
||||||
exit: false,
|
exit: false,
|
||||||
@@ -63,7 +58,7 @@ impl TxThread {
|
|||||||
audio_data: output_buffer,
|
audio_data: output_buffer,
|
||||||
};
|
};
|
||||||
|
|
||||||
self.opus_udp_connection
|
self.opus_connection
|
||||||
.write_all(tap_message.encode_to_vec().as_slice())?;
|
.write_all(tap_message.encode_to_vec().as_slice())?;
|
||||||
|
|
||||||
(self.seq_count, _) = self.seq_count.overflowing_add(1);
|
(self.seq_count, _) = self.seq_count.overflowing_add(1);
|
||||||
File renamed without changes.
Reference in new issue
Block a user