active_call/media/
volume_control.rs1use super::processor::Processor;
2use crate::media::AudioFrame;
3use anyhow::Result;
4use std::sync::{
5 Arc,
6 atomic::{AtomicBool, AtomicU32, Ordering},
7};
8
9#[derive(Debug, Clone)]
11pub struct VolumeControlProcessor {
12 volume_level: Arc<AtomicU32>,
14 muted: Arc<AtomicBool>,
16}
17
18impl Default for VolumeControlProcessor {
19 fn default() -> Self {
20 Self::new()
21 }
22}
23
24impl VolumeControlProcessor {
25 pub fn new() -> Self {
26 Self {
27 volume_level: Arc::new(AtomicU32::new(1.0_f32.to_bits())),
28 muted: Arc::new(AtomicBool::new(false)),
29 }
30 }
31
32 pub fn set_volume(&self, level: f32) {
33 let clamped_level = level.clamp(0.0, 2.0);
34 self.volume_level
35 .store(clamped_level.to_bits(), Ordering::Relaxed);
36 }
37
38 pub fn get_volume(&self) -> f32 {
39 f32::from_bits(self.volume_level.load(Ordering::Relaxed))
40 }
41
42 pub fn set_muted(&self, muted: bool) {
43 self.muted.store(muted, Ordering::Relaxed);
44 }
45
46 pub fn is_muted(&self) -> bool {
47 self.muted.load(Ordering::Relaxed)
48 }
49
50 pub fn toggle_mute(&self) -> bool {
51 !self.muted.fetch_xor(true, Ordering::Relaxed)
53 }
54}
55
56impl Processor for VolumeControlProcessor {
57 fn process_frame(&mut self, frame: &mut AudioFrame) -> Result<()> {
58 if self.is_muted() {
60 if let crate::media::Samples::PCM { samples } = &mut frame.samples {
62 for sample in samples.iter_mut() {
63 *sample = 0;
64 }
65 }
66 return Ok(());
67 }
68
69 let volume = self.get_volume();
71 if (volume - 1.0).abs() > f32::EPSILON {
72 if let crate::media::Samples::PCM { samples } = &mut frame.samples {
73 for sample in samples.iter_mut() {
74 let adjusted = (*sample as f32 * volume) as i16;
75 *sample = adjusted.clamp(i16::MIN, i16::MAX);
76 }
77 }
78 }
79
80 Ok(())
81 }
82}
83
84#[derive(Debug, Clone)]
86pub struct HoldProcessor {
87 on_hold: Arc<AtomicBool>,
89}
90
91impl Default for HoldProcessor {
92 fn default() -> Self {
93 Self::new()
94 }
95}
96
97impl HoldProcessor {
98 pub fn new() -> Self {
99 Self {
100 on_hold: Arc::new(AtomicBool::new(false)),
101 }
102 }
103
104 pub fn set_hold(&self, hold: bool) {
105 self.on_hold.store(hold, Ordering::Relaxed);
106 }
107
108 pub fn is_on_hold(&self) -> bool {
109 self.on_hold.load(Ordering::Relaxed)
110 }
111
112 pub fn toggle_hold(&self) -> bool {
113 !self.on_hold.fetch_xor(true, Ordering::Relaxed)
115 }
116}
117
118impl Processor for HoldProcessor {
119 fn process_frame(&mut self, frame: &mut AudioFrame) -> Result<()> {
120 if self.is_on_hold() {
121 if let crate::media::Samples::PCM { samples } = &mut frame.samples {
125 for sample in samples.iter_mut() {
128 *sample = 0;
129 }
130 }
133 }
134 Ok(())
135 }
136}
137
138#[cfg(test)]
139mod tests {
140 use super::*;
141 use crate::media::Samples;
142
143 #[test]
144 fn test_volume_control() {
145 let processor = VolumeControlProcessor::new();
146
147 assert!((processor.get_volume() - 1.0).abs() < f32::EPSILON);
149 assert!(!processor.is_muted());
150
151 processor.set_volume(0.5);
153 assert!((processor.get_volume() - 0.5).abs() < f32::EPSILON);
154
155 processor.set_muted(true);
157 assert!(processor.is_muted());
158 }
159
160 #[test]
161 fn test_volume_processing() {
162 let mut processor = VolumeControlProcessor::new();
163 processor.set_volume(0.5);
164
165 let mut frame = AudioFrame {
166 track_id: "test".to_string(),
167 samples: Samples::PCM {
168 samples: vec![1000, -1000, 500, -500],
169 },
170 timestamp: 0,
171 sample_rate: 16000,
172 channels: 1,
173 ..Default::default()
174 };
175
176 processor.process_frame(&mut frame).unwrap();
177
178 if let Samples::PCM { samples } = frame.samples {
179 assert_eq!(samples, vec![500, -500, 250, -250]);
180 } else {
181 panic!("Expected PCM samples");
182 }
183 }
184
185 #[test]
186 fn test_mute_processing() {
187 let mut processor = VolumeControlProcessor::new();
188 processor.set_muted(true);
189
190 let mut frame = AudioFrame {
191 track_id: "test".to_string(),
192 samples: Samples::PCM {
193 samples: vec![1000, -1000, 500, -500],
194 },
195 timestamp: 0,
196 sample_rate: 16000,
197 channels: 1,
198 ..Default::default()
199 };
200
201 processor.process_frame(&mut frame).unwrap();
202
203 if let Samples::PCM { samples } = frame.samples {
204 assert_eq!(samples, vec![0, 0, 0, 0]);
205 } else {
206 panic!("Expected PCM samples");
207 }
208 }
209
210 #[test]
211 fn test_hold_processor() {
212 let processor = HoldProcessor::new();
213
214 assert!(!processor.is_on_hold());
216
217 processor.set_hold(true);
219 assert!(processor.is_on_hold());
220
221 let new_state = processor.toggle_hold();
223 assert!(!new_state);
224 assert!(!processor.is_on_hold());
225 }
226}