Persist denoise setting (#24)
Build android container / android-release-builder-container-build (push) Successful in 1s
Build Mumble Web 2 release builder containers / windows-release-builder-container-build (push) Successful in 16s
Build Mumble Web 2 / macos_build (push) Successful in 1m2s
Build Mumble Web 2 / linux_build (push) Successful in 1m26s
Build Mumble Web 2 / windows_build (push) Successful in 3m23s
Build Mumble Web 2 / android_build (push) Successful in 4m59s

Puts the denoise bool into an AudioSettings struct in the model state, and persists changes to user state.

Co-authored-by: Sam Sartor <me@samsartor.com>
Co-committed-by: Sam Sartor <me@samsartor.com>
This commit was merged in pull request #24.
This commit is contained in:
2026-03-30 01:30:14 +00:00
committed by Sam Sartor
parent f0ce15000e
commit 7f35a216cd
2 changed files with 36 additions and 19 deletions
+25 -16
View File
@@ -4,11 +4,8 @@ use dioxus::prelude::*;
use mime_guess::Mime; use mime_guess::Mime;
use mumble_web2_common::{ProxyOverrides, ServerStatus}; use mumble_web2_common::{ProxyOverrides, ServerStatus};
use ordermap::OrderSet; use ordermap::OrderSet;
use std::{ use std::collections::{HashMap, HashSet};
collections::{HashMap, HashSet}, use std::{fmt, sync::Arc};
fmt,
sync::Arc,
};
use crate::imp::{ConfigSystem, ConfigSystemInterface as _, Platform, PlatformInterface as _}; use crate::imp::{ConfigSystem, ConfigSystemInterface as _, Platform, PlatformInterface as _};
@@ -23,6 +20,11 @@ pub enum ConnectionState {
Failed(String), Failed(String),
} }
#[derive(Debug, Clone)]
pub struct AudioSettings {
pub denoise: bool,
}
#[derive(Debug)] #[derive(Debug)]
pub enum Command { pub enum Command {
Connect { Connect {
@@ -50,9 +52,7 @@ pub enum Command {
channel: ChannelId, channel: ChannelId,
user: UserId, user: UserId,
}, },
UpdateMicEffects { UpdateAudioSettings(AudioSettings),
denoise: bool,
},
Disconnect, Disconnect,
} }
@@ -221,6 +221,7 @@ impl ServerState {
pub struct State { pub struct State {
pub status: Signal<ConnectionState>, pub status: Signal<ConnectionState>,
pub server: Signal<ServerState>, pub server: Signal<ServerState>,
pub audio: Signal<AudioSettings>,
} }
impl fmt::Debug for State { impl fmt::Debug for State {
@@ -477,6 +478,7 @@ pub fn ControlView(overrides: Resource<ProxyOverrides>) -> Element {
let state = use_context::<SharedState>(); let state = use_context::<SharedState>();
let status = &state.status; let status = &state.status;
let server = state.server.read(); let server = state.server.read();
let audio = state.audio.read();
let Some(&UserState { let Some(&UserState {
deaf, deaf,
self_deaf, self_deaf,
@@ -574,7 +576,6 @@ pub fn ControlView(overrides: Resource<ProxyOverrides>) -> Element {
}, },
}; };
let denoise = use_signal(|| false);
rsx!( rsx!(
// Server control // Server control
div { div {
@@ -615,18 +616,23 @@ pub fn ControlView(overrides: Resource<ProxyOverrides>) -> Element {
} }
span { class: "spacer" } span { class: "spacer" }
button { button {
class: match denoise() { class: match audio.denoise {
true => "toggle_button is_on", true => "toggle_button is_on",
false => "toggle_button", false => "toggle_button",
}, },
role: "switch", role: "switch",
aria_checked: denoise(), aria_checked: audio.denoise,
onclick: move |_| { onclick: move |_| {
let new_denoise = !denoise(); let state = use_context::<SharedState>();
*denoise.write_unchecked() = new_denoise; let mut audio = state.audio.read().clone();
net.send(UpdateMicEffects { denoise: new_denoise }) audio.denoise = !audio.denoise;
let denoise = audio.denoise;
*state.audio.write_unchecked() = audio;
net.send(UpdateAudioSettings(AudioSettings { denoise: denoise }));
let user_config = use_context::<ConfigSystem>();
user_config.config_set::<bool>("denoise", &denoise);
}, },
match denoise() { match audio.denoise {
true => rsx!(span { class: "material-symbols-outlined", "cadence"}), true => rsx!(span { class: "material-symbols-outlined", "cadence"}),
false => rsx!(span { class: "material-symbols-outlined", "graphic_eq"}), false => rsx!(span { class: "material-symbols-outlined", "graphic_eq"}),
} }
@@ -887,11 +893,14 @@ pub fn app() -> Element {
Platform::request_permissions(); Platform::request_permissions();
}); });
use_root_context(|| ConfigSystem::new().unwrap()); let user_config = use_root_context(|| ConfigSystem::new().unwrap());
let state = use_root_context(|| { let state = use_root_context(|| {
SharedState::new(State { SharedState::new(State {
status: Signal::new(Disconnected), status: Signal::new(Disconnected),
server: Signal::new(Default::default()), server: Signal::new(Default::default()),
audio: Signal::new(AudioSettings {
denoise: user_config.config_get::<bool>("denoise").unwrap_or(true),
}),
}) })
}); });
+11 -3
View File
@@ -26,6 +26,7 @@ use std::time::Duration;
use tracing::error; use tracing::error;
use tracing::info; use tracing::info;
use crate::app::AudioSettings;
use crate::app::SharedState; use crate::app::SharedState;
use crate::app::State; use crate::app::State;
use crate::effects::AudioProcessor; use crate::effects::AudioProcessor;
@@ -71,6 +72,8 @@ pub async fn network_loop<R: AsyncRead + Unpin + 'static, W: AsyncWrite + Unpin
mut reader: FramedRead<R, ControlCodec<Serverbound, Clientbound>>, mut reader: FramedRead<R, ControlCodec<Serverbound, Clientbound>>,
mut writer: FramedWrite<W, ControlCodec<Serverbound, Clientbound>>, mut writer: FramedWrite<W, ControlCodec<Serverbound, Clientbound>>,
) -> Result<(), Error> { ) -> Result<(), Error> {
let audio_settings = state.audio.read().clone();
let (mut send_chan, mut writer_recv_chan) = futures_channel::mpsc::unbounded(); let (mut send_chan, mut writer_recv_chan) = futures_channel::mpsc::unbounded();
spawn(async move { spawn(async move {
while let Some(msg) = writer_recv_chan.next().await { while let Some(msg) = writer_recv_chan.next().await {
@@ -120,10 +123,13 @@ pub async fn network_loop<R: AsyncRead + Unpin + 'static, W: AsyncWrite + Unpin
} }
let mut audio = AudioSystem::new().await?; let mut audio = AudioSystem::new().await?;
if audio_settings.denoise {
audio.set_processor(AudioProcessor::new_denoising());
}
{ {
let send_chan = send_chan.clone(); let send_chan = send_chan.clone();
let mut sequence_num = 0; let mut sequence_num = 0;
audio.start_recording(move |opus_frame, is_terminator| { if let Err(err) = audio.start_recording(move |opus_frame, is_terminator| {
let _ = let _ =
send_chan.unbounded_send(ControlPacket::UDPTunnel(Box::new(VoicePacket::Audio { send_chan.unbounded_send(ControlPacket::UDPTunnel(Box::new(VoicePacket::Audio {
_dst: std::marker::PhantomData, _dst: std::marker::PhantomData,
@@ -134,7 +140,9 @@ pub async fn network_loop<R: AsyncRead + Unpin + 'static, W: AsyncWrite + Unpin
position_info: None, position_info: None,
}))); })));
sequence_num = sequence_num.wrapping_add(2); sequence_num = sequence_num.wrapping_add(2);
}); }) {
error!("could not begin recording: {err:?}")
}
} }
// Create map of session_id -> AudioDecoder // Create map of session_id -> AudioDecoder
@@ -292,7 +300,7 @@ fn accept_command(
let _ = send_chan.unbounded_send(u.into()); let _ = send_chan.unbounded_send(u.into());
} }
Connect { .. } | Disconnect => (), Connect { .. } | Disconnect => (),
UpdateMicEffects { denoise } => { UpdateAudioSettings(AudioSettings { denoise }) => {
if denoise { if denoise {
audio.set_processor(AudioProcessor::new_denoising()); audio.set_processor(AudioProcessor::new_denoising());
} else { } else {