Skip to content

Commit 6afa2b5

Browse files
committed
Ensure all concrete AudioNode types are 'static, Send and Sync
For AudioBufferSourceNode this required some changes - RefCell to Mutex - OnceCell to OnceLock
1 parent fbba66f commit 6afa2b5

File tree

2 files changed

+60
-23
lines changed

2 files changed

+60
-23
lines changed

src/node/audio_buffer_source.rs

Lines changed: 21 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
use std::any::Any;
2-
use std::cell::{OnceCell, RefCell};
2+
use std::sync::{Mutex, OnceLock};
33

44
use crate::buffer::AudioBuffer;
55
use crate::context::{AudioContextRegistration, AudioParamId, BaseAudioContext};
@@ -101,8 +101,8 @@ pub struct AudioBufferSourceNode {
101101
channel_config: ChannelConfig,
102102
detune: AudioParam, // has constraints, no a-rate
103103
playback_rate: AudioParam, // has constraints, no a-rate
104-
buffer: OnceCell<AudioBuffer>,
105-
inner_state: RefCell<InnerState>,
104+
buffer: OnceLock<AudioBuffer>,
105+
inner_state: Mutex<InnerState>,
106106
}
107107

108108
#[derive(Debug, Clone)]
@@ -146,7 +146,7 @@ impl AudioScheduledSourceNode for AudioBufferSourceNode {
146146

147147
fn stop_at(&self, when: f64) {
148148
assert!(
149-
self.inner_state.borrow().source_started,
149+
self.inner_state.lock().unwrap().source_started,
150150
"InvalidStateError cannot stop before start"
151151
);
152152

@@ -219,8 +219,8 @@ impl AudioBufferSourceNode {
219219
channel_config: ChannelConfig::default(),
220220
detune: d_param,
221221
playback_rate: pr_param,
222-
buffer: OnceCell::new(),
223-
inner_state: RefCell::new(inner_state),
222+
buffer: OnceLock::new(),
223+
inner_state: Mutex::new(inner_state),
224224
};
225225

226226
if let Some(buf) = buffer {
@@ -246,12 +246,12 @@ impl AudioBufferSourceNode {
246246
///
247247
/// Panics if the source was already started
248248
pub fn start_at_with_offset_and_duration(&self, start: f64, offset: f64, duration: f64) {
249-
let source_started = &mut self.inner_state.borrow_mut().source_started;
249+
let inner_state = &mut self.inner_state.lock().unwrap();
250250
assert!(
251-
!*source_started,
251+
!inner_state.source_started,
252252
"InvalidStateError: Cannot call `start` twice"
253253
);
254-
*source_started = true;
254+
inner_state.source_started = true;
255255

256256
let control = ControlMessage::StartWithOffsetAndDuration(start, offset, duration);
257257
self.registration.post_message(control);
@@ -297,33 +297,39 @@ impl AudioBufferSourceNode {
297297
}
298298

299299
/// Defines if the playback the [`AudioBuffer`] should be looped
300+
#[allow(clippy::missing_panics_doc)]
300301
pub fn loop_(&self) -> bool {
301-
self.inner_state.borrow().loop_state.is_looping
302+
self.inner_state.lock().unwrap().loop_state.is_looping
302303
}
303304

305+
#[allow(clippy::missing_panics_doc)]
304306
pub fn set_loop(&self, value: bool) {
305-
self.inner_state.borrow_mut().loop_state.is_looping = value;
307+
self.inner_state.lock().unwrap().loop_state.is_looping = value;
306308
self.registration.post_message(ControlMessage::Loop(value));
307309
}
308310

309311
/// Defines the loop start point, in the time reference of the [`AudioBuffer`]
312+
#[allow(clippy::missing_panics_doc)]
310313
pub fn loop_start(&self) -> f64 {
311-
self.inner_state.borrow().loop_state.start
314+
self.inner_state.lock().unwrap().loop_state.start
312315
}
313316

317+
#[allow(clippy::missing_panics_doc)]
314318
pub fn set_loop_start(&self, value: f64) {
315-
self.inner_state.borrow_mut().loop_state.start = value;
319+
self.inner_state.lock().unwrap().loop_state.start = value;
316320
self.registration
317321
.post_message(ControlMessage::LoopStart(value));
318322
}
319323

320324
/// Defines the loop end point, in the time reference of the [`AudioBuffer`]
325+
#[allow(clippy::missing_panics_doc)]
321326
pub fn loop_end(&self) -> f64 {
322-
self.inner_state.borrow().loop_state.end
327+
self.inner_state.lock().unwrap().loop_state.end
323328
}
324329

330+
#[allow(clippy::missing_panics_doc)]
325331
pub fn set_loop_end(&self, value: f64) {
326-
self.inner_state.borrow_mut().loop_state.end = value;
332+
self.inner_state.lock().unwrap().loop_state.end = value;
327333
self.registration
328334
.post_message(ControlMessage::LoopEnd(value));
329335
}

tests/online.rs

Lines changed: 39 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -14,16 +14,47 @@ use web_audio_api::MAX_CHANNELS;
1414
fn require_send_sync_static<T: Send + Sync + 'static>(_: T) {}
1515

1616
#[allow(dead_code)]
17-
fn test_audio_context_send_sync() {
18-
let context = AudioContext::default();
19-
require_send_sync_static(context);
20-
}
17+
fn ensure_send_sync_static() {
18+
require_send_sync_static(AudioContext::default());
2119

22-
#[allow(dead_code)]
23-
fn ensure_audio_node_send_sync() {
2420
let context = AudioContext::default();
25-
let node = context.create_constant_source();
26-
require_send_sync_static(node);
21+
22+
// All available nodes for BaseAudioContext
23+
require_send_sync_static(context.create_analyser());
24+
require_send_sync_static(context.create_biquad_filter());
25+
require_send_sync_static(context.create_buffer_source());
26+
require_send_sync_static(context.create_channel_merger(2));
27+
require_send_sync_static(context.create_channel_splitter(2));
28+
require_send_sync_static(context.create_constant_source());
29+
require_send_sync_static(context.create_convolver());
30+
require_send_sync_static(context.create_delay(1.));
31+
require_send_sync_static(context.create_dynamics_compressor());
32+
require_send_sync_static(context.create_gain());
33+
require_send_sync_static(context.create_iir_filter(vec![], vec![]));
34+
require_send_sync_static(context.create_oscillator());
35+
require_send_sync_static(context.create_panner());
36+
require_send_sync_static(
37+
context.create_periodic_wave(web_audio_api::PeriodicWaveOptions::default()),
38+
);
39+
require_send_sync_static(context.create_stereo_panner());
40+
41+
// Available nodes for online AudioContext
42+
let media_track = web_audio_api::media_streams::MediaStreamTrack::from_iter(vec![]);
43+
let media_stream = web_audio_api::media_streams::MediaStream::from_tracks(vec![media_track]);
44+
require_send_sync_static(context.create_media_stream_source(&media_stream));
45+
require_send_sync_static(context.create_media_stream_destination());
46+
require_send_sync_static(
47+
context.create_media_stream_track_source(&media_stream.get_tracks()[0]),
48+
);
49+
let mut media_element = web_audio_api::MediaElement::new("").unwrap();
50+
require_send_sync_static(context.create_media_element_source(&mut media_element));
51+
52+
// Provided nodes
53+
require_send_sync_static(context.destination());
54+
require_send_sync_static(context.listener());
55+
56+
// AudioParams (borrow from their node, so do not test for 'static)
57+
let _: &(dyn Send + Sync) = context.listener().position_x();
2758
}
2859

2960
#[allow(dead_code)]

0 commit comments

Comments
 (0)