aboutsummaryrefslogtreecommitdiffstats
path: root/mumd
diff options
context:
space:
mode:
authorEskil Queseth <eskilq@kth.se>2020-11-13 23:37:54 +0100
committerEskil Queseth <eskilq@kth.se>2020-11-13 23:37:54 +0100
commit89944f0f56935dfd4c3adca6ff8f1fd52212ee03 (patch)
tree5997ee82d04a185327141300df9a058779efe697 /mumd
parent0a491a4fa431a29668f3cdf5e28b565f39847aca (diff)
downloadmum-89944f0f56935dfd4c3adca6ff8f1fd52212ee03.tar.gz
add mvp for playing sound when stuff happens
Diffstat (limited to 'mumd')
-rw-r--r--mumd/Cargo.toml2
-rw-r--r--mumd/src/audio.rs63
-rw-r--r--mumd/src/audio/output.rs14
-rw-r--r--mumd/src/state.rs4
4 files changed, 75 insertions, 8 deletions
diff --git a/mumd/Cargo.toml b/mumd/Cargo.toml
index 3dfc82c..a7a5ef8 100644
--- a/mumd/Cargo.toml
+++ b/mumd/Cargo.toml
@@ -29,6 +29,8 @@ serde = { version = "1.0", features = ["derive"] }
tokio = { version = "0.2", features = ["full"] }
tokio-tls = "0.3"
tokio-util = { version = "0.3", features = ["codec", "udp"] }
+hound = "3.4.0"
+samplerate = "0.2.2"
libnotify = { version = "1.0", optional = true }
diff --git a/mumd/src/audio.rs b/mumd/src/audio.rs
index 05e3ff5..65da656 100644
--- a/mumd/src/audio.rs
+++ b/mumd/src/audio.rs
@@ -7,9 +7,25 @@ use log::*;
use mumble_protocol::voice::VoicePacketPayload;
use opus::Channels;
use std::collections::hash_map::Entry;
-use std::collections::HashMap;
+use std::collections::{HashMap, VecDeque};
use std::sync::{Arc, Mutex};
use tokio::sync::{mpsc, watch};
+use samplerate::ConverterType;
+use crate::audio::output::SaturatingAdd;
+
+//TODO? move to mumlib
+pub const EVENT_SOUNDS: &[(&str, NotificationEvents)] = &[
+ ("resources/connect.wav", NotificationEvents::ServerConnect),
+ ("resources/disconnect.wav", NotificationEvents::ServerDisconnect),
+];
+
+const SAMPLE_RATE: u32 = 48000;
+
+#[derive(Debug, Eq, PartialEq, Clone, Copy, Hash)]
+pub enum NotificationEvents {
+ ServerConnect,
+ ServerDisconnect,
+}
pub struct Audio {
output_config: StreamConfig,
@@ -24,11 +40,15 @@ pub struct Audio {
user_volumes: Arc<Mutex<HashMap<u32, (f32, bool)>>>,
client_streams: Arc<Mutex<HashMap<u32, output::ClientStream>>>,
+
+ sounds: HashMap<NotificationEvents, Vec<f32>>,
+
+ play_sounds: Arc<Mutex<VecDeque<f32>>>,
}
impl Audio {
pub fn new(input_volume: f32, output_volume: f32) -> Self {
- let sample_rate = SampleRate(48000);
+ let sample_rate = SampleRate(SAMPLE_RATE);
let host = cpal::default_host();
let output_device = host
@@ -71,12 +91,14 @@ impl Audio {
let user_volumes = Arc::new(Mutex::new(HashMap::new()));
let (output_volume_sender, output_volume_receiver) = watch::channel::<f32>(output_volume);
+ let play_sounds = Arc::new(Mutex::new(VecDeque::new()));
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(&play_sounds),
Arc::clone(&client_streams),
output_volume_receiver,
Arc::clone(&user_volumes),
@@ -86,6 +108,7 @@ impl Audio {
SampleFormat::I16 => output_device.build_output_stream(
&output_config,
output::curry_callback::<i16>(
+ Arc::clone(&play_sounds),
Arc::clone(&client_streams),
output_volume_receiver,
Arc::clone(&user_volumes),
@@ -95,6 +118,7 @@ impl Audio {
SampleFormat::U16 => output_device.build_output_stream(
&output_config,
output::curry_callback::<u16>(
+ Arc::clone(&play_sounds),
Arc::clone(&client_streams),
output_volume_receiver,
Arc::clone(&user_volumes),
@@ -160,6 +184,26 @@ impl Audio {
output_stream.play().unwrap();
+ let sounds = EVENT_SOUNDS.iter()
+ .map(|(path, event)| {
+ let reader = hound::WavReader::open(path).unwrap();
+ let spec = reader.spec();
+ debug!("{:?}", spec);
+ let samples = match spec.sample_format {
+ hound::SampleFormat::Float => reader.into_samples::<f32>().map(|e| e.unwrap()).collect::<Vec<_>>(),
+ hound::SampleFormat::Int => reader.into_samples::<i16>().map(|e| cpal::Sample::to_f32(&e.unwrap())).collect::<Vec<_>>(),
+ };
+ let samples = samplerate::convert(
+ spec.sample_rate,
+ SAMPLE_RATE,
+ spec.channels as usize,
+ ConverterType::SincBestQuality,
+ &samples)
+ .unwrap();
+ (*event, samples)
+ })
+ .collect();
+
Self {
output_config,
_output_stream: output_stream,
@@ -167,8 +211,10 @@ impl Audio {
input_volume_sender,
input_channel_receiver: Some(input_receiver),
client_streams,
+ sounds,
output_volume_sender,
user_volumes,
+ play_sounds,
}
}
@@ -250,4 +296,17 @@ impl Audio {
}
}
}
+
+ pub fn play_effect(&mut self, effect: NotificationEvents) {
+ let samples = self.sounds.get(&effect).unwrap();
+
+ let mut play_sounds = self.play_sounds.lock().unwrap();
+
+ for (val, e) in play_sounds.iter_mut().zip(samples.iter()) {
+ *val = val.saturating_add(*e);
+ }
+
+ let l = play_sounds.len();
+ play_sounds.extend(samples.iter().skip(l));
+ }
}
diff --git a/mumd/src/audio/output.rs b/mumd/src/audio/output.rs
index ce116a8..2b58d5b 100644
--- a/mumd/src/audio/output.rs
+++ b/mumd/src/audio/output.rs
@@ -71,8 +71,9 @@ impl SaturatingAdd for u16 {
}
}
-pub fn curry_callback<T: Sample + AddAssign + SaturatingAdd>(
- buf: Arc<Mutex<HashMap<u32, ClientStream>>>,
+pub fn curry_callback<T: Sample + AddAssign + SaturatingAdd + std::fmt::Display>(
+ effect_sound: Arc<Mutex<VecDeque<f32>>>,
+ user_bufs: Arc<Mutex<HashMap<u32, ClientStream>>>,
output_volume_receiver: watch::Receiver<f32>,
user_volumes: Arc<Mutex<HashMap<u32, (f32, bool)>>>,
) -> impl FnMut(&mut [T], &OutputCallbackInfo) + Send + 'static {
@@ -83,8 +84,9 @@ pub fn curry_callback<T: Sample + AddAssign + SaturatingAdd>(
let volume = *output_volume_receiver.borrow();
- let mut lock = buf.lock().unwrap();
- for (id, client_stream) in &mut *lock {
+ let mut effects_sound = effect_sound.lock().unwrap();
+ let mut user_bufs = user_bufs.lock().unwrap();
+ for (id, client_stream) in &mut *user_bufs {
let (user_volume, muted) = user_volumes
.lock()
.unwrap()
@@ -98,5 +100,9 @@ pub fn curry_callback<T: Sample + AddAssign + SaturatingAdd>(
}
}
}
+
+ for sample in data.iter_mut() {
+ *sample = sample.saturating_add(Sample::from(&(effects_sound.pop_front().unwrap_or(0.0) * volume)));
+ }
}
}
diff --git a/mumd/src/state.rs b/mumd/src/state.rs
index 8fe5e36..2c90b7c 100644
--- a/mumd/src/state.rs
+++ b/mumd/src/state.rs
@@ -2,7 +2,7 @@ pub mod channel;
pub mod server;
pub mod user;
-use crate::audio::Audio;
+use crate::audio::{Audio, NotificationEvents};
use crate::network::ConnectionInfo;
use crate::notify;
use crate::state::server::Server;
@@ -85,7 +85,6 @@ impl State {
state
}
- //TODO? move bool inside Result
pub fn handle_command(&mut self, command: Command) -> ExecutionContext {
match command {
Command::ChannelJoin { channel_identifier } => {
@@ -423,6 +422,7 @@ impl State {
&msg.get_name(),
channel.name()
));
+ self.audio.play_effect(NotificationEvents::ServerConnect);
}
}
}