Without this change, driver names don't get matched correctly;
for example "a" can get matched with "alsa" since it only checks
whether the string matches up to the length of the requested
driver name.
This is needed to support CHERI, and thus Arm's experimental Morello
prototype, where pointers are implemented using unforgeable capabilities
that include bounds and permissions metadata to provide fine-grained
spatial and referential memory safety, as well as revocation by sweeping
memory to provide heap temporal memory safety.
On most systems (anything with a flat memory hierarchy rather than using
segment-based addressing), size_t and uintptr_t are the same type.
However, on CHERI, size_t is just an integer offset, whereas uintptr_t
is still a capability as described above. Casting a pointer to size_t
will strip the metadata and validity tag, and casting from size_t to a
pointer will result in a null-derived capability whose validity tag is
not set, and thus cannot be dereferenced without faulting.
The audio and cursor casts were harmless as they intend to stuff an
integer into a pointer, but using uintptr_t is the idiomatic way to do
that and silences our compiler warnings (which our build tool makes
fatal by default as they often indicate real problems). The iconv and
egl casts were true positives as SDL_iconv_t and iconv_t are pointer
types, as is NativeDisplayType on most OSes, so this would have trapped
at run time when using the round-tripped pointers. The gles2 casts were
also harmless; the OpenGL API defines this argument to be a pointer type
(and uses the argument name "pointer"), but it in fact represents an
integer offset, so like audio and cursor the additional idiomatic cast
is needed to silence the warning.
WASAPI_WaitDevice is used for audio playback and capture, but needs to
behave slighty different.
For playback `GetCurrentPadding` returns the padding which is already
queued, so WaitDevice should return when buffer length falls below the
buffer threshold (`maxpadding`).
For capture `GetCurrentPadding` returns the available data which can be
read, so WaitDevice can return as soon as any data is available.
In the old implementation WaitDevice could suddenly hang. This is
because on many capture devices the buffer (`padding`) wasn't filled
fast enough to surpass `maxpadding`. But if at one point (due to unlucky
timing) more than maxpadding frames were available, WaitDevice would not
return anymore.
Issue #3234 is probably related to this.
On modern CPUs, there's no penalty for using the unaligned instruction on
aligned memory, but now it can vectorize unaligned data too, which even if
it's not optimal, is still going to be faster than the scalar fallback.
Fixes#4532.
While we should normally expect _something_ from the stream based on the
AudioStreamAvailable check, it's possible for a device change to flush the
stream at an inconvenient time, causing this function to return 0.
Thing is, this is harmless. Either data will be NULL and the result won't matter
anyway, or the data buffer will be zeroed out and the output will just be
silence for the brief moment that the device change is occurring. Both scenarios
work themselves out, and testing on Windows shows that this behavior is safe.
Some of the SDL_AudioDevice struct members aren't initialized until after returning from the OpenDevice function. Since Pipewire uses it's own processing threads, the callbacks can be entered before all members of SDL_AudioDevice are initialized, such as work_buffer, callbackspec and the processing stream, which creates a race condition. Don't use these members when in the paused state to avoid potentially using uninitialized values and memory.
This prevents the dsp target from stealing the audio subsystem but not
being able to produce sound, so other audio targets further down the list
can make an attempt instead.
Thanks to Frank Praznik who did a lot of the research on this problem!
A user reported that the mpv video player hangs after attempting to
set an unsupported number of channels with the SDL audio output,
because it thinks it's successfully opened the device. This makes
the failure graceful.
Removes the node nickname from sink/source nodes as it doesn't provide any useful information and names now match those used in Pulseaudio, so any stored configuration data will be compatible between the two audio backends.
Constify the min/max period variables, use a #define for the base clock rate used in the calculations and note that changing the upper limit can have dire side effects as it's a hard limit in Pipewire.
Replace "magic numbers" with #defines, explain the requirements when using the userdata pointer in the node_object struct and a few other minor code and comment cleanups.
Use the 'R' (rear) prefixed designations for the rear audio channels instead of 'S' (surround). Surround designated channels are only used in the 8 channel configuration.
Further refactor the device enumeration code to retrieve the default sink/source node IDs from the metadata node. Use the retrieved IDs to sort the device list so that the default devices are at the beginning and thus are the first reported to SDL.
The latency of source nodes can change depending on the overall latency of the processing graph. Incoming audio must therefore always be buffered to ensure uninterrupted delivery.
The SDL_AudioStream path was removed in the input callback as the only thing it was used for was buffering audio outside of Pipewire's min/max period sizes, and that case is now handled by the omnipresent buffer.
Extend device enumeration to retrieve the channel count and default sample rate for sink and source nodes. This required a fairly significant rework of the enumeration procedure as multiple callbacks are involved now. Sink/source nodes are tracked in a separate list during the enumeration process so they can be cleaned up if a device is removed before completion. These changes also simplify any future efforts that may be needed to retrieve additional configuration information from the nodes.
This uses the mechanism added in emscripten-core/emscripten#10843
which was applied to SDL1 and OpenAL. This adds the same for SDL2.
This also reverts commit 865eaddffed50dbd13e6564c3f73902472cf74e8
which did something similar, but the new mechanism is more effective.
The DJGPP compiler emits many warnings for conflicts between print
format specifiers and argument types. To fix the warnings, I added
`SDL_PRIx32` macros for use with `Sint32` and `Uint32` types. The macros
alias those found in <inttypes.h> or fallback to a reasonable default.
As an alternative, print arguments could be cast to plain old integers.
I opted slightly for the current solution as it felt more technically correct,
despite making the format strings more verbose.
Nia Alarie
The NetBSD kernel's audio resampling code is much simpler and lower quality than libsamplerate.
Presumably, if SDL always performs I/O on the audio device in its native frequency, we can avoid resampling audio in the kernel and let SDL do it with libsamplerate instead.
If we fail to connect to the the pa server, we have an assigned context
and mainloop that isn't connected. So, when PULSEAUDIO_pa_context_disconnect
is called, pa asserts and crashes the application.
Assertion 'pa_atomic_load(&(c)->_ref) >= 1' failed at pulse/context.c:1055, function pa_context_disconnect(). Aborting.
When converting audio from signed to unsigned values of vice-versa
the silence value chosen by SDL was the value of the device, not
of the stream that the data was being put into. After conversion
this would lead to a very high or low value, making the speaker
jump to a extreme positon, leading to an audible noise whenever
creating, destroying or playing scilence on a device that reqired
such conversion.
Original code assigned MCIMixSetup.ulSamplesPerSec value to it, but it
is just the freq... We now change spec->samples only either if it is 0
or we changed the frequency, by picking a default of ~46 ms at desired
frequency (code taken from SDL_audio.c:prepare_audiospec()).
With this, the crashes I have been experiencing are gone.
I _think_ this is a right thing to do; it fixes a .wav file I have here that
has blockalign==2 when channels==2 and bitspersample==16, which otherwise
would fail.
This is only supported on PulseAudio. You can set a description when opening
your audio device that will show up in pauvcontrol, which lets you set
per-stream volume levels.
Fixes Bugzilla #4801.