1
1
use std:: any:: Any ;
2
- use std:: sync:: { Mutex , OnceLock } ;
2
+ use std:: sync:: atomic:: Ordering ;
3
+ use std:: sync:: { Arc , Mutex , OnceLock } ;
3
4
4
5
use crate :: buffer:: AudioBuffer ;
5
6
use crate :: context:: { AudioContextRegistration , AudioParamId , BaseAudioContext } ;
6
7
use crate :: param:: { AudioParam , AudioParamDescriptor , AutomationRate } ;
7
8
use crate :: render:: { AudioParamValues , AudioProcessor , AudioRenderQuantum , RenderScope } ;
8
- use crate :: RENDER_QUANTUM_SIZE ;
9
+ use crate :: { AtomicF64 , RENDER_QUANTUM_SIZE } ;
9
10
10
11
use super :: { AudioNode , AudioScheduledSourceNode , ChannelConfig } ;
11
12
@@ -106,6 +107,7 @@ pub struct AudioBufferSourceNode {
106
107
channel_config : ChannelConfig ,
107
108
detune : AudioParam , // has constraints, no a-rate
108
109
playback_rate : AudioParam , // has constraints, no a-rate
110
+ buffer_time : Arc < AtomicF64 > ,
109
111
buffer : OnceLock < AudioBuffer > ,
110
112
inner_state : Mutex < InnerState > ,
111
113
}
@@ -224,6 +226,7 @@ impl AudioBufferSourceNode {
224
226
channel_config : ChannelConfig :: default ( ) ,
225
227
detune : d_param,
226
228
playback_rate : pr_param,
229
+ buffer_time : Arc :: clone ( & renderer. render_state . buffer_time ) ,
227
230
buffer : OnceLock :: new ( ) ,
228
231
inner_state : Mutex :: new ( inner_state) ,
229
232
} ;
@@ -293,6 +296,16 @@ impl AudioBufferSourceNode {
293
296
& self . playback_rate
294
297
}
295
298
299
+ /// Current playhead position in seconds within the [`AudioBuffer`].
300
+ ///
301
+ /// This value is updated at the end of each render quantum.
302
+ ///
303
+ /// Unofficial v2 API extension, not part of the spec yet.
304
+ /// See also: <https://github.com/WebAudio/web-audio-api/issues/2397#issuecomment-709478405>
305
+ pub fn position ( & self ) -> f64 {
306
+ self . buffer_time . load ( Ordering :: Relaxed )
307
+ }
308
+
296
309
/// K-rate [`AudioParam`] that defines a pitch transposition of the file,
297
310
/// expressed in cents
298
311
///
@@ -341,7 +354,7 @@ impl AudioBufferSourceNode {
341
354
}
342
355
343
356
struct AudioBufferRendererState {
344
- buffer_time : f64 ,
357
+ buffer_time : Arc < AtomicF64 > ,
345
358
started : bool ,
346
359
entered_loop : bool ,
347
360
buffer_time_elapsed : f64 ,
@@ -351,7 +364,7 @@ struct AudioBufferRendererState {
351
364
impl Default for AudioBufferRendererState {
352
365
fn default ( ) -> Self {
353
366
Self {
354
- buffer_time : 0. ,
367
+ buffer_time : Arc :: new ( AtomicF64 :: new ( 0. ) ) ,
355
368
started : false ,
356
369
entered_loop : false ,
357
370
buffer_time_elapsed : 0. ,
@@ -463,9 +476,13 @@ impl AudioProcessor for AudioBufferSourceRenderer {
463
476
return false ;
464
477
}
465
478
479
+ // Load the buffer time from the render state.
480
+ // The render state has to be updated before leaving this method!
481
+ let mut buffer_time = self . render_state . buffer_time . load ( Ordering :: Relaxed ) ;
482
+
466
483
// 3. the end of the buffer has been reached.
467
484
if !is_looping {
468
- if computed_playback_rate > 0. && self . render_state . buffer_time >= buffer_duration {
485
+ if computed_playback_rate > 0. && buffer_time >= buffer_duration {
469
486
output. make_silent ( ) ; // also converts to mono
470
487
if !self . ended_triggered {
471
488
scope. send_ended_event ( ) ;
@@ -474,7 +491,7 @@ impl AudioProcessor for AudioBufferSourceRenderer {
474
491
return false ;
475
492
}
476
493
477
- if computed_playback_rate < 0. && self . render_state . buffer_time < 0. {
494
+ if computed_playback_rate < 0. && buffer_time < 0. {
478
495
output. make_silent ( ) ; // also converts to mono
479
496
if !self . ended_triggered {
480
497
scope. send_ended_event ( ) ;
@@ -533,22 +550,21 @@ impl AudioProcessor for AudioBufferSourceRenderer {
533
550
}
534
551
535
552
// check if buffer ends within this block
536
- if self . render_state . buffer_time + block_duration > buffer_duration
537
- || self . render_state . buffer_time + block_duration > self . duration
553
+ if buffer_time + block_duration > buffer_duration
554
+ || buffer_time + block_duration > self . duration
538
555
|| current_time + block_duration > self . stop_time
539
556
{
540
557
let end_index = if current_time + block_duration > self . stop_time
541
- || self . render_state . buffer_time + block_duration > self . duration
558
+ || buffer_time + block_duration > self . duration
542
559
{
543
- let dt = ( self . stop_time - current_time)
544
- . min ( self . duration - self . render_state . buffer_time ) ;
545
- let end_buffer_time = self . render_state . buffer_time + dt;
560
+ let dt = ( self . stop_time - current_time) . min ( self . duration - buffer_time) ;
561
+ let end_buffer_time = buffer_time + dt;
546
562
( end_buffer_time * sample_rate) . round ( ) as usize
547
563
} else {
548
564
buffer. length ( )
549
565
} ;
550
566
// in case of a loop point in the middle of the block, this value
551
- // will be used to recompute `self.render_state. buffer_time` according
567
+ // will be used to recompute `buffer_time` according
552
568
// to the actual loop point.
553
569
let mut loop_point_index: Option < usize > = None ;
554
570
@@ -559,7 +575,7 @@ impl AudioProcessor for AudioBufferSourceRenderer {
559
575
. for_each ( |( buffer_channel, output_channel) | {
560
576
// we need to recompute that for each channel
561
577
let buffer_channel = buffer_channel. as_slice ( ) ;
562
- let mut start_index = ( self . render_state . buffer_time * sample_rate) . round ( ) as usize ;
578
+ let mut start_index = ( buffer_time * sample_rate) . round ( ) as usize ;
563
579
let mut offset = 0 ;
564
580
565
581
for ( index, o) in output_channel. iter_mut ( ) . enumerate ( ) {
@@ -586,14 +602,13 @@ impl AudioProcessor for AudioBufferSourceRenderer {
586
602
} ) ;
587
603
588
604
if let Some ( loop_point_index) = loop_point_index {
589
- self . render_state . buffer_time =
590
- ( ( RENDER_QUANTUM_SIZE - loop_point_index) as f64 / sample_rate)
591
- % buffer_duration;
605
+ buffer_time = ( ( RENDER_QUANTUM_SIZE - loop_point_index) as f64 / sample_rate)
606
+ % buffer_duration;
592
607
} else {
593
- self . render_state . buffer_time += block_duration;
608
+ buffer_time += block_duration;
594
609
}
595
610
} else {
596
- let start_index = ( self . render_state . buffer_time * sample_rate) . round ( ) as usize ;
611
+ let start_index = ( buffer_time * sample_rate) . round ( ) as usize ;
597
612
let end_index = start_index + RENDER_QUANTUM_SIZE ;
598
613
// we can do memcopy
599
614
buffer
@@ -605,10 +620,13 @@ impl AudioProcessor for AudioBufferSourceRenderer {
605
620
output_channel. copy_from_slice ( & buffer_channel[ start_index..end_index] ) ;
606
621
} ) ;
607
622
608
- self . render_state . buffer_time += block_duration;
623
+ buffer_time += block_duration;
609
624
}
610
625
611
626
// update render state
627
+ self . render_state
628
+ . buffer_time
629
+ . store ( buffer_time, Ordering :: Relaxed ) ;
612
630
self . render_state . buffer_time_elapsed += block_duration;
613
631
614
632
return true ;
@@ -657,44 +675,38 @@ impl AudioProcessor for AudioBufferSourceRenderer {
657
675
self . offset = actual_loop_start;
658
676
}
659
677
660
- self . render_state . buffer_time = self . offset ;
678
+ buffer_time = self . offset ;
661
679
self . render_state . started = true ;
662
680
}
663
681
664
682
if is_looping {
665
683
if !self . render_state . entered_loop {
666
684
// playback began before or within loop, and playhead is now past loop start
667
- if self . offset < actual_loop_end
668
- && self . render_state . buffer_time >= actual_loop_start
669
- {
685
+ if self . offset < actual_loop_end && buffer_time >= actual_loop_start {
670
686
self . render_state . entered_loop = true ;
671
687
}
672
688
673
689
// playback began after loop, and playhead is now prior to the loop end
674
690
// @note - only possible when playback_rate < 0 (?)
675
- if self . offset >= actual_loop_end
676
- && self . render_state . buffer_time < actual_loop_end
677
- {
691
+ if self . offset >= actual_loop_end && buffer_time < actual_loop_end {
678
692
self . render_state . entered_loop = true ;
679
693
}
680
694
}
681
695
682
696
// check loop boundaries
683
697
if self . render_state . entered_loop {
684
- while self . render_state . buffer_time >= actual_loop_end {
685
- self . render_state . buffer_time -= actual_loop_end - actual_loop_start;
698
+ while buffer_time >= actual_loop_end {
699
+ buffer_time -= actual_loop_end - actual_loop_start;
686
700
}
687
701
688
- while self . render_state . buffer_time < actual_loop_start {
689
- self . render_state . buffer_time += actual_loop_end - actual_loop_start;
702
+ while buffer_time < actual_loop_start {
703
+ buffer_time += actual_loop_end - actual_loop_start;
690
704
}
691
705
}
692
706
}
693
707
694
- if self . render_state . buffer_time >= 0.
695
- && self . render_state . buffer_time < buffer_duration
696
- {
697
- let position = self . render_state . buffer_time * sampling_ratio;
708
+ if buffer_time >= 0. && buffer_time < buffer_duration {
709
+ let position = buffer_time * sampling_ratio;
698
710
let playhead = position * sample_rate;
699
711
let playhead_floored = playhead. floor ( ) ;
700
712
let prev_frame_index = playhead_floored as usize ; // can't be < 0.
@@ -709,7 +721,7 @@ impl AudioProcessor for AudioBufferSourceRenderer {
709
721
}
710
722
711
723
let time_incr = dt * computed_playback_rate;
712
- self . render_state . buffer_time += time_incr;
724
+ buffer_time += time_incr;
713
725
self . render_state . buffer_time_elapsed += time_incr;
714
726
current_time += dt;
715
727
}
@@ -745,6 +757,11 @@ impl AudioProcessor for AudioBufferSourceRenderer {
745
757
} ) ;
746
758
} ) ;
747
759
760
+ // update render state
761
+ self . render_state
762
+ . buffer_time
763
+ . store ( buffer_time, Ordering :: Relaxed ) ;
764
+
748
765
true
749
766
}
750
767
0 commit comments