Use `spa_loop_invoke()` to invoke a callback on the data loop
to remove an embedded `spa_source` from the data loop.
Embedded `spa_source` objects cannot be safely removed
while the loop is polling without risking potential
use-after-frees.
The core of the issue is the following: what happens if an
active source is destroyed before it could be dispatched?
For loop-managed sources (`struct source_impl`) this was addressed
by storing all destroyed sources in a list, and only freeing them
after dispatching has been finished. (0eb73f0f06)
This approach works for both strictly single-threaded
and `pw_thread_loop` loops assuming the loop is not
reentered.
However, if the loop is reentered, there can still be issues.
Assume that in one iteration sources A and B are active,
and returned from the system call, and source B is destroyed
before the loop starts dispatching. Consider what happens when
"A" is dispatched first, and it reenters the loop with timeout 0.
Imagine there are no new events, so `loop_iterate()` will immediately
return, but it will first destroy everything in the destroy list
(this is done at the end of `loop_iterate()`).
And herein lies the problem. In the previous iteration,
there exists a `spa_poll_event` object which points to source "B",
but that has just been destroyed at the end of the recursive
iteration. This will trigger a use-after-free once the previous
iteration inspects it.
Fix that by processing the destroy list right after first
processing the returned `spa_poll_event` objects, and
"detach" the source from the loop and its iterations
in `process_destroy()` before the source is destroyed.
See #2114#2147
It may be a little confusing that both the loop object
and the `source_impl` objects are referred to with variables
named `impl`. For this reason, rename all source_impl objects
named `impl` to `s`.
It is expected that `nfds` is non-negative in the vast majority
of cases, so hopefully the runtime performance will not be
significantly affected by removing the check. This way
it is guaranteed that the destroy list is processed.
Codec probe connections can trigger bad behavior from oFono if done when
device is busy (e.g. at connect), and they might be done at the same
time as A2DP transport is acquired which cannot work.
Also, oFono will not reply to DBus Acquire, if device does not complete
codec negotiation correctly. This is most likely to happen just after
device connect, when it is busy with other stuff (eg A2DP).
Remove codec probe connections altogether: instead, we guess mSBC if
mSBC is enabled and otherwise CVSD. If the guess turns out to be wrong,
which is unlikely (almost all devices have mSBC), we recreate the
transport with correct codec (from main loop, must not be done in
*_acquire because that can destroy nodes + unload the spa libs while
we're being called from there).
To avoid oFono DBus hangs at startup, add delay before marking the
profile connected, enforcing a time difference to A2DP operations.
Add an option to do a hilbert transform on the generated rear channels
to do a 90 degree pahse shift on them. This can improve spacialization
of the rear channels.
See #861
This allows BT device to connect instantly instead of waiting for profile
timeout when hsp/hfp backend is none, because all available profiles are
connected.
For merger setup (consuming a source) we want to expose the channelmap
of the remixed signal (to the application/sink).
For splitter setup (providing data) we want to expose the channelmap
of the original source (before remixing to sink).
Hide the merge channel props because they contain the channelmap before
mising and we want to expose the remixed signal in merger mode.
This fixes some weird volume issues when an input stream is linked
to a source and is remixing, like when a stereo stream is captured
from a mono source.
Keep track of the format as given in the PortConfig.
Instead of blindly fixating the negotiated format to whatever default,
use the PortConfig format to fixate to something better.
This makes the channels/position, rate or format match the PortConfig
format when this is possible and results in the least amount of conversions.
It mostly improves the handling of wildcard formats, were a stream only
specifies some fields and leaves the other free.
A concrete case is WINE that uses the pulseaudio FIX flags to omit the
number of channels and rate. With this change, the stream will negotiate
to the format of the linked sink and obtain the channelmap from it.
See #876
This reverts commit c474846c42.
In addition, `s->loop` is also checked before dispatching a source.
The destroy list is needed in the presence of threads. The
issue is that a source may be destroyed between `epoll_wait()`
returning and thread loop lock being acquired. If this
source is active, then a use-after-free will be triggered
when the thread loop acquires the lock and starts dispatching
the sources.
thread 1 thread 2
---------- ----------
loop_iterate
spa_loop_control_hook_before
// release lock
pw_thread_loop_lock
spa_system_pollfd_wait
// assume it returns with source A
pw_loop_destroy_source(..., A)
// frees storage of A
pw_thread_loop_unlock
spa_loop_control_hook_after
// acquire the lock
for (...) {
struct spa_source *s = ep[i].data;
s->rmask = ep[i].events;
// use-after-free if `s` refers to
// the previously freed `A`
Fixes#2147
Older gcc versions seem to require the members to appear in the
designated initializer in the order they are in the definition of
the struct when compiling C++.
otherwise compilation fails with:
../spa/plugins/aec/aec-webrtc.cpp:167:1: sorry, unimplemented:
non-trivial designated initializers not supported
};
^
Place the methods on the interface so that we can call them.
Rename create to init because that is what it does.
Add support for listener and events so that we can signal property
changes later.
Move all backends to dynamic libaries loaded with spa_plugin_loader so
new backends not needs changes in pipewire or pipewire dependency to
external code
Change-Id: I702ce047598d0c318d6dc6ac8248062a5c12f643
Use the max error to do a resync. Don't reset the dll, there is no
reason for that.
Don't use _rewind, but instead limit the amount of samples we read and
write
Should keep more stable sync in most cases.