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.
We keep a mapping between the sndfile formats and the format we would
like to decode them to for encoded formats. Make sure we don't mix up
the sample widths between them.
Make sure we don't send encoded formats as raw.
Debug the uncompressed format name correctly.
Fixes#5155
Add a port.passive = follow mode and the node.passive equivalents
out-follow, in-follow, follow.
This makes it possible to control how a port influences the state of
the peer and how the peer influences the state of the node independently.
In passive mode, the port will not make the peer runnable and will also
not become runnable when the peer activates.
In the follow mode, the port will not make the peer runnable but it will
become runnable when the peer is active.
This makes it possible to do new things like (f for follow):
Source -> (f)loopback1-in|loopback1-out(f) -> Sink
It will not make the source and sink run but when one of them start, all
will become runnable.
Or you can now better do the leak node hack that was previously used:
Source -> (f)pw-record
That will only start running when the source is activated by something
else.
With port.passive = true|false|follow there is a potential 4th case
which would activate the peer but not be activated by the peer, which is
not something that makes sense.
This was a hack around some scheduler issues that we should be able to
handle better now.
One of the cases is:
Source -> (p)pw-record
Which would never work otherwise because pw-record does not activate the
Source and when the Source is activated in any other way, pw-record
would not follow.
This will still fail with the current scheduler, but the leaf check is
not so great because it doesn't work in this case:
Source -> (p)loopback-in|loopback-out(p) -> Sink
What is probably required is a passive mode that doesn't activate but
does follows the peer.
Sink/Source pairs should not have the same link-group otherwise the
session manager will not be able to autoconnect them with a loopback or
some other internally linked stream.
Setting the current clock time when resending buffers is often wrong.
Especially for pseudo-live sources - the default mode - it discards
the original buffer time, which again is used by the base-class to
adjust the timestamps further, ultimately resulting in very wrong
timestamps.
Instead, try to calculate the delta between when we originally got the
buffer and now.
Buffer timestamps get adjusted by the base class, GstBaseSrc, even if we
take an additional ref. Arguably the base class should check if buffers
are writable (gst_buffer_make_writable()), which would trigger a buffer
copy. That is currently not the case, though, thus do so on our side.
Notes:
1. Usually a buffer copy doesn't copy the underlying memory, i.e.
copying is cheap.
2. The copy holds a reference to the copied buffer, preventing the
buffer from getting recycled as before.
We used to skip the runnable state from driver nodes because we assume
that they will be activated from other nodes. We however need to make
this more general to all suspendable nodes.
This makes pw-play -> loopback1-sink loopback1-out -> loopback2-sink
loopback-out -> sink also work correctly because the loopback2-sink does
not activate loopback1-out then.
JACK will never return NULL from jack_port_by_id() because the id
and the port_t are the same for JACK.
In PipeWire however we use the serial number as the id and so it can
be removed and become invalid. In this case, return a dummy port
from the client that can be used for some of the basic operations
you can do on a port_t, like get the name etc.
Also make sure that port_name() doesn't return NULL in case we use the
dummy port (which has the client set to NULL).
Fixes#3512
Fix path comparison in is_socket_unix() and don't unset LISTEN_FDS since
the function that uses it is called more than once and it was not unset
when sd_listen_fds() was used.
Fixes#5140
Instead of writing packets sequentially and losing sync on any
frame gap, compute the write position from the VBAN header's
n_frames field. Out-of-order packets land at the correct
ringbuffer offset, matching how module-rtp handles this.
Only advance the writeindex when a packet extends the frontier
so that late arrivals fill gaps without moving the pointer
backwards.
Fixes: https://gitlab.freedesktop.org/pipewire/pipewire/-/issues/5145