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 } ;
@@ -49,54 +47,15 @@ struct PlaybackInfo {
49
47
k : f32 ,
50
48
}
51
49
52
- // The strategy for loop parameters is as follow: store the given values
53
- // in the `loop_control` 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 desynchronised for little while
56
- // but the developer experience will appear more logical, i.e.
57
- // ```no_run
58
- // node.set_loop(true);
59
- // println!("{:?}", node.loop_());
60
- // > true // is guaranteed
61
- // ```
62
- // Note that this seems to be the strategy used by Firefox
63
- #[ derive( Debug ) ]
64
- struct LoopControl {
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 LoopControl {
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
- }
50
+ #[ derive( Debug , Clone ) ]
51
+ struct LoopState {
52
+ pub is_looping : bool ,
53
+ pub start : f64 ,
54
+ pub end : f64 ,
96
55
}
97
56
98
57
/// Instructions to start or stop processing
99
- #[ derive( Debug , Copy , Clone ) ]
58
+ #[ derive( Debug , Clone ) ]
100
59
enum ControlMessage {
101
60
StartWithOffsetAndDuration ( f64 , f64 , f64 ) ,
102
61
Stop ( f64 ) ,
@@ -139,12 +98,17 @@ enum ControlMessage {
139
98
///
140
99
pub struct AudioBufferSourceNode {
141
100
registration : AudioContextRegistration ,
142
- loop_control : LoopControl ,
143
101
channel_config : ChannelConfig ,
144
102
detune : AudioParam , // has constraints, no a-rate
145
103
playback_rate : AudioParam , // has constraints, no a-rate
146
104
buffer : OnceCell < AudioBuffer > ,
147
- source_started : AtomicBool ,
105
+ inner_state : RefCell < InnerState > ,
106
+ }
107
+
108
+ #[ derive( Debug , Clone ) ]
109
+ struct InnerState {
110
+ loop_state : LoopState ,
111
+ source_started : bool ,
148
112
}
149
113
150
114
impl AudioNode for AudioBufferSourceNode {
@@ -181,9 +145,10 @@ impl AudioScheduledSourceNode for AudioBufferSourceNode {
181
145
}
182
146
183
147
fn stop_at ( & self , when : f64 ) {
184
- if !self . source_started . load ( Ordering :: SeqCst ) {
185
- panic ! ( "InvalidStateError cannot stop before start" ) ;
186
- }
148
+ assert ! (
149
+ self . inner_state. borrow( ) . source_started,
150
+ "InvalidStateError cannot stop before start"
151
+ ) ;
187
152
188
153
self . registration . post_message ( ControlMessage :: Stop ( when) ) ;
189
154
}
@@ -226,35 +191,36 @@ impl AudioBufferSourceNode {
226
191
pr_param. set_automation_rate_constrained ( true ) ;
227
192
pr_param. set_value ( playback_rate) ;
228
193
229
- let loop_control = LoopControl {
230
- loop_ : AtomicBool :: new ( loop_) ,
231
- loop_start : AtomicF64 :: new ( loop_start) ,
232
- loop_end : AtomicF64 :: new ( loop_end) ,
194
+ let loop_state = LoopState {
195
+ is_looping : loop_,
196
+ start : loop_start,
197
+ end : loop_end,
233
198
} ;
234
199
235
200
let renderer = AudioBufferSourceRenderer {
236
201
start_time : f64:: MAX ,
237
202
stop_time : f64:: MAX ,
238
203
duration : f64:: MAX ,
239
204
offset : 0. ,
240
- loop_,
241
- loop_start,
242
- loop_end,
243
205
buffer : None ,
244
206
detune : d_proc,
245
207
playback_rate : pr_proc,
208
+ loop_state : loop_state. clone ( ) ,
246
209
render_state : AudioBufferRendererState :: default ( ) ,
247
210
ended_triggered : false ,
248
211
} ;
249
212
213
+ let inner_state = InnerState {
214
+ loop_state,
215
+ source_started : false ,
216
+ } ;
250
217
let node = Self {
251
218
registration,
252
- loop_control,
253
219
channel_config : ChannelConfig :: default ( ) ,
254
220
detune : d_param,
255
221
playback_rate : pr_param,
256
222
buffer : OnceCell :: new ( ) ,
257
- source_started : AtomicBool :: new ( false ) ,
223
+ inner_state : RefCell :: new ( inner_state ) ,
258
224
} ;
259
225
260
226
if let Some ( buf) = buffer {
@@ -280,9 +246,12 @@ impl AudioBufferSourceNode {
280
246
///
281
247
/// Panics if the source was already started
282
248
pub fn start_at_with_offset_and_duration ( & self , start : f64 , offset : f64 , duration : f64 ) {
283
- if self . source_started . swap ( true , Ordering :: SeqCst ) {
284
- panic ! ( "InvalidStateError: Cannot call `start` twice" ) ;
285
- }
249
+ let source_started = & mut self . inner_state . borrow_mut ( ) . source_started ;
250
+ assert ! (
251
+ !* source_started,
252
+ "InvalidStateError: Cannot call `start` twice"
253
+ ) ;
254
+ * source_started = true ;
286
255
287
256
let control = ControlMessage :: StartWithOffsetAndDuration ( start, offset, duration) ;
288
257
self . registration . post_message ( control) ;
@@ -329,32 +298,32 @@ impl AudioBufferSourceNode {
329
298
330
299
/// Defines if the playback the [`AudioBuffer`] should be looped
331
300
pub fn loop_ ( & self ) -> bool {
332
- self . loop_control . loop_ ( )
301
+ self . inner_state . borrow ( ) . loop_state . is_looping
333
302
}
334
303
335
304
pub fn set_loop ( & self , value : bool ) {
336
- self . loop_control . set_loop ( value ) ;
305
+ self . inner_state . borrow_mut ( ) . loop_state . is_looping = value ;
337
306
self . registration . post_message ( ControlMessage :: Loop ( value) ) ;
338
307
}
339
308
340
309
/// Defines the loop start point, in the time reference of the [`AudioBuffer`]
341
310
pub fn loop_start ( & self ) -> f64 {
342
- self . loop_control . loop_start ( )
311
+ self . inner_state . borrow ( ) . loop_state . start
343
312
}
344
313
345
314
pub fn set_loop_start ( & self , value : f64 ) {
346
- self . loop_control . set_loop_start ( value ) ;
315
+ self . inner_state . borrow_mut ( ) . loop_state . start = value ;
347
316
self . registration
348
317
. post_message ( ControlMessage :: LoopStart ( value) ) ;
349
318
}
350
319
351
320
/// Defines the loop end point, in the time reference of the [`AudioBuffer`]
352
321
pub fn loop_end ( & self ) -> f64 {
353
- self . loop_control . loop_end ( )
322
+ self . inner_state . borrow ( ) . loop_state . end
354
323
}
355
324
356
325
pub fn set_loop_end ( & self , value : f64 ) {
357
- self . loop_control . set_loop_end ( value ) ;
326
+ self . inner_state . borrow_mut ( ) . loop_state . end = value ;
358
327
self . registration
359
328
. post_message ( ControlMessage :: LoopEnd ( value) ) ;
360
329
}
@@ -385,28 +354,26 @@ struct AudioBufferSourceRenderer {
385
354
stop_time : f64 ,
386
355
offset : f64 ,
387
356
duration : f64 ,
388
- loop_ : bool ,
389
- loop_start : f64 ,
390
- loop_end : f64 ,
391
357
buffer : Option < AudioBuffer > ,
392
358
detune : AudioParamId ,
393
359
playback_rate : AudioParamId ,
360
+ loop_state : LoopState ,
394
361
render_state : AudioBufferRendererState ,
395
362
ended_triggered : bool ,
396
363
}
397
364
398
365
impl AudioBufferSourceRenderer {
399
- fn handle_control_message ( & mut self , control : ControlMessage ) {
366
+ fn handle_control_message ( & mut self , control : & ControlMessage ) {
400
367
match control {
401
368
ControlMessage :: StartWithOffsetAndDuration ( when, offset, duration) => {
402
- self . start_time = when;
403
- self . offset = offset;
404
- self . duration = duration;
369
+ self . start_time = * when;
370
+ self . offset = * offset;
371
+ self . duration = * duration;
405
372
}
406
- ControlMessage :: Stop ( when) => self . stop_time = when,
407
- ControlMessage :: Loop ( loop_ ) => self . loop_ = loop_ ,
408
- ControlMessage :: LoopStart ( loop_start) => self . loop_start = loop_start,
409
- ControlMessage :: LoopEnd ( loop_end) => self . loop_end = loop_end,
373
+ ControlMessage :: Stop ( when) => self . stop_time = * when,
374
+ ControlMessage :: Loop ( is_looping ) => self . loop_state . is_looping = * is_looping ,
375
+ ControlMessage :: LoopStart ( loop_start) => self . loop_state . start = * loop_start,
376
+ ControlMessage :: LoopEnd ( loop_end) => self . loop_state . end = * loop_end,
410
377
}
411
378
}
412
379
}
@@ -427,10 +394,11 @@ impl AudioProcessor for AudioBufferSourceRenderer {
427
394
let block_duration = dt * RENDER_QUANTUM_SIZE as f64 ;
428
395
let next_block_time = scope. current_time + block_duration;
429
396
430
- // grab all timing information
431
- let loop_ = self . loop_ ;
432
- let loop_start = self . loop_start ;
433
- let loop_end = self . loop_end ;
397
+ let LoopState {
398
+ is_looping,
399
+ start : loop_start,
400
+ end : loop_end,
401
+ } = self . loop_state . clone ( ) ;
434
402
435
403
// these will only be used if `loop_` is true, so no need for `Option`
436
404
let mut actual_loop_start = 0. ;
@@ -485,7 +453,7 @@ impl AudioProcessor for AudioBufferSourceRenderer {
485
453
}
486
454
487
455
// 3. the end of the buffer has been reached.
488
- if !loop_ {
456
+ if !is_looping {
489
457
if computed_playback_rate > 0. && self . render_state . buffer_time >= buffer_duration {
490
458
output. make_silent ( ) ; // also converts to mono
491
459
if !self . ended_triggered {
@@ -590,15 +558,15 @@ impl AudioProcessor for AudioBufferSourceRenderer {
590
558
* o = if buffer_index < end_index {
591
559
buffer_channel[ buffer_index]
592
560
} else {
593
- if loop_ && buffer_index == end_index {
561
+ if is_looping && buffer_index == end_index {
594
562
loop_point_index = Some ( index) ;
595
563
// reset values for the rest of the block
596
564
start_index = 0 ;
597
565
offset = index;
598
566
buffer_index = 0 ;
599
567
}
600
568
601
- if loop_ {
569
+ if is_looping {
602
570
buffer_channel[ buffer_index]
603
571
} else {
604
572
0.
@@ -639,7 +607,7 @@ impl AudioProcessor for AudioBufferSourceRenderer {
639
607
// ---------------------------------------------------------------
640
608
// Slow track
641
609
// ---------------------------------------------------------------
642
- if loop_ {
610
+ if is_looping {
643
611
if loop_start >= 0. && loop_end > 0. && loop_start < loop_end {
644
612
actual_loop_start = loop_start;
645
613
actual_loop_end = loop_end. min ( buffer_duration) ;
@@ -671,19 +639,19 @@ impl AudioProcessor for AudioBufferSourceRenderer {
671
639
if !self . render_state . started {
672
640
self . offset += current_time - self . start_time ;
673
641
674
- if loop_ && computed_playback_rate >= 0. && self . offset >= actual_loop_end {
642
+ if is_looping && computed_playback_rate >= 0. && self . offset >= actual_loop_end {
675
643
self . offset = actual_loop_end;
676
644
}
677
645
678
- if loop_ && computed_playback_rate < 0. && self . offset < actual_loop_start {
646
+ if is_looping && computed_playback_rate < 0. && self . offset < actual_loop_start {
679
647
self . offset = actual_loop_start;
680
648
}
681
649
682
650
self . render_state . buffer_time = self . offset ;
683
651
self . render_state . started = true ;
684
652
}
685
653
686
- if loop_ {
654
+ if is_looping {
687
655
if !self . render_state . entered_loop {
688
656
// playback began before or within loop, and playhead is now past loop start
689
657
if self . offset < actual_loop_end
@@ -772,7 +740,7 @@ impl AudioProcessor for AudioBufferSourceRenderer {
772
740
773
741
fn onmessage ( & mut self , msg : & mut dyn Any ) {
774
742
if let Some ( control) = msg. downcast_ref :: < ControlMessage > ( ) {
775
- self . handle_control_message ( * control) ;
743
+ self . handle_control_message ( control) ;
776
744
return ;
777
745
} ;
778
746
0 commit comments