1
1
//! The `OfflineAudioContext` type
2
2
3
- use std:: sync:: atomic:: AtomicU64 ;
3
+ use std:: sync:: atomic:: { AtomicU64 , AtomicU8 } ;
4
4
use std:: sync:: { Arc , Mutex } ;
5
5
6
6
use crate :: buffer:: AudioBuffer ;
7
- use crate :: context:: { BaseAudioContext , ConcreteBaseAudioContext } ;
7
+ use crate :: context:: { AudioContextState , BaseAudioContext , ConcreteBaseAudioContext } ;
8
8
use crate :: render:: RenderThread ;
9
9
use crate :: { assert_valid_sample_rate, RENDER_QUANTUM_SIZE } ;
10
10
@@ -71,19 +71,23 @@ impl OfflineAudioContext {
71
71
// track number of frames - synced from render thread to control thread
72
72
let frames_played = Arc :: new ( AtomicU64 :: new ( 0 ) ) ;
73
73
let frames_played_clone = Arc :: clone ( & frames_played) ;
74
+ let state = Arc :: new ( AtomicU8 :: new ( AudioContextState :: Suspended as u8 ) ) ;
75
+ let state_clone = Arc :: clone ( & state) ;
74
76
75
77
// setup the render 'thread', which will run inside the control thread
76
78
let renderer = RenderThread :: new (
77
79
sample_rate,
78
80
number_of_channels,
79
81
receiver,
82
+ state_clone,
80
83
frames_played_clone,
81
84
) ;
82
85
83
86
// first, setup the base audio context
84
87
let base = ConcreteBaseAudioContext :: new (
85
88
sample_rate,
86
89
number_of_channels,
90
+ state,
87
91
frames_played,
88
92
sender,
89
93
None ,
@@ -131,7 +135,11 @@ impl OfflineAudioContext {
131
135
..
132
136
} = renderer;
133
137
134
- renderer. render_audiobuffer_sync ( self . length , suspend_callbacks, self )
138
+ self . base . set_state ( AudioContextState :: Running ) ;
139
+ let result = renderer. render_audiobuffer_sync ( self . length , suspend_callbacks, self ) ;
140
+ self . base . set_state ( AudioContextState :: Closed ) ;
141
+
142
+ result
135
143
}
136
144
137
145
/// Given the current connections and scheduled changes, starts rendering audio.
@@ -159,9 +167,15 @@ impl OfflineAudioContext {
159
167
..
160
168
} = renderer;
161
169
162
- renderer
170
+ self . base . set_state ( AudioContextState :: Running ) ;
171
+
172
+ let result = renderer
163
173
. render_audiobuffer ( self . length , suspend_promises, resume_receiver)
164
- . await
174
+ . await ;
175
+
176
+ self . base . set_state ( AudioContextState :: Closed ) ;
177
+
178
+ result
165
179
}
166
180
167
181
/// get the length of rendering audio buffer
@@ -253,7 +267,8 @@ impl OfflineAudioContext {
253
267
. insert ( insert_pos, ( quantum, sender) ) ;
254
268
} // lock is dropped
255
269
256
- receiver. await . unwrap ( )
270
+ receiver. await . unwrap ( ) ;
271
+ self . base ( ) . set_state ( AudioContextState :: Suspended ) ;
257
272
}
258
273
259
274
/// Schedules a suspension of the time progression in the audio context at the specified time
@@ -313,9 +328,15 @@ impl OfflineAudioContext {
313
328
"InvalidStateError: cannot suspend multiple times at the same render quantum" ,
314
329
) ;
315
330
331
+ let boxed_callback = Box :: new ( |ctx : & mut OfflineAudioContext | {
332
+ ctx. base ( ) . set_state ( AudioContextState :: Suspended ) ;
333
+ ( callback) ( ctx) ;
334
+ ctx. base ( ) . set_state ( AudioContextState :: Running ) ;
335
+ } ) ;
336
+
316
337
renderer
317
338
. suspend_callbacks
318
- . insert ( insert_pos, ( quantum, Box :: new ( callback ) ) ) ;
339
+ . insert ( insert_pos, ( quantum, boxed_callback ) ) ;
319
340
}
320
341
321
342
/// Resumes the progression of the OfflineAudioContext's currentTime when it has been suspended
@@ -324,6 +345,7 @@ impl OfflineAudioContext {
324
345
///
325
346
/// Panics when the context is closed or rendering has not started
326
347
pub async fn resume ( & self ) {
348
+ self . base ( ) . set_state ( AudioContextState :: Running ) ;
327
349
self . resume_sender . clone ( ) . send ( ( ) ) . await . unwrap ( )
328
350
}
329
351
}
@@ -339,6 +361,7 @@ mod tests {
339
361
#[ test]
340
362
fn render_empty_graph ( ) {
341
363
let mut context = OfflineAudioContext :: new ( 2 , 555 , 44_100. ) ;
364
+ assert_eq ! ( context. state( ) , AudioContextState :: Suspended ) ;
342
365
let buffer = context. start_rendering_sync ( ) ;
343
366
344
367
assert_eq ! ( context. length( ) , 555 ) ;
@@ -347,6 +370,8 @@ mod tests {
347
370
assert_eq ! ( buffer. length( ) , 555 ) ;
348
371
assert_float_eq ! ( buffer. get_channel_data( 0 ) , & [ 0. ; 555 ] [ ..] , abs_all <= 0. ) ;
349
372
assert_float_eq ! ( buffer. get_channel_data( 1 ) , & [ 0. ; 555 ] [ ..] , abs_all <= 0. ) ;
373
+
374
+ assert_eq ! ( context. state( ) , AudioContextState :: Closed ) ;
350
375
}
351
376
352
377
#[ test]
@@ -365,12 +390,14 @@ mod tests {
365
390
let mut context = OfflineAudioContext :: new ( 1 , len, sample_rate as f32 ) ;
366
391
367
392
context. suspend_sync ( RENDER_QUANTUM_SIZE as f64 / sample_rate, |context| {
393
+ assert_eq ! ( context. state( ) , AudioContextState :: Suspended ) ;
368
394
let mut src = context. create_constant_source ( ) ;
369
395
src. connect ( & context. destination ( ) ) ;
370
396
src. start ( ) ;
371
397
} ) ;
372
398
373
399
context. suspend_sync ( ( 3 * RENDER_QUANTUM_SIZE ) as f64 / sample_rate, |context| {
400
+ assert_eq ! ( context. state( ) , AudioContextState :: Suspended ) ;
374
401
context. destination ( ) . disconnect ( ) ;
375
402
} ) ;
376
403
0 commit comments