Skip to content

Commit a750aa3

Browse files
authored
Merge pull request #329 from b-ma/refactor/merge-controller
Merge `Controller` into `AudioBufferSourceNode`
2 parents cd2c145 + ee7d1cf commit a750aa3

File tree

3 files changed

+86
-139
lines changed

3 files changed

+86
-139
lines changed

src/control.rs

Lines changed: 0 additions & 105 deletions
This file was deleted.

src/lib.rs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,6 @@ mod capacity;
5757
pub use capacity::*;
5858

5959
pub mod context;
60-
pub(crate) mod control;
6160

6261
pub mod media_devices;
6362
pub mod media_recorder;

src/node/audio_buffer_source.rs

Lines changed: 86 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,11 @@
11
use std::cell::OnceCell;
22
use std::sync::atomic::{AtomicBool, Ordering};
3-
use std::sync::Arc;
43

54
use crate::buffer::AudioBuffer;
65
use crate::context::{AudioContextRegistration, AudioParamId, BaseAudioContext};
7-
use crate::control::{Controller, ControllerShared};
86
use crate::param::{AudioParam, AudioParamDescriptor, AutomationRate};
97
use crate::render::{AudioParamValues, AudioProcessor, AudioRenderQuantum, RenderScope};
8+
use crate::AtomicF64;
109
use crate::RENDER_QUANTUM_SIZE;
1110

1211
use super::{AudioNode, AudioScheduledSourceNode, ChannelConfig};
@@ -49,9 +48,55 @@ struct PlaybackInfo {
4948
k: f32,
5049
}
5150

