@@ -5,9 +5,11 @@ use std::sync::{Arc, Mutex};
55
66use crate :: buffer:: AudioBuffer ;
77use crate :: context:: { AudioContextState , BaseAudioContext , ConcreteBaseAudioContext } ;
8+ use crate :: events:: {
9+ Event , EventDispatch , EventHandler , EventPayload , EventType , OfflineAudioCompletionEvent ,
10+ } ;
811use crate :: render:: RenderThread ;
912use crate :: { assert_valid_sample_rate, RENDER_QUANTUM_SIZE } ;
10- use crate :: { Event , OfflineAudioCompletionEvent } ;
1113
1214use crate :: events:: EventLoop ;
1315use futures_channel:: { mpsc, oneshot} ;
@@ -49,10 +51,6 @@ struct OfflineAudioContextRenderer {
4951 suspend_callbacks : Vec < ( usize , Box < OfflineAudioContextCallback > ) > ,
5052 /// channel to listen for `resume` calls on a suspended context
5153 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 > > ,
5654 /// event loop to run after each render quantum
5755 event_loop : EventLoop ,
5856}
@@ -61,18 +59,6 @@ impl BaseAudioContext for OfflineAudioContext {
6159 fn base ( & self ) -> & ConcreteBaseAudioContext {
6260 & self . base
6361 }
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- }
7662}
7763
7864impl OfflineAudioContext {
@@ -138,8 +124,6 @@ impl OfflineAudioContext {
138124 suspend_promises : Vec :: new ( ) ,
139125 suspend_callbacks : Vec :: new ( ) ,
140126 resume_receiver,
141- onstatechange_handler : None ,
142- oncomplete_handler : None ,
143127 event_loop,
144128 } ;
145129
@@ -170,24 +154,25 @@ impl OfflineAudioContext {
170154 . unwrap ( )
171155 . take ( )
172156 . expect ( "InvalidStateError - Cannot call `startRendering` twice" ) ;
157+
173158 let OfflineAudioContextRenderer {
174159 renderer,
175160 suspend_callbacks,
176- oncomplete_handler,
177- mut onstatechange_handler,
178161 event_loop,
179162 ..
180163 } = renderer;
181164
182165 self . base . set_state ( AudioContextState :: Running ) ;
183- Self :: emit_statechange ( & mut onstatechange_handler) ;
184166
185- let result = renderer. render_audiobuffer_sync ( self , suspend_callbacks, event_loop) ;
167+ let result = renderer. render_audiobuffer_sync ( self , suspend_callbacks, & event_loop) ;
186168
187169 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 ( ) ) ) ;
189173
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 ( ) ;
191176
192177 result
193178 }
@@ -216,48 +201,27 @@ impl OfflineAudioContext {
216201 renderer,
217202 suspend_promises,
218203 resume_receiver,
219- oncomplete_handler,
220- mut onstatechange_handler,
204+ event_loop,
221205 ..
222206 } = renderer;
223207
224208 self . base . set_state ( AudioContextState :: Running ) ;
225- Self :: emit_statechange ( & mut onstatechange_handler) ;
226209
227210 let result = renderer
228- . render_audiobuffer ( self . length , suspend_promises, resume_receiver)
211+ . render_audiobuffer ( self . length , suspend_promises, resume_receiver, & event_loop )
229212 . await ;
230213
231214 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 ( ) ) ) ;
233218
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 ( ) ;
235221
236222 result
237223 }
238224
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-
261225 /// get the length of rendering audio buffer
262226 // false positive: OfflineAudioContext is not const
263227 #[ allow( clippy:: missing_const_for_fn, clippy:: unused_self) ]
@@ -434,17 +398,24 @@ impl OfflineAudioContext {
434398 & self ,
435399 callback : F ,
436400 ) {
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) ) ) ;
440414 }
441415
442416 /// Unset the callback to run when the rendering has completed
443- #[ allow( clippy:: missing_panics_doc) ]
444417 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 ) ;
448419 }
449420}
450421
@@ -599,6 +570,23 @@ mod tests {
599570 assert ! ( changed. load( Ordering :: Relaxed ) ) ;
600571 }
601572
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+
602590 #[ test]
603591 fn test_oncomplete ( ) {
604592 let mut context = OfflineAudioContext :: new ( 2 , 555 , 44_100. ) ;
@@ -614,4 +602,22 @@ mod tests {
614602
615603 assert ! ( complete. load( Ordering :: Relaxed ) ) ;
616604 }
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+ }
617623}
0 commit comments