Skip to content

Commit d8f0225

Browse files
authored
Merge pull request #332 from uklotzde/onmessage-mut
AudioProcessor::onmessage(): Pass message as mutable reference
2 parents a750aa3 + 70382ce commit d8f0225

File tree

12 files changed

+99
-87
lines changed

12 files changed

+99
-87
lines changed

examples/worklet.rs

Lines changed: 7 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
use std::any::Any;
2+
13
use rand::Rng;
24

35
use web_audio_api::context::{
@@ -141,15 +143,12 @@ impl AudioProcessor for WhiteNoiseProcessor {
141143
true // source node will always be active
142144
}
143145

144-
fn onmessage(&mut self, msg: Box<dyn std::any::Any + Send + 'static>) {
146+
fn onmessage(&mut self, msg: &mut dyn Any) {
145147
// handle incoming signals requesting for change of color
146-
let msg = match msg.downcast::<NoiseColor>() {
147-
Ok(color) => {
148-
self.color = *color;
149-
return;
150-
}
151-
Err(msg) => msg,
152-
};
148+
if let Some(color) = msg.downcast_ref::<NoiseColor>() {
149+
self.color = *color;
150+
return;
151+
}
153152

154153
// ...add more message handlers here...
155154

src/buffer.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -66,8 +66,8 @@ pub struct AudioBufferOptions {
6666
///
6767
#[derive(Clone, Debug)]
6868
pub struct AudioBuffer {
69-
channels: Vec<ChannelData>,
70-
sample_rate: f32,
69+
pub(crate) channels: Vec<ChannelData>,
70+
pub(crate) sample_rate: f32,
7171
}
7272

7373
impl AudioBuffer {

src/context/mod.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
//! The `BaseAudioContext` interface and the `AudioContext` and `OfflineAudioContext` types
2-
use std::ops::Range;
2+
use std::{any::Any, ops::Range};
33

44
mod base;
55
pub use base::*;
@@ -105,7 +105,7 @@ impl AudioContextRegistration {
105105
///
106106
/// The message will be handled by
107107
/// [`AudioProcessor::onmessage`](crate::render::AudioProcessor::onmessage).
108-
pub fn post_message<M: std::any::Any + Send + 'static>(&self, msg: M) {
108+
pub fn post_message<M: Any + Send + 'static>(&self, msg: M) {
109109
let wrapped = crate::message::ControlMessage::NodeMessage {
110110
id: self.id,
111111
msg: Box::new(msg),

src/message.rs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
//! Message passing from control to render node
22
3+
use std::any::Any;
4+
35
use crate::context::AudioNodeId;
46
use crate::node::ChannelConfig;
57
use crate::render::graph::Graph;
@@ -47,6 +49,6 @@ pub(crate) enum ControlMessage {
4749
/// Generic message to be handled by AudioProcessor
4850
NodeMessage {
4951
id: AudioNodeId,
50-
msg: Box<dyn std::any::Any + Send + 'static>,
52+
msg: Box<dyn Any + Send + 'static>,
5153
},
5254
}

src/node/audio_buffer_source.rs

Lines changed: 17 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
use std::any::Any;
12
use std::cell::OnceCell;
23
use std::sync::atomic::{AtomicBool, Ordering};
34

@@ -769,21 +770,25 @@ impl AudioProcessor for AudioBufferSourceRenderer {
769770
true
770771
}
771772

772-
fn onmessage(&mut self, msg: Box<dyn std::any::Any + Send + 'static>) {
773-
let msg = match msg.downcast::<ControlMessage>() {
774-
Ok(control) => {
775-
self.handle_control_message(*control);
776-
return;
777-
}
778-
Err(msg) => msg,
773+
fn onmessage(&mut self, msg: &mut dyn Any) {
774+
if let Some(control) = msg.downcast_ref::<ControlMessage>() {
775+
self.handle_control_message(*control);
776+
return;
779777
};
780778

781-
let msg = match msg.downcast::<AudioBuffer>() {
782-
Ok(buffer) => {
783-
self.buffer = Some(*buffer);
784-
return;
779+
if let Some(buffer) = msg.downcast_mut::<AudioBuffer>() {
780+
if let Some(current_buffer) = &mut self.buffer {
781+
// Avoid deallocation in the render thread by swapping the buffers.
782+
std::mem::swap(current_buffer, buffer);
783+
} else {
784+
// Creating the tombstone buffer does not cause allocations.
785+
let tombstone_buffer = AudioBuffer {
786+
channels: Default::default(),
787+
sample_rate: Default::default(),
788+
};
789+
self.buffer = Some(std::mem::replace(buffer, tombstone_buffer));
785790
}
786-
Err(msg) => msg,
791+
return;
787792
};
788793

789794
log::warn!("AudioBufferSourceRenderer: Dropping incoming message {msg:?}");

src/node/constant_source.rs

Lines changed: 9 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
use std::any::Any;
2+
13
use crate::context::{AudioContextRegistration, AudioParamId, BaseAudioContext};
24
use crate::param::{AudioParam, AudioParamDescriptor, AutomationRate};
35
use crate::render::{AudioParamValues, AudioProcessor, AudioRenderQuantum, RenderScope};
@@ -202,17 +204,14 @@ impl AudioProcessor for ConstantSourceRenderer {
202204
still_running
203205
}
204206

205-
fn onmessage(&mut self, msg: Box<dyn std::any::Any + Send + 'static>) {
206-
let msg = match msg.downcast::<Schedule>() {
207-
Ok(schedule) => {
208-
match *schedule {
209-
Schedule::Start(v) => self.start_time = v,
210-
Schedule::Stop(v) => self.stop_time = v,
211-
}
212-
return;
207+
fn onmessage(&mut self, msg: &mut dyn Any) {
208+
if let Some(schedule) = msg.downcast_ref::<Schedule>() {
209+
match *schedule {
210+
Schedule::Start(v) => self.start_time = v,
211+
Schedule::Stop(v) => self.stop_time = v,
213212
}
214-
Err(msg) => msg,
215-
};
213+
return;
214+
}
216215

217216
log::warn!("ConstantSourceRenderer: Dropping incoming message {msg:?}");
218217
}

src/node/oscillator.rs

Lines changed: 24 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,12 @@
1+
use std::any::Any;
12
use std::fmt::Debug;
23
use std::sync::atomic::{AtomicU32, Ordering};
34
use std::sync::Arc;
45

56
use crate::context::{AudioContextRegistration, AudioParamId, BaseAudioContext};
67
use crate::param::{AudioParam, AudioParamDescriptor, AutomationRate};
7-
use crate::periodic_wave::PeriodicWave;
88
use crate::render::{AudioParamValues, AudioProcessor, AudioRenderQuantum, RenderScope};
9+
use crate::PeriodicWave;
910
use crate::RENDER_QUANTUM_SIZE;
1011

1112
use super::{
@@ -431,35 +432,32 @@ impl AudioProcessor for OscillatorRenderer {
431432
true
432433
}
433434

434-
fn onmessage(&mut self, msg: Box<dyn std::any::Any + Send + 'static>) {
435-
let msg = match msg.downcast::<OscillatorType>() {
436-
Ok(type_) => {
437-
self.shared_type.store(*type_ as u32, Ordering::Release);
438-
self.type_ = *type_;
439-
return;
440-
}
441-
Err(msg) => msg,
442-
};
435+
fn onmessage(&mut self, msg: &mut dyn Any) {
436+
if let Some(&type_) = msg.downcast_ref::<OscillatorType>() {
437+
self.shared_type.store(type_ as u32, Ordering::Release);
438+
self.type_ = type_;
439+
return;
440+
}
443441

444-
let msg = match msg.downcast::<Schedule>() {
445-
Ok(schedule) => {
446-
match *schedule {
447-
Schedule::Start(v) => self.start_time = v,
448-
Schedule::Stop(v) => self.stop_time = v,
449-
}
450-
return;
442+
if let Some(&schedule) = msg.downcast_ref::<Schedule>() {
443+
match schedule {
444+
Schedule::Start(v) => self.start_time = v,
445+
Schedule::Stop(v) => self.stop_time = v,
451446
}
452-
Err(msg) => msg,
453-
};
447+
return;
448+
}
454449

455-
let msg = match msg.downcast::<PeriodicWave>() {
456-
Ok(periodic_wave) => {
457-
self.periodic_wave = Some(*periodic_wave);
458-
self.type_ = OscillatorType::Custom; // shared type is already updated by control
459-
return;
450+
if let Some(periodic_wave) = msg.downcast_mut::<PeriodicWave>() {
451+
if let Some(current_periodic_wave) = &mut self.periodic_wave {
452+
// Avoid deallocation in the render thread by swapping the wavetable buffers.
453+
std::mem::swap(current_periodic_wave, periodic_wave)
454+
} else {
455+
// The default wavetable buffer is empty and does not cause allocations.
456+
self.periodic_wave = Some(std::mem::take(periodic_wave));
460457
}
461-
Err(msg) => msg,
462-
};
458+
self.type_ = OscillatorType::Custom; // shared type is already updated by control
459+
return;
460+
}
463461

464462
log::warn!("OscillatorRenderer: Dropping incoming message {msg:?}");
465463
}

src/param.rs

Lines changed: 23 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
//! AudioParam interface
2+
use std::any::Any;
23
use std::slice::{Iter, IterMut};
34
use std::sync::atomic::{AtomicBool, Ordering};
45
use std::sync::Arc;
@@ -641,22 +642,27 @@ impl AudioProcessor for AudioParamProcessor {
641642
true // has intrinsic value
642643
}
643644

644-
fn onmessage(&mut self, msg: Box<dyn std::any::Any + Send + 'static>) {
645-
let msg = match msg.downcast::<AutomationRate>() {
646-
Ok(automation_rate) => {
647-
self.automation_rate = *automation_rate;
648-
self.shared_parts.store_automation_rate(*automation_rate);
649-
return;
650-
}
651-
Err(msg) => msg,
652-
};
645+
fn onmessage(&mut self, msg: &mut dyn Any) {
646+
if let Some(automation_rate) = msg.downcast_ref::<AutomationRate>() {
647+
self.automation_rate = *automation_rate;
648+
self.shared_parts.store_automation_rate(*automation_rate);
649+
return;
650+
}
653651

654-
let msg = match msg.downcast::<AudioParamEvent>() {
655-
Ok(event) => {
656-
self.handle_incoming_event(*event);
657-
return;
658-
}
659-
Err(msg) => msg,
652+
if let Some(event) = msg.downcast_mut::<AudioParamEvent>() {
653+
// Avoid deallocation of the event by replacing it with a tombstone.
654+
let tombstone_event = AudioParamEvent {
655+
event_type: AudioParamEventType::SetValue,
656+
value: Default::default(),
657+
time: Default::default(),
658+
time_constant: None,
659+
cancel_time: None,
660+
duration: None,
661+
values: None,
662+
};
663+
let event = std::mem::replace(event, tombstone_event);
664+
self.handle_incoming_event(event);
665+
return;
660666
};
661667

662668
log::warn!("AudioParamProcessor: Dropping incoming message {msg:?}");
@@ -3161,7 +3167,7 @@ mod tests {
31613167
};
31623168
let (param, mut render) = audio_param_pair(opts, context.mock_registration());
31633169

3164-
render.onmessage(Box::new(AutomationRate::K));
3170+
render.onmessage(&mut AutomationRate::K);
31653171
render.handle_incoming_event(param.set_value_at_time_raw(2., 0.000001));
31663172

31673173
let vs = render.compute_intrinsic_values(0., 1., 10);
@@ -3180,7 +3186,7 @@ mod tests {
31803186
};
31813187
let (param, mut render) = audio_param_pair(opts, context.mock_registration());
31823188

3183-
render.onmessage(Box::new(AutomationRate::A));
3189+
render.onmessage(&mut AutomationRate::A);
31843190
render.handle_incoming_event(param.set_value_at_time_raw(2., 0.000001));
31853191

31863192
let vs = render.compute_intrinsic_values(0., 1., 10);

src/periodic_wave.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,7 @@ pub struct PeriodicWaveOptions {
6969
/// - `cargo run --release --example oscillators`
7070
///
7171
// Basically a wrapper around Arc<Vec<f32>>, so `PeriodicWave`s are cheap to clone
72-
#[derive(Debug, Clone)]
72+
#[derive(Debug, Clone, Default)]
7373
pub struct PeriodicWave {
7474
wavetable: Arc<Vec<f32>>,
7575
}

src/render/graph.rs

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
//! The audio graph topology and render algorithm
2+
use std::any::Any;
23
use std::cell::RefCell;
34
use std::panic::{self, AssertUnwindSafe};
45

@@ -190,11 +191,7 @@ impl Graph {
190191
self.nodes.get_mut(&index).unwrap().get_mut().cycle_breaker = true;
191192
}
192193

193-
pub fn route_message(
194-
&mut self,
195-
index: AudioNodeId,
196-
msg: Box<dyn std::any::Any + Send + 'static>,
197-
) {
194+
pub fn route_message(&mut self, index: AudioNodeId, msg: &mut dyn Any) {
198195
self.nodes
199196
.get_mut(&index)
200197
.unwrap()

0 commit comments

Comments
 (0)