servo_media_audio/
offline_sink.rs1use crate::block::{Chunk, FRAMES_PER_BLOCK_USIZE};
2use crate::render_thread::AudioRenderThreadMsg;
3use servo_media_streams::MediaSocket;
4use crate::sink::{AudioSink, AudioSinkError};
5use std::cell::{Cell, RefCell};
6use std::sync::mpsc::Sender;
7
8pub struct ProcessedAudio(Box<[f32]>);
9
10impl AsRef<[f32]> for ProcessedAudio {
11 fn as_ref(&self) -> &[f32] {
12 &self.0
13 }
14}
15
16pub struct OfflineAudioSink {
17 buffer: RefCell<Option<Vec<f32>>>,
18 channel_count: usize,
19 has_enough_data: Cell<bool>,
20 length: usize,
21 rendered_blocks: Cell<usize>,
22 eos_callback: RefCell<Option<Box<dyn Fn(Box<dyn AsRef<[f32]>>) + Send + Sync + 'static>>>,
23}
24
25impl OfflineAudioSink {
26 pub fn new(channel_count: usize, length: usize) -> Self {
27 Self {
28 buffer: RefCell::new(None),
29 channel_count,
30 has_enough_data: Cell::new(false),
31 length,
32 rendered_blocks: Cell::new(0),
33 eos_callback: RefCell::new(None),
34 }
35 }
36}
37
38impl AudioSink for OfflineAudioSink {
39 fn init(&self, _: f32, _: Sender<AudioRenderThreadMsg>) -> Result<(), AudioSinkError> {
40 Ok(())
41 }
42 fn init_stream(&self, _: u8, _: f32, _: Box<dyn MediaSocket>) -> Result<(), AudioSinkError> {
43 unreachable!("OfflineAudioSink should never be used for MediaStreamDestinationNode")
44 }
45 fn play(&self) -> Result<(), AudioSinkError> {
46 self.has_enough_data.set(false);
47 Ok(())
48 }
49
50 fn stop(&self) -> Result<(), AudioSinkError> {
51 self.has_enough_data.set(true);
52 Ok(())
53 }
54
55 fn has_enough_data(&self) -> bool {
56 self.has_enough_data.get()
57 || (self.rendered_blocks.get() * FRAMES_PER_BLOCK_USIZE >= self.length)
58 }
59
60 fn push_data(&self, mut chunk: Chunk) -> Result<(), AudioSinkError> {
61 let offset = self.rendered_blocks.get() * FRAMES_PER_BLOCK_USIZE;
62 let (last, copy_len) = if self.length - offset <= FRAMES_PER_BLOCK_USIZE {
63 (true, self.length - offset)
64 } else {
65 (false, FRAMES_PER_BLOCK_USIZE)
66 };
67 let mut buffer = self.buffer.borrow_mut();
68 if buffer.is_none() {
69 *buffer = Some(vec![0.; self.channel_count * self.length]);
70 }
71 if chunk.len() == 0 {
72 chunk.blocks.push(Default::default());
73 }
74 if chunk.blocks[0].is_empty() {
75 chunk.blocks[0].explicit_silence();
76 }
77 if let Some(ref mut buffer) = *buffer {
78 for channel_number in 0..self.channel_count {
79 let channel_offset = offset + (channel_number * self.length);
80 let channel_data = &mut buffer[channel_offset..channel_offset + copy_len];
81 channel_data
82 .copy_from_slice(&chunk.blocks[0].data_chan(channel_number as u8)[0..copy_len]);
83 }
84 };
85 self.rendered_blocks.set(self.rendered_blocks.get() + 1);
86
87 if last {
88 if let Some(callback) = self.eos_callback.borrow_mut().take() {
89 let processed_audio = ProcessedAudio(buffer.take().unwrap().into_boxed_slice());
90 callback(Box::new(processed_audio));
91 }
92 }
93
94 Ok(())
95 }
96
97 fn set_eos_callback(
98 &self,
99 callback: Box<dyn Fn(Box<dyn AsRef<[f32]>>) + Send + Sync + 'static>,
100 ) {
101 *self.eos_callback.borrow_mut() = Some(callback);
102 }
103}