51+
// The strategy for loop parameters is as follow: store the given values
52+
// in the `loop_control` thread safe instance which only lives in control
53+
// thread(s) and send a message to the render thread which stores the raw values.
54+
// Values between control and render side might be desynchronised for little while
55+
// but the developer experience will appear more logical, i.e.
56+
// ```no_run
57+
// node.set_loop(true);
58+
// println!("{:?}", node.loop_());
59+
// > true // is guaranteed
60+
// ```
61+
// Note that this seems to be the strategy used by Firefox
62+
#[derive(Debug)]
63+
struct LoopControl {
64+
loop_: AtomicBool,
65+
loop_start: AtomicF64,
66+
loop_end: AtomicF64,
67+
}
68+
69+
// Uses the canonical ordering for handover of values,
70+
// i.e. `Acquire` on load and `Release` on store.
71+
impl LoopControl {
72+
fn loop_(&self) -> bool {
73+
self.loop_.load(Ordering::Acquire)
74+
}
75+
76+
fn set_loop(&self, loop_: bool) {
77+
self.loop_.store(loop_, Ordering::Release);
78+
}
79+
80+
fn loop_start(&self) -> f64 {
81+
self.loop_start.load(Ordering::Acquire)
82+
}
83+
84+
fn set_loop_start(&self, loop_start: f64) {
85+
self.loop_start.store(loop_start, Ordering::Release);
86+
}
87+
88+
fn loop_end(&self) -> f64 {
89+
self.loop_end.load(Ordering::Acquire)
90+
}
91+
92+
fn set_loop_end(&self, loop_end: f64) {
93+
self.loop_end.store(loop_end, Ordering::Release);
94+
}
95+
}
96+
5297
/// Instructions to start or stop processing
5398
#[derive(Debug, Copy, Clone)]
54-
enum Control {
99+
enum ControlMessage {
55100
StartWithOffsetAndDuration(f64, f64, f64),
56101
Stop(f64),
57102
Loop(bool),
@@ -93,7 +138,7 @@ enum Control {
93138
///
94139
pub struct AudioBufferSourceNode {
95140
registration: AudioContextRegistration,
96-
controller_shared: Arc<ControllerShared>,
141+
loop_control: LoopControl,
97142
channel_config: ChannelConfig,
98143
detune: AudioParam, // has constraints, no a-rate
99144
playback_rate: AudioParam, // has constraints, no a-rate
@@ -139,7 +184,7 @@ impl AudioScheduledSourceNode for AudioBufferSourceNode {
139184
panic!("InvalidStateError cannot stop before start");
140185
}
141186

142-
self.registration.post_message(Control::Stop(when));
187+
self.registration.post_message(ControlMessage::Stop(when));
143188
}
144189
}
145190

@@ -156,9 +201,8 @@ impl AudioBufferSourceNode {
156201
playback_rate,
157202
} = options;
158203

159-
// @todo - these parameters can't be changed to a-rate
204+
// these parameters can't be changed to a-rate
160205
// @see - <https://webaudio.github.io/web-audio-api/#audioparam-automation-rate-constraints>
161-
// @see - https://github.com/orottier/web-audio-api-rs/issues/29
162206
let detune_param_options = AudioParamDescriptor {
163207
min_value: f32::MIN,
164208
max_value: f32::MAX,
@@ -181,18 +225,20 @@ impl AudioBufferSourceNode {
181225
pr_param.set_automation_rate_constrained(true);
182226
pr_param.set_value(playback_rate);
183227

184-
let mut controller = Controller::default();
185-
controller.set_loop(loop_);
186-
controller.set_loop_start(loop_start);
187-
controller.set_loop_end(loop_end);
188-
let controller_shared = Arc::clone(controller.shared());
228+
let loop_control = LoopControl {
229+
loop_: AtomicBool::new(loop_),
230+
loop_start: AtomicF64::new(loop_start),
231+
loop_end: AtomicF64::new(loop_end),
232+
};
189233

190234
let renderer = AudioBufferSourceRenderer {
191235
start_time: f64::MAX,
192236
stop_time: f64::MAX,
193237
duration: f64::MAX,
194238
offset: 0.,
195-
controller,
239+
loop_,
240+
loop_start,
241+
loop_end,
196242
buffer: None,
197243
detune: d_proc,
198244
playback_rate: pr_proc,
@@ -202,7 +248,7 @@ impl AudioBufferSourceNode {
202248

203249
let node = Self {
204250
registration,
205-
controller_shared,
251+
loop_control,
206252
channel_config: ChannelConfig::default(),
207253
detune: d_param,
208254
playback_rate: pr_param,
@@ -237,7 +283,7 @@ impl AudioBufferSourceNode {
237283
panic!("InvalidStateError: Cannot call `start` twice");
238284
}
239285

240-
let control = Control::StartWithOffsetAndDuration(start, offset, duration);
286+
let control = ControlMessage::StartWithOffsetAndDuration(start, offset, duration);
241287
self.registration.post_message(control);
242288
}
243289

@@ -282,29 +328,34 @@ impl AudioBufferSourceNode {
282328

283329
/// Defines if the playback the [`AudioBuffer`] should be looped
284330
pub fn loop_(&self) -> bool {
285-
self.controller_shared.loop_()
331+
self.loop_control.loop_()
286332
}
287333

288334
pub fn set_loop(&self, value: bool) {
289-
self.registration.post_message(Control::Loop(value));
335+
self.loop_control.set_loop(value);
336+
self.registration.post_message(ControlMessage::Loop(value));
290337
}
291338

292339
/// Defines the loop start point, in the time reference of the [`AudioBuffer`]
293340
pub fn loop_start(&self) -> f64 {
294-
self.controller_shared.loop_start()
341+
self.loop_control.loop_start()
295342
}
296343

297344
pub fn set_loop_start(&self, value: f64) {
298-
self.registration.post_message(Control::LoopStart(value));
345+
self.loop_control.set_loop_start(value);
346+
self.registration
347+
.post_message(ControlMessage::LoopStart(value));
299348
}
300349

301350
/// Defines the loop end point, in the time reference of the [`AudioBuffer`]
302351
pub fn loop_end(&self) -> f64 {
303-
self.controller_shared.loop_end()
352+
self.loop_control.loop_end()
304353
}
305354

306355
pub fn set_loop_end(&self, value: f64) {
307-
self.registration.post_message(Control::LoopEnd(value));
356+
self.loop_control.set_loop_end(value);
357+
self.registration
358+
.post_message(ControlMessage::LoopEnd(value));
308359
}
309360
}
310361

@@ -333,7 +384,9 @@ struct AudioBufferSourceRenderer {
333384
stop_time: f64,
334385
offset: f64,
335386
duration: f64,
336-
controller: Controller,
387+
loop_: bool,
388+
loop_start: f64,
389+
loop_end: f64,
337390
buffer: Option<AudioBuffer>,
338391
detune: AudioParamId,
339392
playback_rate: AudioParamId,
@@ -342,17 +395,17 @@ struct AudioBufferSourceRenderer {
342395
}
343396

344397
impl AudioBufferSourceRenderer {
345-
fn handle_control_message(&mut self, control: Control) {
398+
fn handle_control_message(&mut self, control: ControlMessage) {
346399
match control {
347-
Control::StartWithOffsetAndDuration(start, offset, duration) => {
348-
self.start_time = start;
400+
ControlMessage::StartWithOffsetAndDuration(when, offset, duration) => {
401+
self.start_time = when;
349402
self.offset = offset;
350403
self.duration = duration;
351404
}
352-
Control::Stop(v) => self.stop_time = v,
353-
Control::Loop(v) => self.controller.set_loop(v),
354-
Control::LoopStart(v) => self.controller.set_loop_start(v),
355-
Control::LoopEnd(v) => self.controller.set_loop_end(v),
405+
ControlMessage::Stop(when) => self.stop_time = when,
406+
ControlMessage::Loop(loop_) => self.loop_ = loop_,
407+
ControlMessage::LoopStart(loop_start) => self.loop_start = loop_start,
408+
ControlMessage::LoopEnd(loop_end) => self.loop_end = loop_end,
356409
}
357410
}
358411
}
@@ -374,9 +427,9 @@ impl AudioProcessor for AudioBufferSourceRenderer {
374427
let next_block_time = scope.current_time + block_duration;
375428

376429
// grab all timing information
377-
let loop_ = self.controller.loop_();
378-
let loop_start = self.controller.loop_start();
379-
let loop_end = self.controller.loop_end();
430+
let loop_ = self.loop_;
431+
let loop_start = self.loop_start;
432+
let loop_end = self.loop_end;
380433

381434
// these will only be used if `loop_` is true, so no need for `Option`
382435
let mut actual_loop_start = 0.;
@@ -717,7 +770,7 @@ impl AudioProcessor for AudioBufferSourceRenderer {
717770
}
718771

719772
fn onmessage(&mut self, msg: Box<dyn std::any::Any + Send + 'static>) {
720-
let msg = match msg.downcast::<Control>() {
773+
let msg = match msg.downcast::<ControlMessage>() {
721774
Ok(control) => {
722775
self.handle_control_message(*control);
723776
return;

0 commit comments

Comments
 (0)