PortAudio / portaudio

PortAudio is a cross-platform, open-source C language library for real-time audio input and output.
Other
1.39k stars 291 forks source link

Add support for Web Audio (Emscripten/WebAssembly) #887

Open fwcd opened 4 months ago

fwcd commented 4 months ago

Fixes #497

This is a work-in-progress, from-scratch implementation of a Web Audio hostapi, using the Wasm Audio Worklets API, which Emscripten already provides nice C/C++ wrappers for.

Useful resources

RossBencina commented 4 months ago

Cool. Great that you're working on this. We look forward to merging it when its ready.

Please give a status update from time to time and let us know when you're ready for a code review. Ideally we'd like to hear from multiple users who are successfully using this host API.

fwcd commented 4 months ago

When building with -Werror I get

portaudio/src/common/pa_converters.c:344:32: error: implicit conversion from 'int' to 'float' changes value from 2147483647 to 2147483648 [-Werror,-Wimplicit-const-int-float-conversion]
  344 |         double scaled = *src * 0x7FFFFFFF;
      |                              ~ ^~~~~~~~~~
portaudio/src/common/pa_converters.c:389:32: error: implicit conversion from 'int' to 'float' changes value from 2147483647 to 2147483648 [-Werror,-Wimplicit-const-int-float-conversion]
  389 |         double scaled = *src * 0x7FFFFFFF;
      |                              ~ ^~~~~~~~~~
portaudio/src/common/pa_converters.c:508:32: error: implicit conversion from 'int' to 'float' changes value from 2147483647 to 2147483648 [-Werror,-Wimplicit-const-int-float-conversion]
  508 |         double scaled = *src * 0x7FFFFFFF;
      |                              ~ ^~~~~~~~~~
3 errors generated.

Any ideas? At first glance this looks like an issue outside this PR's scope. Perhaps something funky happens because we are compiling for a 32-bit platform (wasm32)?

fwcd commented 4 months ago

Status update: There is audio! It currently only supports the default 2-channel output device, but paex_sine and paex_saw already sound like sine/saw waves.

It would be really cool if we could get rid of -sASYNCIFY to avoid imposing this mode on downstream consumers, but that seems to be nontrivial, unfortunately: https://github.com/emscripten-core/emscripten/issues/18853#issuecomment-1987442770

fwcd commented 4 months ago

I've added some highly experimental support for building without -sASYNCIFY via the PA_WEBAUDIO_ASYNCIFY flag (which still defaults to on). It mainly replaces the sleep implementation with a blocking emscripten_thread_sleep and avoids awaiting any audio context-related calls. We'll have to be extra careful to not block the main thread in that case and PortAudio would have to be invoked from a worker thread. However, for the audio context-related methods to be available from a worker, it looks like we will have to wait for

This is also why the examples, even with -sPROXY_TO_THREAD currently don't run when PA_WEBAUDIO_ASYNCIFY is off. We could manually proxy everything audio context-related to the main thread, but I haven't had time to look into how hard that would be to implement (and how to avoid potential deadlocks).