diff options
| author | Gustav Sörnäs <gustav@sornas.net> | 2020-10-21 03:37:22 +0200 |
|---|---|---|
| committer | Gustav Sörnäs <gustav@sornas.net> | 2020-10-21 03:37:22 +0200 |
| commit | c9846394ac6cddd82442baadcabad653a28fed66 (patch) | |
| tree | b92afa32fa1e56f5542d921c8f9f1f3befa06648 /mumd/src/audio/output.rs | |
| parent | 1c18f57afe3eae3d61ad44c899d57332e0f71e0c (diff) | |
| download | mum-c9846394ac6cddd82442baadcabad653a28fed66.tar.gz | |
refactor audio into input.rs and output.rs
Diffstat (limited to 'mumd/src/audio/output.rs')
| -rw-r--r-- | mumd/src/audio/output.rs | 90 |
1 files changed, 90 insertions, 0 deletions
diff --git a/mumd/src/audio/output.rs b/mumd/src/audio/output.rs new file mode 100644 index 0000000..94e4b21 --- /dev/null +++ b/mumd/src/audio/output.rs @@ -0,0 +1,90 @@ +use cpal::{OutputCallbackInfo, Sample}; +use mumble_protocol::voice::VoicePacketPayload; +use opus::Channels; +use std::collections::{HashMap, VecDeque}; +use std::ops::AddAssign; +use std::sync::{Arc, Mutex}; + +pub struct ClientStream { + buffer: VecDeque<f32>, //TODO ring buffer? + opus_decoder: opus::Decoder, +} + +impl ClientStream { + pub fn new(sample_rate: u32, channels: u16) -> Self { + Self { + buffer: VecDeque::new(), + opus_decoder: opus::Decoder::new( + sample_rate, + match channels { + 1 => Channels::Mono, + 2 => Channels::Stereo, + _ => unimplemented!("Only 1 or 2 channels supported, got {}", channels), + }, + ) + .unwrap(), + } + } + + pub fn decode_packet(&mut self, payload: VoicePacketPayload, channels: usize) { + match payload { + VoicePacketPayload::Opus(bytes, _eot) => { + 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 = self + .opus_decoder + .decode_float(&bytes, &mut out, false) + .expect("Error decoding"); + out.truncate(parsed); + self.buffer.extend(out); + } + _ => { + unimplemented!("Payload type not supported"); + } + } + } +} + +pub trait SaturatingAdd { + fn saturating_add(self, rhs: Self) -> Self; +} + +impl SaturatingAdd for f32 { + fn saturating_add(self, rhs: Self) -> Self { + match self + rhs { + a if a < -1.0 => -1.0, + a if a > 1.0 => 1.0, + a => a, + } + } +} + +impl SaturatingAdd for i16 { + fn saturating_add(self, rhs: Self) -> Self { + i16::saturating_add(self, rhs) + } +} + +impl SaturatingAdd for u16 { + fn saturating_add(self, rhs: Self) -> Self { + u16::saturating_add(self, rhs) + } +} + +pub fn curry_callback<T: Sample + AddAssign + SaturatingAdd>( + buf: Arc<Mutex<HashMap<u32, ClientStream>>>, +) -> 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 mut lock = buf.lock().unwrap(); + for client_stream in lock.values_mut() { + for sample in data.iter_mut() { + *sample = sample.saturating_add(Sample::from( + &client_stream.buffer.pop_front().unwrap_or(0.0), + )); + } + } + } +} |
