aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.gitignore1
-rw-r--r--Cargo.lock494
-rw-r--r--Cargo.toml1
-rw-r--r--dmvop.toml81
-rw-r--r--src/args.rs3
-rw-r--r--src/device_selector.rs78
-rw-r--r--src/main.rs22
7 files changed, 649 insertions, 31 deletions
diff --git a/.gitignore b/.gitignore
index ea8c4bf..12ab8d8 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1 +1,2 @@
/target
+/models
diff --git a/Cargo.lock b/Cargo.lock
index 26f6e6e..675bc9c 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -41,6 +41,28 @@ dependencies = [
]
[[package]]
+name = "alsa"
+version = "0.11.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "812947049edcd670a82cd5c73c3661d2e58468577ba8489de58e1a73c04cbd5d"
+dependencies = [
+ "alsa-sys",
+ "bitflags 2.13.0",
+ "cfg-if",
+ "libc",
+]
+
+[[package]]
+name = "alsa-sys"
+version = "0.4.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ad7569085a265dd3f607ebecce7458eaab2132a84393534c95b18dcbc3f31e04"
+dependencies = [
+ "libc",
+ "pkg-config",
+]
+
+[[package]]
name = "android_system_properties"
version = "0.1.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -214,7 +236,16 @@ version = "0.5.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2c132eebf10f5cad5289222520a4a058514204aed6d791f1cf4fe8088b82d15f"
dependencies = [
- "objc2",
+ "objc2 0.5.2",
+]
+
+[[package]]
+name = "block2"
+version = "0.6.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "cdeb9d870516001442e364c5220d3574d2da8dc765554b4a617230d33fa58ef5"
+dependencies = [
+ "objc2 0.6.4",
]
[[package]]
@@ -372,6 +403,16 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1d07550c9036bf2ae0c684c4297d503f838287c83c53686d05370d0e139ae570"
[[package]]
+name = "combine"
+version = "4.6.7"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ba5a308b75df32fe02788e748662718f03fde005016435c444eea572398219fd"
+dependencies = [
+ "bytes",
+ "memchr",
+]
+
+[[package]]
name = "constant_time_eq"
version = "0.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -433,6 +474,20 @@ dependencies = [
]
[[package]]
+name = "coreaudio-rs"
+version = "0.14.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7d5d7dca3ebcf65a035582c9ad4385371a9d9ee6537474d2a278f4e1e475bb58"
+dependencies = [
+ "bitflags 2.13.0",
+ "libc",
+ "objc2-audio-toolbox",
+ "objc2-core-audio",
+ "objc2-core-audio-types",
+ "objc2-core-foundation",
+]
+
+[[package]]
name = "coreaudio-sys"
version = "0.2.18"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -442,6 +497,36 @@ dependencies = [
]
[[package]]
+name = "cpal"
+version = "0.18.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5f77b11176c37874be37e8d691c946e31b2b8c357abce9526f6a99eb469e1028"
+dependencies = [
+ "alsa",
+ "block2 0.6.2",
+ "coreaudio-rs 0.14.2",
+ "dasp_sample",
+ "jni",
+ "js-sys",
+ "libc",
+ "mach2",
+ "ndk",
+ "ndk-context",
+ "num-derive",
+ "num-traits",
+ "objc2 0.6.4",
+ "objc2-audio-toolbox",
+ "objc2-avf-audio",
+ "objc2-core-audio",
+ "objc2-core-audio-types",
+ "objc2-core-foundation",
+ "objc2-foundation 0.3.2",
+ "web-sys",
+ "windows 0.62.2",
+ "windows-core 0.62.2",
+]
+
+[[package]]
name = "cpufeatures"
version = "0.2.17"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -500,6 +585,12 @@ dependencies = [
]
[[package]]
+name = "dasp_sample"
+version = "0.11.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0c87e182de0887fd5361989c677c4e8f5000cd9491d6d563161a8f3a5519fc7f"
+
+[[package]]
name = "deflate64"
version = "0.1.12"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -561,6 +652,16 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bd0c93bb4b0c6d9b77f4435b0ae98c24d17f1c45b2ff844c6151a07256ca923b"
[[package]]
+name = "dispatch2"
+version = "0.3.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1e0e367e4e7da84520dedcac1901e4da967309406d1e51017ae1abfb97adbd38"
+dependencies = [
+ "bitflags 2.13.0",
+ "objc2 0.6.4",
+]
+
+[[package]]
name = "displaydoc"
version = "0.2.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -576,6 +677,7 @@ name = "dumb-voice-protocol"
version = "0.1.0"
dependencies = [
"clap",
+ "cpal",
"pinyin",
"serde",
"tokio",
@@ -1152,6 +1254,64 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8f42a60cbdf9a97f5d2305f08a87dc4e09308d1276d28c869c684d7777685682"
[[package]]
+name = "jni"
+version = "0.22.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5efd9a482cf3a427f00d6b35f14332adc7902ce91efb778580e180ff90fa3498"
+dependencies = [
+ "cfg-if",
+ "combine",
+ "jni-macros",
+ "jni-sys 0.4.1",
+ "log",
+ "simd_cesu8",
+ "thiserror 2.0.18",
+ "walkdir",
+ "windows-link",
+]
+
+[[package]]
+name = "jni-macros"
+version = "0.22.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a00109accc170f0bdb141fed3e393c565b6f5e072365c3bd58f5b062591560a3"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "rustc_version",
+ "simd_cesu8",
+ "syn",
+]
+
+[[package]]
+name = "jni-sys"
+version = "0.3.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "41a652e1f9b6e0275df1f15b32661cf0d4b78d4d87ddec5e0c3c20f097433258"
+dependencies = [
+ "jni-sys 0.4.1",
+]
+
+[[package]]
+name = "jni-sys"
+version = "0.4.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c6377a88cb3910bee9b0fa88d4f42e1d2da8e79915598f65fb0c7ee14c878af2"
+dependencies = [
+ "jni-sys-macros",
+]
+
+[[package]]
+name = "jni-sys-macros"
+version = "0.4.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "38c0b942f458fe50cdac086d2f946512305e5631e720728f2a61aabcd47a6264"
+dependencies = [
+ "quote",
+ "syn",
+]
+
+[[package]]
name = "jobserver"
version = "0.1.34"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -1286,6 +1446,12 @@ dependencies = [
]
[[package]]
+name = "mach2"
+version = "0.6.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "dae608c151f68243f2b000364e1f7b186d9c29845f7d2d85bd31b9ad77ad552b"
+
+[[package]]
name = "malloc_buf"
version = "0.0.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -1360,6 +1526,35 @@ dependencies = [
]
[[package]]
+name = "ndk"
+version = "0.9.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c3f42e7bbe13d351b6bead8286a43aac9534b82bd3cc43e47037f012ebfd62d4"
+dependencies = [
+ "bitflags 2.13.0",
+ "jni-sys 0.3.1",
+ "log",
+ "ndk-sys",
+ "num_enum",
+ "thiserror 1.0.69",
+]
+
+[[package]]
+name = "ndk-context"
+version = "0.1.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "27b02d87554356db9e9a873add8782d4ea6e3e58ea071a9adb9a2e8ddb884a8b"
+
+[[package]]
+name = "ndk-sys"
+version = "0.6.0+11769913"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ee6cda3051665f1fb8d9e08fc35c96d5a244fb1be711a03b71118828afc9a873"
+dependencies = [
+ "jni-sys 0.3.1",
+]
+
+[[package]]
name = "nix"
version = "0.27.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -1405,6 +1600,17 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "521739c6d2bac4aa25192232afe6841231376b2b26d4d9fae5ecf8ca5772e441"
[[package]]
+name = "num-derive"
+version = "0.4.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ed3955f1a9c7c0c15e092f9c887db08b1fc683305fdf6eb6684f22555355e202"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn",
+]
+
+[[package]]
name = "num-integer"
version = "0.1.46"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -1423,6 +1629,28 @@ dependencies = [
]
[[package]]
+name = "num_enum"
+version = "0.7.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5d0bca838442ec211fa11de3a8b0e0e8f3a4522575b5c4c06ed722e005036f26"
+dependencies = [
+ "num_enum_derive",
+ "rustversion",
+]
+
+[[package]]
+name = "num_enum_derive"
+version = "0.7.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "680998035259dcfcafe653688bf2aa6d3e2dc05e98be6ab46afb089dc84f1df8"
+dependencies = [
+ "proc-macro-crate",
+ "proc-macro2",
+ "quote",
+ "syn",
+]
+
+[[package]]
name = "objc"
version = "0.2.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -1460,6 +1688,77 @@ dependencies = [
]
[[package]]
+name = "objc2"
+version = "0.6.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3a12a8ed07aefc768292f076dc3ac8c48f3781c8f2d5851dd3d98950e8c5a89f"
+dependencies = [
+ "objc2-encode",
+]
+
+[[package]]
+name = "objc2-audio-toolbox"
+version = "0.3.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6948501a91121d6399b79abaa33a8aa4ea7857fe019f341b8c23ad6e81b79b08"
+dependencies = [
+ "bitflags 2.13.0",
+ "libc",
+ "objc2 0.6.4",
+ "objc2-core-audio",
+ "objc2-core-audio-types",
+ "objc2-core-foundation",
+ "objc2-foundation 0.3.2",
+]
+
+[[package]]
+name = "objc2-avf-audio"
+version = "0.3.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "13a380031deed8e99db00065c45937da434ca987c034e13b87e4441f9e4090be"
+dependencies = [
+ "bitflags 2.13.0",
+ "objc2 0.6.4",
+ "objc2-foundation 0.3.2",
+]
+
+[[package]]
+name = "objc2-core-audio"
+version = "0.3.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e1eebcea8b0dbff5f7c8504f3107c68fc061a3eb44932051c8cf8a68d969c3b2"
+dependencies = [
+ "dispatch2",
+ "objc2 0.6.4",
+ "objc2-core-audio-types",
+ "objc2-core-foundation",
+ "objc2-foundation 0.3.2",
+]
+
+[[package]]
+name = "objc2-core-audio-types"
+version = "0.3.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5a89f2ec274a0cf4a32642b2991e8b351a404d290da87bb6a9a9d8632490bd1c"
+dependencies = [
+ "bitflags 2.13.0",
+ "objc2 0.6.4",
+]
+
+[[package]]
+name = "objc2-core-foundation"
+version = "0.3.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2a180dd8642fa45cdb7dd721cd4c11b1cadd4929ce112ebd8b9f5803cc79d536"
+dependencies = [
+ "bitflags 2.13.0",
+ "block2 0.6.2",
+ "dispatch2",
+ "libc",
+ "objc2 0.6.4",
+]
+
+[[package]]
name = "objc2-encode"
version = "4.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -1472,10 +1771,23 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0ee638a5da3799329310ad4cfa62fbf045d5f56e3ef5ba4149e7452dcf89d5a8"
dependencies = [
"bitflags 2.13.0",
- "block2",
+ "block2 0.5.1",
"dispatch",
"libc",
- "objc2",
+ "objc2 0.5.2",
+]
+
+[[package]]
+name = "objc2-foundation"
+version = "0.3.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e3e0adef53c21f888deb4fa59fc59f7eb17404926ee8a6f59f5df0fd7f9f3272"
+dependencies = [
+ "bitflags 2.13.0",
+ "block2 0.6.2",
+ "libc",
+ "objc2 0.6.4",
+ "objc2-core-foundation",
]
[[package]]
@@ -1667,6 +1979,15 @@ dependencies = [
]
[[package]]
+name = "proc-macro-crate"
+version = "3.5.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e67ba7e9b2b56446f1d419b1d807906278ffa1a658a8a5d8a39dcb1f5a78614f"
+dependencies = [
+ "toml_edit 0.25.12+spec-1.1.0",
+]
+
+[[package]]
name = "proc-macro2"
version = "1.0.106"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -1816,6 +2137,15 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "94300abf3f1ae2e2b8ffb7b58043de3d399c73fa6f4b73826402a5c457614dbe"
[[package]]
+name = "rustc_version"
+version = "0.4.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "cfcb3a22ef46e85b45de6ee7e79d063319ebb6594faafcf1c225ea92ab6e9b92"
+dependencies = [
+ "semver",
+]
+
+[[package]]
name = "rustfft"
version = "6.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -1888,6 +2218,15 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9774ba4a74de5f7b1c1451ed6cd5285a32eddb5cccb8cc655a4e50009e06477f"
[[package]]
+name = "same-file"
+version = "1.0.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502"
+dependencies = [
+ "winapi-util",
+]
+
+[[package]]
name = "schannel"
version = "0.1.29"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -1940,6 +2279,12 @@ dependencies = [
]
[[package]]
+name = "semver"
+version = "1.0.28"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8a7852d02fc848982e0c167ef163aaff9cd91dc640ba85e263cb1ce46fae51cd"
+
+[[package]]
name = "serde"
version = "1.0.228"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -2052,6 +2397,22 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "703d5c7ef118737c72f1af64ad2f6f8c5e1921f818cdcb97b8fe6fc69bf66214"
[[package]]
+name = "simd_cesu8"
+version = "1.1.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "94f90157bb87cddf702797c5dadfa0be7d266cdf49e22da2fcaa32eff75b2c33"
+dependencies = [
+ "rustc_version",
+ "simdutf8",
+]
+
+[[package]]
+name = "simdutf8"
+version = "0.1.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e3a9fe34e3e7a50316060351f37187a3f546bce95496156754b601a5fa71b76e"
+
+[[package]]
name = "slab"
version = "0.4.12"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -2328,8 +2689,8 @@ checksum = "dc1beb996b9d83529a9e75c17a1686767d148d70663143c7854d8b4a09ced362"
dependencies = [
"serde",
"serde_spanned",
- "toml_datetime",
- "toml_edit",
+ "toml_datetime 0.6.11",
+ "toml_edit 0.22.27",
]
[[package]]
@@ -2342,6 +2703,15 @@ dependencies = [
]
[[package]]
+name = "toml_datetime"
+version = "1.1.1+spec-1.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3165f65f62e28e0115a00b2ebdd37eb6f3b641855f9d636d3cd4103767159ad7"
+dependencies = [
+ "serde_core",
+]
+
+[[package]]
name = "toml_edit"
version = "0.22.27"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -2350,9 +2720,30 @@ dependencies = [
"indexmap",
"serde",
"serde_spanned",
- "toml_datetime",
+ "toml_datetime 0.6.11",
"toml_write",
- "winnow",
+ "winnow 0.7.15",
+]
+
+[[package]]
+name = "toml_edit"
+version = "0.25.12+spec-1.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d2153edc6955a6c354fad8f5efd38b6a8769bdccf9fe50f8e1329f81b0baa5d7"
+dependencies = [
+ "indexmap",
+ "toml_datetime 1.1.1+spec-1.1.0",
+ "toml_parser",
+ "winnow 1.0.3",
+]
+
+[[package]]
+name = "toml_parser"
+version = "1.1.2+spec-1.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a2abe9b86193656635d2411dc43050282ca48aa31c2451210f4202550afb7526"
+dependencies = [
+ "winnow 1.0.3",
]
[[package]]
@@ -2578,18 +2969,18 @@ version = "0.3.1"
source = "git+https://github.com/Weicao-CatilGrass/vtx-engine?rev=35b954ad50ec6211e6a25ca4777d1685311f696e#35b954ad50ec6211e6a25ca4777d1685311f696e"
dependencies = [
"aec3",
- "block2",
+ "block2 0.5.1",
"chrono",
"core-foundation 0.10.1",
- "coreaudio-rs",
+ "coreaudio-rs 0.11.3",
"directories",
"dispatch",
"futures",
"hound",
"libc",
"libloading",
- "objc2",
- "objc2-foundation",
+ "objc2 0.5.2",
+ "objc2-foundation 0.2.2",
"pipewire",
"reqwest",
"rustfft",
@@ -2600,11 +2991,21 @@ dependencies = [
"toml",
"tracing",
"uuid",
- "windows",
+ "windows 0.58.0",
"zip",
]
[[package]]
+name = "walkdir"
+version = "2.5.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "29790946404f91d9c5d06f9874efddea1dc06c5efe94541a7d6863108e3a5e4b"
+dependencies = [
+ "same-file",
+ "winapi-util",
+]
+
+[[package]]
name = "want"
version = "0.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -2723,6 +3124,15 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
[[package]]
+name = "winapi-util"
+version = "0.1.11"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c2a7b1c03c876122aa43f3020e6c3c3ee5c05081c9a00739faf7503aeba10d22"
+dependencies = [
+ "windows-sys 0.61.2",
+]
+
+[[package]]
name = "winapi-x86_64-pc-windows-gnu"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -2739,6 +3149,27 @@ dependencies = [
]
[[package]]
+name = "windows"
+version = "0.62.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "527fadee13e0c05939a6a05d5bd6eec6cd2e3dbd648b9f8e447c6518133d8580"
+dependencies = [
+ "windows-collections",
+ "windows-core 0.62.2",
+ "windows-future",
+ "windows-numerics",
+]
+
+[[package]]
+name = "windows-collections"
+version = "0.3.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "23b2d95af1a8a14a3c7367e1ed4fc9c20e0a26e79551b1454d72583c97cc6610"
+dependencies = [
+ "windows-core 0.62.2",
+]
+
+[[package]]
name = "windows-core"
version = "0.58.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -2765,6 +3196,17 @@ dependencies = [
]
[[package]]
+name = "windows-future"
+version = "0.3.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e1d6f90251fe18a279739e78025bd6ddc52a7e22f921070ccdc67dde84c605cb"
+dependencies = [
+ "windows-core 0.62.2",
+ "windows-link",
+ "windows-threading",
+]
+
+[[package]]
name = "windows-implement"
version = "0.58.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -2815,6 +3257,16 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f0805222e57f7521d6a62e36fa9163bc891acd422f971defe97d64e70d0a4fe5"
[[package]]
+name = "windows-numerics"
+version = "0.3.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6e2e40844ac143cdb44aead537bbf727de9b044e107a0f1220392177d15b0f26"
+dependencies = [
+ "windows-core 0.62.2",
+ "windows-link",
+]
+
+[[package]]
name = "windows-registry"
version = "0.6.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -2921,6 +3373,15 @@ dependencies = [
]
[[package]]
+name = "windows-threading"
+version = "0.2.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3949bd5b99cafdf1c7ca86b43ca564028dfe27d66958f2470940f73d86d75b37"
+dependencies = [
+ "windows-link",
+]
+
+[[package]]
name = "windows_aarch64_gnullvm"
version = "0.48.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -3020,6 +3481,15 @@ dependencies = [
]
[[package]]
+name = "winnow"
+version = "1.0.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0592e1c9d151f854e6fd382574c3a0855250e1d9b2f99d9281c6e6391af352f1"
+dependencies = [
+ "memchr",
+]
+
+[[package]]
name = "wit-bindgen"
version = "0.57.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
diff --git a/Cargo.toml b/Cargo.toml
index d8fc385..fe20b28 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -15,6 +15,7 @@ toml = "0.8"
tokio = { version = "1.52.3", features = ["net", "rt", "rt-multi-thread", "macros"] }
tracing-subscriber = { version = "0.3.19", features = ["env-filter"] }
pinyin = { version = "0.11.0", features = ["with_tone", "with_tone_num", "with_tone_num_end"] }
+cpal = "0.18.1"
[dependencies.vtx-engine]
git = "https://github.com/Weicao-CatilGrass/vtx-engine"
diff --git a/dmvop.toml b/dmvop.toml
new file mode 100644
index 0000000..c80bacb
--- /dev/null
+++ b/dmvop.toml
@@ -0,0 +1,81 @@
+## DMVOP Config File
+## Name this file `dmvop.toml` and place it in the working dir to be auto-detected!
+##
+## DMVOP will auto-load this config file to avoid repeated CLI args
+
+## Your audio input device, you can query with `dmvop --list-devices`
+## Use `auto` to automatically get the device in use
+device = "auto"
+
+## Output format
+## Sets the text format after transcription
+## Supported parameters:
+## - %{vol} Volume
+## - %{word} Content
+## - %{confid} Confidence score
+format = "%{word} (%%{vol})" # Hello. (%50)
+
+## Whisper model selection
+## Use `dmvop --list-models` to view available models
+## Use `dmvop --download-model=<NAME>` to download available models
+## (Model download and reading directory is configured in `models_dir`, relative to the current configuration directory)
+model = "base.en"
+
+## Expected language for Whisper to recognize
+## This makes it more inclined to recognize the specified language
+lang = "en"
+
+## Expected output mode
+output = [
+ ## Directly use stdout to output to terminal
+ "stdout",
+
+ ## Directly use stderr to output to terminal
+ # "stderr",
+
+ ## TCP service mode
+ ## After the client connects to the current port (port configured in `port`)
+ ## DMVOP will automatically broadcast output to all connected clients
+ # "tcp",
+
+ ## UDP service mode
+ ## The client sends a message packet to the current port to complete the handshake (port configured in `port`)
+ ## After that, DMVOP will automatically send content to the first client that handshook
+ # "udp",
+
+ ## UDP broadcast mode
+ ## When enabled, DMVOP will directly broadcast messages to all devices on the LAN listening to the specified port
+ ## (port configured in `port`, subnet mask configured in `subnet_mask`)
+ # "udp-broadcast",
+
+ ## IPC socket mode
+ ## Sends messages to the specified Unix socket file
+ ## (use `socket_file` to specify the socket file)
+ ## Note: This mode is only supported on UNIX
+ # "ipc"
+]
+
+## Port used in UDP / TCP / UDP_BROADCAST mode
+port = 5117
+
+## Instant mode
+## Shorter detection time, closer to real-time
+instant = false
+
+## Model file storage directory
+## Used to specify the directory for downloading and reading Whisper model files
+## (Relative to the current configuration directory)
+models_dir = "./models"
+
+## Subnet mask
+## Used in UDP broadcast mode to specify the subnet mask for broadcasting
+subnet_mask = "255.255.255.0"
+
+## IPC socket file path
+## Used in IPC socket mode to specify the Unix socket file
+## Note: This mode is only supported on UNIX systems
+socket_file = "./dmvop.sock"
+
+## Post-processor
+## After text parsing, a post-processor can be used to process the text content
+# post = "+pinyin(tone)"
diff --git a/src/args.rs b/src/args.rs
index 9a4bd0d..1f0b7df 100644
--- a/src/args.rs
+++ b/src/args.rs
@@ -69,7 +69,8 @@ pub struct DMVOPArguments {
long = "device",
alias = "dev",
allow_hyphen_values = true,
- require_equals = true
+ require_equals = true,
+ default_value = "auto"
)]
pub device_name: Option<String>,
diff --git a/src/device_selector.rs b/src/device_selector.rs
new file mode 100644
index 0000000..12f8a79
--- /dev/null
+++ b/src/device_selector.rs
@@ -0,0 +1,78 @@
+use cpal::traits::{DeviceTrait, HostTrait};
+
+/// Pick the best input device from the available list.
+///
+/// - `"auto"` → query OS default input device via cpal, match against list
+/// - `"<name>"` → match by device ID or name; exits if not found
+/// - `None` → exits with error
+pub fn pick_device<'a>(
+ name: &Option<String>,
+ devices: &'a [vtx_engine::AudioDevice],
+) -> Option<&'a vtx_engine::AudioDevice> {
+ let name = match name {
+ Some(n) if n == "auto" || n.is_empty() => return pick_auto(devices),
+ Some(n) => n.as_str(),
+ None => {
+ eprintln!(
+ "[dmvop] No device specified. Use --device=<name> or --list-devices to see available devices."
+ );
+ std::process::exit(1);
+ }
+ };
+
+ // Try exact match by id or name
+ if let Some(d) = devices.iter().find(|d| d.id == name || d.name == name) {
+ return Some(d);
+ }
+
+ eprintln!(
+ "[dmvop] Device '{}' not found. Use --list-devices to see available devices.",
+ name
+ );
+ std::process::exit(1);
+}
+
+/// Use cpal to find the system's default input device, then match it
+/// against the vtx-engine device list by WASAPI ID.
+fn pick_auto<'a>(devices: &'a [vtx_engine::AudioDevice]) -> Option<&'a vtx_engine::AudioDevice> {
+ let host = cpal::default_host();
+ let device = match host.default_input_device() {
+ Some(d) => d,
+ None => {
+ eprintln!("[dmvop] No default input device found.");
+ return devices.first();
+ }
+ };
+
+ // Get the WASAPI device ID from cpal
+ let cpal_device_id = match device.id() {
+ Ok(id) => id,
+ Err(_) => return devices.first(),
+ };
+ let cpal_raw_id = cpal_device_id.id().to_string();
+
+ // Match against vtx-engine devices by ID (substring — cpal might omit braces)
+ for dev in devices {
+ let dev_id_clean = dev.id.trim_matches('{').trim_matches('}');
+ let cpal_id_clean = cpal_raw_id.trim_matches('{').trim_matches('}');
+ if dev_id_clean.contains(cpal_id_clean) || cpal_id_clean.contains(dev_id_clean) {
+ return Some(dev);
+ }
+ }
+
+ // Fallback: match by name (cpal DeviceId Display includes host:raw_id)
+ let cpal_display = cpal_device_id.to_string().to_lowercase();
+ for dev in devices {
+ if cpal_display.contains(&dev.name.to_lowercase())
+ || dev.name.to_lowercase().contains(&cpal_display)
+ {
+ return Some(dev);
+ }
+ }
+
+ eprintln!(
+ "[dmvop] Default device ({}) not matched, using first available.",
+ cpal_raw_id
+ );
+ devices.first()
+}
diff --git a/src/main.rs b/src/main.rs
index 2aa68ac..87f7657 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -3,7 +3,9 @@ pub mod post_proc;
mod args;
pub use args::*;
+mod device_selector;
mod output_protocol;
+
use clap::Parser;
use output_protocol::OutputProtocol;
use std::path::PathBuf;
@@ -220,30 +222,14 @@ async fn main() {
// ---------------------------------------------------------------
// Find the requested device and start capture
// ---------------------------------------------------------------
- let device_name = match &args.device_name {
- Some(n) => n.as_str(),
- None => {
- eprintln!(
- "[dmvop] No device specified. Use --device=<name> or --list-devices to see available devices."
- );
- std::process::exit(1);
- }
- };
-
- let device = devices
- .iter()
- .find(|d| d.id == device_name || d.name == device_name)
- .or_else(|| devices.first());
+ let device = device_selector::pick_device(&args.device_name, &devices);
match &device {
Some(d) => {
debug_log!("[dmvop] Using input device: {} (id: {})", d.name, d.id);
}
None => {
- eprintln!(
- "[dmvop] Device '{}' not found and no fallback available.",
- device_name
- );
+ eprintln!("[dmvop] No input devices found. Make sure a microphone is connected.");
std::process::exit(1);
}
}