mirror of
https://github.com/jamiepine/voicebox.git
synced 2026-09-20 15:20:39 -07:00
Enhance AudioPlayer component for native playback and debugging
- Improved the useNativePlayback logic to include detailed console logging for better debugging. - Updated auto-play functionality to fetch runtime profile channels and channels, ensuring accurate playback decisions. - Refactored audio playback handling to support native audio routing with enhanced error handling and logging. - Introduced a new MultiSelect component for improved channel selection in VoicesTab. - Updated FloatingGenerateBox to include selectedProfileId in audio setting. - Added new dependencies for audio processing in Cargo.toml and Cargo.lock.
This commit is contained in:
Generated
+383
-5
@@ -32,6 +32,28 @@ dependencies = [
|
||||
"alloc-no-stdlib",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "alsa"
|
||||
version = "0.9.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ed7572b7ba83a31e20d1b48970ee402d2e3e0537dcfe0a3ff4d6eb7508617d43"
|
||||
dependencies = [
|
||||
"alsa-sys",
|
||||
"bitflags 2.10.0",
|
||||
"cfg-if",
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "alsa-sys"
|
||||
version = "0.3.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "db8fee663d06c4e303404ef5f40488a53e062f89ba8bfed81f42325aafad1527"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"pkg-config",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "android_system_properties"
|
||||
version = "0.1.5"
|
||||
@@ -56,6 +78,12 @@ dependencies = [
|
||||
"derive_arbitrary",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "arrayvec"
|
||||
version = "0.7.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7c02d123df017efcdfbd739ef81735b36c5ba83ec3c59c80a9d7ecc718f92e50"
|
||||
|
||||
[[package]]
|
||||
name = "atk"
|
||||
version = "0.18.2"
|
||||
@@ -276,6 +304,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6354c81bbfd62d9cfa9cb3c773c2b7b2a3a482d569de977fd0e961f6e7c00583"
|
||||
dependencies = [
|
||||
"find-msvc-tools",
|
||||
"jobserver",
|
||||
"libc",
|
||||
"shlex",
|
||||
]
|
||||
|
||||
@@ -416,6 +446,17 @@ dependencies = [
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "coreaudio-rs"
|
||||
version = "0.11.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "321077172d79c662f64f5071a03120748d5bb652f5231570141be24cfcd2bace"
|
||||
dependencies = [
|
||||
"bitflags 1.3.2",
|
||||
"core-foundation-sys",
|
||||
"coreaudio-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "coreaudio-sys"
|
||||
version = "0.2.17"
|
||||
@@ -425,6 +466,29 @@ dependencies = [
|
||||
"bindgen",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "cpal"
|
||||
version = "0.15.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "873dab07c8f743075e57f524c583985fbaf745602acbe916a01539364369a779"
|
||||
dependencies = [
|
||||
"alsa",
|
||||
"core-foundation-sys",
|
||||
"coreaudio-rs",
|
||||
"dasp_sample",
|
||||
"jni",
|
||||
"js-sys",
|
||||
"libc",
|
||||
"mach2",
|
||||
"ndk 0.8.0",
|
||||
"ndk-context",
|
||||
"oboe",
|
||||
"wasm-bindgen",
|
||||
"wasm-bindgen-futures",
|
||||
"web-sys",
|
||||
"windows 0.54.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "cpufeatures"
|
||||
version = "0.2.17"
|
||||
@@ -540,6 +604,12 @@ dependencies = [
|
||||
"syn 2.0.114",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "dasp_sample"
|
||||
version = "0.11.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0c87e182de0887fd5361989c677c4e8f5000cd9491d6d563161a8f3a5519fc7f"
|
||||
|
||||
[[package]]
|
||||
name = "deranged"
|
||||
version = "0.5.5"
|
||||
@@ -755,6 +825,12 @@ dependencies = [
|
||||
"windows-sys 0.61.2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "extended"
|
||||
version = "0.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "af9673d8203fcb076b19dfd17e38b3d4ae9f44959416ea532ce72415a6020365"
|
||||
|
||||
[[package]]
|
||||
name = "fastrand"
|
||||
version = "2.3.0"
|
||||
@@ -1653,6 +1729,16 @@ version = "0.3.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8eaf4bc02d17cbdd7ff4c7438cafcdf7fb9a4613313ad11b4f8fefe7d3fa0130"
|
||||
|
||||
[[package]]
|
||||
name = "jobserver"
|
||||
version = "0.1.34"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9afb3de4395d6b3e67a780b6de64b51c978ecf11cb9a462c66be7d4ca9039d33"
|
||||
dependencies = [
|
||||
"getrandom 0.3.4",
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "js-sys"
|
||||
version = "0.3.85"
|
||||
@@ -1814,6 +1900,15 @@ version = "0.1.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c41e0c4fef86961ac6d6f8a82609f55f31b05e4fce149ac5710e439df7619ba4"
|
||||
|
||||
[[package]]
|
||||
name = "mach2"
|
||||
version = "0.4.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d640282b302c0bb0a2a8e0233ead9035e3bed871f0b7e81fe4a1ec829765db44"
|
||||
dependencies = [
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "malloc_buf"
|
||||
version = "0.0.6"
|
||||
@@ -1929,6 +2024,20 @@ dependencies = [
|
||||
"windows-sys 0.60.2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ndk"
|
||||
version = "0.8.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2076a31b7010b17a38c01907c45b945e8f11495ee4dd588309718901b1f7a5b7"
|
||||
dependencies = [
|
||||
"bitflags 2.10.0",
|
||||
"jni-sys",
|
||||
"log",
|
||||
"ndk-sys 0.5.0+25.2.9519653",
|
||||
"num_enum",
|
||||
"thiserror 1.0.69",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ndk"
|
||||
version = "0.9.0"
|
||||
@@ -1938,7 +2047,7 @@ dependencies = [
|
||||
"bitflags 2.10.0",
|
||||
"jni-sys",
|
||||
"log",
|
||||
"ndk-sys",
|
||||
"ndk-sys 0.6.0+11769913",
|
||||
"num_enum",
|
||||
"raw-window-handle",
|
||||
"thiserror 1.0.69",
|
||||
@@ -1950,6 +2059,15 @@ version = "0.1.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "27b02d87554356db9e9a873add8782d4ea6e3e58ea071a9adb9a2e8ddb884a8b"
|
||||
|
||||
[[package]]
|
||||
name = "ndk-sys"
|
||||
version = "0.5.0+25.2.9519653"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8c196769dd60fd4f363e11d948139556a344e79d451aeb2fa2fd040738ef7691"
|
||||
dependencies = [
|
||||
"jni-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ndk-sys"
|
||||
version = "0.6.0+11769913"
|
||||
@@ -1987,6 +2105,17 @@ version = "0.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "cf97ec579c3c42f953ef76dbf8d55ac91fb219dde70e49aa4a6b7d74e9919050"
|
||||
|
||||
[[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 2.0.114",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "num-integer"
|
||||
version = "0.1.46"
|
||||
@@ -2260,6 +2389,29 @@ dependencies = [
|
||||
"objc2-security",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "oboe"
|
||||
version = "0.6.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e8b61bebd49e5d43f5f8cc7ee2891c16e0f41ec7954d36bcb6c14c5e0de867fb"
|
||||
dependencies = [
|
||||
"jni",
|
||||
"ndk 0.8.0",
|
||||
"ndk-context",
|
||||
"num-derive",
|
||||
"num-traits",
|
||||
"oboe-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "oboe-sys"
|
||||
version = "0.6.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6c8bb09a4a2b1d668170cfe0a7d5bc103f8999fb316c98099b6a9939c9f2e79d"
|
||||
dependencies = [
|
||||
"cc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "once_cell"
|
||||
version = "1.21.3"
|
||||
@@ -3448,7 +3600,7 @@ checksum = "aac18da81ebbf05109ab275b157c22a653bb3c12cf884450179942f81bcbf6c3"
|
||||
dependencies = [
|
||||
"bytemuck",
|
||||
"js-sys",
|
||||
"ndk",
|
||||
"ndk 0.9.0",
|
||||
"objc2",
|
||||
"objc2-core-foundation",
|
||||
"objc2-core-graphics",
|
||||
@@ -3542,6 +3694,201 @@ dependencies = [
|
||||
"serde_json",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "symphonia"
|
||||
version = "0.5.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5773a4c030a19d9bfaa090f49746ff35c75dfddfa700df7a5939d5e076a57039"
|
||||
dependencies = [
|
||||
"lazy_static",
|
||||
"symphonia-bundle-flac",
|
||||
"symphonia-bundle-mp3",
|
||||
"symphonia-codec-aac",
|
||||
"symphonia-codec-adpcm",
|
||||
"symphonia-codec-alac",
|
||||
"symphonia-codec-pcm",
|
||||
"symphonia-codec-vorbis",
|
||||
"symphonia-core",
|
||||
"symphonia-format-caf",
|
||||
"symphonia-format-isomp4",
|
||||
"symphonia-format-mkv",
|
||||
"symphonia-format-ogg",
|
||||
"symphonia-format-riff",
|
||||
"symphonia-metadata",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "symphonia-bundle-flac"
|
||||
version = "0.5.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c91565e180aea25d9b80a910c546802526ffd0072d0b8974e3ebe59b686c9976"
|
||||
dependencies = [
|
||||
"log",
|
||||
"symphonia-core",
|
||||
"symphonia-metadata",
|
||||
"symphonia-utils-xiph",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "symphonia-bundle-mp3"
|
||||
version = "0.5.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4872dd6bb56bf5eac799e3e957aa1981086c3e613b27e0ac23b176054f7c57ed"
|
||||
dependencies = [
|
||||
"lazy_static",
|
||||
"log",
|
||||
"symphonia-core",
|
||||
"symphonia-metadata",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "symphonia-codec-aac"
|
||||
version = "0.5.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4c263845aa86881416849c1729a54c7f55164f8b96111dba59de46849e73a790"
|
||||
dependencies = [
|
||||
"lazy_static",
|
||||
"log",
|
||||
"symphonia-core",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "symphonia-codec-adpcm"
|
||||
version = "0.5.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2dddc50e2bbea4cfe027441eece77c46b9f319748605ab8f3443350129ddd07f"
|
||||
dependencies = [
|
||||
"log",
|
||||
"symphonia-core",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "symphonia-codec-alac"
|
||||
version = "0.5.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8413fa754942ac16a73634c9dfd1500ed5c61430956b33728567f667fdd393ab"
|
||||
dependencies = [
|
||||
"log",
|
||||
"symphonia-core",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "symphonia-codec-pcm"
|
||||
version = "0.5.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4e89d716c01541ad3ebe7c91ce4c8d38a7cf266a3f7b2f090b108fb0cb031d95"
|
||||
dependencies = [
|
||||
"log",
|
||||
"symphonia-core",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "symphonia-codec-vorbis"
|
||||
version = "0.5.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f025837c309cd69ffef572750b4a2257b59552c5399a5e49707cc5b1b85d1c73"
|
||||
dependencies = [
|
||||
"log",
|
||||
"symphonia-core",
|
||||
"symphonia-utils-xiph",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "symphonia-core"
|
||||
version = "0.5.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ea00cc4f79b7f6bb7ff87eddc065a1066f3a43fe1875979056672c9ef948c2af"
|
||||
dependencies = [
|
||||
"arrayvec",
|
||||
"bitflags 1.3.2",
|
||||
"bytemuck",
|
||||
"lazy_static",
|
||||
"log",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "symphonia-format-caf"
|
||||
version = "0.5.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b8faf379316b6b6e6bbc274d00e7a592e0d63ff1a7e182ce8ba25e24edd3d096"
|
||||
dependencies = [
|
||||
"log",
|
||||
"symphonia-core",
|
||||
"symphonia-metadata",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "symphonia-format-isomp4"
|
||||
version = "0.5.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "243739585d11f81daf8dac8d9f3d18cc7898f6c09a259675fc364b382c30e0a5"
|
||||
dependencies = [
|
||||
"encoding_rs",
|
||||
"log",
|
||||
"symphonia-core",
|
||||
"symphonia-metadata",
|
||||
"symphonia-utils-xiph",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "symphonia-format-mkv"
|
||||
version = "0.5.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "122d786d2c43a49beb6f397551b4a050d8229eaa54c7ddf9ee4b98899b8742d0"
|
||||
dependencies = [
|
||||
"lazy_static",
|
||||
"log",
|
||||
"symphonia-core",
|
||||
"symphonia-metadata",
|
||||
"symphonia-utils-xiph",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "symphonia-format-ogg"
|
||||
version = "0.5.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2b4955c67c1ed3aa8ae8428d04ca8397fbef6a19b2b051e73b5da8b1435639cb"
|
||||
dependencies = [
|
||||
"log",
|
||||
"symphonia-core",
|
||||
"symphonia-metadata",
|
||||
"symphonia-utils-xiph",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "symphonia-format-riff"
|
||||
version = "0.5.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c2d7c3df0e7d94efb68401d81906eae73c02b40d5ec1a141962c592d0f11a96f"
|
||||
dependencies = [
|
||||
"extended",
|
||||
"log",
|
||||
"symphonia-core",
|
||||
"symphonia-metadata",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "symphonia-metadata"
|
||||
version = "0.5.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "36306ff42b9ffe6e5afc99d49e121e0bd62fe79b9db7b9681d48e29fa19e6b16"
|
||||
dependencies = [
|
||||
"encoding_rs",
|
||||
"lazy_static",
|
||||
"log",
|
||||
"symphonia-core",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "symphonia-utils-xiph"
|
||||
version = "0.5.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ee27c85ab799a338446b68eec77abf42e1a6f1bb490656e121c6e27bfbab9f16"
|
||||
dependencies = [
|
||||
"symphonia-core",
|
||||
"symphonia-metadata",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "syn"
|
||||
version = "1.0.109"
|
||||
@@ -3618,9 +3965,9 @@ dependencies = [
|
||||
"lazy_static",
|
||||
"libc",
|
||||
"log",
|
||||
"ndk",
|
||||
"ndk 0.9.0",
|
||||
"ndk-context",
|
||||
"ndk-sys",
|
||||
"ndk-sys 0.6.0+11769913",
|
||||
"objc2",
|
||||
"objc2-app-kit",
|
||||
"objc2-foundation",
|
||||
@@ -4498,12 +4845,14 @@ dependencies = [
|
||||
"base64 0.22.1",
|
||||
"core-foundation-sys",
|
||||
"coreaudio-sys",
|
||||
"cpal",
|
||||
"hound",
|
||||
"objc",
|
||||
"scopeguard",
|
||||
"screencapturekit",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"symphonia",
|
||||
"tauri",
|
||||
"tauri-build",
|
||||
"tauri-plugin-dialog",
|
||||
@@ -4816,6 +5165,16 @@ dependencies = [
|
||||
"windows-version",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows"
|
||||
version = "0.54.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9252e5725dbed82865af151df558e754e4a3c2c30818359eb17465f1346a1b49"
|
||||
dependencies = [
|
||||
"windows-core 0.54.0",
|
||||
"windows-targets 0.52.6",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows"
|
||||
version = "0.61.3"
|
||||
@@ -4859,6 +5218,16 @@ dependencies = [
|
||||
"windows-core 0.62.2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows-core"
|
||||
version = "0.54.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "12661b9c89351d684a50a8a643ce5f608e20243b9fb84687800163429f161d65"
|
||||
dependencies = [
|
||||
"windows-result 0.1.2",
|
||||
"windows-targets 0.52.6",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows-core"
|
||||
version = "0.61.2"
|
||||
@@ -4961,6 +5330,15 @@ dependencies = [
|
||||
"windows-link 0.2.1",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows-result"
|
||||
version = "0.1.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5e383302e8ec8515204254685643de10811af0ed97ea37210dc26fb0032647f8"
|
||||
dependencies = [
|
||||
"windows-targets 0.52.6",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows-result"
|
||||
version = "0.3.4"
|
||||
@@ -5316,7 +5694,7 @@ dependencies = [
|
||||
"jni",
|
||||
"kuchikiki",
|
||||
"libc",
|
||||
"ndk",
|
||||
"ndk 0.9.0",
|
||||
"objc2",
|
||||
"objc2-app-kit",
|
||||
"objc2-core-foundation",
|
||||
|
||||
@@ -23,7 +23,7 @@ tokio = { version = "1", features = ["full"] }
|
||||
hound = "3.5"
|
||||
base64 = "0.22"
|
||||
cpal = "0.15"
|
||||
symphonia = { version = "0.5", features = ["wav", "pcm"] }
|
||||
symphonia = { version = "0.5", features = ["all"] }
|
||||
scopeguard = "1.2.0"
|
||||
|
||||
[target.'cfg(target_os = "macos")'.dependencies]
|
||||
|
||||
Binary file not shown.
@@ -58,10 +58,16 @@ impl AudioOutputState {
|
||||
audio_data: Vec<u8>,
|
||||
device_ids: Vec<String>,
|
||||
) -> Result<(), String> {
|
||||
eprintln!("play_audio_to_devices called with {} bytes, {} device IDs", audio_data.len(), device_ids.len());
|
||||
eprintln!("Requested device IDs: {:?}", device_ids);
|
||||
|
||||
// Decode audio file (assuming WAV format)
|
||||
eprintln!("Decoding audio data...");
|
||||
let (samples, sample_rate, channels) = self.decode_wav(&audio_data)?;
|
||||
eprintln!("Audio decoded: {} samples, {}Hz, {} channels", samples.len(), sample_rate, channels);
|
||||
|
||||
// Find devices by ID
|
||||
eprintln!("Enumerating output devices...");
|
||||
let devices: Vec<Device> = self
|
||||
.host
|
||||
.output_devices()
|
||||
@@ -69,7 +75,9 @@ impl AudioOutputState {
|
||||
.filter_map(|device| {
|
||||
let name = device.name().ok()?;
|
||||
let id = format!("device_{}", name.replace(' ', "_").to_lowercase());
|
||||
eprintln!("Found device: {} (id: {})", name, id);
|
||||
if device_ids.contains(&id) {
|
||||
eprintln!(" -> Matched! Will play to this device");
|
||||
Some(device)
|
||||
} else {
|
||||
None
|
||||
@@ -78,15 +86,21 @@ impl AudioOutputState {
|
||||
.collect();
|
||||
|
||||
if devices.is_empty() {
|
||||
eprintln!("ERROR: No matching devices found");
|
||||
return Err("No matching devices found".to_string());
|
||||
}
|
||||
|
||||
eprintln!("Playing to {} device(s)", devices.len());
|
||||
// Play to each device
|
||||
for device in devices {
|
||||
self.play_to_device(&device, samples.clone(), sample_rate, channels)
|
||||
.map_err(|e| format!("Failed to play to device: {}", e))?;
|
||||
for (i, device) in devices.iter().enumerate() {
|
||||
let device_name = device.name().unwrap_or_else(|_| "unknown".to_string());
|
||||
eprintln!("Playing to device {}/{}: {}", i + 1, devices.len(), device_name);
|
||||
self.play_to_device(device, samples.clone(), sample_rate, channels)
|
||||
.map_err(|e| format!("Failed to play to device {}: {}", device_name, e))?;
|
||||
eprintln!("Successfully started playback on device: {}", device_name);
|
||||
}
|
||||
|
||||
eprintln!("play_audio_to_devices completed successfully");
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -94,83 +108,120 @@ impl AudioOutputState {
|
||||
use symphonia::core::formats::FormatOptions;
|
||||
use symphonia::core::io::MediaSourceStream;
|
||||
use symphonia::core::meta::MetadataOptions;
|
||||
use symphonia::core::probe::Probe;
|
||||
|
||||
eprintln!("decode_wav: Creating MediaSourceStream from {} bytes", data.len());
|
||||
let mss = MediaSourceStream::new(
|
||||
Box::new(std::io::Cursor::new(data)),
|
||||
Box::new(std::io::Cursor::new(data.to_vec())),
|
||||
Default::default(),
|
||||
);
|
||||
|
||||
let mut probe = Probe::default();
|
||||
let mut format = probe
|
||||
eprintln!("decode_wav: Probing audio format...");
|
||||
let mut format = symphonia::default::get_probe()
|
||||
.format(
|
||||
&Default::default(),
|
||||
mss,
|
||||
&FormatOptions::default(),
|
||||
&MetadataOptions::default(),
|
||||
)
|
||||
.map_err(|e| format!("Failed to probe audio: {}", e))?
|
||||
.map_err(|e| {
|
||||
eprintln!("decode_wav: Failed to probe audio: {}", e);
|
||||
format!("Failed to probe audio: {}", e)
|
||||
})?
|
||||
.format;
|
||||
|
||||
eprintln!("decode_wav: Audio format probed successfully");
|
||||
|
||||
eprintln!("decode_wav: Finding audio track...");
|
||||
let track = format
|
||||
.tracks()
|
||||
.iter()
|
||||
.find(|t| t.codec_params.codec != symphonia::core::codecs::CODEC_TYPE_NULL)
|
||||
.ok_or("No audio track found")?;
|
||||
.ok_or_else(|| {
|
||||
eprintln!("decode_wav: No audio track found");
|
||||
"No audio track found".to_string()
|
||||
})?;
|
||||
|
||||
let sample_rate = track
|
||||
.codec_params
|
||||
.sample_rate
|
||||
.ok_or("No sample rate found")?;
|
||||
.ok_or_else(|| {
|
||||
eprintln!("decode_wav: No sample rate found in track");
|
||||
"No sample rate found".to_string()
|
||||
})?;
|
||||
|
||||
let channels = track
|
||||
.codec_params
|
||||
.channels
|
||||
.ok_or("No channels found")?
|
||||
.ok_or_else(|| {
|
||||
eprintln!("decode_wav: No channels found in track");
|
||||
"No channels found".to_string()
|
||||
})?
|
||||
.count() as u16;
|
||||
|
||||
eprintln!("decode_wav: Track info - sample_rate: {}, channels: {}", sample_rate, channels);
|
||||
|
||||
eprintln!("decode_wav: Creating decoder...");
|
||||
let mut decoder = symphonia::default::get_codecs()
|
||||
.make(&track.codec_params, &Default::default())
|
||||
.map_err(|e| format!("Failed to create decoder: {}", e))?;
|
||||
.map_err(|e| {
|
||||
eprintln!("decode_wav: Failed to create decoder: {}", e);
|
||||
format!("Failed to create decoder: {}", e)
|
||||
})?;
|
||||
|
||||
eprintln!("decode_wav: Decoder created successfully");
|
||||
|
||||
let mut samples = Vec::new();
|
||||
let mut packet_count = 0;
|
||||
eprintln!("decode_wav: Starting packet decoding loop...");
|
||||
loop {
|
||||
let packet = match format.next_packet() {
|
||||
Ok(packet) => packet,
|
||||
Err(_) => break, // End of stream
|
||||
Err(e) => {
|
||||
eprintln!("decode_wav: End of stream or error: {:?}", e);
|
||||
break;
|
||||
}
|
||||
};
|
||||
|
||||
packet_count += 1;
|
||||
let decoded = decoder
|
||||
.decode(&packet)
|
||||
.map_err(|e| format!("Decode error: {}", e))?;
|
||||
.map_err(|e| {
|
||||
eprintln!("decode_wav: Decode error on packet {}: {}", packet_count, e);
|
||||
format!("Decode error: {}", e)
|
||||
})?;
|
||||
|
||||
// Convert to f32 samples by matching on the buffer type
|
||||
use symphonia::core::audio::{AudioBufferRef, Signal};
|
||||
use symphonia::core::conv::FromSample;
|
||||
|
||||
// Convert to f32 samples
|
||||
let spec = *decoded.spec();
|
||||
let duration = decoded.capacity() as u64;
|
||||
let num_channels = spec.channels.count();
|
||||
let num_frames = decoded.frames();
|
||||
|
||||
// Handle multi-channel audio
|
||||
if spec.channels.count() == 1 {
|
||||
// Mono
|
||||
let plane = decoded.plane(0);
|
||||
for i in 0..duration {
|
||||
if let Some(&sample) = plane.get(i as usize) {
|
||||
samples.push(sample as f32 / 32768.0);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// Multi-channel - interleave
|
||||
for i in 0..duration {
|
||||
for ch in 0..spec.channels.count() {
|
||||
if let Some(plane) = decoded.plane(ch) {
|
||||
if let Some(&sample) = plane.get(i as usize) {
|
||||
samples.push(sample as f32 / 32768.0);
|
||||
}
|
||||
}
|
||||
}
|
||||
eprintln!("decode_wav: Packet {} - {} frames, {} channels", packet_count, num_frames, num_channels);
|
||||
|
||||
// Interleave samples from all channels
|
||||
for frame_idx in 0..num_frames {
|
||||
for ch in 0..num_channels {
|
||||
let sample_f32 = match &decoded {
|
||||
AudioBufferRef::U8(buf) => f32::from_sample(buf.chan(ch)[frame_idx]),
|
||||
AudioBufferRef::U16(buf) => f32::from_sample(buf.chan(ch)[frame_idx]),
|
||||
AudioBufferRef::U24(buf) => f32::from_sample(buf.chan(ch)[frame_idx]),
|
||||
AudioBufferRef::U32(buf) => f32::from_sample(buf.chan(ch)[frame_idx]),
|
||||
AudioBufferRef::S8(buf) => f32::from_sample(buf.chan(ch)[frame_idx]),
|
||||
AudioBufferRef::S16(buf) => f32::from_sample(buf.chan(ch)[frame_idx]),
|
||||
AudioBufferRef::S24(buf) => f32::from_sample(buf.chan(ch)[frame_idx]),
|
||||
AudioBufferRef::S32(buf) => f32::from_sample(buf.chan(ch)[frame_idx]),
|
||||
AudioBufferRef::F32(buf) => buf.chan(ch)[frame_idx],
|
||||
AudioBufferRef::F64(buf) => buf.chan(ch)[frame_idx] as f32,
|
||||
};
|
||||
samples.push(sample_f32);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
eprintln!("decode_wav: Decoded {} packets, total {} samples", packet_count, samples.len());
|
||||
eprintln!("decode_wav: Returning sample_rate={}, channels={}", sample_rate, channels);
|
||||
Ok((samples, sample_rate, channels))
|
||||
}
|
||||
|
||||
@@ -181,6 +232,10 @@ impl AudioOutputState {
|
||||
sample_rate: u32,
|
||||
channels: u16,
|
||||
) -> Result<(), String> {
|
||||
let device_name = device.name().unwrap_or_else(|_| "unknown".to_string());
|
||||
eprintln!("play_to_device: Starting playback to device: {}", device_name);
|
||||
eprintln!("play_to_device: Input - {} samples, {}Hz, {} channels", samples.len(), sample_rate, channels);
|
||||
|
||||
let config = device
|
||||
.default_output_config()
|
||||
.map_err(|e| format!("Failed to get default config: {}", e))?;
|
||||
@@ -188,16 +243,29 @@ impl AudioOutputState {
|
||||
// Prepare samples for the device's format
|
||||
let device_sample_rate = config.sample_rate().0;
|
||||
let device_channels = config.channels();
|
||||
let device_sample_format = config.sample_format();
|
||||
|
||||
eprintln!("play_to_device: Device config - {}Hz, {} channels, format: {:?}",
|
||||
device_sample_rate, device_channels, device_sample_format);
|
||||
|
||||
// Resample if needed (simple linear interpolation for now)
|
||||
let resampled = if device_sample_rate != sample_rate {
|
||||
self.resample(&samples, sample_rate, device_sample_rate)
|
||||
eprintln!("play_to_device: Resampling from {}Hz to {}Hz", sample_rate, device_sample_rate);
|
||||
let result = self.resample(&samples, sample_rate, device_sample_rate);
|
||||
eprintln!("play_to_device: Resampled {} samples to {} samples", samples.len(), result.len());
|
||||
result
|
||||
} else {
|
||||
eprintln!("play_to_device: No resampling needed");
|
||||
samples
|
||||
};
|
||||
|
||||
// Interleave/convert channels if needed
|
||||
eprintln!("play_to_device: Interleaving channels from {} to {} channels", channels, device_channels);
|
||||
let interleaved = self.interleave_channels(&resampled, channels, device_channels);
|
||||
eprintln!("play_to_device: Interleaved to {} samples", interleaved.len());
|
||||
|
||||
// Calculate duration before moving interleaved
|
||||
let duration_secs = (interleaved.len() as f64 / (device_sample_rate as f64 * device_channels as f64)).ceil() as u64 + 1;
|
||||
|
||||
// Create shared buffer for playback
|
||||
let buffer: Arc<Mutex<Vec<f32>>> = Arc::new(Mutex::new(interleaved));
|
||||
@@ -289,14 +357,24 @@ impl AudioOutputState {
|
||||
_ => return Err("Unsupported sample format".to_string()),
|
||||
};
|
||||
|
||||
stream.play().map_err(|e| format!("Failed to play stream: {}", e))?;
|
||||
eprintln!("play_to_device: Starting stream playback...");
|
||||
stream.play().map_err(|e| {
|
||||
eprintln!("play_to_device: Failed to play stream: {}", e);
|
||||
format!("Failed to play stream: {}", e)
|
||||
})?;
|
||||
|
||||
eprintln!("play_to_device: Stream started successfully");
|
||||
|
||||
// Keep stream alive until playback completes
|
||||
// In a real implementation, we'd track this and clean up when done
|
||||
eprintln!("play_to_device: Keeping stream alive for ~{} seconds", duration_secs.min(30));
|
||||
std::thread::spawn(move || {
|
||||
std::thread::sleep(std::time::Duration::from_secs(30)); // Max 30s
|
||||
let sleep_duration = std::time::Duration::from_secs(duration_secs.min(30));
|
||||
std::thread::sleep(sleep_duration);
|
||||
eprintln!("play_to_device: Stream sleep completed, stream will be dropped");
|
||||
});
|
||||
|
||||
eprintln!("play_to_device: Function completed successfully");
|
||||
Ok(())
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user