Commit graph

4285 commits

Author SHA1 Message Date
Wim Taymans
a3da53f66e alsa: fix seq compilation 2025-07-30 18:54:16 +02:00
Wim Taymans
7f7b4be82d alsa: use the safer pod parser for control events 2025-07-30 18:43:34 +02:00
Wim Taymans
6d07eaea1f seq: rework port handling
Dynamically allocate ports as we need them.
Use port lists to iterate active ports.
2025-07-30 17:32:02 +02:00
Wim Taymans
8f45cfcbc9 audiomixer: rework the port logic
Use port lists for faster and safer updates of the mixer ports.
2025-07-30 16:49:45 +02:00
Pauli Virtanen
847982eb0e resample: keep fractional part of in_rate when interpolating
When interpolating with rate correction != 1.0, don't floor the
resulting input rate to the nearest smallest integer.

This allows rate corrections < 1/in_rate to have some effect, and
reduces jumps in the response. One of the jumps is inconveniently
between rate=1.0 and rate=1.0+eps and will cause rate corrections to
oscillate if target rate varies close to 1.0.
2025-07-30 07:59:52 +00:00
Pauli Virtanen
244d5a1cc1 resample: use fixed point for resample phase and input rate
If phase is float, calculations in impl_native_in_len/out_len can
produce wrong results due to rounding error.

It's probably better to not be in the business of predicting
floating-point rounding, so replace this by fixed-point arithmetic.

Also make sure `offset+1` cannot overflow data->filter array in
do_resample_inter* due to float multiplication possibly rounding up.
2025-07-30 07:59:52 +00:00
Pauli Virtanen
3cade43cf3 test-resample: add test for floating point rounding producing bad in_len
If phase is float, calculations in impl_native_in_len/out_len don't
necessarily match with do_resample, because e.g.

    float phase0 = 7999.99;
    float phase = phase0;
    int frac = 8000, out_rate = 8000, n = 64, count = 0;
    for (int j = 0; j < n; ++j) {
        phase += frac;
        if (phase >= out_rate) {
                phase -= out_rate;
                count++;
        }
    }
    printf("count = %d\n", count);      /* count = 64 */

    count = (int)(phase0 + n*frac) / out_rate;
    printf("count = %d\n", count);      /* count = 65 */

don't give the same result.

Also add test where floating point multiplication rounding up to nearest
in

    float ph = phase * pm;
    uint32_t offset = (uint32_t)floorf(ph);

computation results to offset+1 > data->n_phases, accessing filter array
beyond bounds.  (The accessed value is still inside allocated memory
block, but contains unrelated values; the test passes silently.)
2025-07-30 07:59:52 +00:00
Pauli Virtanen
84e8d59782 resample: fix off-by-one in out_len calculation
Fix off-by-one and add test.
2025-07-30 07:59:52 +00:00
Wim Taymans
3785896533 mixer: rework the control mixers to use the parser
Using the parser for the spa_pod_sequence in the data buffers is
required in order to safely read the pods while there could be
concurrent writes.

See #4822
2025-07-29 15:33:43 +02:00
Wim Taymans
56e2d52b65 control: fix fastpath compilation 2025-07-27 17:17:55 +02:00
Wim Taymans
927ab0f4b8 control: improve port handling in control mixer
Use lists to manage the free, allocated and acitve mixer ports. We can
then avoid some checks and make things more threadsafe.
2025-07-27 16:51:52 +02:00
Wim Taymans
0b0912cc5b resample: optimize phase scaling
Precalculate the constant factor to avoid a division for each sample.
2025-07-23 14:11:11 +02:00
Wim Taymans
b52c490709 resample: fix compilation
Also fix a compiler warning in clang
2025-07-23 12:52:27 +02:00
Wim Taymans
d2a9141913 resample: avoid calculating GCD in rate updates
We don't actually need to calculate the GCD for each resampler rate
update. The GCD is only used to scale the in/out rates when using the
full resampler and this we can cache and reuse when we did the setup.

The interpolating resampler can work perfectly fine with a GCD of 1 and
so we can just assume that.
2025-07-23 12:23:20 +02:00
Wim Taymans
fcc49ad517 resample: reorder resample function setup
We also don't need to copy the resampler function name with each dynamic
function update, this is just for debugging.
2025-07-23 11:55:49 +02:00
Wim Taymans
685aed1de2 alsa: update resampler requested size before reading
spa_alsa_read is called from the source process function when we are a
follower and no buffer is ready yet.

