1pub mod input;
6pub mod output;
7pub mod sound_effects;
8pub mod transformers;
9
10use crate::error::AudioError;
11use crate::network::VoiceStreamType;
12use crate::state::StatePhase;
13
14use futures_util::stream::Stream;
15use futures_util::StreamExt;
16use mumble_protocol::voice::{VoicePacket, VoicePacketPayload};
17use mumble_protocol::Serverbound;
18use mumlib::config::SoundEffect;
19use std::collections::{hash_map::Entry, HashMap};
20use std::fmt::Debug;
21use std::sync::{Arc, Mutex};
22use tokio::sync::watch;
23
24use self::input::{AudioInputDevice, DefaultAudioInputDevice};
25use self::output::{AudioOutputDevice, ClientStream, DefaultAudioOutputDevice};
26use self::sound_effects::NotificationEvents;
27
28const SAMPLE_RATE: u32 = 48000;
30
31pub struct AudioInput {
34 device: DefaultAudioInputDevice,
35
36 channel_receiver:
38 Arc<tokio::sync::Mutex<Box<dyn Stream<Item = VoicePacket<Serverbound>> + Unpin>>>,
39}
40
41impl AudioInput {
42 pub fn new(
43 input_volume: f32,
44 disable_noise_gate: bool,
45 phase_watcher: watch::Receiver<StatePhase>,
46 ) -> Result<Self, AudioError> {
47 let mut default =
48 DefaultAudioInputDevice::new(input_volume, disable_noise_gate, phase_watcher, 4)?;
49
50 let opus_stream = default
51 .sample_receiver()
52 .unwrap()
53 .enumerate()
54 .map(|(i, e)| VoicePacket::Audio {
55 _dst: std::marker::PhantomData,
56 target: 0, session_id: (), seq_num: i as u64,
59 payload: VoicePacketPayload::Opus(e.into(), false),
60 position_info: None,
61 });
62
63 default.play()?;
64
65 let res = Self {
66 device: default,
67 channel_receiver: Arc::new(tokio::sync::Mutex::new(Box::new(opus_stream))),
68 };
69 Ok(res)
70 }
71
72 pub fn receiver(
73 &self,
74 ) -> Arc<tokio::sync::Mutex<Box<dyn Stream<Item = VoicePacket<Serverbound>> + Unpin>>> {
75 Arc::clone(&self.channel_receiver)
76 }
77
78 pub fn set_volume(&self, input_volume: f32) {
79 self.device.set_volume(input_volume);
80 }
81}
82
83impl Debug for AudioInput {
84 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
85 f.debug_struct("AudioInput")
86 .field("device", &self.device)
87 .field("channel_receiver", &"receiver")
88 .finish()
89 }
90}
91
92#[derive(Debug)]
93pub struct AudioOutput {
97 device: DefaultAudioOutputDevice,
98 user_volumes: Arc<Mutex<HashMap<u32, (f32, bool)>>>,
100
101 client_streams: Arc<Mutex<ClientStream>>,
105
106 sounds: HashMap<NotificationEvents, Vec<f32>>,
108}
109
110impl AudioOutput {
111 pub fn new(output_volume: f32) -> Result<Self, AudioError> {
112 let user_volumes = Arc::new(std::sync::Mutex::new(HashMap::new()));
113
114 let default = DefaultAudioOutputDevice::new(output_volume, Arc::clone(&user_volumes))?;
115 default.play()?;
116
117 let client_streams = default.client_streams();
118
119 let mut res = Self {
120 device: default,
121 sounds: HashMap::new(),
122 client_streams,
123 user_volumes,
124 };
125 res.load_sound_effects(&[]);
126 Ok(res)
127 }
128
129 pub fn load_sound_effects(&mut self, overrides: &[SoundEffect]) {
132 self.sounds = sound_effects::load_sound_effects(overrides, self.device.num_channels());
133 }
134
135 pub fn decode_packet_payload(
137 &self,
138 stream_type: VoiceStreamType,
139 session_id: u32,
140 payload: VoicePacketPayload,
141 ) {
142 self.client_streams
143 .lock()
144 .unwrap()
145 .decode_packet((stream_type, session_id), payload);
146 }
147
148 pub fn set_volume(&self, output_volume: f32) {
150 self.device.set_volume(output_volume);
151 }
152
153 pub fn set_user_volume(&self, id: u32, volume: f32) {
155 match self.user_volumes.lock().unwrap().entry(id) {
156 Entry::Occupied(mut entry) => {
157 entry.get_mut().0 = volume;
158 }
159 Entry::Vacant(entry) => {
160 entry.insert((volume, false));
161 }
162 }
163 }
164
165 pub fn set_mute(&self, id: u32, mute: bool) {
167 match self.user_volumes.lock().unwrap().entry(id) {
168 Entry::Occupied(mut entry) => {
169 entry.get_mut().1 = mute;
170 }
171 Entry::Vacant(entry) => {
172 entry.insert((1.0, mute));
173 }
174 }
175 }
176
177 pub fn play_effect(&self, effect: NotificationEvents) {
179 let samples = self.sounds.get(&effect).unwrap();
180 self.client_streams
181 .lock()
182 .unwrap()
183 .add_sound_effect(samples);
184 }
185}