File tree Expand file tree Collapse file tree 2 files changed +28
-8
lines changed Expand file tree Collapse file tree 2 files changed +28
-8
lines changed Original file line number Diff line number Diff line change @@ -27,11 +27,9 @@ export class Audio {
2727 defaultAudioCallback,
2828 speechAudioCallback,
2929 } : AudioOptions ) {
30- this . context = new AudioContext ( {
31- // The highest rate is the sound expression synth.
32- sampleRate : 44100 ,
33- } ) ;
34-
30+ if ( ! this . context ) {
31+ throw new Error ( "Context must be pre-created from a user event" ) ;
32+ }
3533 this . muteNode = this . context . createGain ( ) ;
3634 this . muteNode . gain . setValueAtTime (
3735 this . muted ? 0 : 1 ,
@@ -62,6 +60,16 @@ export class Audio {
6260 ) ;
6361 }
6462
63+ async createAudioContextFromUserInteraction ( ) : Promise < void > {
64+ this . context = new AudioContext ( {
65+ // The highest rate is the sound expression synth.
66+ sampleRate : 44100 ,
67+ } ) ;
68+ if ( this . context . state === "suspended" ) {
69+ return this . context . resume ( ) ;
70+ }
71+ }
72+
6573 playSoundExpression ( expr : string ) {
6674 const soundEffects = parseSoundEffects ( replaceBuiltinSound ( expr ) ) ;
6775 const onDone = ( ) => {
@@ -138,6 +146,9 @@ export class Audio {
138146
139147 boardStopped ( ) {
140148 this . stopOscillator ( ) ;
149+ this . speech ?. dispose ( ) ;
150+ this . soundExpression ?. dispose ( ) ;
151+ this . default ?. dispose ( ) ;
141152 }
142153
143154 private stopOscillator ( ) {
@@ -188,4 +199,9 @@ class BufferedAudio {
188199 }
189200 source . start ( startTime ) ;
190201 }
202+
203+ dispose ( ) {
204+ // Prevent calls into WASM when the buffer nodes finish.
205+ this . callback = ( ) => { } ;
206+ }
191207}
Original file line number Diff line number Diff line change @@ -230,9 +230,10 @@ export class Board {
230230 this . initializePlayButton ( ) ;
231231 // We start stopped.
232232 this . displayStoppedState ( ) ;
233- this . playButton . addEventListener ( "click" , ( ) =>
234- this . notifications . onRequestFlash ( )
235- ) ;
233+ this . playButton . addEventListener ( "click" , async ( ) => {
234+ await this . audio . createAudioContextFromUserInteraction ( ) ;
235+ this . notifications . onRequestFlash ( ) ;
236+ } ) ;
236237
237238 this . updateTranslationsInternal ( ) ;
238239 this . notifications . onReady ( this . getState ( ) ) ;
@@ -481,6 +482,9 @@ export class Board {
481482 * @returns A promise that resolves when the simulator is stopped.
482483 */
483484 async stop ( brief : boolean = false ) : Promise < void > {
485+ // Preemptively stop audio so that we don't call into WASM for more data
486+ this . audio . boardStopped ( ) ;
487+
484488 if ( this . panicTimeout ) {
485489 clearTimeout ( this . panicTimeout ) ;
486490 this . panicTimeout = null ;
You can’t perform that action at this time.
0 commit comments