1use super::INTERNAL_SAMPLERATE;
2use super::track::track_codec::TrackCodec;
3use crate::event::{EventSender, SessionEvent};
4use crate::media::{AudioFrame, Samples, SourcePacket};
5use anyhow::Result;
6use std::any::Any;
7use std::sync::{Arc, Mutex, RwLock};
8use tokio::sync::mpsc;
9
10pub trait Processor: Send + Sync + Any {
11 fn process_frame(&mut self, frame: &mut AudioFrame) -> Result<()>;
12}
13
14pub fn convert_to_mono(samples: &mut Vec<i16>, channels: u16) {
15 if channels != 2 {
16 return;
17 }
18 let mut i = 0;
19 let mut j = 0;
20 while i < samples.len() {
21 let l = samples[i] as i32;
22 let r = samples[i + 1] as i32;
23 samples[j] = ((l + r) / 2) as i16;
24 i += 2;
25 j += 1;
26 }
27 samples.truncate(j);
28}
29
30impl Default for AudioFrame {
31 fn default() -> Self {
32 Self {
33 track_id: "".to_string(),
34 samples: Samples::Empty,
35 timestamp: 0,
36 sample_rate: 16000,
37 channels: 1,
38 src_packet: None,
39 speech_probability: None,
40 }
41 }
42}
43
44impl Samples {
45 pub fn is_empty(&self) -> bool {
46 match self {
47 Samples::PCM { samples } => samples.is_empty(),
48 Samples::RTP { payload, .. } => payload.is_empty(),
49 Samples::Empty => true,
50 }
51 }
52}
53
54#[derive(Clone)]
55pub struct ProcessorChain {
56 processors: Arc<Mutex<Vec<Box<dyn Processor>>>>,
57 pub codec: TrackCodec,
58 sample_rate: u32,
59 pub force_decode: bool,
60 pub raw_tap: Arc<RwLock<Option<mpsc::UnboundedSender<AudioFrame>>>>,
69}
70
71fn lock_processors(
82 processors: &Mutex<Vec<Box<dyn Processor>>>,
83) -> std::sync::MutexGuard<'_, Vec<Box<dyn Processor>>> {
84 processors.lock().unwrap_or_else(|e| e.into_inner())
85}
86
87impl ProcessorChain {
88 pub fn new(_sample_rate: u32) -> Self {
89 Self {
90 processors: Arc::new(Mutex::new(Vec::new())),
91 codec: TrackCodec::new(),
92 sample_rate: INTERNAL_SAMPLERATE,
93 force_decode: true,
94 raw_tap: Arc::new(RwLock::new(None)),
95 }
96 }
97 pub fn set_raw_tap(&mut self, tap: Option<mpsc::UnboundedSender<AudioFrame>>) {
98 *self.raw_tap.write().unwrap() = tap;
99 }
100 fn raw_tap(&self) -> Option<mpsc::UnboundedSender<AudioFrame>> {
101 self.raw_tap.read().unwrap().clone()
102 }
103 pub fn insert_processor(&mut self, processor: Box<dyn Processor>) {
104 lock_processors(&self.processors).insert(0, processor);
105 }
106 pub fn append_processor(&mut self, processor: Box<dyn Processor>) {
107 lock_processors(&self.processors).push(processor);
108 }
109
110 pub fn has_processor<T: 'static>(&self) -> bool {
111 let processors = lock_processors(&self.processors);
112 processors
113 .iter()
114 .any(|processor| (processor.as_ref() as &dyn Any).is::<T>())
115 }
116
117 pub fn remove_processor<T: 'static>(&self) {
118 let mut processors = lock_processors(&self.processors);
119 processors.retain(|processor| !(processor.as_ref() as &dyn Any).is::<T>());
120 }
121
122 pub fn process_frame(&mut self, frame: &mut AudioFrame) -> Result<()> {
123 let mut processors = lock_processors(&self.processors);
124 if !self.force_decode && processors.is_empty() && self.raw_tap().is_none() {
125 return Ok(());
126 }
127 match &mut frame.samples {
128 Samples::RTP {
129 payload_type,
130 payload,
131 sequence_number,
132 } => {
133 if TrackCodec::is_audio(*payload_type) {
134 let (decoded_sample_rate, channels, samples) =
135 self.codec.decode(*payload_type, &payload);
136 let src_packet = SourcePacket {
137 sequence_number: *sequence_number,
138 payload_type: *payload_type,
139 payload: std::mem::take(payload),
140 };
141 frame.src_packet = Some(src_packet);
142 frame.channels = channels;
143 frame.samples = Samples::PCM { samples };
144 frame.sample_rate = decoded_sample_rate;
145 }
146 }
147 _ => {}
148 }
149
150 if let Some(tap) = self.raw_tap()
153 && let Samples::PCM { samples } = &frame.samples
154 && !samples.is_empty()
155 && frame.sample_rate > 0
156 {
157 let mut raw = frame.clone();
158 raw.src_packet = None;
159 let mono = match &mut raw.samples {
160 Samples::PCM { samples } => samples,
161 _ => unreachable!("checked PCM above"),
162 };
163 if raw.channels == 2 {
164 convert_to_mono(mono, 2);
165 raw.channels = 1;
166 }
167 let _ = tap.send(raw);
168 }
169
170 if let Samples::PCM { samples } = &mut frame.samples {
171 if frame.sample_rate != self.sample_rate {
172 let new_samples = self.codec.resample(
173 std::mem::take(samples),
174 frame.sample_rate,
175 self.sample_rate,
176 );
177 *samples = new_samples;
178 frame.sample_rate = self.sample_rate;
179 }
180 if frame.channels == 2 {
181 convert_to_mono(samples, 2);
182 frame.channels = 1;
183 }
184 }
185 for processor in processors.iter_mut() {
187 processor.process_frame(frame)?;
188 }
189 Ok(())
190 }
191}
192
193pub struct SubscribeProcessor {
194 event_sender: EventSender,
195 track_id: String,
196 track_index: u8, }
198
199impl SubscribeProcessor {
200 pub fn new(event_sender: EventSender, track_id: String, track_index: u8) -> Self {
201 Self {
202 event_sender,
203 track_id,
204 track_index,
205 }
206 }
207}
208
209impl Processor for SubscribeProcessor {
210 fn process_frame(&mut self, frame: &mut AudioFrame) -> Result<()> {
211 if let Samples::PCM { samples } = &frame.samples {
212 if !samples.is_empty() {
213 let pcm_data = audio_codec::samples_to_bytes(samples);
214 let mut data = Vec::with_capacity(pcm_data.len() + 1);
215 data.push(self.track_index);
216 data.extend_from_slice(&pcm_data);
217
218 let event = SessionEvent::Binary {
219 track_id: self.track_id.clone(),
220 timestamp: frame.timestamp,
221 data,
222 };
223 self.event_sender.send(event).ok();
224 }
225 }
226 Ok(())
227 }
228}
229
230#[cfg(test)]
231mod tests {
232 use super::*;
233
234 #[test]
240 fn raw_tap_visible_to_clones_taken_before_attach() {
241 let mut chain = ProcessorChain::new(INTERNAL_SAMPLERATE);
242 let mut worker = chain.clone();
243
244 let (tx, mut rx) = mpsc::unbounded_channel();
245 chain.set_raw_tap(Some(tx));
246
247 let mut frame = AudioFrame {
248 track_id: "track".to_string(),
249 samples: Samples::PCM {
250 samples: vec![100i16; 160],
251 },
252 sample_rate: 8000,
253 channels: 1,
254 ..Default::default()
255 };
256 worker.process_frame(&mut frame).unwrap();
257
258 let raw = rx
259 .try_recv()
260 .expect("raw tap should receive a frame from a pre-attach clone");
261 assert_eq!(raw.sample_rate, 8000);
262 assert_eq!(raw.channels, 1);
263 match raw.samples {
264 Samples::PCM { samples } => assert_eq!(samples.len(), 160),
265 _ => panic!("expected PCM samples on the raw tap"),
266 }
267 assert_eq!(frame.sample_rate, INTERNAL_SAMPLERATE);
269 }
270
271 #[test]
274 fn raw_tap_detach_visible_to_clones() {
275 let mut chain = ProcessorChain::new(INTERNAL_SAMPLERATE);
276 let (tx, _rx) = mpsc::unbounded_channel();
277 chain.set_raw_tap(Some(tx));
278 let mut worker = chain.clone();
279 chain.set_raw_tap(None);
280
281 let mut frame = AudioFrame {
282 track_id: "track".to_string(),
283 samples: Samples::PCM {
284 samples: vec![100i16; 160],
285 },
286 sample_rate: 8000,
287 channels: 1,
288 ..Default::default()
289 };
290 worker.process_frame(&mut frame).unwrap();
291 assert_eq!(frame.sample_rate, INTERNAL_SAMPLERATE);
292 }
293
294 #[test]
298 fn process_frame_tolerates_zero_sample_rate() {
299 let mut chain = ProcessorChain::new(INTERNAL_SAMPLERATE);
300 let mut frame = AudioFrame {
301 track_id: "track".to_string(),
302 samples: Samples::PCM {
303 samples: vec![100i16; 160],
304 },
305 sample_rate: 0,
306 channels: 1,
307 ..Default::default()
308 };
309
310 chain.process_frame(&mut frame).unwrap();
311 assert_eq!(frame.sample_rate, INTERNAL_SAMPLERATE);
312 match frame.samples {
313 Samples::PCM { samples } => assert_eq!(samples.len(), 160),
314 _ => panic!("expected PCM samples"),
315 }
316 }
317}