Commit graph

353 commits

Author SHA1 Message Date
Martin Geier
d04ee91714 plugins: alsa: increase follower write synchronization when htimestamps are enabled
alsa_write_sync can insert or remove some data from alsa when
resynchronization is needed.
Avail and delay are equal when high precision timestamps are not allowed.
When the high precision timestamps are enabled, the delay is avail
adjusted to current_time.

Signed-off-by: Martin Geier <martin.geier@streamunlimited.com>
2025-06-13 22:14:34 +00:00
Wim Taymans
3fdcf0d34c alsa: reset alsa_sync when linked
When a linked node needs to be resynced we actually never clear the
flag or reset the dll. Move the code around so that it still does
the reset of the flag and dll without actually doing the resync in
the ringbuffer when it is a linked node.
2025-06-11 13:06:54 +02:00
Wim Taymans
524da5962d alsa: reset dll in prepare
When we do_prepare, always reset the dll. We already set the alsa_sync
field but that is only used by followers to resync in some cases.

When reseting the dll, we also reset the next_time and base_time values,
we however need to do this before calculating the error in update_time
when we are the driver in IRQ mode or else we get some crazy error
that distorts the rate estimation.
2025-06-11 13:03:18 +02:00
Martin Geier
4976ac7ef9 alsa-pcm: add dsd bit order parameter
Signed-off-by: Martin Geier <martin.geier@streamunlimited.com>
2025-06-10 16:28:48 +02:00
Martin Geier
9afa0cd270 alsa-pcm: enable interrupts after alsa recovery
Interrupts are disabled in alsa_irq_wakeup_event -> playback_ready method
to not produce another wakeups when waiting for a new data. Interrupts are
enabled again when a new data arrives in a method spa_alsa_write.
In rare cases, when there is multiple streams providing data and one of
them is disconnected, a new data fails to be delivered and the spa_alsa_write
is not called. Not providing data produces underrun and alsa-pcm invokes
recovery process. Recovery process starts a new playback, but without interrupts
enabled is graph not triggered and new data are not delivered (to enable
interrupts). Recovery process keeps running in loop.
Now the interrupts are enabled again after the recovery and the starvation
should not occur.

Signed-off-by: Martin Geier <martin.geier@streamunlimited.com>
2025-06-10 16:28:46 +02:00
Wim Taymans
9b36e576cb alsa: handle NULL io
It is possible that the port io is set to NULL when the node is
negotiating or destroying.

Fixes #4734
2025-06-10 10:54:36 +02:00
Wim Taymans
f7fdafc203 loop: add method to run a function with the lock
Convert some _invoke to _locked
2025-05-29 10:17:16 +02:00
Wim Taymans
f068e4ba85 alsa: rework the channel params
Avoid adding a None choice, just add one single value without a choice
when the min == max. In that case we can also add a channel position.
2025-05-08 18:17:45 +02:00
Wim Taymans
2d8080cbde alsa: only use default rate and channels when valid
Check the user provided rate and channels and only use them to limit the
rate and channels when they are valid.
2025-05-08 18:16:53 +02:00
Wim Taymans
ff0d6d5677 alsa: clamp audio.channels to MAX_CHANNELS
So that we don't end up trying to use too many channels later on.
2025-05-08 18:14:02 +02:00
Wim Taymans
b2695f86cf alsa-pcm: handle and warn about a driver bug wrt channels
If the driver returns a larger min than max channel count, log a warning
and swap the two numbers.

See #4687
2025-05-08 16:01:18 +02:00
Stefan Ursella
fb7c37aeb4 alsa-pcm: recognize headroom to calculate max_error and max_resync 2025-03-03 12:26:05 +01:00
Andrew Sayers
db972b5bc1 Downgrade snd_pcm_mmap_commit error to warning 2025-01-21 11:20:23 +00:00
Pauli Virtanen
dcccfcab7f spa: acp: get and emit UCM information for SplitPCM devices
When api.alsa.split-enable=true for ACP device, instruct UCM to not
use alsa-lib plugins for SplitPCM devices.

Grab the information from UCM for the intended channel remapping, and
add the splitting information to the nodes emitted.