Part of the rate correction was performed by the ALSA driver when it
woke up but now, the resampler has updated the requested size and we
need to requery it before we can start reading samples.

Otherwise, we end up with requested samples from before the rate update
and we might not give enough samples to the resampler. In that case, the
adapter will call us again and we will again try to produce a buffer
worth of the requested samples, which will xrun.
2025-07-22 16:48:43 +02:00
Niklas Carlsson
fc3a199ca2 filter-graph: fix index off by one in dsp_delay_c
Checking w + 1 > n_buffer means that w will go to n_buffer, which
in turn leads to reading buffer[2 * n_buffer].
2025-07-22 15:44:08 +02:00
Karl Relton
9189b1d8b7 Add ACP for Logitech 407 USB PC Speaker set 2025-07-21 12:25:26 +00:00
Karl Relton
eac495f0e7 Option of analog or iec958 stereo output, both merging volume switches 2025-07-21 12:19:13 +00:00
Karl Relton
47e8984450 Upload New File 2025-07-21 12:17:40 +00:00
Wim Taymans
f2fb0b0aa5 alsa: update resample state in all cases
We need to manually recheck the resample state when the matching state
got updated.
2025-07-18 19:20:00 +02:00
Wim Taymans
5fba59b41d mixer-dsp: fix compilation with fastpath debug 2025-07-18 19:19:34 +02:00
Wim Taymans
ce2989891d alsa: init the bw_max value
Otherwise, rate matching doesn't work when it's left to 0.0.
2025-07-18 18:21:18 +02:00
Wim Taymans
5cd7b1de16 mixer-dsp: rework the port management
Keep a list of active ports in the port_list. These are all ports added
with add_port and not yet removed. When a port is removed, move it to
the free_list and reuse the port later when needed.

Update a mix_list of ports when a valid io is set on a port. This then
makes it possible to more efficiently and safely iterate the ports in
the processing loop.
2025-07-18 16:43:22 +02:00
Wim Taymans
ec5d2d2a29 audioconvert: rework the stage recalc a little
Use bits to capture the work that is needed. We clear the bit when
we added the stage, when all bits are cleared we have nothing more to
do. This avoids having to check multiple bookleans.

Make a helper function to calculate the destination buffer. When all
bits are cleared, we can use the output buffer.
2025-07-18 12:10:30 +02:00
Wim Taymans
8babd0bc4e audioconvert: remove unused field 2025-07-18 12:02:28 +02:00
Carlos Rafael Giani
c504851dca alsa-compress-offload-sink: Improve write_queued_output_buffers comments 2025-07-18 10:53:59 +02:00
Carlos Rafael Giani
48716a72b1 alsa-compress-offload-sink: Remove unused variable 2025-07-18 10:53:52 +02:00
Carlos Rafael Giani
14b242c737 node-driver: Make sure the discont clock flag does not remain set forever
If the timer was canceled, the discont flag needs to be set. But in the
next cycle, unless the timer was canceled again, that flag should not
remain set.
2025-07-18 10:52:13 +02:00
Carlos Rafael Giani
bb022c1b84 node-driver: Handle realtime clock modifications
If the user alters the realtime clock (for example by using the "date"
command in the shell), and the node driver uses the realtime clock as
the timerfd clock, then the scheduled graph cycle invocation may not
take place, or may take place much later than planned, because the
timestamp that was passed to spa_system_timerfd_settime() is now invalid.
Configure the timer to automatically be canceled if the realtime clock
is modified so that the graph cycle can be rescheduled with an updated
timestamp that is actually usable with the altered realtime clock.
2025-07-17 13:13:34 +00:00
Wim Taymans
ece2890c8b meson: remove avutils as a ONNX dependency 2025-07-17 14:08:20 +02:00
Wim Taymans
6605caa39e filter-graph: add ONNX plugin
It uses the onnxruntime library to parse the onnx file and construct a
neural network. It uses the label field to setup the plugin and how to
map the various tensors of the model to input, output, control and
notify ports.

Add an example config for how to use the silero VAD ONNX model with the
noise gate.
2025-07-17 13:16:00 +02:00
Wim Taymans
b3dddfed6a filter-chain: add Level control input port for noisegate
This makes it possible to use another volume measurement algorithm to
drive the noise gate, such as a VAD algorithm.
2025-07-17 12:12:24 +02:00
Wim Taymans
4b37f3db3d filter-graph: move loop out of the NULL check 2025-07-17 12:12:22 +02:00
Carlos Rafael Giani
67711e899c audioadapter: Add more log lines 2025-07-16 10:58:48 +02:00
Wim Taymans
328e101f37 alsa: don't try to activate resampling with unknown rates
If the driver or our rate is not known yet, don't assume we will need to
resample.
2025-07-15 15:06:24 +02:00
Wim Taymans
0be61add02 Revert "spa: alsa: Try to get driver rate before setting up matching"
This reverts commit 019b53ace8.

