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 {
123 for sample in samples.iter_mut() {
126 *sample = 0;
127 }
128 }
129 }
130 Ok(())
131 }
132}
133
134#[cfg(test)]
135mod tests {
136 use super::*;
137 use crate::media::Samples;
138
139 #[test]
140 fn test_volume_control() {
141 let processor = VolumeControlProcessor::new();
142
143 assert!((processor.get_volume() - 1.0).abs() < f32::EPSILON);
145 assert!(!processor.is_muted());
146
147 processor.set_volume(0.5);
149 assert!((processor.get_volume() - 0.5).abs() < f32::EPSILON);
150
151 processor.set_muted(true);
153 assert!(processor.is_muted());
154 }
155
156 #[test]
157 fn test_volume_processing() {
158 let mut processor = VolumeControlProcessor::new();
159 processor.set_volume(0.5);
160
161 let mut frame = AudioFrame {
162 track_id: "test".to_string(),
163 samples: Samples::PCM {
164 samples: vec![1000, -1000, 500, -500],
165 },
166 timestamp: 0,
167 sample_rate: 16000,
168 channels: 1,
169 ..Default::default()
170 };
171
172 processor.process_frame(&mut frame).unwrap();
173
174 if let Samples::PCM { samples } = frame.samples {
175 assert_eq!(samples, vec![500, -500, 250, -250]);
176 } else {
177 panic!("Expected PCM samples");
178 }
179 }
180
181 #[test]
182 fn test_mute_processing() {
183 let mut processor = VolumeControlProcessor::new();
184 processor.set_muted(true);
185
186 let mut frame = AudioFrame {
187 track_id: "test".to_string(),
188 samples: Samples::PCM {
189 samples: vec![1000, -1000, 500, -500],
190 },
191 timestamp: 0,
192 sample_rate: 16000,
193 channels: 1,
194 ..Default::default()
195 };
196
197 processor.process_frame(&mut frame).unwrap();
198
199 if let Samples::PCM { samples } = frame.samples {
200 assert_eq!(samples, vec![0, 0, 0, 0]);
201 } else {
202 panic!("Expected PCM samples");
203 }
204 }
205
206 #[test]
207 fn test_hold_processor() {
208 let processor = HoldProcessor::new();
209
210 assert!(!processor.is_on_hold());
212
213 processor.set_hold(true);
215 assert!(processor.is_on_hold());
216
217 let new_state = processor.toggle_hold();
219 assert!(!new_state);
220 assert!(!processor.is_on_hold());
221 }
222}