diff options
| author | Gustav Sörnäs <gustav@sornas.net> | 2021-06-19 17:29:04 +0200 |
|---|---|---|
| committer | Gustav Sörnäs <gustav@sornas.net> | 2021-06-19 17:29:04 +0200 |
| commit | ee13c1662eba47ffe2716bdc26bbfcd0609ff521 (patch) | |
| tree | 443c4dc15ba7dd897f8de80a8fb094780c1628ae /mumd | |
| parent | a3be71e2f6b21ae4c8bac8b7ffd1d3f147357339 (diff) | |
| parent | 4a1d75e0f5f960c59dfba153212aca4830c28237 (diff) | |
| download | mum-ee13c1662eba47ffe2716bdc26bbfcd0609ff521.tar.gz | |
Merge remote-tracking branch 'origin/positional-positioning' into ogg
Diffstat (limited to 'mumd')
| -rw-r--r-- | mumd/src/audio.rs | 2 | ||||
| -rw-r--r-- | mumd/src/audio/input.rs | 4 | ||||
| -rw-r--r-- | mumd/src/audio/output.rs | 108 | ||||
| -rw-r--r-- | mumd/src/audio/transformers.rs | 6 |
4 files changed, 84 insertions, 36 deletions
diff --git a/mumd/src/audio.rs b/mumd/src/audio.rs index a04f0da..46fcca4 100644 --- a/mumd/src/audio.rs +++ b/mumd/src/audio.rs @@ -143,6 +143,6 @@ impl AudioOutput { pub fn play_effect(&self, effect: NotificationEvents) { let samples = self.sounds.get(&effect).unwrap(); - self.client_streams.lock().unwrap().extend(None, samples); + self.client_streams.lock().unwrap().add_sound_effect(samples); } } diff --git a/mumd/src/audio/input.rs b/mumd/src/audio/input.rs index a1227e3..25d15d5 100644 --- a/mumd/src/audio/input.rs +++ b/mumd/src/audio/input.rs @@ -29,8 +29,8 @@ pub fn callback<T: Sample>( buffer.extend(data.by_ref().take(buffer_size - buffer.len())); let encoded = transformers .iter_mut() - .try_fold(&mut buffer[..], |acc, e| e.transform(acc)) - .map(|buf| opus_encoder.encode_vec_float(&*buf, buffer_size).unwrap()); + .try_fold((opus::Channels::Mono, &mut buffer[..]), |acc, e| e.transform(acc)) + .map(|buf| opus_encoder.encode_vec_float(&*buf.1, buffer_size).unwrap()); if let Some(encoded) = encoded { if let Err(e) = input_sender.try_send(encoded) { diff --git a/mumd/src/audio/output.rs b/mumd/src/audio/output.rs index 9f2ac25..924893a 100644 --- a/mumd/src/audio/output.rs +++ b/mumd/src/audio/output.rs @@ -2,22 +2,71 @@ use crate::audio::SAMPLE_RATE; use crate::error::{AudioError, AudioStream}; use crate::network::VoiceStreamType; +use bytes::Bytes; use cpal::traits::{DeviceTrait, HostTrait, StreamTrait}; use cpal::{OutputCallbackInfo, Sample, SampleFormat, SampleRate, StreamConfig}; +use dasp_ring_buffer::Bounded; use log::*; use mumble_protocol::voice::VoicePacketPayload; use std::collections::{HashMap, VecDeque}; +use std::iter; use std::ops::AddAssign; use std::sync::{Arc, Mutex}; use tokio::sync::watch; type ClientStreamKey = (VoiceStreamType, u32); +pub struct ClientAudioData { + buf: Bounded<Vec<f32>>, + output_channels: opus::Channels, + //we need two since a client can hypothetically send both mono + //and stereo packets, and we can't switch a decoder on the fly + //to reuse it + mono_decoder: opus::Decoder, + stereo_decoder: opus::Decoder, +} + +impl ClientAudioData { + pub fn new(sample_rate: u32, output_channels: opus::Channels) -> Self { + Self { + mono_decoder: opus::Decoder::new(sample_rate, opus::Channels::Mono).unwrap(), + stereo_decoder: opus::Decoder::new(sample_rate, opus::Channels::Stereo).unwrap(), + output_channels, + buf: Bounded::from_full(vec![0.0; sample_rate as usize * output_channels as usize]), //buffer 1 s of audio + } + } + + pub fn store_packet(&mut self, bytes: Bytes) { + let packet_channels = opus::packet::get_nb_channels(&bytes).unwrap(); + let (decoder, channels) = match packet_channels { + opus::Channels::Mono => (&mut self.mono_decoder, 1), + opus::Channels::Stereo => (&mut self.stereo_decoder, 2), + }; + let mut out: Vec<f32> = vec![0.0; 720 * channels * 4]; //720 is because that is the max size of packet we can get that we want to decode + let parsed = decoder + .decode_float(&bytes, &mut out, false) + .expect("Error decoding"); + out.truncate(parsed); + match (packet_channels, self.output_channels) { + (opus::Channels::Mono, opus::Channels::Mono) | (opus::Channels::Stereo, opus::Channels::Stereo) => for sample in out { + self.buf.push(sample); + }, + (opus::Channels::Mono, opus::Channels::Stereo) => for sample in out { + self.buf.push(sample); + self.buf.push(sample); + }, + (opus::Channels::Stereo, opus::Channels::Mono) => for sample in out.into_iter().step_by(2) { + self.buf.push(sample); + }, + } + } +} + pub struct ClientStream { - buffer_clients: HashMap<ClientStreamKey, (VecDeque<f32>, opus::Decoder)>, //TODO ring buffer? + buffer_clients: HashMap<ClientStreamKey, ClientAudioData>, buffer_effects: VecDeque<f32>, sample_rate: u32, - channels: opus::Channels, + output_channels: opus::Channels, } impl ClientStream { @@ -31,29 +80,20 @@ impl ClientStream { buffer_clients: HashMap::new(), buffer_effects: VecDeque::new(), sample_rate, - channels, + output_channels: channels, } } - fn get_client(&mut self, client: ClientStreamKey) -> &mut (VecDeque<f32>, opus::Decoder) { - let sample_rate = self.sample_rate; - let channels = self.channels; - self.buffer_clients.entry(client).or_insert_with(|| { - let opus_decoder = opus::Decoder::new(sample_rate, channels).unwrap(); - (VecDeque::new(), opus_decoder) - }) + fn get_client(&mut self, client: ClientStreamKey) -> &mut ClientAudioData { + self.buffer_clients.entry(client).or_insert( + ClientAudioData::new(self.sample_rate, self.output_channels) + ) } pub fn decode_packet(&mut self, client: ClientStreamKey, payload: VoicePacketPayload) { match payload { VoicePacketPayload::Opus(bytes, _eot) => { - let mut out: Vec<f32> = vec![0.0; 720 * (self.channels as usize) * 4]; //720 is because that is the max size of packet we can get that we want to decode - let (buffer, decoder) = self.get_client(client); - let parsed = decoder - .decode_float(&bytes, &mut out, false) - .expect("Error decoding"); - out.truncate(parsed); - buffer.extend(&out); + self.get_client(client).store_packet(bytes); } _ => { unimplemented!("Payload type not supported"); @@ -61,12 +101,8 @@ impl ClientStream { } } - pub fn extend(&mut self, client: Option<ClientStreamKey>, values: &[f32]) { - let buffer = match client { - Some(x) => &mut self.get_client(x).0, - None => &mut self.buffer_effects, - }; - buffer.extend(values.iter().copied()); + pub fn add_sound_effect(&mut self, values: &[f32]) { + self.buffer_effects.extend(values.iter().copied()); } } @@ -144,32 +180,43 @@ impl DefaultAudioOutputDevice { let err_fn = |err| error!("An error occurred on the output audio stream: {}", err); let (output_volume_sender, output_volume_receiver) = watch::channel::<f32>(output_volume); + let output_channels = match output_config.channels { + 1 => opus::Channels::Mono, + 2 => opus::Channels::Stereo, + _ => { + warn!("Trying to output to an unsupported number of channels ({}), defaulting to mono", output_config.channels); + opus::Channels::Mono + } + }; let output_stream = match output_supported_sample_format { SampleFormat::F32 => output_device.build_output_stream( &output_config, - curry_callback::<f32>( + callback::<f32>( Arc::clone(&client_streams), output_volume_receiver, user_volumes, + output_channels, ), err_fn, ), SampleFormat::I16 => output_device.build_output_stream( &output_config, - curry_callback::<i16>( + callback::<i16>( Arc::clone(&client_streams), output_volume_receiver, user_volumes, + output_channels, ), err_fn, ), SampleFormat::U16 => output_device.build_output_stream( &output_config, - curry_callback::<u16>( + callback::<u16>( Arc::clone(&client_streams), output_volume_receiver, user_volumes, + output_channels, ), err_fn, ), @@ -211,10 +258,11 @@ impl AudioOutputDevice for DefaultAudioOutputDevice { } } -pub fn curry_callback<T: Sample + AddAssign + SaturatingAdd + std::fmt::Display>( +pub fn callback<T: Sample + AddAssign + SaturatingAdd + std::fmt::Display>( user_bufs: Arc<Mutex<ClientStream>>, output_volume_receiver: watch::Receiver<f32>, user_volumes: Arc<Mutex<HashMap<u32, (f32, bool)>>>, + output_channels: opus::Channels, ) -> impl FnMut(&mut [T], &OutputCallbackInfo) + Send + 'static { move |data: &mut [T], _info: &OutputCallbackInfo| { for sample in data.iter_mut() { @@ -227,10 +275,10 @@ pub fn curry_callback<T: Sample + AddAssign + SaturatingAdd + std::fmt::Display> let user_volumes = user_volumes.lock().unwrap(); for (k, v) in user_bufs.buffer_clients.iter_mut() { let (user_volume, muted) = user_volumes.get(&k.1).cloned().unwrap_or((1.0, false)); - for sample in data.iter_mut() { - if !muted { + if !muted { + for (sample, val) in data.iter_mut().zip(v.buf.drain().chain(iter::repeat(0.0))) { *sample = sample.saturating_add(Sample::from( - &(v.0.pop_front().unwrap_or(0.0) * volume * user_volume), + &(val * volume * user_volume), )); } } diff --git a/mumd/src/audio/transformers.rs b/mumd/src/audio/transformers.rs index 25e28b8..91cf3ac 100644 --- a/mumd/src/audio/transformers.rs +++ b/mumd/src/audio/transformers.rs @@ -2,7 +2,7 @@ pub trait Transformer { /// Do the transform. Returning `None` is interpreted as "the buffer is unwanted". /// The implementor is free to modify the buffer however it wants to. - fn transform<'a>(&mut self, buf: &'a mut [f32]) -> Option<&'a mut [f32]>; + fn transform<'a>(&mut self, buf: (opus::Channels, &'a mut [f32])) -> Option<(opus::Channels, &'a mut [f32])>; } /// A struct representing a noise gate transform. @@ -25,7 +25,7 @@ impl NoiseGate { } impl Transformer for NoiseGate { - fn transform<'a>(&mut self, buf: &'a mut [f32]) -> Option<&'a mut [f32]> { + fn transform<'a>(&mut self, (channels, buf): (opus::Channels, &'a mut [f32])) -> Option<(opus::Channels, &'a mut [f32])> { const MUTE_PERCENTAGE: f32 = 0.1; let max = buf.iter().map(|e| e.abs()).max_by(|a, b| a.partial_cmp(b).unwrap()).unwrap(); @@ -43,7 +43,7 @@ impl Transformer for NoiseGate { if self.open == 0 { None } else { - Some(buf) + Some((channels, buf)) } } } |
