@@ -48,14 +48,28 @@ struct OfflineAudioContextRenderer {
48
48
suspend_callbacks : Vec < ( usize , Box < OfflineAudioContextCallback > ) > ,
49
49
/// channel to listen for `resume` calls on a suspended context
50
50
resume_receiver : mpsc:: Receiver < ( ) > ,
51
- /// event handler for oncomplete event
51
+ /// event handler for statechange event
52
+ onstatechange_handler : Option < Box < dyn FnMut ( Event ) + Send + ' static > > ,
53
+ /// event handler for complete event
52
54
oncomplete_handler : Option < Box < dyn FnOnce ( OfflineAudioCompletionEvent ) + Send + ' static > > ,
53
55
}
54
56
55
57
impl BaseAudioContext for OfflineAudioContext {
56
58
fn base ( & self ) -> & ConcreteBaseAudioContext {
57
59
& self . base
58
60
}
61
+
62
+ fn set_onstatechange < F : FnMut ( Event ) + Send + ' static > ( & self , callback : F ) {
63
+ if let Some ( renderer) = self . renderer . lock ( ) . unwrap ( ) . as_mut ( ) {
64
+ renderer. onstatechange_handler = Some ( Box :: new ( callback) ) ;
65
+ }
66
+ }
67
+
68
+ fn clear_onstatechange ( & self ) {
69
+ if let Some ( renderer) = self . renderer . lock ( ) . unwrap ( ) . as_mut ( ) {
70
+ renderer. onstatechange_handler = None ;
71
+ }
72
+ }
59
73
}
60
74
61
75
impl OfflineAudioContext {
@@ -114,6 +128,7 @@ impl OfflineAudioContext {
114
128
suspend_promises : Vec :: new ( ) ,
115
129
suspend_callbacks : Vec :: new ( ) ,
116
130
resume_receiver,
131
+ onstatechange_handler : None ,
117
132
oncomplete_handler : None ,
118
133
} ;
119
134
@@ -147,15 +162,20 @@ impl OfflineAudioContext {
147
162
let OfflineAudioContextRenderer {
148
163
renderer,
149
164
suspend_callbacks,
150
- mut oncomplete_handler,
165
+ oncomplete_handler,
166
+ mut onstatechange_handler,
151
167
..
152
168
} = renderer;
153
169
154
170
self . base . set_state ( AudioContextState :: Running ) ;
171
+ Self :: emit_statechange ( & mut onstatechange_handler) ;
172
+
155
173
let result = renderer. render_audiobuffer_sync ( self . length , suspend_callbacks, self ) ;
174
+
156
175
self . base . set_state ( AudioContextState :: Closed ) ;
176
+ Self :: emit_statechange ( & mut onstatechange_handler) ;
157
177
158
- Self :: emit_oncomplete ( & mut oncomplete_handler, & result) ;
178
+ Self :: emit_complete ( oncomplete_handler, & result) ;
159
179
160
180
result
161
181
}
@@ -184,28 +204,31 @@ impl OfflineAudioContext {
184
204
renderer,
185
205
suspend_promises,
186
206
resume_receiver,
187
- mut oncomplete_handler,
207
+ oncomplete_handler,
208
+ mut onstatechange_handler,
188
209
..
189
210
} = renderer;
190
211
191
212
self . base . set_state ( AudioContextState :: Running ) ;
213
+ Self :: emit_statechange ( & mut onstatechange_handler) ;
192
214
193
215
let result = renderer
194
216
. render_audiobuffer ( self . length , suspend_promises, resume_receiver)
195
217
. await ;
196
218
197
219
self . base . set_state ( AudioContextState :: Closed ) ;
220
+ Self :: emit_statechange ( & mut onstatechange_handler) ;
198
221
199
- Self :: emit_oncomplete ( & mut oncomplete_handler, & result) ;
222
+ Self :: emit_complete ( oncomplete_handler, & result) ;
200
223
201
224
result
202
225
}
203
226
204
- fn emit_oncomplete (
205
- oncomplete_handler : & mut Option < Box < dyn FnOnce ( OfflineAudioCompletionEvent ) + Send > > ,
227
+ fn emit_complete (
228
+ oncomplete_handler : Option < Box < dyn FnOnce ( OfflineAudioCompletionEvent ) + Send > > ,
206
229
result : & AudioBuffer ,
207
230
) {
208
- if let Some ( callback) = oncomplete_handler. take ( ) {
231
+ if let Some ( callback) = oncomplete_handler {
209
232
let event = OfflineAudioCompletionEvent {
210
233
rendered_buffer : result. clone ( ) ,
211
234
event : Event { type_ : "complete" } ,
@@ -214,6 +237,15 @@ impl OfflineAudioContext {
214
237
}
215
238
}
216
239
240
+ fn emit_statechange ( onstatechange_handler : & mut Option < Box < dyn FnMut ( Event ) + Send > > ) {
241
+ if let Some ( callback) = onstatechange_handler. as_mut ( ) {
242
+ let event = Event {
243
+ type_ : "statechange" ,
244
+ } ;
245
+ ( callback) ( event) ;
246
+ }
247
+ }
248
+
217
249
/// get the length of rendering audio buffer
218
250
// false positive: OfflineAudioContext is not const
219
251
#[ allow( clippy:: missing_const_for_fn, clippy:: unused_self) ]
@@ -540,6 +572,21 @@ mod tests {
540
572
context. suspend_sync ( 0.0 , |_| ( ) ) ;
541
573
}
542
574
575
+ #[ test]
576
+ fn test_onstatechange ( ) {
577
+ let mut 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 _ = context. start_rendering_sync ( ) ;
586
+
587
+ assert ! ( changed. load( Ordering :: Relaxed ) ) ;
588
+ }
589
+
543
590
#[ test]
544
591
fn test_oncomplete ( ) {
545
592
let mut context = OfflineAudioContext :: new ( 2 , 555 , 44_100. ) ;
0 commit comments