@@ -5,9 +5,11 @@ use std::sync::{Arc, Mutex};
5
5
6
6
use crate :: buffer:: AudioBuffer ;
7
7
use crate :: context:: { AudioContextState , BaseAudioContext , ConcreteBaseAudioContext } ;
8
+ use crate :: events:: {
9
+ Event , EventDispatch , EventHandler , EventPayload , EventType , OfflineAudioCompletionEvent ,
10
+ } ;
8
11
use crate :: render:: RenderThread ;
9
12
use crate :: { assert_valid_sample_rate, RENDER_QUANTUM_SIZE } ;
10
- use crate :: { Event , OfflineAudioCompletionEvent } ;
11
13
12
14
use crate :: events:: EventLoop ;
13
15
use futures_channel:: { mpsc, oneshot} ;
@@ -49,10 +51,6 @@ struct OfflineAudioContextRenderer {
49
51
suspend_callbacks : Vec < ( usize , Box < OfflineAudioContextCallback > ) > ,
50
52
/// channel to listen for `resume` calls on a suspended context
51
53
resume_receiver : mpsc:: Receiver < ( ) > ,
52
- /// event handler for statechange event
53
- onstatechange_handler : Option < Box < dyn FnMut ( Event ) + Send + ' static > > ,
54
- /// event handler for complete event
55
- oncomplete_handler : Option < Box < dyn FnOnce ( OfflineAudioCompletionEvent ) + Send + ' static > > ,
56
54
/// event loop to run after each render quantum
57
55
event_loop : EventLoop ,
58
56
}
@@ -61,18 +59,6 @@ impl BaseAudioContext for OfflineAudioContext {
61
59
fn base ( & self ) -> & ConcreteBaseAudioContext {
62
60
& self . base
63
61
}
64
-
65
- fn set_onstatechange < F : FnMut ( Event ) + Send + ' static > ( & self , callback : F ) {
66
- if let Some ( renderer) = self . renderer . lock ( ) . unwrap ( ) . as_mut ( ) {
67
- renderer. onstatechange_handler = Some ( Box :: new ( callback) ) ;
68
- }
69
- }
70
-
71
- fn clear_onstatechange ( & self ) {
72
- if let Some ( renderer) = self . renderer . lock ( ) . unwrap ( ) . as_mut ( ) {
73
- renderer. onstatechange_handler = None ;
74
- }
75
- }
76
62
}
77
63
78
64
impl OfflineAudioContext {
@@ -138,8 +124,6 @@ impl OfflineAudioContext {
138
124
suspend_promises : Vec :: new ( ) ,
139
125
suspend_callbacks : Vec :: new ( ) ,
140
126
resume_receiver,
141
- onstatechange_handler : None ,
142
- oncomplete_handler : None ,
143
127
event_loop,
144
128
} ;
145
129
@@ -170,24 +154,25 @@ impl OfflineAudioContext {
170
154
. unwrap ( )
171
155
. take ( )
172
156
. expect ( "InvalidStateError - Cannot call `startRendering` twice" ) ;
157
+
173
158
let OfflineAudioContextRenderer {
174
159
renderer,
175
160
suspend_callbacks,
176
- oncomplete_handler,
177
- mut onstatechange_handler,
178
161
event_loop,
179
162
..
180
163
} = renderer;
181
164
182
165
self . base . set_state ( AudioContextState :: Running ) ;
183
- Self :: emit_statechange ( & mut onstatechange_handler) ;
184
166
185
- let result = renderer. render_audiobuffer_sync ( self , suspend_callbacks, event_loop) ;
167
+ let result = renderer. render_audiobuffer_sync ( self , suspend_callbacks, & event_loop) ;
186
168
187
169
self . base . set_state ( AudioContextState :: Closed ) ;
188
- Self :: emit_statechange ( & mut onstatechange_handler) ;
170
+ let _ = self
171
+ . base
172
+ . send_event ( EventDispatch :: complete ( result. clone ( ) ) ) ;
189
173
190
- Self :: emit_complete ( oncomplete_handler, & result) ;
174
+ // spin the event loop once more to handle the statechange/complete events
175
+ event_loop. handle_pending_events ( ) ;
191
176
192
177
result
193
178
}
@@ -216,48 +201,27 @@ impl OfflineAudioContext {
216
201
renderer,
217
202
suspend_promises,
218
203
resume_receiver,
219
- oncomplete_handler,
220
- mut onstatechange_handler,
204
+ event_loop,
221
205
..
222
206
} = renderer;
223
207
224
208
self . base . set_state ( AudioContextState :: Running ) ;
225
- Self :: emit_statechange ( & mut onstatechange_handler) ;
226
209
227
210
let result = renderer
228
- . render_audiobuffer ( self . length , suspend_promises, resume_receiver)
211
+ . render_audiobuffer ( self . length , suspend_promises, resume_receiver, & event_loop )
229
212
. await ;
230
213
231
214
self . base . set_state ( AudioContextState :: Closed ) ;
232
- Self :: emit_statechange ( & mut onstatechange_handler) ;
215
+ let _ = self
216
+ . base
217
+ . send_event ( EventDispatch :: complete ( result. clone ( ) ) ) ;
233
218
234
- Self :: emit_complete ( oncomplete_handler, & result) ;
219
+ // spin the event loop once more to handle the statechange/complete events
220
+ event_loop. handle_pending_events ( ) ;
235
221
236
222
result
237
223
}
238
224
239
- fn emit_complete (
240
- oncomplete_handler : Option < Box < dyn FnOnce ( OfflineAudioCompletionEvent ) + Send > > ,
241
- result : & AudioBuffer ,
242
- ) {
243
- if let Some ( callback) = oncomplete_handler {
244
- let event = OfflineAudioCompletionEvent {
245
- rendered_buffer : result. clone ( ) ,
246
- event : Event { type_ : "complete" } ,
247
- } ;
248
- ( callback) ( event) ;
249
- }
250
- }
251
-
252
- fn emit_statechange ( onstatechange_handler : & mut Option < Box < dyn FnMut ( Event ) + Send > > ) {
253
- if let Some ( callback) = onstatechange_handler. as_mut ( ) {
254
- let event = Event {
255
- type_ : "statechange" ,
256
- } ;
257
- ( callback) ( event) ;
258
- }
259
- }
260
-
261
225
/// get the length of rendering audio buffer
262
226
// false positive: OfflineAudioContext is not const
263
227
#[ allow( clippy:: missing_const_for_fn, clippy:: unused_self) ]
@@ -434,17 +398,24 @@ impl OfflineAudioContext {
434
398
& self ,
435
399
callback : F ,
436
400
) {
437
- if let Some ( renderer) = self . renderer . lock ( ) . unwrap ( ) . as_mut ( ) {
438
- renderer. oncomplete_handler = Some ( Box :: new ( callback) ) ;
439
- }
401
+ let callback = move |v| match v {
402
+ EventPayload :: Complete ( v) => {
403
+ let event = OfflineAudioCompletionEvent {
404
+ rendered_buffer : v,
405
+ event : Event { type_ : "complete" } ,
406
+ } ;
407
+ callback ( event)
408
+ }
409
+ _ => unreachable ! ( ) ,
410
+ } ;
411
+
412
+ self . base ( )
413
+ . set_event_handler ( EventType :: Complete , EventHandler :: Once ( Box :: new ( callback) ) ) ;
440
414
}
441
415
442
416
/// Unset the callback to run when the rendering has completed
443
- #[ allow( clippy:: missing_panics_doc) ]
444
417
pub fn clear_oncomplete ( & self ) {
445
- if let Some ( renderer) = self . renderer . lock ( ) . unwrap ( ) . as_mut ( ) {
446
- renderer. oncomplete_handler = None ;
447
- }
418
+ self . base ( ) . clear_event_handler ( EventType :: Complete ) ;
448
419
}
449
420
}
450
421
@@ -599,6 +570,23 @@ mod tests {
599
570
assert ! ( changed. load( Ordering :: Relaxed ) ) ;
600
571
}
601
572
573
+ #[ test]
574
+ fn test_onstatechange_async ( ) {
575
+ use futures:: executor;
576
+
577
+ let context = OfflineAudioContext :: new ( 2 , 555 , 44_100. ) ;
578
+
579
+ let changed = Arc :: new ( AtomicBool :: new ( false ) ) ;
580
+ let changed_clone = Arc :: clone ( & changed) ;
581
+ context. set_onstatechange ( move |_event| {
582
+ changed_clone. store ( true , Ordering :: Relaxed ) ;
583
+ } ) ;
584
+
585
+ let _ = executor:: block_on ( context. start_rendering ( ) ) ;
586
+
587
+ assert ! ( changed. load( Ordering :: Relaxed ) ) ;
588
+ }
589
+
602
590
#[ test]
603
591
fn test_oncomplete ( ) {
604
592
let mut context = OfflineAudioContext :: new ( 2 , 555 , 44_100. ) ;
@@ -614,4 +602,22 @@ mod tests {
614
602
615
603
assert ! ( complete. load( Ordering :: Relaxed ) ) ;
616
604
}
605
+
606
+ #[ test]
607
+ fn test_oncomplete_async ( ) {
608
+ use futures:: executor;
609
+
610
+ let context = OfflineAudioContext :: new ( 2 , 555 , 44_100. ) ;
611
+
612
+ let complete = Arc :: new ( AtomicBool :: new ( false ) ) ;
613
+ let complete_clone = Arc :: clone ( & complete) ;
614
+ context. set_oncomplete ( move |event| {
615
+ assert_eq ! ( event. rendered_buffer. length( ) , 555 ) ;
616
+ complete_clone. store ( true , Ordering :: Relaxed ) ;
617
+ } ) ;
618
+
619
+ let _ = executor:: block_on ( context. start_rendering ( ) ) ;
620
+
621
+ assert ! ( complete. load( Ordering :: Relaxed ) ) ;
622
+ }
617
623
}
0 commit comments