1
1
use std:: any:: Any ;
2
- use std:: cell:: OnceCell ;
3
- use std:: sync:: atomic:: { AtomicBool , Ordering } ;
2
+ use std:: cell:: { OnceCell , RefCell } ;
4
3
5
4
use crate :: buffer:: AudioBuffer ;
6
5
use crate :: context:: { AudioContextRegistration , AudioParamId , BaseAudioContext } ;
7
6
use crate :: param:: { AudioParam , AudioParamDescriptor , AutomationRate } ;
8
7
use crate :: render:: { AudioParamValues , AudioProcessor , AudioRenderQuantum , RenderScope } ;
9
- use crate :: AtomicF64 ;
10
8
use crate :: RENDER_QUANTUM_SIZE ;
11
9
12
10
use super :: { AudioNode , AudioScheduledSourceNode , ChannelConfig } ;
@@ -21,9 +19,10 @@ use super::{AudioNode, AudioScheduledSourceNode, ChannelConfig};
21
19
// float playbackRate = 1;
22
20
// };
23
21
//
24
- // @note - Does not extend AudioNodeOptions because AudioNodeOptions are
25
- // useless for source nodes as they instruct how to upmix the inputs.
26
- // This is a common source of confusion, see e.g. https://github.com/mdn/content/pull/18472
22
+ // @note - Does extend AudioNodeOptions but they are useless for source nodes as
23
+ // they instruct how to upmix the inputs.
24
+ // This is a common source of confusion, see e.g. https://github.com/mdn/content/pull/18472, and
25
+ // an issue in the spec, see discussion in https://github.com/WebAudio/web-audio-api/issues/2496
27
26
#[ derive( Clone , Debug ) ]
28
27
pub struct AudioBufferSourceOptions {
29
28
pub buffer : Option < AudioBuffer > ,
@@ -53,54 +52,15 @@ struct PlaybackInfo {
53
52
k : f32 ,
54
53
}
55
54
56
- // The strategy for loop parameters is as follow: store the given values
57
- // in the `loop_control` thread safe instance which only lives in control
58
- // thread(s) and send a message to the render thread which stores the raw values.
59
- // Values between control and render side might be desynchronised for little while
60
- // but the developer experience will appear more logical, i.e.
61
- // ```no_run
62
- // node.set_loop(true);
63
- // println!("{:?}", node.loop_());
64
- // > true // is guaranteed
65
- // ```
66
- // Note that this seems to be the strategy used by Firefox
67
- #[ derive( Debug ) ]
68
- struct LoopControl {
69
- loop_ : AtomicBool ,
70
- loop_start : AtomicF64 ,
71
- loop_end : AtomicF64 ,
72
- }
73
-
74
- // Uses the canonical ordering for handover of values,
75
- // i.e. `Acquire` on load and `Release` on store.
76
- impl LoopControl {
77
- fn loop_ ( & self ) -> bool {
78
- self . loop_ . load ( Ordering :: Acquire )
79
- }
80
-
81
- fn set_loop ( & self , loop_ : bool ) {
82
- self . loop_ . store ( loop_, Ordering :: Release ) ;
83
- }
84
-
85
- fn loop_start ( & self ) -> f64 {
86
- self . loop_start . load ( Ordering :: Acquire )
87
- }
88
-
89
- fn set_loop_start ( & self , loop_start : f64 ) {
90
- self . loop_start . store ( loop_start, Ordering :: Release ) ;
91
- }
92
-
93
- fn loop_end ( & self ) -> f64 {
94
- self . loop_end . load ( Ordering :: Acquire )
95
- }
96
-
97
- fn set_loop_end ( & self , loop_end : f64 ) {
98
- self . loop_end . store ( loop_end, Ordering :: Release ) ;
99
- }
55
+ #[ derive( Debug , Clone ) ]
56
+ struct LoopState {
57
+ pub is_looping : bool ,
58
+ pub start : f64 ,
59
+ pub end : f64 ,
100
60
}
101
61
102
62
/// Instructions to start or stop processing
103
- #[ derive( Debug , Copy , Clone ) ]
63
+ #[ derive( Debug , Clone ) ]
104
64
enum ControlMessage {
105
65
StartWithOffsetAndDuration ( f64 , f64 , f64 ) ,
106
66
Stop ( f64 ) ,
@@ -143,12 +103,17 @@ enum ControlMessage {
143
103
///
144
104
pub struct AudioBufferSourceNode {
145
105
registration : AudioContextRegistration ,
146
- loop_control : LoopControl ,
147
106
channel_config : ChannelConfig ,
148
107
detune : AudioParam , // has constraints, no a-rate
149
108
playback_rate : AudioParam , // has constraints, no a-rate
150
109
buffer : OnceCell < AudioBuffer > ,
151
- source_started : AtomicBool ,
110
+ inner_state : RefCell < InnerState > ,
111
+ }
112
+
113
+ #[ derive( Debug , Clone ) ]
114
+ struct InnerState {
115
+ loop_state : LoopState ,
116
+ source_started : bool ,
152
117
}
153
118
154
119
impl AudioNode for AudioBufferSourceNode {
@@ -185,9 +150,10 @@ impl AudioScheduledSourceNode for AudioBufferSourceNode {
185
150
}
186
151
187
152
fn stop_at ( & self , when : f64 ) {
188
- if !self . source_started . load ( Ordering :: SeqCst ) {
189
- panic ! ( "InvalidStateError cannot stop before start" ) ;
190
- }
153
+ assert ! (
154
+ self . inner_state. borrow( ) . source_started,
155
+ "InvalidStateError cannot stop before start"
156
+ ) ;
191
157
192
158
self . registration . post_message ( ControlMessage :: Stop ( when) ) ;
193
159
}
@@ -230,35 +196,36 @@ impl AudioBufferSourceNode {
230
196
pr_param. set_automation_rate_constrained ( true ) ;
231
197
pr_param. set_value ( playback_rate) ;
232
198
233
- let loop_control = LoopControl {
234
- loop_ : AtomicBool :: new ( loop_) ,
235
- loop_start : AtomicF64 :: new ( loop_start) ,
236
- loop_end : AtomicF64 :: new ( loop_end) ,
199
+ let loop_state = LoopState {
200
+ is_looping : loop_,
201
+ start : loop_start,
202
+ end : loop_end,
237
203
} ;
238
204
239
205
let renderer = AudioBufferSourceRenderer {
240
206
start_time : f64:: MAX ,
241
207
stop_time : f64:: MAX ,
242
208
duration : f64:: MAX ,
243
209
offset : 0. ,
244
- loop_,
245
- loop_start,
246
- loop_end,
247
210
buffer : None ,
248
211
detune : d_proc,
249
212
playback_rate : pr_proc,
213
+ loop_state : loop_state. clone ( ) ,
250
214
render_state : AudioBufferRendererState :: default ( ) ,
251
215
ended_triggered : false ,
252
216
} ;
253
217
218
+ let inner_state = InnerState {
219
+ loop_state,
220
+ source_started : false ,
221
+ } ;
254
222
let node = Self {
255
223
registration,
256
- loop_control,
257
224
channel_config : ChannelConfig :: default ( ) ,
258
225
detune : d_param,
259
226
playback_rate : pr_param,
260
227
buffer : OnceCell :: new ( ) ,
261
- source_started : AtomicBool :: new ( false ) ,
228
+ inner_state : RefCell :: new ( inner_state ) ,
262
229
} ;
263
230
264
231
if let Some ( buf) = buffer {
@@ -284,9 +251,12 @@ impl AudioBufferSourceNode {
284
251
///
285
252
/// Panics if the source was already started
286
253
pub fn start_at_with_offset_and_duration ( & self , start : f64 , offset : f64 , duration : f64 ) {
287
- if self . source_started . swap ( true , Ordering :: SeqCst ) {
288
- panic ! ( "InvalidStateError: Cannot call `start` twice" ) ;
289
- }
254
+ let source_started = & mut self . inner_state . borrow_mut ( ) . source_started ;
255
+ assert ! (
256
+ !* source_started,
257
+ "InvalidStateError: Cannot call `start` twice"
258
+ ) ;
259
+ * source_started = true ;
290
260
291
261
let control = ControlMessage :: StartWithOffsetAndDuration ( start, offset, duration) ;
292
262
self . registration . post_message ( control) ;
@@ -333,32 +303,32 @@ impl AudioBufferSourceNode {
333
303
334
304
/// Defines if the playback the [`AudioBuffer`] should be looped
335
305
pub fn loop_ ( & self ) -> bool {
336
- self . loop_control . loop_ ( )
306
+ self . inner_state . borrow ( ) . loop_state . is_looping
337
307
}
338
308
339
309
pub fn set_loop ( & self , value : bool ) {
340
- self . loop_control . set_loop ( value ) ;
310
+ self . inner_state . borrow_mut ( ) . loop_state . is_looping = value ;
341
311
self . registration . post_message ( ControlMessage :: Loop ( value) ) ;
342
312
}
343
313
344
314
/// Defines the loop start point, in the time reference of the [`AudioBuffer`]
345
315
pub fn loop_start ( & self ) -> f64 {
346
- self . loop_control . loop_start ( )
316
+ self . inner_state . borrow ( ) . loop_state . start
347
317
}
348
318
349
319
pub fn set_loop_start ( & self , value : f64 ) {
350
- self . loop_control . set_loop_start ( value ) ;
320
+ self . inner_state . borrow_mut ( ) . loop_state . start = value ;
351
321
self . registration
352
322
. post_message ( ControlMessage :: LoopStart ( value) ) ;
353
323
}
354
324
355
325
/// Defines the loop end point, in the time reference of the [`AudioBuffer`]
356
326
pub fn loop_end ( & self ) -> f64 {
357
- self . loop_control . loop_end ( )
327
+ self . inner_state . borrow ( ) . loop_state . end
358
328
}
359
329
360
330
pub fn set_loop_end ( & self , value : f64 ) {
361
- self . loop_control . set_loop_end ( value ) ;
331
+ self . inner_state . borrow_mut ( ) . loop_state . end = value ;
362
332
self . registration
363
333
. post_message ( ControlMessage :: LoopEnd ( value) ) ;
364
334
}
@@ -389,28 +359,26 @@ struct AudioBufferSourceRenderer {
389
359
stop_time : f64 ,
390
360
offset : f64 ,
391
361
duration : f64 ,
392
- loop_ : bool ,
393
- loop_start : f64 ,
394
- loop_end : f64 ,
395
362
buffer : Option < AudioBuffer > ,
396
363
detune : AudioParamId ,
397
364
playback_rate : AudioParamId ,
365
+ loop_state : LoopState ,
398
366
render_state : AudioBufferRendererState ,
399
367
ended_triggered : bool ,
400
368
}
401
369
402
370
impl AudioBufferSourceRenderer {
403
- fn handle_control_message ( & mut self , control : ControlMessage ) {
371
+ fn handle_control_message ( & mut self , control : & ControlMessage ) {
404
372
match control {
405
373
ControlMessage :: StartWithOffsetAndDuration ( when, offset, duration) => {
406
- self . start_time = when;
407
- self . offset = offset;
408
- self . duration = duration;
374
+ self . start_time = * when;
375
+ self . offset = * offset;
376
+ self . duration = * duration;
409
377
}
410
- ControlMessage :: Stop ( when) => self . stop_time = when,
411
- ControlMessage :: Loop ( loop_ ) => self . loop_ = loop_ ,
412
- ControlMessage :: LoopStart ( loop_start) => self . loop_start = loop_start,
413
- ControlMessage :: LoopEnd ( loop_end) => self . loop_end = loop_end,
378
+ ControlMessage :: Stop ( when) => self . stop_time = * when,
379
+ ControlMessage :: Loop ( is_looping ) => self . loop_state . is_looping = * is_looping ,
380
+ ControlMessage :: LoopStart ( loop_start) => self . loop_state . start = * loop_start,
381
+ ControlMessage :: LoopEnd ( loop_end) => self . loop_state . end = * loop_end,
414
382
}
415
383
}
416
384
}
@@ -431,10 +399,11 @@ impl AudioProcessor for AudioBufferSourceRenderer {
431
399
let block_duration = dt * RENDER_QUANTUM_SIZE as f64 ;
432
400
let next_block_time = scope. current_time + block_duration;
433
401
434
- // grab all timing information
435
- let loop_ = self . loop_ ;
436
- let loop_start = self . loop_start ;
437
- let loop_end = self . loop_end ;
402
+ let LoopState {
403
+ is_looping,
404
+ start : loop_start,
405
+ end : loop_end,
406
+ } = self . loop_state . clone ( ) ;
438
407
439
408
// these will only be used if `loop_` is true, so no need for `Option`
440
409
let mut actual_loop_start = 0. ;
@@ -489,7 +458,7 @@ impl AudioProcessor for AudioBufferSourceRenderer {
489
458
}
490
459
491
460
// 3. the end of the buffer has been reached.
492
- if !loop_ {
461
+ if !is_looping {
493
462
if computed_playback_rate > 0. && self . render_state . buffer_time >= buffer_duration {
494
463
output. make_silent ( ) ; // also converts to mono
495
464
if !self . ended_triggered {
@@ -594,15 +563,15 @@ impl AudioProcessor for AudioBufferSourceRenderer {
594
563
* o = if buffer_index < end_index {
595
564
buffer_channel[ buffer_index]
596
565
} else {
597
- if loop_ && buffer_index == end_index {
566
+ if is_looping && buffer_index == end_index {
598
567
loop_point_index = Some ( index) ;
599
568
// reset values for the rest of the block
600
569
start_index = 0 ;
601
570
offset = index;
602
571
buffer_index = 0 ;
603
572
}
604
573
605
- if loop_ {
574
+ if is_looping {
606
575
buffer_channel[ buffer_index]
607
576
} else {
608
577
0.
@@ -643,7 +612,7 @@ impl AudioProcessor for AudioBufferSourceRenderer {
643
612
// ---------------------------------------------------------------
644
613
// Slow track
645
614
// ---------------------------------------------------------------
646
- if loop_ {
615
+ if is_looping {
647
616
if loop_start >= 0. && loop_end > 0. && loop_start < loop_end {
648
617
actual_loop_start = loop_start;
649
618
actual_loop_end = loop_end. min ( buffer_duration) ;
@@ -675,19 +644,19 @@ impl AudioProcessor for AudioBufferSourceRenderer {
675
644
if !self . render_state . started {
676
645
self . offset += current_time - self . start_time ;
677
646
678
- if loop_ && computed_playback_rate >= 0. && self . offset >= actual_loop_end {
647
+ if is_looping && computed_playback_rate >= 0. && self . offset >= actual_loop_end {
679
648
self . offset = actual_loop_end;
680
649
}
681
650
682
- if loop_ && computed_playback_rate < 0. && self . offset < actual_loop_start {
651
+ if is_looping && computed_playback_rate < 0. && self . offset < actual_loop_start {
683
652
self . offset = actual_loop_start;
684
653
}
685
654
686
655
self . render_state . buffer_time = self . offset ;
687
656
self . render_state . started = true ;
688
657
}
689
658
690
- if loop_ {
659
+ if is_looping {
691
660
if !self . render_state . entered_loop {
692
661
// playback began before or within loop, and playhead is now past loop start
693
662
if self . offset < actual_loop_end
@@ -776,7 +745,7 @@ impl AudioProcessor for AudioBufferSourceRenderer {
776
745
777
746
fn onmessage ( & mut self , msg : & mut dyn Any ) {
778
747
if let Some ( control) = msg. downcast_ref :: < ControlMessage > ( ) {
779
- self . handle_control_message ( * control) ;
748
+ self . handle_control_message ( control) ;
780
749
return ;
781
750
} ;
782
751
0 commit comments