Skip to content

Commit 3d0d960

Browse files
committed
refactor: remove controller + inverse logic
1 parent 1686a04 commit 3d0d960

File tree

3 files changed

+87
-138
lines changed

3 files changed

+87
-138
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: 87 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,9 @@ use std::sync::Arc;
44

55
use crate::buffer::AudioBuffer;
66
use crate::context::{AudioContextRegistration, AudioParamId, BaseAudioContext};
7-
use crate::control::{Controller, ControllerShared};
87
use crate::param::{AudioParam, AudioParamDescriptor, AutomationRate};
98
use crate::render::{AudioParamValues, AudioProcessor, AudioRenderQuantum, RenderScope};
9+
use crate::AtomicF64;
1010
use crate::RENDER_QUANTUM_SIZE;
1111

1212
use super::{AudioNode, AudioScheduledSourceNode, ChannelConfig};
@@ -49,9 +49,55 @@ struct PlaybackInfo {
4949
k: f32,
5050
}
5151

52+
// The strategy for loop parameters is as follow: store the given values
53+
// in the loop_parameter thread safe instance which only lives in control
54+
// thread(s) and send a message to the render thread which stores the raw values.
55+
// Values between control and render side might be desynchronized for while
56+
// but the developer experience will appear more logical, i.e.
57+
// ```no_run
58+
// node.set_loop(true);
59+
// node._loop_
60+
// > true // is guaranteed
61+
// ```
62+
// Note that this seems to be the strategy used by Firefox
63+
#[derive(Debug)]
64+
struct LoopParameters {
65+
loop_: AtomicBool,
66+
loop_start: AtomicF64,
67+
loop_end: AtomicF64,
68+
}
69+
70+
// Uses the canonical ordering for handover of values,
71+
// i.e. `Acquire` on load and `Release` on store.
72+
impl LoopParameters {
73+
fn loop_(&self) -> bool {
74+
self.loop_.load(Ordering::Acquire)
75+
}
76+
77+
fn set_loop(&self, loop_: bool) {
78+
self.loop_.store(loop_, Ordering::Release);
79+
}
80+
81+
fn loop_start(&self) -> f64 {
82+
self.loop_start.load(Ordering::Acquire)
83+
}
84+
85+
fn set_loop_start(&self, loop_start: f64) {
86+
self.loop_start.store(loop_start, Ordering::Release);
87+
}
88+
89+
fn loop_end(&self) -> f64 {
90+
self.loop_end.load(Ordering::Acquire)
91+
}
92+
93+
fn set_loop_end(&self, loop_end: f64) {
94+
self.loop_end.store(loop_end, Ordering::Release);
95+
}
96+
}
97+
5298
/// Instructions to start or stop processing
5399
#[derive(Debug, Copy, Clone)]
54-
enum Control {
100+
enum ControlMessage {
55101
StartWithOffsetAndDuration(f64, f64, f64),
56102
Stop(f64),
57103
Loop(bool),
@@ -93,7 +139,7 @@ enum Control {
93139
///
94140
pub struct AudioBufferSourceNode {
95141
registration: AudioContextRegistration,
96-
controller_shared: Arc<ControllerShared>,
142+
loop_parameters: Arc<LoopParameters>,
97143
channel_config: ChannelConfig,
98144
detune: AudioParam, // has constraints, no a-rate
99145
playback_rate: AudioParam, // has constraints, no a-rate
@@ -139,7 +185,7 @@ impl AudioScheduledSourceNode for AudioBufferSourceNode {
139185
panic!("InvalidStateError cannot stop before start");
140186
}
141187

142-
self.registration.post_message(Control::Stop(when));
188+
self.registration.post_message(ControlMessage::Stop(when));
143189
}
144190
}
145191

@@ -156,9 +202,8 @@ impl AudioBufferSourceNode {
156202
playback_rate,
157203
} = options;
158204

159-
// @todo - these parameters can't be changed to a-rate
205+
// these parameters can't be changed to a-rate
160206
// @see - <https://webaudio.github.io/web-audio-api/#audioparam-automation-rate-constraints>
161-
// @see - https://github.com/orottier/web-audio-api-rs/issues/29
162207
let detune_param_options = AudioParamDescriptor {
163208
min_value: f32::MIN,
164209
max_value: f32::MAX,
@@ -181,18 +226,21 @@ impl AudioBufferSourceNode {
181226
pr_param.set_automation_rate_constrained(true);
182227
pr_param.set_value(playback_rate);
183228

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());
229+
// loop parameters
230+
let loop_parameters = Arc::new(LoopParameters {
231+
loop_: AtomicBool::new(loop_),
232+
loop_start: AtomicF64::new(loop_start),
233+
loop_end: AtomicF64::new(loop_end),
234+
});
189235

190236
let renderer = AudioBufferSourceRenderer {
191237
start_time: f64::MAX,
192238
stop_time: f64::MAX,
193239
duration: f64::MAX,
194240
offset: 0.,
195-
controller,
241+
loop_,
242+
loop_start,
243+
loop_end,
196244
buffer: None,
197245
detune: d_proc,
198246
playback_rate: pr_proc,
@@ -202,7 +250,7 @@ impl AudioBufferSourceNode {
202250

203251
let node = Self {
204252
registration,
205-
controller_shared,
253+
loop_parameters,
206254
channel_config: ChannelConfig::default(),
207255
detune: d_param,
208256
playback_rate: pr_param,
@@ -237,7 +285,7 @@ impl AudioBufferSourceNode {
237285
panic!("InvalidStateError: Cannot call `start` twice");
238286
}
239287

240-
let control = Control::StartWithOffsetAndDuration(start, offset, duration);
288+
let control = ControlMessage::StartWithOffsetAndDuration(start, offset, duration);
241289
self.registration.post_message(control);
242290
}
243291

@@ -282,29 +330,34 @@ impl AudioBufferSourceNode {
282330

283331
/// Defines if the playback the [`AudioBuffer`] should be looped
284332
pub fn loop_(&self) -> bool {
285-
self.controller_shared.loop_()
333+
self.loop_parameters.loop_()
286334
}
287335

288336
pub fn set_loop(&self, value: bool) {
289-
self.registration.post_message(Control::Loop(value));
337+
self.loop_parameters.set_loop(value);
338+
self.registration.post_message(ControlMessage::Loop(value));
290339
}
291340

292341
/// Defines the loop start point, in the time reference of the [`AudioBuffer`]
293342
pub fn loop_start(&self) -> f64 {
294-
self.controller_shared.loop_start()
343+
self.loop_parameters.loop_start()
295344
}
296345

297346
pub fn set_loop_start(&self, value: f64) {
298-
self.registration.post_message(Control::LoopStart(value));
347+
self.loop_parameters.set_loop_start(value);
348+
self.registration
349+
.post_message(ControlMessage::LoopStart(value));
299350
}
300351

301352
/// Defines the loop end point, in the time reference of the [`AudioBuffer`]
302353
pub fn loop_end(&self) -> f64 {
303-
self.controller_shared.loop_end()
354+
self.loop_parameters.loop_end()
304355
}
305356

306357
pub fn set_loop_end(&self, value: f64) {
307-
self.registration.post_message(Control::LoopEnd(value));
358+
self.loop_parameters.set_loop_end(value);
359+
self.registration
360+
.post_message(ControlMessage::LoopEnd(value));
308361
}
309362
}
310363

@@ -333,7 +386,9 @@ struct AudioBufferSourceRenderer {
333386
stop_time: f64,
334387
offset: f64,
335388
duration: f64,
336-
controller: Controller,
389+
loop_: bool,
390+
loop_start: f64,
391+
loop_end: f64,
337392
buffer: Option<AudioBuffer>,
338393
detune: AudioParamId,
339394
playback_rate: AudioParamId,
@@ -342,17 +397,17 @@ struct AudioBufferSourceRenderer {
342397
}
343398

344399
impl AudioBufferSourceRenderer {
345-
fn handle_control_message(&mut self, control: Control) {
400+
fn handle_control_message(&mut self, control: ControlMessage) {
346401
match control {
347-
Control::StartWithOffsetAndDuration(start, offset, duration) => {
348-
self.start_time = start;
402+
ControlMessage::StartWithOffsetAndDuration(when, offset, duration) => {
403+
self.start_time = when;
349404
self.offset = offset;
350405
self.duration = duration;
351406
}
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),
407+
ControlMessage::Stop(when) => self.stop_time = when,
408+
ControlMessage::Loop(loop_) => self.loop_ = loop_,
409+
ControlMessage::LoopStart(loop_start) => self.loop_start = loop_start,
410+
ControlMessage::LoopEnd(loop_end) => self.loop_end = loop_end,
356411
}
357412
}
358413
}
@@ -374,9 +429,9 @@ impl AudioProcessor for AudioBufferSourceRenderer {
374429
let next_block_time = scope.current_time + block_duration;
375430

376431
// 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();
432+
let loop_ = self.loop_;
433+
let loop_start = self.loop_start;
434+
let loop_end = self.loop_end;
380435

381436
// these will only be used if `loop_` is true, so no need for `Option`
382437
let mut actual_loop_start = 0.;
@@ -717,7 +772,7 @@ impl AudioProcessor for AudioBufferSourceRenderer {
717772
}
718773

719774
fn onmessage(&mut self, msg: Box<dyn std::any::Any + Send + 'static>) {
720-
let msg = match msg.downcast::<Control>() {
775+
let msg = match msg.downcast::<ControlMessage>() {
721776
Ok(control) => {
722777
self.handle_control_message(*control);
723778
return;

0 commit comments

Comments
 (0)