Skip to content

Audio Worklets #16449

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 75 commits into from
Feb 5, 2023
Merged

Audio Worklets #16449

merged 75 commits into from
Feb 5, 2023

Conversation

juj
Copy link
Collaborator

@juj juj commented Mar 8, 2022

Add support for Wasm Audio Worklets, based on Wasm Workers.

Wasm Audio Worklets enables code to create Wasm-based Web Audio processing nodes, that run on a dedicated thread of their own. (all such nodes run sequentially on a single main audio thread, there won't be a single thread for each node)

Fix Chrome not continuing the AudioWorklet processing if a number 1 is returned from the callback - must return 'true' specifically.

Add new tone generator sample.

Adjust comment.

Use MessagePort.onmessage instead of add/removeEventListener(), since onmessage .start()s the MessagePort automatically.

Fix name noise-generator to tone-generator

Improve assertions.
@juj
Copy link
Collaborator Author

juj commented Mar 16, 2022

This PR has now been merged on top of latest main, and is good for final review and landing.

@juj juj enabled auto-merge (squash) March 16, 2022 14:26
@kripken
Copy link
Member

kripken commented Mar 25, 2022

What do you think about adding a doc page with an overview of the API and some simple examples? I think that would be useful in general for users later but also help in review.

How does this relate to WebAudio? I see webaudio.h also has methods related to that and not to audio worklets. I'm not very familiar with either WebAudio or AudioWorklets however so maybe that's something obvious, apologies if so.

Also please add a changelog entry.

@kripken
Copy link
Member

kripken commented Mar 25, 2022

cc @hoch , this might interest you (no worries if you don't have time, of course).

@tklajnscek
Copy link
Contributor

Hey @juj!

Finally got around to testing this out along with the general wasm workers support. Thanks for all the work on this!

The first realization I had was that with pure wasm workers none of the standard library code will work multithreaded (e.g. malloc will not be thread-safe etc) and we have quite a bit of code (from 3rd parties as well) that would need to change so for the foreseeable future pthreads is what we're stuck with.

Looking through the tests I realized we can run pthreads and wasm workers side by side so I set out to test running just the audio worklet bit as a wasm worker using this the code from this PR, but with pthreads enabled the JS doesn't load in an audio worklet context.

First it asserts, but removing that it tries running PThread.init and fails etc.

So I went and took this PR's branch, rebased it on latest main for ease of testing and made a few changes to skip over any remains of PThread code when not running in a PThread context.

Here's the commit - I can't do an automatically mergable PR to this branch because it's on a rebased branch:
tklajnscek@1824e25

This makes the simple example work.

I'll run some more complex setup and update here.

@tklajnscek
Copy link
Contributor

Here's quick status update...

I was able to make it work with a combination of pthreads for normal threads and wasm workers for the audio worklet code.

I used the synchronization primitives from wasm_worker.h to setup the communication between the audio worklet and the pthreads and it worked fine.

In this specific use case I had to get a middleware product ready for production so I actually trimmed down the worklet code so much that in the end the pthread part uses wasm_worker sync primitives in C++ code compiled to wasm like you'd expect, but the audio worklet part is pure javascript that uses Atomics.notify etc directly and it works fine and avoids a dependency on this PR in our deployment :)

I will schedule some time in the following weeks to look at our full blown audio playback engine in the context of this PR and to see what it would take to make the audio worklet code not depend on pthreads at all, but have some other priorities I need to deal with first (like always) :)

@juj
Copy link
Collaborator Author

juj commented Apr 12, 2022

What do you think about adding a doc page with an overview of the API and some simple examples? I think that would be useful in general for users later but also help in review.

Sure, I'll add a doc page. The added tests serve as simple examples, so pointing users to them to get started.

How does this relate to WebAudio? I see webaudio.h also has methods related to that and not to audio worklets. I'm not very familiar with either WebAudio or AudioWorklets however so maybe that's something obvious, apologies if so.

Audio Worklets are a subpart of Web Audio API. So in order to enable integration with Audio Worklets, we need to have at least a minimal integration/understanding of Web Audio AudioContext object with the PR. That is why I added a shallow shim that allows creating an AudioContext from C side, and then a C&JS mechanism to manage the Wasm AudioContext<->int opaque handle binding.

Also please add a changelog entry.

Will do, I'll address review once I get through my next round of bug PRs.

@juj
Copy link
Collaborator Author

juj commented Feb 2, 2023

I noticed when merging with main that there were some regressions with compatibility against main. Updated with fixes to those, and fixed the test suites to work again. Would be be closer towards a merge? :)

emcc.py Outdated
@@ -2352,6 +2352,19 @@ def phase_linker_setup(options, state, newargs):
settings.WASM_WORKER_FILE = unsuffixed(os.path.basename(target)) + '.ww.js'
settings.JS_LIBRARIES.append((0, shared.path_from_root('src', 'library_wasm_worker.js')))

settings.SUPPORTS_GLOBALTHIS = settings.MIN_CHROME_VERSION >= 71 and settings.MIN_EDGE_VERSION >= 79 and settings.MIN_FIREFOX_VERSION >= 65 and settings.MIN_IE_VERSION == settings.TARGET_NOT_SUPPORTED and settings.MIN_SAFARI_VERSION >= 120100 # and settings.MIN_NODE_VERSION >= 120000
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Rather than baking this into emcc.py, see

https://github.com/emscripten-core/emscripten/blob/main/tools/feature_matrix.py

The numbers can be in there and this place can call caniuse().

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Check

