aboutsummaryrefslogtreecommitdiffstats
path: root/mumd
diff options
context:
space:
mode:
Diffstat (limited to 'mumd')
-rw-r--r--mumd/src/audio.rs41
-rw-r--r--mumd/src/audio/output.rs10
-rw-r--r--mumd/src/state.rs45
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);
}
}