fix: isolate continuous-mode mic capture and clarify voice settings
- Use a separate Microphone instance for continuous-mode VAD monitoring so it no longer races with the transmit capture path. - Respect selected input device in continuous-mode monitor subscription. - Make talk-mode and Sonora processing labels clearer in settings UI.
This commit is contained in:
@@ -991,15 +991,21 @@ impl App {
|
|||||||
|
|
||||||
// Continuous talk: monitor mic input when in continuous mode
|
// Continuous talk: monitor mic input when in continuous mode
|
||||||
if self.talk_mode == audio::TalkMode::Continuous {
|
if self.talk_mode == audio::TalkMode::Continuous {
|
||||||
let mic = self.mic.clone();
|
let selected_input_device = self.selected_input_device.clone();
|
||||||
let session_id = self.session_id;
|
let session_id = self.session_id;
|
||||||
subs.push(Subscription::run_with_id(
|
subs.push(Subscription::run_with_id(
|
||||||
(session_id, "continuous"),
|
(session_id, "continuous", selected_input_device.clone()),
|
||||||
iced::stream::channel(100, move |mut sender| async move {
|
iced::stream::channel(100, move |mut sender| async move {
|
||||||
|
let mic = Arc::new(Mutex::new(audio::Microphone::new()));
|
||||||
let (sample_tx, sample_rx) = std::sync::mpsc::channel();
|
let (sample_tx, sample_rx) = std::sync::mpsc::channel();
|
||||||
{
|
{
|
||||||
let mut mic_guard = mic.lock().await;
|
let mut mic_guard = mic.lock().await;
|
||||||
if mic_guard.start(None, sample_tx).is_err() {
|
let device = if selected_input_device.is_empty() {
|
||||||
|
None
|
||||||
|
} else {
|
||||||
|
Some(selected_input_device.as_str())
|
||||||
|
};
|
||||||
|
if mic_guard.start(device, sample_tx).is_err() {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+46
-18
@@ -643,36 +643,59 @@ impl App {
|
|||||||
.width(560),
|
.width(560),
|
||||||
);
|
);
|
||||||
|
|
||||||
let talk_mode_text = match self.talk_mode {
|
|
||||||
audio::TalkMode::PushToTalk => "Push-to-Talk (hold V)",
|
|
||||||
audio::TalkMode::Continuous => "Continuous (voice activation)",
|
|
||||||
};
|
|
||||||
|
|
||||||
let nc_label = self.nc_method.label();
|
let nc_label = self.nc_method.label();
|
||||||
let sonora_noise_label = self.sonora_settings.noise_suppression_level.label();
|
let sonora_noise_label = self.sonora_settings.noise_suppression_level.label();
|
||||||
|
|
||||||
let voice_col = column![
|
let voice_col = column![
|
||||||
text("Voice Activation Mode").size(13),
|
text("Talk Mode").size(13),
|
||||||
text(talk_mode_text).size(12).style(text::secondary),
|
text("Choose how your microphone starts transmitting.").size(12).style(text::secondary),
|
||||||
vertical_space().height(8),
|
vertical_space().height(8),
|
||||||
text("Push-to-Talk Key").size(13),
|
text("Push-to-Talk Key").size(13),
|
||||||
text("V (hold to talk)").size(12).style(text::secondary),
|
text("V (hold to talk)").size(12).style(text::secondary),
|
||||||
vertical_space().height(8),
|
vertical_space().height(8),
|
||||||
text("Noise Cancellation").size(13),
|
text("Microphone Processing Backend").size(13),
|
||||||
text(nc_label).size(12).style(text::secondary),
|
text(nc_label).size(12).style(text::secondary),
|
||||||
]
|
]
|
||||||
.spacing(4)
|
.spacing(4)
|
||||||
.padding(16);
|
.padding(16);
|
||||||
|
|
||||||
let voice_col = voice_col.push(
|
let voice_col = voice_col.push(row![
|
||||||
button(text("Toggle Voice Mode").size(11))
|
button(text("Push-to-Talk").size(11))
|
||||||
.padding([4, 12])
|
.padding([4, 12])
|
||||||
.style(theme::secondary_button)
|
.style(if self.talk_mode == audio::TalkMode::PushToTalk {
|
||||||
.on_press(Message::ToggleTalkMode),
|
theme::primary_button
|
||||||
|
} else {
|
||||||
|
theme::secondary_button
|
||||||
|
})
|
||||||
|
.on_press(if self.talk_mode == audio::TalkMode::PushToTalk {
|
||||||
|
Message::Noop
|
||||||
|
} else {
|
||||||
|
Message::ToggleTalkMode
|
||||||
|
}),
|
||||||
|
button(text("Voice Activation").size(11))
|
||||||
|
.padding([4, 12])
|
||||||
|
.style(if self.talk_mode == audio::TalkMode::Continuous {
|
||||||
|
theme::primary_button
|
||||||
|
} else {
|
||||||
|
theme::secondary_button
|
||||||
|
})
|
||||||
|
.on_press(if self.talk_mode == audio::TalkMode::Continuous {
|
||||||
|
Message::Noop
|
||||||
|
} else {
|
||||||
|
Message::ToggleTalkMode
|
||||||
|
}),
|
||||||
|
]
|
||||||
|
.spacing(8)
|
||||||
|
.align_y(iced::Alignment::Center));
|
||||||
|
|
||||||
|
let voice_col = voice_col.push(
|
||||||
|
text("Advanced options below only affect microphone cleanup, not playback.")
|
||||||
|
.size(11)
|
||||||
|
.style(text::secondary),
|
||||||
);
|
);
|
||||||
|
|
||||||
let voice_col = noise_cancel::NoiseCancelMethod::all().iter().copied().fold(
|
let voice_col = noise_cancel::NoiseCancelMethod::all().iter().copied().fold(
|
||||||
voice_col.push(text("Noise Cancel Backend").size(11).style(text::secondary)),
|
voice_col.push(text("Processing backend").size(11).style(text::secondary)),
|
||||||
|column, method| {
|
|column, method| {
|
||||||
let label = method.label().to_string();
|
let label = method.label().to_string();
|
||||||
column.push(
|
column.push(
|
||||||
@@ -691,7 +714,10 @@ impl App {
|
|||||||
let voice_col = if self.nc_method == noise_cancel::NoiseCancelMethod::Sonora {
|
let voice_col = if self.nc_method == noise_cancel::NoiseCancelMethod::Sonora {
|
||||||
let voice_col = voice_col
|
let voice_col = voice_col
|
||||||
.push(vertical_space().height(8))
|
.push(vertical_space().height(8))
|
||||||
.push(text("Sonora Noise Suppression").size(11).style(text::secondary))
|
.push(text("Advanced Sonora Processing").size(13))
|
||||||
|
.push(text("Tune noise cleanup, auto gain, and low-frequency filtering.").size(11).style(text::secondary))
|
||||||
|
.push(vertical_space().height(4))
|
||||||
|
.push(text("Noise Suppression Strength").size(11).style(text::secondary))
|
||||||
.push(text(sonora_noise_label).size(12).style(text::secondary));
|
.push(text(sonora_noise_label).size(12).style(text::secondary));
|
||||||
|
|
||||||
let voice_col = noise_cancel::NoiseSuppressionLevelSetting::all()
|
let voice_col = noise_cancel::NoiseSuppressionLevelSetting::all()
|
||||||
@@ -712,11 +738,12 @@ impl App {
|
|||||||
|
|
||||||
voice_col
|
voice_col
|
||||||
.push(vertical_space().height(8))
|
.push(vertical_space().height(8))
|
||||||
|
.push(text("Automatic Gain Control").size(11).style(text::secondary))
|
||||||
.push(
|
.push(
|
||||||
button(text(if self.sonora_settings.agc_enabled {
|
button(text(if self.sonora_settings.agc_enabled {
|
||||||
"AGC2: On"
|
"AGC2 On"
|
||||||
} else {
|
} else {
|
||||||
"AGC2: Off"
|
"AGC2 Off"
|
||||||
})
|
})
|
||||||
.size(11))
|
.size(11))
|
||||||
.padding([4, 12])
|
.padding([4, 12])
|
||||||
@@ -727,11 +754,12 @@ impl App {
|
|||||||
})
|
})
|
||||||
.on_press(Message::ToggleSonoraAgc),
|
.on_press(Message::ToggleSonoraAgc),
|
||||||
)
|
)
|
||||||
|
.push(text("High-Pass Filter").size(11).style(text::secondary))
|
||||||
.push(
|
.push(
|
||||||
button(text(if self.sonora_settings.high_pass_enabled {
|
button(text(if self.sonora_settings.high_pass_enabled {
|
||||||
"High-Pass: On"
|
"High-Pass On"
|
||||||
} else {
|
} else {
|
||||||
"High-Pass: Off"
|
"High-Pass Off"
|
||||||
})
|
})
|
||||||
.size(11))
|
.size(11))
|
||||||
.padding([4, 12])
|
.padding([4, 12])
|
||||||
|
|||||||
Reference in New Issue
Block a user