Session manager can then look at that, and load nodes to do the channel
splitting.
2024-12-21 16:03:19 +02:00
Wim Taymans
e2a0d720f9 alsa: reduce debug level that got accidentally increased 2024-12-03 16:44:45 +01:00
Wim Taymans
22f0b858b1 alsa: improve target bandwidth calculation
Also use the average error to calculate the bandwidth. If we are not
around 0, we should increase the bandwidth.
2024-12-03 12:11:20 +01:00
Arun Raghavan
7bc84305e6 spa: alsa: Don't assume all PCMs have a card
dmix/dsnoop devices, for example, don't have an associated card, so all
the card-related checks don't make sense. Let's explicitly deal with
this case.

Fixes: https://gitlab.freedesktop.org/pipewire/pipewire/-/issues/4432
2024-11-29 12:12:28 -05:00
Arun Raghavan
4c09451e77 spa: alsa: Fix key name suggestion in log message
We use api.alsa.pcm.card to look up the PCM's card if we don't know it
by other means.
2024-11-29 10:55:39 -05:00
Arun Raghavan
90075b838c spa: alsa: Try to initialise card_index from path if needed
If the PCM is loaded directly using only api.alsa.path,
state->card_index may never be initialised, and then we end up opening
the wrong ctl device. Let's try a fallback for this case.
2024-11-22 10:36:26 -05:00
Wim Taymans
1084cc24b6 alsa: handle the case where the driver is destroyed
When the driver node is destroyed (like when unplugging the cable) it
will drop/pause all of the follower ALSA nodes. This is something that
happens internally because of how the ALSA nodes work together, on the
PipeWire level, the nodes are still running and they will just be moved to
another driver.

The problem is that nothing will then start the nodes again after moving
it to the new driver. Fix this by keeping track of the desired target
state of the ALSA node and restoring that state when we detect that we are
paused when moved to a new driver.

Fixes #4401
2024-11-15 16:09:36 +01:00
Wim Taymans
d32ab4d8ea alsa: remove unused variable 2024-11-14 12:03:55 +01:00
Wim Taymans
6549e313ef alsa: clean up followers and our driver link in _clear
When we are going to be freed, make sure we remove ourself from the
driver list and also remove all the followers that we might still have.

Fixes #4355
2024-10-21 15:47:21 +02:00
Wim Taymans
fa1ec61cf0 profiler: add followerClock block
Add a new followerClock block in the profiler info. This is only set
when the follower could be a driver and it contains the clock info used
for following the driver, mostly the rate difference and delay.

Dump this info in pw-profiler -J

Make sure we always set the info in the clock, especially also when we
are following.
2024-10-09 11:31:54 +02:00
Wim Taymans
0db2171cd9 alsa: dynamically adjust the DLL bandwidth
Keep a running average and variance of the error. Use this to
periodically update the DLL bandwidth. When the variance gets smaller,
we update the DLL more slowly to stay closer to the ideal rate.

This seems to improve the rate stability.
2024-10-04 10:47:47 +02:00
Wim Taymans
e2991f6398 json: add helper function to parse channel positions
Use the helper instead of duplicating the same code.

Also add some helpers to parse a json array of uint32_t

Move some functions to convert between type name and id.
2024-09-18 09:54:34 +02:00
Wim Taymans
cd81b5f39a spa: add spa_json_begin_array/object and relaxed versions
Add spa_json_begin_array/object to replace
spa_json_init+spa_json_begin_array/object

This function is better because it does not waste a useless spa_json
structure as an iterator. The relaxed versions also error out when the
container is mismatched because parsing a mismatched container is not
going to give any results anyway.
2024-09-16 09:50:33 +02:00
Stefan Ursella
189f2ec95b alsa-pcm: unlink pcm when driver is changed to a different pcm
We have to unlink pcms when they are linked to a driver from
a different pcm.

When a playback and a capture pcm is linked and we start
the playback pcm and the capture pcm later this can leads
to a 'EPIPE' error on the capture device.

...
spa.alsa: hw:3,0c: snd_pcm_start: Broken pipe
...
2024-09-06 08:42:20 +00:00
Arun Raghavan
9cd2bbc585 alsa-pcm: Lower the frequency of USB gadget rate updates
While the spec allows for 1ppm changes, our rate matching logic applies
these changes quite often, which can be spammy on USB. I haven't seen
hosts mind this, but it seems like it might be a problem at some point.

