feat: UAC USB microphone passthrough

- Add UAC1 gadget function (ConfigFS) with optimized endpoint config
- Browser mic capture with Opus encoding via WebCodecs AudioEncoder
- WebSocket audio transport (Opus 64kbps, 100x bandwidth reduction vs raw PCM)
- aplay subprocess for reliable PCM playback to USB gadget
- Settings toggle + ActionBar mic button (hidden when UAC disabled)
- Dynamic PCM device resolution (/proc/asound)
- c_chmask=0 + req_number=4 fixes DWC3 composite isochronous endpoint issue
This commit is contained in:
arounyf
2026-07-23 06:56:53 +00:00
parent 4e32b05124
commit e9bed3688f
27 changed files with 977 additions and 16 deletions

View File

@@ -308,7 +308,7 @@ async fn main() -> anyhow::Result<()> {
#[cfg(unix)]
if let Err(e) = otg_service
.apply_config(&config.hid, &config.msd, &config.otg_network)
.apply_config(&config.hid, &config.msd, &config.otg_network, &config.uac)
.await
{
tracing::warn!("Failed to apply OTG config: {}", e);
@@ -579,6 +579,24 @@ async fn main() -> anyhow::Result<()> {
data_dir.clone(),
);
// Initialize UAC playback writer if UAC is enabled
if config.uac.enabled {
let uac_cfg = one_kvm::audio::uac_streamer::UacPlaybackConfig {
sample_rate: config.uac.sample_rate,
channels: config.uac.channels as u16,
..Default::default()
};
match one_kvm::audio::uac_streamer::UacPlaybackWriter::start(uac_cfg) {
Ok(writer) => {
*state.uac_playback.write().await = Some(writer);
tracing::info!("UAC playback writer started");
}
Err(e) => {
tracing::warn!("Failed to start UAC playback writer: {}", e);
}
}
}
if config.watchdog.enabled {
if let Err(error) = state.watchdog.enable().await {
tracing::error!(