Cancellation handlers use setjmp/longjmp, for which the C99
specification has the following note:
> 17.3.2.1 (3)
> All accessible objects have values, and all other components of the
> abstract machine) have state, as of the time the longjmp function was
> called, except that the values of objects of automatic storage
> duration that are local to the function containing the invocation of
> the corresponding setjmp macro that do not have volatile-qualified
> type and have been changed between the setjmp invocation and longjmp
> call are indeterminate.
While everything works fine with GCC, with Clang we see that the
cancellation handler doesn't seem to have an effect (loop-test fails
when it notices that its spa_source's priv and mask have not been
cleaned up).
The underlying cause is that the compiler can assume data.ep_count is
only used in loop_iterate_cancel(), and so can be cached in a register.
When we access that field in the cancellation handler, it was never
actually written to the memory on the stack, so the read in
cancellation_handler() does not see the current value.
We fix this by marking all fields on the stack that we expect to be
modified in loop_iterate_cancel() as volatile, forcing the memory to be
updated and correctly available to the cancellation handler.
This fixes a missing definition error in thread.c:
../src/pipewire/thread.c:129:30: error: use of undeclared identifier 'SCHED_RESET_ON_FORK'
129 | SPA_FLAG_UPDATE(new_policy, SCHED_RESET_ON_FORK, reset_on_fork);
pipewire-jack defines TYPE_ID_VIDEO=1 between audio and MIDI, shifting
TYPE_ID_MIDI to 2. This caused jack_port_type_id() to return 2 for MIDI
ports, breaking compatibility with jack1/jack2 which return 1.
The jack_port_type_id() return value is part of the public JACK API and
consumers such as jackdbus rely on the conventional values established
by jack1/jack2: 0 for audio, 1 for MIDI.
Map internal TYPE_ID_* values to their jack1/jack2 compatible equivalents
before returning. All MIDI variants (MIDI, OSC, UMP) map to 1. Video has
no jack1/jack2 equivalent so maps to 3, beyond the conventional range.
The jack_activate loop was only queuing NOTIFY_TYPE_PORTREGISTRATION
for the activating client's own ports. Ports belonging to other clients
— including all WirePlumber-managed ports and MIDI ports — were silently
skipped due to the o->port.port->client != c condition.
This caused two observable bugs for clients using libjackserver (e.g.
jackdbus):
- JackPortRegistrationCallback was not fired for any pre-existing
foreign ports at activate time, leaving the patchbay empty unless
the session manager happened to start after the client.
- JACK MIDI ports were never announced via callback, even though they
are correctly returned by jack_get_ports().
The graph_order_callback fallback (used by jackdbus for initial port
enumeration) is also ineffective here because pipewire-jack only fires
it on connection events, not on activate.
Fix by iterating all non-removed foreign ports in the object list and
queuing registration callbacks for those whose node is active, matching
the semantics already implemented in node_info() for ports of nodes
that transition to running state after activate.
As stated in https://pubs.opengroup.org/onlinepubs/9799919799//basedefs/netinet_in.h.html,
> The <netinet/in.h> header shall define the sockaddr_in structure [...]
This fixes the following build error:
In file included from ../src/modules/module-protocol-native.c:44:
../src/modules/network-utils.h:96:35: error: incomplete definition of type 'struct sockaddr_in'
96 | if (inet_ntop(sa->ss_family, &in->sin_addr, ip, len) == NULL)
| ~~^
NULL tags are never handled and so tags just keeps configured on the
ports. It's also hard to know the direction from the NULL data.
Instead, send an empty Tag with the direction to clear everything.
Always do a control change to the instances when they are created. This
is to make sure the internal state is synced to the control values.
The sofa filter and biquads need this to correctly configure themselves
after a suspend.
Fixes#5152
Now that the loop_leave function will assert when the unlock fails we
need to be extra careful with the cancellable loop. If it cancels inside
the poll or one of the before/after callbacks we need to make sure that
we lock the loop correctly again or we will create an assert later on.
Do this by pushing the cleanup earlier and then record all the things we
managed to do before we get canceled. If we ever get canceled and the
lock was unlocked but not locked again, fix this up.
Fix fixes issues when using the JACK API causing assertions when the
data loop is stopped/cancelled.
Don't close an -1 fd in clear_data.
If we let the client allocate buffer, set our fd and data to invalid
values. If the client decides to renegotiate before we get the buffer
data we might otherwise try to clear the mem_id (default 0) or
close the fd (also default 0).
Fixes#5162
If a file descriptor is expected to be closed by the associated `pw_memblock`,
and closing fails, then that usually signals a more serious issue in the memory
accounting. So add a log message when that happens.
Calling "iterate()" on a loop that has not been entered by the
calling thread is invalid. So try to diagnose misbehaving applications
on a "best effort" basis by checking `impl::enter_count`.
This is not a foolproof check, and can also technically cause data
races while reading the variable.
See #5148
Previously when parameters were enumarated, it was checked if at least one
param was known for `id`. If not, `-ENOENT` was returned to signal that
this param id is not supported.
This is not necessarily true, since a param id might be supported, but it
might have zero params at the moment, in which case an unexpected error
would be returned.
Fix that by using `pw_param_info_find()` with the underlying impl object
to check if the param id is actually supported.
If the param enumeration fails, do not set `spa_param_info::user` to 1
indicating that the result is cached. Doing so can lead to the first
(uncached) call failing, while the rest will succeed (with 0 params).
HFP codecs don't have a direction dependent "target" profile, and this
function was returning false if A2DP is disabled.
Don't check target profile for HFP, leave checks to backend.
Fixes HFP-only configurations, which were missing profiles.
Non-spec compliant devices may set multiple bits in code config, which
we currently reject in validate_config().
enum_config() does work to deal with multiple bits set, but this is
never used, so write the code in a simpler way to return a single
configuration.
Non-spec compliant devices may set multiple bits in AAC AOT, which is
invalid.
In this case, we should normalize to MPEG-2 AAC LC which is the
mandatory value in spec, not to MPEG-4 AAC LC. In select_config() we
also prefer MPEG-2 over MPEG-4.
Some non-spec compliant devices (Sony XB100) set multiple bits
in all AAC field, including the frequency & channels.
Although they set multiple bits, these devices appear to intend that the
sender picks some specific format and uses it, and don't work correctly
with the others.
validate_config() already picks one configuration, so use the result in
enum_config(), instead of allowing also other settings.
Assume devices generally want preferably 44.1 kHz stereo.
Note we cannot reject the configuration, as BlueZ does not necessarily
retry, leaving the device connected but with no audio.
When there is no DBus session bus, creation of the telephony backend
fails, and we later crash on null ptr deref.
In this case, avoid crash trying to create telephony_ag or iterate its
call list.
We already support more float variants than standard JSON in the relaxed
format, adding extra restrictions does not actually help much. If you
need to know if this is a value JSON number, there is now a function to
check that instead.
We can only use non-shared memory when both nodes live in the same
process _and_ we can be sure the output port is never going to be linked
to a remote node because it is exclusive.
This fixes the case where a null-sink is loaded inside the process space
of the server and linked to the ALSA sink. This would create a link
without shared mem and then as soon as something else (out of process)
wants to link to the null-sink output, it would get a -22 EINVAL
negotiation error because the memory can't be shared.
Fixes#5159
If we are going to produce valid JSON we need to do a better JSON number
check because our own float and int parser can accept more variants
and will let through numbers that are not valid JSON.
See #5161
Some sound cards are only adapted for Android/macOS and other
systems, without considering Linux. The hardware-reported dB
volume is incorrect (while the percentage volume is normal).
Add support for the ignore-dB option to simplify compatibility.
For example, the 3206:0798 HP SIMGOT GEW1 Sound Card reports:
numid=4,iface=MIXER,name='PCM Playback Volume'
; type=INTEGER,access=rw---R--,values=2,min=0,max=100,step=0
: values=100,100
| dBminmax-min=0.00dB,max=0.39dB
This dB value does not match actual audio perception, and the
vendor attributed this issue to non-target system compatibility.