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