Skip to content

Commit 9ff6e8a

Browse files
authored
Audio: clean up event listeners and buffer view on destroy (#75)
The Audio constructor binds three window-level event listeners (keydown / click / touchend) to drive startPlayback. They're only removed when startPlayback() fires; if the Emulator is destroyed before the user produces a gesture — or if an embedder recreates the Emulator multiple times before that happens — the listeners stayed attached to a stale Audio instance forever. Audio also holds a TypedArray view (this.buffer) into the wasm heap region returned by _get_audio_buffer_ptr. After Emulator destroy() calls _emulator_delete + _free, that backing memory is gone, and any held reference to the buffer view points at freed memory. Add Audio.destroy(): removes the gesture listeners and nulls out the buffer view. Call it from Emulator.destroy() before _emulator_delete so the cleanup happens while the wasm pointer is still valid.
1 parent e3caa27 commit 9ff6e8a

1 file changed

Lines changed: 12 additions & 0 deletions

File tree

docs/simple.js

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -194,6 +194,7 @@ class Emulator {
194194
this.cancelAnimationFrame();
195195
clearInterval(this.rewindIntervalId);
196196
this.rewind.destroy();
197+
this.audio.destroy();
197198
this.module._emulator_delete(this.e);
198199
this.module._free(this.romDataPtr);
199200
}
@@ -658,6 +659,17 @@ class Audio {
658659
if (!this.started) { return; }
659660
Audio.ctx.resume();
660661
}
662+
663+
destroy() {
664+
if (this.boundStartPlayback) {
665+
window.removeEventListener('keydown', this.boundStartPlayback, true);
666+
window.removeEventListener('click', this.boundStartPlayback, true);
667+
window.removeEventListener('touchend', this.boundStartPlayback, true);
668+
this.boundStartPlayback = null;
669+
}
670+
this.buffer = null;
671+
this.started = false;
672+
}
661673
}
662674

663675
Audio.ctx = new AudioContext;

0 commit comments

Comments
 (0)