audio: wire user's microphone choice through start_native_capture + live session
Day 1 follow-up to 96980c7. The device-picker UI in Settings now
actually takes effect: settings.microphoneDevice flows from the Svelte
store, through the Tauri invoke, into MicrophoneCapture::start_with_device
on the Rust side.
Touched paths (back-to-front):
- src-tauri/src/commands/audio.rs:start_native_capture — new optional
`device_name: Option<String>` parameter; routes to start_with_device
when set, falls back to auto-select start() when None or empty.
- src-tauri/src/commands/live.rs:StartLiveTranscriptionConfig — new
optional `microphone_device: Option<String>` field with same
semantics (rename_all = "camelCase" maps it to microphoneDevice on
the wire).
- src-tauri/src/commands/live.rs:run_live_session — picks
start_with_device when an explicit name is provided.
- src/lib/pages/DictationPage.svelte — passes
microphoneDevice: settings.microphoneDevice || null in the invoke.
Behaviour:
- "Auto" in the picker (empty string) -> backend auto-selects, skipping
monitor sources and validating by RMS energy.
- Specific device -> backend opens that device by exact name; if it has
been disconnected the user gets a clear error pointing them back at
Settings.
cargo check -p kon-audio passes clean. Tauri-crate cargo check requires
cmake (pre-existing infra dependency for whisper-rs-sys); install via
`sudo dnf install cmake clang-devel`.
This commit is contained in:
@@ -38,23 +38,38 @@ impl NativeCaptureState {
|
||||
|
||||
/// Start native microphone capture via cpal.
|
||||
/// Streams 16kHz mono PCM chunks to the frontend via `native-pcm` events.
|
||||
///
|
||||
/// `device_name`: explicit device name (from `list_audio_devices`) or None / ""
|
||||
/// to auto-select. The frontend passes `settings.microphoneDevice` here so the
|
||||
/// user's pick from Settings → Audio → Microphone takes effect.
|
||||
#[tauri::command]
|
||||
pub async fn start_native_capture(
|
||||
app: tauri::AppHandle,
|
||||
state: tauri::State<'_, NativeCaptureState>,
|
||||
device_name: Option<String>,
|
||||
) -> Result<(), String> {
|
||||
eprintln!("[native-capture] start_native_capture called");
|
||||
eprintln!(
|
||||
"[native-capture] start_native_capture called (device='{}')",
|
||||
device_name.as_deref().unwrap_or("<auto>")
|
||||
);
|
||||
|
||||
// Stop any existing capture
|
||||
if let Some(tx) = state.stop_tx.lock().unwrap().take() {
|
||||
drop(tx);
|
||||
}
|
||||
|
||||
let (capture, rx) = MicrophoneCapture::start().map_err(|e| {
|
||||
let (capture, rx) = match device_name.as_deref() {
|
||||
Some(name) if !name.is_empty() => MicrophoneCapture::start_with_device(name),
|
||||
_ => MicrophoneCapture::start(),
|
||||
}
|
||||
.map_err(|e| {
|
||||
eprintln!("[native-capture] MicrophoneCapture::start failed: {e}");
|
||||
e.to_string()
|
||||
})?;
|
||||
eprintln!("[native-capture] cpal capture started successfully");
|
||||
eprintln!(
|
||||
"[native-capture] cpal capture started successfully on '{}'",
|
||||
capture.device_name
|
||||
);
|
||||
|
||||
// Wrap capture in Arc<Mutex> so it can be moved into the blocking task
|
||||
let capture = Arc::new(Mutex::new(Some(capture)));
|
||||
|
||||
Reference in New Issue
Block a user