#include EMSCRIPTEN_WEBAUDIO_T audioContext; void initialize_audio_context() { EM_ASM({ let audioContext = emscriptenGetAudioObject($0); if (audioContext.state != 'running') { audioContext.resume(); } }, audioContext); } void play_to_html(some args) { initialize_audio_context(); //sends messages to the audio thread emscripten_audio_incoming.add_element(std::move(notes)); } extern "C" { EMSCRIPTEN_KEEPALIVE void play_string(char* s) { initialize_audio_context(); play_to_html(stuff here); free(s); } } int main() { // Create an audio context. there does not seem to be any point to waiting for user input to do this. it makes desktop slower on first click. and ios still has that "need to tap a few times" problem EmscriptenWebAudioCreateAttributes attrs = {}; audioContext = emscripten_create_audio_context(&attrs); // and kick off Audio Worklet scope initialization, which shares the Wasm Module and Memory to the AudioWorklet scope and initializes its stack. emscripten_start_wasm_audio_worklet_thread_async(audioContext, wasmAudioWorkletStack, sizeof(wasmAudioWorkletStack), WebAudioWorkletThreadInitialized, 0); }