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