The request will be needed later, so store that directly in the
completion ring buffer for easy access.
This is fine even though `impl::requestComplete()` calls `Request::reuse()`
because only the request cookie is used in `libcamera_on_fd_events()` and
that remains constant during the lifetime of a request object.
The handling of `impl::pendingRequests` is a bit problematic because,
for example, during startup, if `spa_libcamera_buffer_recycle()` observes
that `impl::active == false`, then it will try to append to `impl::pendingRequests`,
which is being iterated in the main thread in `spa_libcamera_stream_on()`.
That is not allowed on an `std::deque`.
So instead remove it altogether, and simply queue all requests when starting.
After `libcamera::Camera::stop()` returns, every request is guaranteed not
to be used by libcamera, and they can be freely reused, so this is safe to do.
This also removes the need for calling `spa_libcamera_buffer_recycle()` when
the buffers are set/unset on a port since that function no longer changes
anything apart from updating `buffer::flags` but `spa_libcamera_alloc_buffers()`
is modified appropriately to take care of that. And in the case of
`spa_libcamera_clear_buffers()` clearing the flag is not required because the
next `spa_libcamera_alloc_buffers()` call will reset reset the flags.
Currently only a single stream is used. This makes it easy to associate
each request with the appropriate frame buffer when it is created. In
turn, this makes reusing requests a bit simpler and a bit more efficient.
So do that: add buffers to requests when they are allocated in `allocBuffers()`.
At the moment the libcamera buffer allocation is completely tied to format
negotiation. `freeBuffers()` undoes `allocBuffers()`. And `allocBuffers()`
is called as part of `spa_libcamera_set_format()`. Therefore `freeBuffers()`
should be called independent of the state of the buffers on any port.
Otherwise unsetting the format while there are no buffers on the port will
cause the libcamera requests and buffers not to be released correctly. Similarly,
removing the buffers from a port would clear the libcamera requests and buffers,
making the node unusable without setting a new format.
`freeBuffers()` should undo exactly what `allocBuffers()` does. However,
it currently also clears `impl::pendingRequests`, but that is filled
by `spa_libcamera_buffer_recycle()` during `spa_libcamera_alloc_buffers()`.
So remove the clearing of `impl::pendingRequests` from `freeBuffers()` and
move it directly into `spa_libcamera_clear_buffers()`.
Debian supports many architectures, and it is relatively easy to work
with multiarch packages, and finally `meson env2mfile` supports
generating cross files with the `--debarch` option.
Previously only native builds were done in the CI, so use debian to
build pipewire for multiple architectures.
Some packages are unfortunately not multiarch compatible, so a separate
container is built for every architecture.
Check if the "TracerPid" field in `/proc/self/status` is non-zero. This does
not need libcap, and does not depend on capabilities, and it also works under
qemu user emulation.
Instead of applying each control separately, collect them into a
`libcamera::ControlList`, and try to apply them at the end.
Furthermore, instead of doing a blocking loop invoke, use `spa_loop_locked()`
as it is sufficient to update `impl::ctrls`.
After this change control setting works in a more "atomic" way since every
control is parsed and checked before actually reaching the camera. It is
also detected if the given control is not supported by the camera.
This fixes the case when synchronization is established but actually not
valid anymore. In such a case, the code would _first_ write to the ring
buffer (at the wrong position due to the invalid sync), and _then_ detect
the bogus synchronization. Reorder the code blocks to _first_ check the
current sync, then resynchronize if neeeded (or perform initial sync if
no sync is established yet), and _then_ write to the ring buffer.
Until now, the timestamp check was comparing the timestamp delta against
the value of the "quantum" variable. However, the timestamps use clock
samples as units, while the "quantum" variable uses nanoseconds. The
outcome is that this check virtually never returned true. Use the
spa_io_clock duration instead of that quantum nanosecond duration to make
the check actually work.
Also, do not just rely on vast timestamp deltas to detect discontinuities;
instead, check first for the presence of the SPA_IO_CLOCK_FLAG_DISCONT
flag to detect said discontinuities.
Use a dynamic spa pod builder when enumerating controls since previous
changes can report more information from any given control. Also increase
the stack buffer size to 4096 bytes.
For enumerated controls of type `libcamera::ControlTypeInteger32`, libcamera
provides the names of the enumerators, so add them to `SPA_PROP_INFO_labels`.
If the `libcamera::ControlInfo` object explicitly lists the values of a
control, then use those values when adding `SPA_PROP_INFO_type` to
construct an enumerated choice object.
If libcamera does not provide a default value, then the average of the
minimum and maximum values is taken. The same logic is duplicated for
`float` and `int32_t`, so move it into a function template.
`SPA_POD_CHOICE_Bool()` assumes that both true and false are available,
which may not be the case for libcamera controls, so manualy construct
the enumerated choice object and only add the actually available options.
This allows to use clang-include-cleaner tool without <pipewire/foo.h>
headers being automatically added when <pipewire/pipewire.h> is included
instead.
See https://issues.webrtc.org/issues/422940461
The body code didn't use atomic loads, so it had undefined behavior if
the body was concurrently modified. Use atomic loads to fix this.
Since the memory order is __ATOMIC_RELAXED this has no runtime overhead.
Also add barriers around a strncpy call and cast to volatile before
checking for a NUL terminator, though NUL-terminated strings in shared
memory are unuseable. There are some places where bytewise atomic
memcpy(), which doesn't currently exist, is needed. Instead, try to
fake it by using two barriers around memcpy().
Set LD_LIBRARY_PATH to have processes spawned by test load the right
library.
Mark openal-info test skipped if ASAN is enabled. The problem is that
openal-info would need LD_PRELOAD to work properly then. Just disable
the test then.
At the moment errors are printed using `pw_log_error()`, however, that does
not display them by default because `client.conf` sets `log.level=0`.
Use `fprintf()` and always print the errors.
Instead of implicitly acting on the current thread if the provided thread
handle is unknown, return an error. This behaviour is not depended on inside
pipewire, and if needed, special casing e.g. `thread == NULL` could be added,
but any random `thread` value shouldn't affect the current thread.
At the moment, the camera manager shared pointer is released when the last
listener is removed, and recreated when the first listener is added. This
is the same behaviour that the alsa and v4l2 monitors implement with their
respective udev, inotify monitors.
However, for `libcamera::CameraManager`, this is likely not the best way
for multiple reasons:
(a) it is a complex object with significant construction and starting cost,
which includes starting threads and usually loading shared libraries;
(b) usually one listener is added right after creating, and it is removed
right before destruction, in which there are real no advantages;
(c) the camera manager, being a shared resource, might very well be kept
alive by some other component, in which case there is again not much
real benefit.
So simplify the code by getting a camera manager reference at the beginning
and keeping it until the libcamera monitor is destroyed.
This also fixes a race condition where a hot-plugged camera might not have
been detected if the libcamera event was emitted between these two:
collect_existing_devices(impl);
start_monitor(impl);
The `impl::{add,remove}Camera` functions do the same thing except
for one value, the type of the hotplug event. Add a private method
to `impl` that implements the common parts.
An eventfd is used to signal the data loop from the libcamera request
completion event handler. Previously, this eventfd was created and
installed after the camera has been started and requests were queued.
This is problematic because it creates a small time frame where the
libcamera request completion handler will run in a state where the
eventfd is not fully set up.
Fix that by settup up the eventfd before the camera is started.
Currently the plugin uses a single configuration during its entire lifetime.
So generate that configuration during initialization and hold on to it.
This makes the code a bit simpler, and also fixes issues stemming from missed
calls to `spa_libcamera_get_config()` as well as no error checking of
`libcamera::Camera::generateConfiguration()`.