diff options
| -rw-r--r-- | Cargo.lock | 157 | ||||
| -rw-r--r-- | mumd/Cargo.toml | 2 | ||||
| -rw-r--r-- | mumd/src/audio.rs | 63 | ||||
| -rw-r--r-- | mumd/src/audio/output.rs | 14 | ||||
| -rw-r--r-- | mumd/src/state.rs | 4 |
5 files changed, 221 insertions, 19 deletions
@@ -1,6 +1,15 @@ # This file is automatically @generated by Cargo. # It is not intended for manual editing. [[package]] +name = "aho-corasick" +version = "0.7.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7404febffaa47dac81aa44dba71523c9d069b1bdc50a77db41195149e17f68e5" +dependencies = [ + "memchr", +] + +[[package]] name = "alsa" version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -72,9 +81,32 @@ dependencies = [ [[package]] name = "bindgen" -version = "0.53.3" +version = "0.51.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c72a978d268b1d70b0e963217e60fdabd9523a941457a6c42a7315d15c7e89e5" +checksum = "ebd71393f1ec0509b553aa012b9b58e81dadbdff7130bd3b8cba576e69b32f75" +dependencies = [ + "bitflags", + "cexpr", + "cfg-if", + "clang-sys", + "clap", + "env_logger", + "lazy_static", + "log", + "peeking_take_while", + "proc-macro2", + "quote", + "regex", + "rustc-hash", + "shlex", + "which", +] + +[[package]] +name = "bindgen" +version = "0.53.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "99de13bb6361e01e493b3db7928085dcc474b7ba4f5481818e53a89d76b8393f" dependencies = [ "bitflags", "cexpr", @@ -122,9 +154,9 @@ checksum = "ed67cbde08356238e75fc4656be4749481eeffb09e19f320a25237d5221c985d" [[package]] name = "cexpr" -version = "0.4.0" +version = "0.3.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f4aedb84272dbe89af497cf81375129abda4fc0a9e7c5d317498c15cc30c0d27" +checksum = "fce5b5fb86b0c57c20c834c1b412fd09c77c8a59b9473f86272709e78874cd1d" dependencies = [ "nom", ] @@ -150,9 +182,9 @@ dependencies = [ [[package]] name = "clang-sys" -version = "0.29.3" +version = "0.28.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fe6837df1d5cba2397b835c8530f51723267e16abbf83892e9e5af4f0e5dd10a" +checksum = "81de550971c976f176130da4b2978d3b524eaa0fd9ac31f3ceb5ae1231fb4853" dependencies = [ "glob", "libc", @@ -185,6 +217,15 @@ dependencies = [ ] [[package]] +name = "cmake" +version = "0.1.44" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0e56268c17a6248366d66d4a47a3381369d068cce8409bb1716ed77ea32163bb" +dependencies = [ + "cc", +] + +[[package]] name = "colored" version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -233,7 +274,7 @@ version = "0.2.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d6570ee6e089131e928d5ec9236db9e818aa3cf850f48b0eec6ef700571271d4" dependencies = [ - "bindgen", + "bindgen 0.53.1", ] [[package]] @@ -278,6 +319,19 @@ dependencies = [ ] [[package]] +name = "env_logger" +version = "0.6.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aafcde04e90a5226a6443b7aabdb016ba2f8307c847d524724bd9b346dd1a2d3" +dependencies = [ + "atty", + "humantime", + "log", + "regex", + "termcolor", +] + +[[package]] name = "fern" version = "0.5.9" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -522,6 +576,21 @@ dependencies = [ ] [[package]] +name = "hound" +version = "3.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a164bb2ceaeff4f42542bdb847c41517c78a60f5649671b2a07312b6e117549" + +[[package]] +name = "humantime" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "df004cfca50ef23c36850aaaa59ad52cc70d0e90243c3c7737a4dd32dc7a3c4f" +dependencies = [ + "quick-error", +] + +[[package]] name = "iovec" version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -624,6 +693,16 @@ dependencies = [ ] [[package]] +name = "libsamplerate-sys" +version = "0.1.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "66575d1d489214f8767f90de2b1e115626d8277ca09d7c39549652a9602309eb" +dependencies = [ + "bindgen 0.51.1", + "cmake", +] + +[[package]] name = "lock_api" version = "0.3.4" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -760,6 +839,7 @@ dependencies = [ "cpal", "futures", "futures-util", + "hound", "ipc-channel", "libnotify", "log", @@ -768,6 +848,7 @@ dependencies = [ "native-tls", "openssl", "opus", + "samplerate", "serde", "tokio", "tokio-tls", @@ -830,9 +911,9 @@ dependencies = [ [[package]] name = "nom" -version = "5.1.2" +version = "4.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ffb4262d26ed83a1c0a33a38fe2bb15797329c85770da05e6b828ddb782627af" +checksum = "2ad2a91a8e869eeb30b9cb3119ae87773a8f4ae617f41b1eb9c154b2905f7bd6" dependencies = [ "memchr", "version_check", @@ -1049,6 +1130,12 @@ dependencies = [ ] [[package]] +name = "quick-error" +version = "1.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1d01941d82fa2ab50be1e79e6714289dd7cde78eba4c074bc5a4374f650dfe0" + +[[package]] name = "quote" version = "1.0.7" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -1110,7 +1197,10 @@ version = "1.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8963b85b8ce3074fecffde43b4b0dded83ce2f367dc8d363afc56679f3ee820b" dependencies = [ + "aho-corasick", + "memchr", "regex-syntax", + "thread_local", ] [[package]] @@ -1144,6 +1234,15 @@ dependencies = [ ] [[package]] +name = "samplerate" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a6913e9f2ad7d0aa9528523f7e4385e160d690c66d43bb8bd7559f1be705aee8" +dependencies = [ + "libsamplerate-sys", +] + +[[package]] name = "schannel" version = "0.1.19" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -1298,6 +1397,15 @@ dependencies = [ ] [[package]] +name = "termcolor" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bb6bfa289a4d7c5766392812c0a1f4c1ba45afa1ad47803c11e1f407d846d75f" +dependencies = [ + "winapi-util", +] + +[[package]] name = "textwrap" version = "0.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -1327,6 +1435,15 @@ dependencies = [ ] [[package]] +name = "thread_local" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d40c6d1b69745a6ec6fb1ca717914848da4b44ae29d9b3080cbee91d72a69b14" +dependencies = [ + "lazy_static", +] + +[[package]] name = "time" version = "0.1.44" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -1440,9 +1557,9 @@ checksum = "f1bddf1187be692e79c5ffeab891132dfb0f236ed36a43c7ed39f1165ee20191" [[package]] name = "version_check" -version = "0.9.2" +version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b5a972e5669d67ba988ce3dc826706fb0a8b01471c088cb0b6110b805cc36aed" +checksum = "914b1a6776c4c929a602fafd8bc742e06365d4bcbe48c30f9cca5824f70dc9dd" [[package]] name = "void" @@ -1527,6 +1644,15 @@ dependencies = [ ] [[package]] +name = "which" +version = "3.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d011071ae14a2f6671d0b74080ae0cd8ebf3a6f8c9589a2cd45f23126fe29724" +dependencies = [ + "libc", +] + +[[package]] name = "winapi" version = "0.2.8" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -1555,6 +1681,15 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" [[package]] +name = "winapi-util" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "70ec6ce85bb158151cae5e5c87f95a8e97d2c0c4b001223f33a334e3ce5de178" +dependencies = [ + "winapi 0.3.9", +] + +[[package]] name = "winapi-x86_64-pc-windows-gnu" version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" 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); } } } |
