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>
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.
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.
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>
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.
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.
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
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.
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.
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.
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.
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
...
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.
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.
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.
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
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>
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>
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>
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>
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>
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.
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")
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.
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
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.