@kripken
Copy link
Member

kripken commented Feb 2, 2023

Lgtm aside from the caniuse issue and the discussion around the comparison to ENVIRONMENT_IS_PTHREAD (but that discussion doesn't matter much).

@juj
Copy link
Collaborator Author

juj commented Feb 3, 2023

Lgtm aside from the caniuse issue and the discussion around the comparison to ENVIRONMENT_IS_PTHREAD (but that discussion doesn't matter much).

Updated code to utilize caniuse. On the ENVIRONMENT_IS_PTHREAD / ENVIRONMENT_IS_AUDIO_WORKLET part, I think the current code form is required.

juj added 3 commits February 3, 2023 13:34
… IN_TEST_HARNESS increased in size (added 'typeof ENVIRONMENT_IS_AUDIO_WORKLET&&ENVIRONMENT_IS_AUDIO_WORKLET)' code)
Copy link
Member

@kripken kripken left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

lgtm!

Great to have this functionality, I know many have been waiting for it.

@juj juj merged commit 5402fc9 into emscripten-core:main Feb 5, 2023
@Jonathhhan
Copy link
Contributor

Thank you very much for implementing this. :)

mighty1231 added a commit to mighty1231/emscripten that referenced this pull request Dec 9, 2024
This commit changes the old term `readAsmConstArgs` to the
new term `readEmAsmArgs`, due to conflict of emscripten-core#16449 and emscripten-core#18218

Background history:

1. emscripten-core#16449 proposed, introducing AudioWorklet earlier
2. emscripten-core#18218 proposed, renaming readAsmConstArgs to readEmAsmArgs
3. emscripten-core#18218 merged earlier
4. emscripten-core#16449 merged later, using the old term `readAsmConstArgs`
mighty1231 added a commit to mighty1231/emscripten that referenced this pull request Feb 13, 2025
This commit changes the old term `readAsmConstArgs` to the
new term `readEmAsmArgs`, due to conflict of emscripten-core#16449 and emscripten-core#18218

Background history:

1. emscripten-core#16449 proposed, introducing AudioWorklet earlier
2. emscripten-core#18218 proposed, renaming readAsmConstArgs to readEmAsmArgs
3. emscripten-core#18218 merged earlier
4. emscripten-core#16449 merged later, using the old term `readAsmConstArgs`
mighty1231 added a commit to mighty1231/emscripten that referenced this pull request Feb 21, 2025
It fixes emscripten_audio_worklet_post_function_sig, which was
previously not worked, and enhances test to cover all
emscripten_audio_worklet_post_function_*.

In order to fix, it changes the old term `readAsmConstArgs` to
the new term `readEmAsmArgs`, due to conflict of emscripten-core#16449 and emscripten-core#18218

Background history:

1. emscripten-core#16449 proposed, introducing AudioWorklet earlier
2. emscripten-core#18218 proposed, renaming readAsmConstArgs to readEmAsmArgs
3. emscripten-core#18218 merged earlier
4. emscripten-core#16449 merged later, using the old term `readAsmConstArgs`

enhance the test for cover all emscripten_audio_worklet_post_function_*
mighty1231 added a commit to mighty1231/emscripten that referenced this pull request Feb 21, 2025
It fixes emscripten_audio_worklet_post_function_sig, which was
previously not worked, and enhances test to cover all
emscripten_audio_worklet_post_function_*.

In order to fix, it changes the old term `readAsmConstArgs` to
the new term `readEmAsmArgs`, due to conflict of emscripten-core#16449 and emscripten-core#18218

Background history:

1. emscripten-core#16449 proposed, introducing AudioWorklet earlier
2. emscripten-core#18218 proposed, renaming readAsmConstArgs to readEmAsmArgs
3. emscripten-core#18218 merged earlier
4. emscripten-core#16449 merged later, using the old term `readAsmConstArgs`

enhance the test for cover all emscripten_audio_worklet_post_function_*
mighty1231 added a commit to mighty1231/emscripten that referenced this pull request Feb 21, 2025
It fixes emscripten_audio_worklet_post_function_sig, which was
previously not worked, and enhances test to cover all
emscripten_audio_worklet_post_function_*.

In order to fix, it changes the old term `readAsmConstArgs` to
the new term `readEmAsmArgs`, due to conflict of emscripten-core#16449 and emscripten-core#18218

Background history:

1. emscripten-core#16449 proposed, introducing AudioWorklet earlier
2. emscripten-core#18218 proposed, renaming readAsmConstArgs to readEmAsmArgs
3. emscripten-core#18218 merged earlier
4. emscripten-core#16449 merged later, using the old term `readAsmConstArgs`

enhance the test for cover all emscripten_audio_worklet_post_function_*
mighty1231 added a commit to mighty1231/emscripten that referenced this pull request Feb 25, 2025
It fixes emscripten_audio_worklet_post_function_sig, which was
previously not worked, and enhances test to cover all
emscripten_audio_worklet_post_function_*.

In order to fix, it changes the old term `readAsmConstArgs` to
the new term `readEmAsmArgs`, due to conflict of emscripten-core#16449 and emscripten-core#18218

Background history:

1. emscripten-core#16449 proposed, introducing AudioWorklet earlier
2. emscripten-core#18218 proposed, renaming readAsmConstArgs to readEmAsmArgs
3. emscripten-core#18218 merged earlier
4. emscripten-core#16449 merged later, using the old term `readAsmConstArgs`

enhance the test for cover all emscripten_audio_worklet_post_function_*
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

10 participants