diff options
| author | Eskil <eskilq@kth.se> | 2020-11-03 22:02:32 +0100 |
|---|---|---|
| committer | Eskil <eskilq@kth.se> | 2020-11-03 22:02:32 +0100 |
| commit | d6496cb0f6abba855b04338fa8bc5aaa89487c29 (patch) | |
| tree | 929f5c18babe5bc27676c88aae6b9d3795b09917 /mumd | |
| parent | 831182b69eb1bbfedfad1288b73a822241f18d25 (diff) | |
| parent | 972c11fe66c17728981ec57796c78fb70c7bd180 (diff) | |
| download | mum-d6496cb0f6abba855b04338fa8bc5aaa89487c29.tar.gz | |
Merge branch 'audio-volume' into 'main'
Refactor of config and add support for changing global output volume and individual user's volume
See merge request gustav/mum!28
Diffstat (limited to 'mumd')
| -rw-r--r-- | mumd/src/audio.rs | 41 | ||||
| -rw-r--r-- | mumd/src/audio/output.rs | 10 | ||||
| -rw-r--r-- | mumd/src/state.rs | 45 |
3 files changed, 75 insertions, 21 deletions
diff --git a/mumd/src/audio.rs b/mumd/src/audio.rs index ad4a762..9f837f7 100644 --- a/mumd/src/audio.rs +++ b/mumd/src/audio.rs @@ -19,6 +19,10 @@ pub struct Audio { input_channel_receiver: Option<mpsc::Receiver<VoicePacketPayload>>, input_volume_sender: watch::Sender<f32>, + output_volume_sender: watch::Sender<f32>, + + user_volumes: Arc<Mutex<HashMap<u32, f32>>>, + client_streams: Arc<Mutex<HashMap<u32, output::ClientStream>>>, } @@ -65,21 +69,36 @@ impl Audio { let err_fn = |err| error!("An error occurred on the output audio stream: {}", err); + let user_volumes = Arc::new(Mutex::new(HashMap::new())); + let (output_volume_sender, output_volume_receiver) = watch::channel::<f32>(1.0); + let client_streams = Arc::new(Mutex::new(HashMap::new())); let output_stream = match output_supported_sample_format { SampleFormat::F32 => output_device.build_output_stream( &output_config, - output::curry_callback::<f32>(Arc::clone(&client_streams)), + output::curry_callback::<f32>( + Arc::clone(&client_streams), + output_volume_receiver, + Arc::clone(&user_volumes), + ), err_fn, ), SampleFormat::I16 => output_device.build_output_stream( &output_config, - output::curry_callback::<i16>(Arc::clone(&client_streams)), + output::curry_callback::<i16>( + Arc::clone(&client_streams), + output_volume_receiver, + Arc::clone(&user_volumes), + ), err_fn, ), SampleFormat::U16 => output_device.build_output_stream( &output_config, - output::curry_callback::<u16>(Arc::clone(&client_streams)), + output::curry_callback::<u16>( + Arc::clone(&client_streams), + output_volume_receiver, + Arc::clone(&user_volumes), + ), err_fn, ), } @@ -109,7 +128,7 @@ impl Audio { input_encoder, input_sender, input_config.sample_rate.0, - input_volume_receiver.clone(), + input_volume_receiver, 4, // 10 ms ), err_fn, @@ -120,7 +139,7 @@ impl Audio { input_encoder, input_sender, input_config.sample_rate.0, - input_volume_receiver.clone(), + input_volume_receiver, 4, // 10 ms ), err_fn, @@ -131,7 +150,7 @@ impl Audio { input_encoder, input_sender, input_config.sample_rate.0, - input_volume_receiver.clone(), + input_volume_receiver, 4, // 10 ms ), err_fn, @@ -148,6 +167,8 @@ impl Audio { input_volume_sender, input_channel_receiver: Some(input_receiver), client_streams, + output_volume_sender, + user_volumes, } } @@ -203,4 +224,12 @@ impl Audio { pub fn set_input_volume(&self, input_volume: f32) { self.input_volume_sender.broadcast(input_volume).unwrap(); } + + pub fn set_output_volume(&self, output_volume: f32) { + self.output_volume_sender.broadcast(output_volume).unwrap(); + } + + pub fn set_user_volume(&self, id: u32, volume: f32) { + self.user_volumes.lock().unwrap().insert(id, volume); + } } diff --git a/mumd/src/audio/output.rs b/mumd/src/audio/output.rs index 94e4b21..56da596 100644 --- a/mumd/src/audio/output.rs +++ b/mumd/src/audio/output.rs @@ -4,6 +4,7 @@ use opus::Channels; use std::collections::{HashMap, VecDeque}; use std::ops::AddAssign; use std::sync::{Arc, Mutex}; +use tokio::sync::watch; pub struct ClientStream { buffer: VecDeque<f32>, //TODO ring buffer? @@ -72,17 +73,22 @@ impl SaturatingAdd for u16 { pub fn curry_callback<T: Sample + AddAssign + SaturatingAdd>( buf: Arc<Mutex<HashMap<u32, ClientStream>>>, + output_volume_receiver: watch::Receiver<f32>, + user_volumes: Arc<Mutex<HashMap<u32, f32>>>, ) -> impl FnMut(&mut [T], &OutputCallbackInfo) + Send + 'static { move |data: &mut [T], _info: &OutputCallbackInfo| { for sample in data.iter_mut() { *sample = Sample::from(&0.0); } + let volume = *output_volume_receiver.borrow(); + let mut lock = buf.lock().unwrap(); - for client_stream in lock.values_mut() { + for (id, client_stream) in &mut *lock { + let user_volume = user_volumes.lock().unwrap().get(id).cloned().unwrap_or(1.0); for sample in data.iter_mut() { *sample = sample.saturating_add(Sample::from( - &client_stream.buffer.pop_front().unwrap_or(0.0), + &(client_stream.buffer.pop_front().unwrap_or(0.0) * volume * user_volume), )); } } diff --git a/mumd/src/state.rs b/mumd/src/state.rs index 306ded8..56ce030 100644 --- a/mumd/src/state.rs +++ b/mumd/src/state.rs @@ -53,7 +53,7 @@ pub enum StatePhase { } pub struct State { - config: Option<Config>, + config: Config, server: Option<Server>, audio: Audio, @@ -217,12 +217,35 @@ impl State { .unwrap(); now!(Ok(None)) } + Command::ConfigReload => { + self.reload_config(); + now!(Ok(None)) + } Command::InputVolumeSet(volume) => { self.audio.set_input_volume(volume); now!(Ok(None)) } - Command::ConfigReload => { - self.reload_config(); + Command::OutputVolumeSet(volume) => { + self.audio.set_output_volume(volume); + now!(Ok(None)) + } + Command::UserVolumeSet(string, volume) => { + if !matches!(*self.phase_receiver().borrow(), StatePhase::Connected) { + return now!(Err(Error::DisconnectedError)); + } + let user_id = match self + .server() + .unwrap() + .users() + .iter() + .find(|e| e.1.name() == &string) + .map(|e| *e.0) + { + None => return now!(Err(Error::InvalidUsernameError(string))), + Some(v) => v, + }; + + self.audio.set_user_volume(user_id, volume); now!(Ok(None)) } Command::ServerStatus { host, port } => ExecutionContext::Ping( @@ -379,16 +402,12 @@ impl State { } pub fn reload_config(&mut self) { - if let Some(config) = mumlib::config::read_default_cfg() { - self.config = Some(config); - let config = &self.config.as_ref().unwrap(); - if let Some(audio_config) = &config.audio { - if let Some(input_volume) = audio_config.input_volume { - self.audio.set_input_volume(input_volume); - } - } - } else { - warn!("config file not found"); + self.config = mumlib::config::read_default_cfg(); + if let Some(input_volume) = self.config.audio.input_volume { + self.audio.set_input_volume(input_volume); + } + if let Some(output_volume) = self.config.audio.output_volume { + self.audio.set_output_volume(output_volume); } } |
