ma_resource_manager_data_buffer_node_unacquire frees the node synchronously
when it observes a non-MA_BUSY result (the "sound isn't loading" branch). But
a decoded-paged node publishes result == MA_SUCCESS as soon as it is playable,
while ma_job_process__resource_manager__page_data_buffer_node jobs keep running
to decode the remaining pages. Those jobs reference the node and increment its
executionPointer at their tail, several instructions after the result becomes
observable. A concurrent unacquire that sees a non-BUSY result therefore frees
the node out from under the page job tail, which then reads and atomically
increments freed (and possibly recycled) memory.
The node carries the same order / executionPointer ticket scheme as the data
buffer, and the MA_BUSY branch already relies on it (it posts an ordered
FREE_DATA_BUFFER_NODE job). Only the synchronous shortcut skipped it. Make it
wait for executionPointer to catch up to executionCounter before freeing, so no
job is still referencing the node -- the same fix as
ma_resource_manager_data_buffer_uninit for the buffer level, one level down.
Caught by ThreadSanitizer.
ma_resource_manager_data_buffer_uninit takes a synchronous teardown path as
soon as it observes result == MA_SUCCESS, freeing the buffer. But the load
job (ma_job_process__resource_manager__load_data_buffer) publishes that
result code via a CAS several instructions before it finishes referencing
the buffer: it still reads has_connector() and does the executionPointer
increment afterward. A concurrent uninit that observes MA_SUCCESS therefore
frees the buffer out from under the job tail, which then reads and
atomically increments freed (and possibly recycled) memory.
The asynchronous free path is safe because it waits on the order /
executionPointer ticket scheme; the synchronous shortcut bypassed it. Make
the synchronous path wait for executionPointer to catch up to
executionCounter before tearing down, so no job is still referencing the
buffer. Caught by ThreadSanitizer.
This addresses a case when PulseAudio may negotiate S24_32 which is not
a format supported by miniaudio. This commit does two things to guard
against this:
* The requested format is now explicitly used instead of using the
queried format from `pa_context_get_source_info_by_name()`.
* The `PA_STREAM_FIX_FORMAT` stream flag is no longer used as that can
possibly negotiate something different to what we request. I.e., it
can possibly give us S24_32 which is not usable.
For some reason, 64-bit pointer arguments are casted to Numbers
in Emscripten's type handling (which causes conversion errors when
passing them back to native code)