web_audio_api/
media_element.rs1use std::error::Error;
2use std::path::PathBuf;
3use std::sync::atomic::{AtomicBool, Ordering};
4use std::sync::Arc;
5
6use creek::{ReadDiskStream, SeekMode, SymphoniaDecoder};
7use crossbeam_channel::{Receiver, Sender};
8
9use crate::{AtomicF64, AudioBuffer, RENDER_QUANTUM_SIZE};
10
11pub(crate) struct RTSStream {
13 stream: ReadDiskStream<SymphoniaDecoder>,
14 number_of_channels: usize,
15 current_time: Arc<AtomicF64>,
16 receiver: Receiver<MediaElementAction>,
17 loop_: Arc<AtomicBool>,
18 paused: Arc<AtomicBool>,
19 playback_rate: Arc<AtomicF64>,
20}
21
22impl std::fmt::Debug for RTSStream {
23 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
24 f.debug_struct("RTSStream")
25 .field("number_of_channels", &self.number_of_channels)
26 .finish_non_exhaustive()
27 }
28}
29
30pub(crate) enum MediaElementAction {
32 Seek(f64),
34 SetLoop(bool),
36 Play,
38 Pause,
40 SetPlaybackRate(f64),
42}
43
44pub struct MediaElement {
49 stream: Option<RTSStream>,
50 current_time: Arc<AtomicF64>,
51 sender: Sender<MediaElementAction>,
52 loop_: Arc<AtomicBool>,
53 paused: Arc<AtomicBool>,
54 playback_rate: Arc<AtomicF64>,
55}
56
57impl std::fmt::Debug for MediaElement {
58 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
59 f.debug_struct("MediaElement")
60 .field("stream", &self.stream)
61 .field("current_time", &self.current_time())
62 .field("loop", &self.loop_())
63 .field("paused", &self.paused())
64 .field("playback_rate", &self.playback_rate())
65 .finish_non_exhaustive()
66 }
67}
68
69impl MediaElement {
70 pub fn new<P: Into<PathBuf>>(file: P) -> Result<Self, Box<dyn Error>> {
72 let mut read_disk_stream = ReadDiskStream::<SymphoniaDecoder>::new(
74 file, 0, Default::default(), )?;
78 let number_of_channels = read_disk_stream.info().num_channels as usize;
79
80 let _ = read_disk_stream.cache(0, 0);
82
83 read_disk_stream.seek(0, SeekMode::default())?;
86
87 read_disk_stream.block_until_ready()?;
89
90 let (sender, receiver) = crossbeam_channel::bounded(32);
95 let current_time = Arc::new(AtomicF64::new(0.));
97
98 let loop_ = Arc::new(AtomicBool::new(false));
99 let paused = Arc::new(AtomicBool::new(true));
100 let playback_rate = Arc::new(AtomicF64::new(1.));
101
102 let rts_stream = RTSStream {
103 stream: read_disk_stream,
104 number_of_channels,
105 current_time: Arc::clone(¤t_time),
106 receiver,
107 loop_: Arc::clone(&loop_),
108 paused: Arc::clone(&paused),
109 playback_rate: Arc::clone(&playback_rate),
110 };
111
112 Ok(Self {
113 stream: Some(rts_stream),
114 current_time,
115 sender,
116 loop_,
117 paused,
118 playback_rate,
119 })
120 }
121
122 pub(crate) fn take_stream(&mut self) -> Option<RTSStream> {
123 self.stream.take()
124 }
125
126 pub fn current_time(&self) -> f64 {
127 self.current_time.load(Ordering::SeqCst)
128 }
129
130 pub fn set_current_time(&self, value: f64) {
131 let _ = self.sender.send(MediaElementAction::Seek(value));
132 }
133
134 pub fn loop_(&self) -> bool {
135 self.loop_.load(Ordering::SeqCst)
136 }
137
138 pub fn set_loop(&self, value: bool) {
139 let _ = self.sender.send(MediaElementAction::SetLoop(value));
140 }
141
142 pub fn play(&self) {
143 let _ = self.sender.send(MediaElementAction::Play);
144 }
145
146 pub fn pause(&self) {
147 let _ = self.sender.send(MediaElementAction::Pause);
148 }
149
150 pub fn paused(&self) -> bool {
151 self.paused.load(Ordering::SeqCst)
152 }
153
154 pub fn playback_rate(&self) -> f64 {
155 self.playback_rate.load(Ordering::SeqCst)
156 }
157
158 pub fn set_playback_rate(&self, value: f64) {
159 let _ = self.sender.send(MediaElementAction::SetPlaybackRate(value));
160 }
161}
162
163impl Iterator for RTSStream {
164 type Item = Result<AudioBuffer, Box<dyn Error + Send + Sync>>;
165
166 fn next(&mut self) -> Option<Self::Item> {
167 let sample_rate = self.stream.info().sample_rate.unwrap() as f32;
168
169 if let Ok(msg) = self.receiver.try_recv() {
170 use MediaElementAction::*;
171 match msg {
172 Seek(value) => {
173 self.current_time.store(value, Ordering::SeqCst);
174 let frame = (value * sample_rate as f64) as usize;
175 self.stream.seek(frame, SeekMode::default()).unwrap();
176 }
177 SetLoop(value) => {
178 self.loop_.store(value, Ordering::SeqCst);
179 }
180 Play => self.paused.store(false, Ordering::SeqCst),
181 Pause => self.paused.store(true, Ordering::SeqCst),
182 SetPlaybackRate(value) => self.playback_rate.store(value, Ordering::SeqCst),
183 };
184 }
185
186 if self.paused.load(Ordering::SeqCst) {
187 let silence = AudioBuffer::from(
188 vec![vec![0.; RENDER_QUANTUM_SIZE]; self.number_of_channels],
189 sample_rate,
190 );
191 return Some(Ok(silence));
192 }
193
194 let playback_rate = self.playback_rate.load(Ordering::SeqCst).abs();
195 let _reverse = playback_rate < 0.; let samples = (RENDER_QUANTUM_SIZE as f64 * playback_rate) as usize;
197
198 let next = match self.stream.read(samples) {
199 Ok(data) => {
200 let channels: Vec<_> = (0..data.num_channels())
201 .map(|i| data.read_channel(i).to_vec())
202 .collect();
203 let buf = AudioBuffer::from(channels, sample_rate * playback_rate as f32);
204
205 if self.loop_.load(Ordering::SeqCst) && data.reached_end_of_file() {
206 self.stream.seek(0, SeekMode::default()).unwrap();
207 self.current_time.store(0., Ordering::SeqCst);
208 } else {
209 let current_time = self.current_time.load(Ordering::SeqCst);
210 self.current_time.store(
211 current_time + (RENDER_QUANTUM_SIZE as f64 / sample_rate as f64),
212 Ordering::SeqCst,
213 );
214 }
215
216 Ok(buf)
217 }
218 Err(e) => Err(Box::new(e) as _),
219 };
220
221 Some(next)
222 }
223}