Skip to content

Commit 88c1c04

Browse files
authored
Merge pull request #497 from orottier/feature/audio_process_event_owned
Change ScriptProcessorNode::onaudioprocess API - use owned buffer value
2 parents cb43d87 + 5b48747 commit 88c1c04

File tree

5 files changed

+30
-10
lines changed

5 files changed

+30
-10
lines changed

examples/script_processor.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ fn main() {
2828
});
2929

3030
let node = context.create_script_processor(512, 1, 1);
31-
node.set_onaudioprocess(|e| {
31+
node.set_onaudioprocess(|mut e| {
3232
let mut rng = rand::thread_rng();
3333
e.output_buffer
3434
.get_channel_data_mut(0)

src/context/mod.rs

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -88,9 +88,8 @@ impl From<u8> for AudioContextState {
8888
/// Only when implementing the AudioNode trait manually, this struct is of any concern.
8989
///
9090
/// This object allows for communication with the render thread and dynamic lifetime management.
91-
//
92-
// The only way to construct this object is by calling [`BaseAudioContext::register`]
93-
#[derive(Clone)]
91+
// The only way to construct this object is by calling [`BaseAudioContext::register`].
92+
// This struct should not derive Clone because of the Drop handler.
9493
pub struct AudioContextRegistration {
9594
/// the audio context in which nodes and connections lives
9695
context: ConcreteBaseAudioContext,

src/events.rs

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
use crate::context::ConcreteBaseAudioContext;
12
use crate::context::{AudioContextState, AudioNodeId};
23
use crate::{AudioBuffer, AudioRenderCapacityEvent};
34

@@ -52,6 +53,19 @@ pub struct AudioProcessingEvent {
5253
/// The time when the audio will be played in the same time coordinate system as the
5354
/// AudioContext's currentTime.
5455
pub playback_time: f64,
56+
pub(crate) registration: Option<(ConcreteBaseAudioContext, AudioNodeId)>,
57+
}
58+
59+
impl Drop for AudioProcessingEvent {
60+
fn drop(&mut self) {
61+
if let Some((context, id)) = self.registration.take() {
62+
let wrapped = crate::message::ControlMessage::NodeMessage {
63+
id,
64+
msg: llq::Node::new(Box::new(self.output_buffer.clone())),
65+
};
66+
context.send_control_msg(wrapped);
67+
}
68+
}
5569
}
5670

5771
/// The OfflineAudioCompletionEvent Event interface

src/node/script_processor.rs

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -137,20 +137,26 @@ impl ScriptProcessorNode {
137137
/// the inputBuffer attribute. The audio data which is the result of the processing (or the
138138
/// synthesized data if there are no inputs) is then placed into the outputBuffer.
139139
///
140+
/// The output buffer is shipped back to the render thread when the AudioProcessingEvent goes
141+
/// out of scope, so be sure not to store it somewhere.
142+
///
140143
/// Only a single event handler is active at any time. Calling this method multiple times will
141144
/// override the previous event handler.
142-
pub fn set_onaudioprocess<F: FnMut(&mut AudioProcessingEvent) + Send + 'static>(
145+
pub fn set_onaudioprocess<F: FnMut(AudioProcessingEvent) + Send + 'static>(
143146
&self,
144147
mut callback: F,
145148
) {
146-
let registration = self.registration.clone();
149+
// We need these fields to ship the output buffer to the render thread
150+
let base = self.registration().context().clone();
151+
let id = self.registration().id();
152+
147153
let callback = move |v| {
148154
let mut payload = match v {
149155
EventPayload::AudioProcessing(v) => v,
150156
_ => unreachable!(),
151157
};
152-
callback(&mut payload);
153-
registration.post_message(payload.output_buffer);
158+
payload.registration = Some((base.clone(), id));
159+
callback(payload);
154160
};
155161

156162
self.context().set_event_handler(
@@ -305,7 +311,7 @@ mod tests {
305311

306312
let node = context.create_script_processor(BUFFER_SIZE, 0, 1);
307313
node.connect(&context.destination());
308-
node.set_onaudioprocess(|e| {
314+
node.set_onaudioprocess(|mut e| {
309315
e.output_buffer.get_channel_data_mut(0).fill(1.); // set all samples to 1.
310316
});
311317

@@ -336,7 +342,7 @@ mod tests {
336342
// 2 input channels, 2 output channels
337343
let node = context.create_script_processor(BUFFER_SIZE, 2, 2);
338344
node.connect(&context.destination());
339-
node.set_onaudioprocess(|e| {
345+
node.set_onaudioprocess(|mut e| {
340346
// left output buffer is left input * 2
341347
e.output_buffer
342348
.get_channel_data_mut(0)

src/render/processor.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,7 @@ impl AudioWorkletGlobalScope {
6868
input_buffer,
6969
output_buffer,
7070
playback_time,
71+
registration: None,
7172
};
7273
let dispatch = EventDispatch::audio_processing(self.node_id.get(), event);
7374
let _ = self.event_sender.try_send(dispatch);

0 commit comments

Comments
 (0)