Additionally, if we also have bind ctls enabled, every pitch update is
also a wakeup for ourselves (whether or not we're listening for the
pitch ctls, since the mixer fd does not distinguish between ctls, those
are filtered after we wake up).

The 10ppm threshold is empirically tested as being not "too noisy" (i.e.
when updates happen, I can see them scroll by with `amixer events`).

If necessary, we can make this configurable in the future.
2024-07-31 12:00:07 -04:00
Arun Raghavan
0dc17d8d88 spa: alsa: Fix stale function name in comment 2024-07-17 20:07:57 -04:00
Pauli Virtanen
ea19554e8d spa: alsa: recognize plug+a52 as a52 device strings
HDMI/AC3 profiles use plug+a52 for a52 output, and should be handled
like a52.
2024-07-05 16:06:17 +03:00
Wim Taymans
b1bb0ead3c alsa: remove unused variables 2024-06-30 21:23:00 +02:00
Stefan Ursella
0b39c4ec68 alsa-pcm: add basic bind-ctl write functionality 2024-06-28 12:00:16 +02:00
Wim Taymans
9d1d1fcbef impl-port: add port.group property
Can be used to group ports together. Mostly because they are all from
the same stream and split into multiple ports by audioconvert/adapter.

Also useful for the alsa sequence to group client ports together.

Also interesting when pw-filter would be able to handle streams in the
future to find out what ports belong to what streams.
2024-06-24 13:38:09 +02:00
Wim Taymans
1ae4374ccf Fix compilation with -Werror=float-conversion
Better make the conversions explicit so that we don't get any surprises.

Fixes #4065
2024-06-18 12:17:56 +02:00
Stefan Ursella
898f854ca7 alsa-pcm: check if bound ctls are valid before using it.
When bound_ctl info cannot be read this array elem info
is set to NULL in 'fetch_bind_ctl'. So when we iterate
the bound_ctl array we always have to check this.
2024-06-07 07:21:45 +00:00
Arun Raghavan
2f9a5e0694 alsa: Use hw:X for accessing card ctl
In ACP mode, we might be accessing front:0 as the PCM, and using that
string to generate the ctl device name does not make sense. In
PulseAudio, we used the card index to generate a hw:X string, and we
replicate that here.

Fixes: https://gitlab.freedesktop.org/pipewire/pipewire/-/issues/4028
2024-05-28 10:39:24 +03:00
Stefan Ursella
9c31cf1271 alsa: read hw synced ring buffer position when caller is not the same pcm
When the caller is a different pcm it is not shure that the
IRQs are synchronised. So read the real ring buffer position.
2024-05-05 09:31:54 +00:00
Lukas Rusak
9e88aafa30 alsa-pcm: don't force quantum for iec958 formats
This fixes an issue introduced in 771f71f622
where the quantum is forced and may break applications the specify their
own quantum.

Signed-off-by: Lukas Rusak <lorusak@gmail.com>
2024-04-30 09:34:19 +02:00
Martin Geier
5c8799a480 alsa-pcm: set threshold to final value before set_swparams is called
This patch fixes use case, when disable_tsched is set and
api.alsa.period-size is set to value different from default quantum size.

In a such configuration, threshold needs to be set to a final value
before snd_pcm_sw_params_set_avail_min is called to get IRQs with
right timing.

Avail minimum is calculated from a threshold set in the check_position_config.
The method returned different value for threshold right before playback
started and after the playback started. Therefore threshold used in
the snd_pcm_sw_params_set_avail_min was incorrect.

Force the check_position_config to use configured values when called
from spa_alsa_prepare as this method is called when starting new playback
and the state->period_frames and the state->rate are already known.

Signed-off-by: Martin Geier <martin.geier@streamunlimited.com>
2024-04-09 09:03:49 +00:00
Martin Geier
4c11a2aa9a alsa-pcm: start playback immediately if there is start delay set
Without this change, playback_ready or capture_ready was called
immediately after spa_alsa_start even tho start-delay was set.
Ready function was called with not precise "nsec" value, as "nsec"
plus latency should return time when the next buffer should be played
which wasn't true as start-delay was not included.

Now the playback is started immediately when the start_delay is set.
The alsa_do_wakeup_work is still called immediately but two things can
happened. Either start-delay is smaller then max_error and *_ready
function is called immediately, or start-delay is bigger then max_error
and state->next_time will be updated to correct value.

