1
1
use std:: cell:: OnceCell ;
2
2
use std:: sync:: atomic:: { AtomicBool , Ordering } ;
3
- use std:: sync:: Arc ;
4
3
5
4
use crate :: buffer:: AudioBuffer ;
6
5
use crate :: context:: { AudioContextRegistration , AudioParamId , BaseAudioContext } ;
7
- use crate :: control:: { Controller , ControllerShared } ;
8
6
use crate :: param:: { AudioParam , AudioParamDescriptor , AutomationRate } ;
9
7
use crate :: render:: { AudioParamValues , AudioProcessor , AudioRenderQuantum , RenderScope } ;
8
+ use crate :: AtomicF64 ;
10
9
use crate :: RENDER_QUANTUM_SIZE ;
11
10
12
11
use super :: { AudioNode , AudioScheduledSourceNode , ChannelConfig } ;
@@ -49,9 +48,55 @@ struct PlaybackInfo {
49
48
k : f32 ,
50
49
}
51
50
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
+
52
97
/// Instructions to start or stop processing
53
98
#[ derive( Debug , Copy , Clone ) ]
54
- enum Control {
99
+ enum ControlMessage {
55
100
StartWithOffsetAndDuration ( f64 , f64 , f64 ) ,
56
101
Stop ( f64 ) ,
57
102
Loop ( bool ) ,
@@ -93,7 +138,7 @@ enum Control {
93
138
///
94
139
pub struct AudioBufferSourceNode {
95
140
registration : AudioContextRegistration ,
96
- controller_shared : Arc < ControllerShared > ,
141
+ loop_control : LoopControl ,
97
142
channel_config : ChannelConfig ,
98
143
detune : AudioParam , // has constraints, no a-rate
99
144
playback_rate : AudioParam , // has constraints, no a-rate
@@ -139,7 +184,7 @@ impl AudioScheduledSourceNode for AudioBufferSourceNode {
139
184
panic ! ( "InvalidStateError cannot stop before start" ) ;
140
185
}
141
186
142
- self . registration . post_message ( Control :: Stop ( when) ) ;
187
+ self . registration . post_message ( ControlMessage :: Stop ( when) ) ;
143
188
}
144
189
}
145
190
@@ -156,9 +201,8 @@ impl AudioBufferSourceNode {
156
201
playback_rate,
157
202
} = options;
158
203
159
- // @todo - these parameters can't be changed to a-rate
204
+ // these parameters can't be changed to a-rate
160
205
// @see - <https://webaudio.github.io/web-audio-api/#audioparam-automation-rate-constraints>
161
- // @see - https://github.com/orottier/web-audio-api-rs/issues/29
162
206
let detune_param_options = AudioParamDescriptor {
163
207
min_value : f32:: MIN ,
164
208
max_value : f32:: MAX ,
@@ -181,18 +225,20 @@ impl AudioBufferSourceNode {
181
225
pr_param. set_automation_rate_constrained ( true ) ;
182
226
pr_param. set_value ( playback_rate) ;
183
227
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
+ } ;
189
233
190
234
let renderer = AudioBufferSourceRenderer {
191
235
start_time : f64:: MAX ,
192
236
stop_time : f64:: MAX ,
193
237
duration : f64:: MAX ,
194
238
offset : 0. ,
195
- controller,
239
+ loop_,
240
+ loop_start,
241
+ loop_end,
196
242
buffer : None ,
197
243
detune : d_proc,
198
244
playback_rate : pr_proc,
@@ -202,7 +248,7 @@ impl AudioBufferSourceNode {
202
248
203
249
let node = Self {
204
250
registration,
205
- controller_shared ,
251
+ loop_control ,
206
252
channel_config : ChannelConfig :: default ( ) ,
207
253
detune : d_param,
208
254
playback_rate : pr_param,
@@ -237,7 +283,7 @@ impl AudioBufferSourceNode {
237
283
panic ! ( "InvalidStateError: Cannot call `start` twice" ) ;
238
284
}
239
285
240
- let control = Control :: StartWithOffsetAndDuration ( start, offset, duration) ;
286
+ let control = ControlMessage :: StartWithOffsetAndDuration ( start, offset, duration) ;
241
287
self . registration . post_message ( control) ;
242
288
}
243
289
@@ -282,29 +328,34 @@ impl AudioBufferSourceNode {
282
328
283
329
/// Defines if the playback the [`AudioBuffer`] should be looped
284
330
pub fn loop_ ( & self ) -> bool {
285
- self . controller_shared . loop_ ( )
331
+ self . loop_control . loop_ ( )
286
332
}
287
333
288
334
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) ) ;
290
337
}
291
338
292
339
/// Defines the loop start point, in the time reference of the [`AudioBuffer`]
293
340
pub fn loop_start ( & self ) -> f64 {
294
- self . controller_shared . loop_start ( )
341
+ self . loop_control . loop_start ( )
295
342
}
296
343
297
344
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) ) ;
299
348
}
300
349
301
350
/// Defines the loop end point, in the time reference of the [`AudioBuffer`]
302
351
pub fn loop_end ( & self ) -> f64 {
303
- self . controller_shared . loop_end ( )
352
+ self . loop_control . loop_end ( )
304
353
}
305
354
306
355
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) ) ;
308
359
}
309
360
}
310
361
@@ -333,7 +384,9 @@ struct AudioBufferSourceRenderer {
333
384
stop_time : f64 ,
334
385
offset : f64 ,
335
386
duration : f64 ,
336
- controller : Controller ,
387
+ loop_ : bool ,
388
+ loop_start : f64 ,
389
+ loop_end : f64 ,
337
390
buffer : Option < AudioBuffer > ,
338
391
detune : AudioParamId ,
339
392
playback_rate : AudioParamId ,
@@ -342,17 +395,17 @@ struct AudioBufferSourceRenderer {
342
395
}
343
396
344
397
impl AudioBufferSourceRenderer {
345
- fn handle_control_message ( & mut self , control : Control ) {
398
+ fn handle_control_message ( & mut self , control : ControlMessage ) {
346
399
match control {
347
- Control :: StartWithOffsetAndDuration ( start , offset, duration) => {
348
- self . start_time = start ;
400
+ ControlMessage :: StartWithOffsetAndDuration ( when , offset, duration) => {
401
+ self . start_time = when ;
349
402
self . offset = offset;
350
403
self . duration = duration;
351
404
}
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 ,
356
409
}
357
410
}
358
411
}
@@ -374,9 +427,9 @@ impl AudioProcessor for AudioBufferSourceRenderer {
374
427
let next_block_time = scope. current_time + block_duration;
375
428
376
429
// 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 ;
380
433
381
434
// these will only be used if `loop_` is true, so no need for `Option`
382
435
let mut actual_loop_start = 0. ;
@@ -717,7 +770,7 @@ impl AudioProcessor for AudioBufferSourceRenderer {
717
770
}
718
771
719
772
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 > ( ) {
721
774
Ok ( control) => {
722
775
self . handle_control_message ( * control) ;
723
776
return ;
0 commit comments