cd68819feb added code to follow the state
change of the node because at the time it the Start code was async and
it was better to complete it before emitting the state.
9b80855821 however made the Start command
sync again and so we can safely emit the running state in the Start.
The effect is that the Running state change is emitted first and then
the node eventfd is added to the data loop that can then call the process
callback. Having the process callback happen before the RUNNING state
change is unexpected and racy.
The idea of fd2db174c1 was to allow for
property updates after the global was registered but this check was not
removed to actually make this happen.
Fixes#4851
Follow various other elements like glupload and gtk4paintablesink and
print the negotiated caps at a higher priority than debug. A small
quality of life improvement to facilitate debugging.
When clearing the buffers, remove the stale pointers and file descriptors
as accidental reuse of those is problematic and potentially difficult to
diagnose. Do this for every data plane.
Also clear the node's `buffer` structures to remove any references to
the provided `spa_buffer` objects and related metadata.
The current handling of `SPA_DATA_MemPtr` is not entirely correct because
its handling of multi-planar buffers is not appropriate: it leaks memory
mappings because it overwrites `buffer::ptr` for each plane.
Since this data type should not really be in use in normal deployments,
let's remove it for now.
After e0e8bf083 ("spa: libcamera: source: create eventfd before starting camera"),
things are still not entirely correct. This change ensures that if starting
the camera fails, then the runtime state, most importantly the ring buffer
of completed requests is restored to its initial state.
Furthermore, it is also ensured that `impl::active` can never be observed
by the data thread while it is being changed, which is achieved by setting
it before/after adding/removing the event source.
While concurrent `spa_loop_add_source()` invocations work with the current
main epoll-based implementation, this is not guaranteed, so lock the loop.
Similarly to how it is done elsewhere and for removal already.
pipewire assumes that the buffers are removed from a port when its format is
changed even without an explicit call to `port_use_buffer()`.
So if the format is not just tested, clear the buffers, as well as the libcamera
requests and buffers because they are also recreated when a new format is set.
This matches the behaviour of the v4l2 plugin. Furthermore, this change also
removes the call to `spa_libcamera_use_buffers()` because that function does
nothing. And finally this change necessitates that the current format is always
reset (when not testing), not just before reaching `spa_libcamera_set_format()`.
Remove the code that is supposed to compare the current and the to-be-set
format for returning early if they match. This is removed:
* v4l2 also does not have it either;
* it needs more consideration (there are not properly handled fields);
* it would make later changes somewhat more complicated.
Since `impl::requestComplete()` runs in an internal libcamera thread, extra care
would need to be taken to validate all accesses to common data structures. For
example, the function might call `spa_libcamera_buffer_recycle()`, which accesses
`impl::ctrls`, which would be unsafe because it could read or modified at the same
time on the data thread. So move the processing of requests to the data loop.
It is possible that multiple requests complete before the data loop can run
`libcamera_on_fd_events()`. However, previously only the earliest item was
processed from the ring buffer, meaning that in those cases request processing
could be lagging request completion by multiple requests.
Fix that by getting the number of available requests and processing them all.
Presently, the ring buffer of completed requests is only cleared
when the buffers are removed from the port. This is not entirely
correct since pause/start commands do not clear the buffers but
they stop the camera. As a consequence, it is possible that some
completed requests stay in the ring buffer, causing them to be
mistakenly processed when the camera is started next.
So reset the ring buffer after the camera is stopped, the same time
as the queue of free buffers is cleared.
A `libcamera::Request` is directly tied to the camera, not any ports ("streams")
of it. So move the request completion ring buffer into the `impl` struct.
This is a prerequisite for supporting multiple libcamera streams (~ exposing
multiple ports on the node) in the future.
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.