Signed-off-by: Martin Geier <martin.geier@streamunlimited.com>
2024-04-09 09:03:49 +00:00
Martin Geier
1e6dad14d3 alsa-pcm: use headroom to calculate minimum available frames for non time scheduling
Alsa needs to call handler soon enough to have headroom plus threshold
frames in the buffer and not only threshold left.

Signed-off-by: Martin Geier <martin.geier@streamunlimited.com>
2024-04-09 09:03:49 +00:00
Martin Geier
b4ed8dcf14 alsa-pcm: do not allow headroom plus threshold be bigger then the alsa buffer
Headroom are extra samples available in alsa buffer on top of a threshold.
Its use to prefill alsa buffer with silence before the playback starts
and later its use to calculate target number of a frames in the alsa buffer
when get_status is called. Target is calculated as headroom plus
threshold, which should be smaller then buffer size to make sense.

Signed-off-by: Martin Geier <martin.geier@streamunlimited.com>
Signed-off-by: Carlos Rafael Giani <crg7475@mailbox.org>
2024-04-09 09:03:49 +00:00
Arun Raghavan
e4da3b95f5 alsa-pcm: Fix copy-pasto while listing ctls
Can cause a crash on startup under some circumstances.
2024-04-06 07:25:39 +00:00
Arun Raghavan
46e6fd2ae4 spa: alsa: Read ctl events instead of doing a global diff
This does a couple of things: first, we implement revents demangling,
which seems to be required (although hw: devices work fine without it).

The second is to actually read the ctl events so we can tell when
elements we care about have changed, instead of reading everything and
trying to do a diff.

The latter is also required from a correctness perspective, as otherwise
the ctl might keep triggering wakeups while the fd is ready to be read.
2024-03-14 10:13:41 -04:00
Barnabás Pőcze
cf984fcd4c spa: alsa: fix clang build
Variable declarations after a label are not allowed,
and clang does not accept them. Fix the build failure
by removing the variable.

Fixes b3fbd0e607 ("alsa-pcm: add_bind_ctl_param: add support for array")
2024-03-07 17:16:55 +00:00
Emil Svendsen
b3fbd0e607 alsa-pcm: add_bind_ctl_param: add support for array
ALSA controls are represented as an array. So let's make it possible to
handle array's and bytes.
2024-03-06 08:44:13 +01:00
Emil Svendsen
96f35e15a0 alsa-pcm: bind_ctl: add better ctl name matching
For matching kctl without the numid you need to specify interface,
device, subdevice, name and index. So the current implementation can
only match kctls on IFACE_PCM, device 0, subdevice 0 and index 0.

Instead of adding all these matching parameters this commit fetches all
kctls attached to the audio card and match on the first occurred kctl
with matching name.

This should be sufficient for audio cards with unique kctl names. When
non unique names are needed, more kctl matching parameters needs to be
added.
2024-03-05 17:48:56 +00:00
Emil Svendsen
81d8ecf0dc alsa-pcm: snd_ctl_open: remove device suffix
ALSA controls can only be opened on the card itself and will fail when
trying to open controls on the ALSA device. The device name we get may
or may not include the device suffix. If no suffix is present the
default device is 0 that's why currently it works on most audio cards.
But all other devices above 0 needs the suffix [1].

[1]
Device 0: hw:cardname
Device 0: hw:cardname,0
Device 1: hw:cardname,1
Device 2: hw:cardname,2
Device X: hw:cardname,X
2024-03-04 09:45:37 +00:00
Dimitrios Katsaros
c1eacce3fc alsa: Use hi-res timestamps in irq mode when available
We know in IRQ mode that any valid hi-res timestamp that the
driver privides will be before the wakeup event in pipewire.

This makes it so in IRQ mode we use better timestamping when possible,
which decreases jitter injected into the DLL, which in turn reduces
the amount of oscillations the resampler is exposed to.
2024-03-01 21:46:21 +01:00
Dimitrios Katsaros
539fdc5477 alsa: Added handle for controlling htimestamp autodisable
You can now do this to permanently enable htimestamp:

pw-cli s 38 Props '{ params: [ api.alsa.htimestamp.max-errors: 0, api.alsa.htimestamp: true ]}'
2024-02-20 11:30:48 +01:00