Skip to main content

web_audio_api/
lib.rs

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
12/// Render quantum size, the audio graph is rendered in blocks of RENDER_QUANTUM_SIZE samples
13/// see. <https://webaudio.github.io/web-audio-api/#render-quantum>
14pub(crate) const RENDER_QUANTUM_SIZE: usize = 128;
15
16/// Maximum number of channels for audio processing
17pub 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/// Atomic float 64, only `load` and `store` are supported, no arithmetic
98#[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
127/// Assert that the given sample rate is valid.
128///
129/// Note that in practice sample rates should stand between 8000Hz (lower bound for
130/// voice based applications, e.g. see phone bandwidth) and 96000Hz (for very high
131/// quality audio applications and spectrum manipulation).
132/// Most common sample rates for musical applications are 44100 and 48000.
133///
134/// The Web Audio API specification requires implementations to support every
135/// sample rate in the inclusive range `[3000, 768000]`.
136///
137/// - see <https://webaudio.github.io/web-audio-api/#sample-rates>
138///
139/// # Panics
140///
141/// This function will panic if the given sample rate is outside the inclusive
142/// range `[3000, 768000]`.
143///
144#[track_caller]
145#[inline(always)]
146pub(crate) fn assert_valid_sample_rate(sample_rate: f32) {
147    let min_sample_rate = 3_000.;
148    let max_sample_rate = 768_000.;
149
150    assert!(
151        sample_rate >= min_sample_rate && sample_rate <= max_sample_rate,
152        "NotSupportedError - Invalid sample rate: {:?}, should be in the range [{:?}, {:?}]",
153        sample_rate,
154        min_sample_rate,
155        max_sample_rate,
156    );
157}
158
159/// Assert that the given number of channels is valid.
160///
161/// # Panics
162///
163/// This function will panic if:
164/// - the given number of channels is outside the [1, 32] range,
165///   32 being defined by the MAX_CHANNELS constant.
166///
167#[track_caller]
168#[inline(always)]
169pub(crate) fn assert_valid_number_of_channels(number_of_channels: usize) {
170    assert!(
171        number_of_channels > 0 && number_of_channels <= MAX_CHANNELS,
172        "NotSupportedError - Invalid number of channels: {:?} is outside range [1, {:?}]",
173        number_of_channels,
174        MAX_CHANNELS
175    );
176}
177
178/// Assert that the given channel number is valid according to the number of channels
179/// of an Audio asset (e.g. [`AudioBuffer`]).
180///
181/// # Panics
182///
183/// This function will panic if:
184/// - the given channel number is greater than or equal to the given number of channels.
185///
186#[track_caller]
187#[inline(always)]
188pub(crate) fn assert_valid_channel_number(channel_number: usize, number_of_channels: usize) {
189    assert!(
190        channel_number < number_of_channels,
191        "IndexSizeError - Invalid channel number {:?} (number of channels: {:?})",
192        channel_number,
193        number_of_channels
194    );
195}
196
197/// Assert that the given value number is a valid buffer length, i.e. greater than zero
198///
199/// # Panics
200///
201/// This function will panic if:
202/// - the given value is not lower than or equal to zero
203///
204#[track_caller]
205#[inline(always)]
206pub(crate) fn assert_valid_buffer_length(length: usize) {
207    assert!(
208        length > 0,
209        "NotSupportedError - Invalid length: {:?} is less than or equal to minimum bound (0)",
210        length,
211    );
212}
213
214/// Assert that the given value number is a valid time information, i.e. greater
215/// than or equal to zero and finite.
216///
217/// # Panics
218///
219/// This function will panic if:
220/// - the given value is not finite and lower than zero
221///
222#[track_caller]
223#[inline(always)]
224pub(crate) fn assert_valid_time_value(value: f64) {
225    assert!(
226        value.is_finite(),
227        "TypeError - The provided time value is non-finite.",
228    );
229
230    assert!(
231        value >= 0.,
232        "RangeError - The provided time value ({:?}) cannot be negative",
233        value
234    );
235}
236
237pub(crate) trait AudioBufferIter: Iterator<Item = FallibleBuffer> + Send + 'static {}
238
239impl<M: Iterator<Item = FallibleBuffer> + Send + 'static> AudioBufferIter for M {}
240
241type FallibleBuffer = Result<AudioBuffer, Box<dyn Error + Send + Sync>>;
242
243#[cfg(test)]
244mod tests {
245    use float_eq::assert_float_eq;
246
247    use super::*;
248
249    #[test]
250    fn test_atomic_f64() {
251        let f = AtomicF64::new(2.0);
252        assert_float_eq!(f.load(Ordering::SeqCst), 2.0, abs <= 0.);
253
254        f.store(3.0, Ordering::SeqCst);
255        assert_float_eq!(f.load(Ordering::SeqCst), 3.0, abs <= 0.);
256    }
257
258    #[test]
259    fn test_valid_sample_rate() {
260        assert_valid_sample_rate(48000.);
261        assert_valid_sample_rate(3_000.);
262        assert_valid_sample_rate(768_000.);
263    }
264
265    #[test]
266    #[should_panic]
267    fn test_invalid_sample_rate_too_small() {
268        assert_valid_sample_rate(2_999.);
269    }
270
271    #[test]
272    #[should_panic]
273    fn test_invalid_sample_rate_too_big() {
274        assert_valid_sample_rate(768_001.);
275    }
276
277    #[test]
278    #[should_panic]
279    fn test_invalid_number_of_channels_min() {
280        assert_valid_number_of_channels(0);
281    }
282
283    #[test]
284    #[should_panic]
285    fn test_invalid_number_of_channels_max() {
286        assert_valid_number_of_channels(33);
287    }
288
289    #[test]
290    fn test_valid_number_of_channels() {
291        assert_valid_number_of_channels(1);
292        assert_valid_number_of_channels(32);
293    }
294
295    #[test]
296    #[should_panic]
297    fn test_invalid_time_value_non_finite() {
298        assert_valid_time_value(f64::NAN);
299    }
300
301    #[test]
302    #[should_panic]
303    fn test_invalid_time_value_negative() {
304        assert_valid_time_value(-1.);
305    }
306
307    #[test]
308    fn test_valid_time_value() {
309        assert_valid_time_value(0.);
310        assert_valid_time_value(1.);
311    }
312}