Skip to content

Commit 73d6a15

Browse files
committed
Guard AudioParam::automation_rate with a Mutex to prevent data races
See discussion at #427
1 parent e114103 commit 73d6a15

File tree

1 file changed

+14
-11
lines changed

1 file changed

+14
-11
lines changed

src/param.rs

Lines changed: 14 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
//! AudioParam interface
22
use std::any::Any;
33
use std::slice::{Iter, IterMut};
4-
use std::sync::atomic::{Ordering};
5-
use std::sync::{Arc, OnceLock};
4+
use std::sync::atomic::Ordering;
5+
use std::sync::{Arc, Mutex, OnceLock};
66

77
use arrayvec::ArrayVec;
88

@@ -274,11 +274,9 @@ pub(crate) struct AudioParamRaw {
274274
default_value: f32, // immutable
275275
min_value: f32, // immutable
276276
max_value: f32, // immutable
277-
automation_rate: AutomationRate,
278277
automation_rate_constrained: bool,
278+
automation_rate: Arc<Mutex<AutomationRate>>,
279279
current_value: Arc<AtomicF32>,
280-
// TODO Use `Weak` instead of `Arc`. The `AudioParamProcessor` is the owner.
281-
// shared_parts: Arc<AudioParamShared>,
282280
}
283281

284282
impl AudioNode for AudioParam {
@@ -320,21 +318,24 @@ impl AudioNode for AudioParam {
320318
impl AudioParam {
321319
/// Current value of the automation rate of the AudioParam
322320
pub fn automation_rate(&self) -> AutomationRate {
323-
self.raw_parts.automation_rate
321+
*self.raw_parts.automation_rate.lock().unwrap()
324322
}
325323

326324
/// Update the current value of the automation rate of the AudioParam
327325
///
328326
/// # Panics
329327
///
330328
/// Some nodes have automation rate constraints and may panic when updating the value.
331-
pub fn set_automation_rate(&mut self, value: AutomationRate) {
329+
pub fn set_automation_rate(&self, value: AutomationRate) {
332330
if self.raw_parts.automation_rate_constrained && value != self.automation_rate() {
333331
panic!("InvalidStateError: automation rate cannot be changed for this param");
334332
}
335333

336-
self.raw_parts.automation_rate = value;
334+
let mut guard = self.raw_parts.automation_rate.lock().unwrap();
335+
*guard = value;
337336
self.registration().post_message(value);
337+
drop(guard); // drop guard after sending message to prevent out of order arrivals on
338+
// concurrent access
338339
}
339340

340341
pub(crate) fn set_automation_rate_constrained(&mut self, value: bool) {
@@ -387,7 +388,9 @@ impl AudioParam {
387388
assert_is_finite(value);
388389
// current_value should always be clamped
389390
let clamped = value.clamp(self.raw_parts.min_value, self.raw_parts.max_value);
390-
self.raw_parts.current_value.store(clamped, Ordering::Release);
391+
self.raw_parts
392+
.current_value
393+
.store(clamped, Ordering::Release);
391394

392395
// this event is meant to update param intrinsic value before any calculation
393396
// is done, will behave as SetValueAtTime with `time == block_timestamp`
@@ -1583,8 +1586,8 @@ pub(crate) fn audio_param_pair(
15831586
default_value,
15841587
max_value,
15851588
min_value,
1586-
automation_rate,
15871589
automation_rate_constrained: false,
1590+
automation_rate: Arc::new(Mutex::new(automation_rate)),
15881591
current_value: Arc::clone(&current_value),
15891592
},
15901593
};
@@ -1679,7 +1682,7 @@ mod tests {
16791682
min_value: 0.,
16801683
max_value: 1.,
16811684
};
1682-
let (mut param, _render) = audio_param_pair(opts, context.mock_registration());
1685+
let (param, _render) = audio_param_pair(opts, context.mock_registration());
16831686

16841687
param.set_automation_rate(AutomationRate::K);
16851688
assert_eq!(param.automation_rate(), AutomationRate::K);

0 commit comments

Comments
 (0)