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 mumble_web2_common::{ProxyOverrides, ServerStatus};
use ordermap::OrderSet;
use std::{
collections::{HashMap, HashSet},
fmt,
sync::Arc,
};
use std::collections::{HashMap, HashSet};
use std::{fmt, sync::Arc};
use crate::imp::{ConfigSystem, ConfigSystemInterface as _, Platform, PlatformInterface as _};
@@ -23,6 +20,11 @@ pub enum ConnectionState {
Failed(String),
}
#[derive(Debug, Clone)]
pub struct AudioSettings {
pub denoise: bool,
}
#[derive(Debug)]
pub enum Command {
Connect {
@@ -50,9 +52,7 @@ pub enum Command {
channel: ChannelId,
user: UserId,
},
UpdateMicEffects {
denoise: bool,
},
UpdateAudioSettings(AudioSettings),
Disconnect,
}
@@ -221,6 +221,7 @@ impl ServerState {
pub struct State {
pub status: Signal<ConnectionState>,
pub server: Signal<ServerState>,
pub audio: Signal<AudioSettings>,
}
impl fmt::Debug for State {
@@ -477,6 +478,7 @@ pub fn ControlView(overrides: Resource<ProxyOverrides>) -> Element {
let state = use_context::<SharedState>();
let status = &state.status;
let server = state.server.read();
let audio = state.audio.read();
let Some(&UserState {
deaf,
self_deaf,
@@ -574,7 +576,6 @@ pub fn ControlView(overrides: Resource<ProxyOverrides>) -> Element {
},
};
let denoise = use_signal(|| false);
rsx!(
// Server control
div {
@@ -615,18 +616,23 @@ pub fn ControlView(overrides: Resource<ProxyOverrides>) -> Element {
}
span { class: "spacer" }
button {
class: match denoise() {
class: match audio.denoise {
true => "toggle_button is_on",
false => "toggle_button",
},
role: "switch",
aria_checked: denoise(),
aria_checked: audio.denoise,
onclick: move |_| {
let new_denoise = !denoise();
*denoise.write_unchecked() = new_denoise;
net.send(UpdateMicEffects { denoise: new_denoise })
let state = use_context::<SharedState>();
let mut audio = state.audio.read().clone();
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"}),
false => rsx!(span { class: "material-symbols-outlined", "graphic_eq"}),
}
@@ -887,11 +893,14 @@ pub fn app() -> Element {
Platform::request_permissions();
});
use_root_context(|| ConfigSystem::new().unwrap());
let user_config = use_root_context(|| ConfigSystem::new().unwrap());
let state = use_root_context(|| {
SharedState::new(State {
status: Signal::new(Disconnected),
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::info;
use crate::app::AudioSettings;
use crate::app::SharedState;
use crate::app::State;
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 writer: FramedWrite<W, ControlCodec<Serverbound, Clientbound>>,
) -> Result<(), Error> {
let audio_settings = state.audio.read().clone();
let (mut send_chan, mut writer_recv_chan) = futures_channel::mpsc::unbounded();
spawn(async move {
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?;
if audio_settings.denoise {
audio.set_processor(AudioProcessor::new_denoising());
}
{
let send_chan = send_chan.clone();
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 _ =
send_chan.unbounded_send(ControlPacket::UDPTunnel(Box::new(VoicePacket::Audio {
_dst: std::marker::PhantomData,
@@ -134,7 +140,9 @@ pub async fn network_loop<R: AsyncRead + Unpin + 'static, W: AsyncWrite + Unpin
position_info: None,
})));
sequence_num = sequence_num.wrapping_add(2);
});
}) {
error!("could not begin recording: {err:?}")
}
}
// Create map of session_id -> AudioDecoder
@@ -292,7 +300,7 @@ fn accept_command(
let _ = send_chan.unbounded_send(u.into());
}
Connect { .. } | Disconnect => (),
UpdateMicEffects { denoise } => {
UpdateAudioSettings(AudioSettings { denoise }) => {
if denoise {
audio.set_processor(AudioProcessor::new_denoising());
} else {