This is a result of a different problem, that the rates are compared
when they are unset.
2025-07-15 14:52:31 +02:00
Demi Marie Obenour
b04da87e38 pod: check that choices are not empty
Before using the contents of a choice, check that it is not empty to
avoid reading out of bounds.
2025-07-15 10:13:18 +02:00
Demi Marie Obenour
fb315b9050 *: Missing bounds checks in POD handling
There were missing bounds checks for ill-formed POD all over the place.
2025-07-15 10:13:17 +02:00
Demi Marie Obenour
5bfc3e6b03 spa: v4l2: avoid integer wraparound to out of bounds read
I'm not sure if untrusted input can reach this point.
2025-07-15 10:13:17 +02:00
Barnabás Pőcze
2c2808fab1 spa: libcamera: manager: fix id allocation
There is an issue in the id allocation mechanism which can result
in the different devices having the same id. Specifically, consider
the scenario where there are only two cameras, which have just been
added. In this case `impl::devices` looks like this:

   (0, camA) | (1, camB) | (?, nullptr) | ...

Now assume that `camA` is removed, after which the array appears
as follows:

  (1, camB) | (1, nullptr) | (?, nullptr) | ...

Then assume that a new camera appears. When `get_free_id()` runs,
when `i == 1`, it will observe that `devices[i].camera == nullptr`,
so it selects `1` as the id. Leading to the following:

  (1, camB) | (1, camC) | (?, nullptr) | ...

This is of course incorrect. The set of ids must be unique. When
wireplumber is faced with this situation it destroys the device
object for `camB` when `camC` is emitted.

Fix this by simply not moving elements in the `devices` array,
leaving everything where it is. In which case the array looks
like this:

  (nullptr) | (camB) | (nullptr) | ... // after `camA` removal
  (camC) | (camB) | (nullptr) | ... // after `camC` appearance

Note that `device::id` is removed, and the id is now derived from
the position in `impl::devices`.
2025-07-15 08:12:54 +00:00
Barnabás Pőcze
db3d91ebeb spa: libcamera: use nullptr instead of NULL 2025-07-15 08:12:54 +00:00
Barnabás Pőcze
4fa11619a2 spa: libcamera: use C++ style casts 2025-07-15 08:12:54 +00:00
Barnabás Pőcze
bb8223bff1 spa: libcamera: use anon ns instead of static
Move most things into anonymous namespaces for internal linkage
instead of using `static`. This shortes declarations and makes it
hard to forget.
2025-07-15 08:12:54 +00:00
Barnabás Pőcze
cb71071d93 spa: libcamera: device: remove empty line 2025-07-15 08:12:54 +00:00
Barnabás Pőcze
e19a8bb5cd spa: libcamera: source: inline mmap_init()
The function has a single caller is essentially just a wrapper only
calling `mmap_init()`. So inline it into `spa_libcamera_alloc_buffers()`.
2025-07-15 08:12:54 +00:00
Barnabás Pőcze
561a9d6ebb spa: libcamera: source: set "corrupted" flag if applicable
If the libcamera `FrameMetadata` reports anything other than `FrameSuccess`,
then set `SPA_META_HEADER_FLAG_CORRUPTED`, notifying the application that
the frame may be unusable.
2025-07-15 08:12:54 +00:00
Barnabás Pőcze
0022fc90b7 spa: libcamera: source: use union for transferring control value
Use a union since only one member is active at a time, and use the
proper `libcamera::ControlType` enum to store the type instead of a
bare number. Also remove an unnecessary cast.
2025-07-15 08:12:54 +00:00
Barnabás Pőcze
f94f4de6ff spa: libcamera: source: simplify control mapping
Remove the `impl` parameter as it is not used, and use C++ range
based for loops.
2025-07-15 08:12:54 +00:00
Barnabás Pőcze
311b3cc37f spa: libcamera: source: do not make expensive queries multiple times
`StreamFormats::pixelformats()` and `StreamFormats::sizes()` both
return newly created `std::vector`s, so do not call them multiple
times.
2025-07-15 08:12:54 +00:00