1#![doc = include_str!("../README.md")]
2#![warn(rust_2018_idioms)]
3#![warn(rust_2021_compatibility)]
4#![warn(clippy::missing_panics_doc)]
5#![warn(clippy::clone_on_ref_ptr)]
6#![deny(trivial_numeric_casts)]
7#![deny(missing_debug_implementations)]
8
9use std::error::Error;
10use std::sync::atomic::{AtomicU32, AtomicU64, Ordering};
11
12pub(crate) const RENDER_QUANTUM_SIZE: usize = 128;
15
16pub const MAX_CHANNELS: usize = 32;
18
19mod buffer;
20pub use buffer::*;
21
22mod capacity;
23pub use capacity::*;
24
25mod playback_stats;
26pub use playback_stats::*;
27
28pub mod context;
29
30pub mod media_devices;
31pub mod media_recorder;
32pub mod media_streams;
33
34pub mod node;
35
36mod events;
37pub use events::*;
38
39mod message_port;
40pub use message_port::MessagePort;
41
42mod param;
43pub use param::*;
44
45mod periodic_wave;
46pub use periodic_wave::*;
47
48mod render;
49
50mod stats;
51
52mod spatial;
53pub use spatial::AudioListener;
54
55mod io;
56
57mod analysis;
58mod message;
59
60mod decoding;
61
62mod media_element;
63pub use media_element::MediaElement;
64
65mod resampling;
66pub mod worklet;
67
68#[repr(transparent)]
69pub(crate) struct AtomicF32 {
70 bits: AtomicU32,
71}
72
73impl std::fmt::Debug for AtomicF32 {
74 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
75 f.write_fmt(format_args!("{}", self.load(Ordering::Relaxed)))
76 }
77}
78
79impl AtomicF32 {
80 #[must_use]
81 pub fn new(value: f32) -> Self {
82 Self {
83 bits: AtomicU32::new(value.to_bits()),
84 }
85 }
86
87 #[must_use]
88 pub fn load(&self, ordering: Ordering) -> f32 {
89 f32::from_bits(self.bits.load(ordering))
90 }
91
92 pub fn store(&self, value: f32, ordering: Ordering) {
93 self.bits.store(value.to_bits(), ordering);
94 }
95}
96
97#[repr(transparent)]
99pub(crate) struct AtomicF64 {
100 bits: AtomicU64,
101}
102
103impl std::fmt::Debug for AtomicF64 {
104 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
105 f.write_fmt(format_args!("{}", self.load(Ordering::Relaxed)))
106 }
107}
108
109impl AtomicF64 {
110 #[must_use]
111 pub fn new(value: f64) -> Self {
112 Self {
113 bits: AtomicU64::new(value.to_bits()),
114 }
115 }
116
117 #[must_use]
118 pub fn load(&self, ordering: Ordering) -> f64 {
119 f64::from_bits(self.bits.load(ordering))
120 }
121
122 pub fn store(&self, value: f64, ordering: Ordering) {
123 self.bits.store(value.to_bits(), ordering);
124 }
125}
126
127pub(crate) const MIN_SAMPLE_RATE: f32 = 3_000.;
146
147pub(crate) const MAX_SAMPLE_RATE: f32 = 768_000.;
149
150#[inline(always)]
155pub(crate) fn is_valid_sample_rate(sample_rate: f32) -> bool {
156 (MIN_SAMPLE_RATE..=MAX_SAMPLE_RATE).contains(&sample_rate)
157}
158
159#[track_caller]
160#[inline(always)]
161pub(crate) fn assert_valid_sample_rate(sample_rate: f32) {
162 assert!(
163 is_valid_sample_rate(sample_rate),
164 "NotSupportedError - Invalid sample rate: {:?}, should be in the range [{:?}, {:?}]",
165 sample_rate,
166 MIN_SAMPLE_RATE,
167 MAX_SAMPLE_RATE,
168 );
169}
170
171#[track_caller]
180#[inline(always)]
181pub(crate) fn assert_valid_number_of_channels(number_of_channels: usize) {
182 assert!(
183 number_of_channels > 0 && number_of_channels <= MAX_CHANNELS,
184 "NotSupportedError - Invalid number of channels: {:?} is outside range [1, {:?}]",
185 number_of_channels,
186 MAX_CHANNELS
187 );
188}
189
190#[track_caller]
199#[inline(always)]
200pub(crate) fn assert_valid_channel_number(channel_number: usize, number_of_channels: usize) {
201 assert!(
202 channel_number < number_of_channels,
203 "IndexSizeError - Invalid channel number {:?} (number of channels: {:?})",
204 channel_number,
205 number_of_channels
206 );
207}
208
209#[track_caller]
217#[inline(always)]
218pub(crate) fn assert_valid_buffer_length(length: usize) {
219 assert!(
220 length > 0,
221 "NotSupportedError - Invalid length: {:?} is less than or equal to minimum bound (0)",
222 length,
223 );
224}
225
226#[track_caller]
235#[inline(always)]
236pub(crate) fn assert_valid_time_value(value: f64) {
237 assert!(
238 value.is_finite(),
239 "TypeError - The provided time value is non-finite.",
240 );
241
242 assert!(
243 value >= 0.,
244 "RangeError - The provided time value ({:?}) cannot be negative",
245 value
246 );
247}
248
249pub(crate) trait AudioBufferIter: Iterator<Item = FallibleBuffer> + Send + 'static {}
250
251impl<M: Iterator<Item = FallibleBuffer> + Send + 'static> AudioBufferIter for M {}
252
253type FallibleBuffer = Result<AudioBuffer, Box<dyn Error + Send + Sync>>;
254
255#[cfg(test)]
256mod tests {
257 use float_eq::assert_float_eq;
258
259 use super::*;
260
261 #[test]
262 fn test_atomic_f64() {
263 let f = AtomicF64::new(2.0);
264 assert_float_eq!(f.load(Ordering::SeqCst), 2.0, abs <= 0.);
265
266 f.store(3.0, Ordering::SeqCst);
267 assert_float_eq!(f.load(Ordering::SeqCst), 3.0, abs <= 0.);
268 }
269
270 #[test]
271 fn test_valid_sample_rate() {
272 assert_valid_sample_rate(48000.);
273 assert_valid_sample_rate(3_000.);
274 assert_valid_sample_rate(768_000.);
275 }
276
277 #[test]
278 #[should_panic]
279 fn test_invalid_sample_rate_too_small() {
280 assert_valid_sample_rate(2_999.);
281 }
282
283 #[test]
284 #[should_panic]
285 fn test_invalid_sample_rate_too_big() {
286 assert_valid_sample_rate(768_001.);
287 }
288
289 #[test]
290 #[should_panic]
291 fn test_invalid_number_of_channels_min() {
292 assert_valid_number_of_channels(0);
293 }
294
295 #[test]
296 #[should_panic]
297 fn test_invalid_number_of_channels_max() {
298 assert_valid_number_of_channels(33);
299 }
300
301 #[test]
302 fn test_valid_number_of_channels() {
303 assert_valid_number_of_channels(1);
304 assert_valid_number_of_channels(32);
305 }
306
307 #[test]
308 #[should_panic]
309 fn test_invalid_time_value_non_finite() {
310 assert_valid_time_value(f64::NAN);
311 }
312
313 #[test]
314 #[should_panic]
315 fn test_invalid_time_value_negative() {
316 assert_valid_time_value(-1.);
317 }
318
319 #[test]
320 fn test_valid_time_value() {
321 assert_valid_time_value(0.);
322 assert_valid_time_value(1.);
323 }
324}