We would timestamp within an unlikely block, which would introduce
additional jitter to current_time, which would have an impact on
the performance of the timer sensitive code.
Always reevaluate the rate matching even when we did not change the
follower state.
It is possible that we were a follower from some node with the same
clock and now become a follower of a node with a different clock. The
follower state doesn't change but we need to activate the rate matching
logic in that case.
Fixes rate matching in pro audio (playback) when capture and playback
are moved to another driver.
We can increase the MAX_LATENCY again if we increase the amount of
buffers when we are using a small buffer.
Normally we ask for 4 * quantum-limit as the buffer. This should be good
to use 1 buffer and quantum-limit as the quantum with enough headroom
to not run out of buffers.
If we are however using less buffer-frames we need to be careful and
allocate an extra buffer. Imagine using a buffer of 4096 frames, we can
support a quantum of up to 2048 frames if we use 2 buffers.
See #3744
Half of the buffersize is not enough to support as a max-quantum, we
need to divide by (4 * frame_scale) to allow some headroom and account
for the DSD scaling. We do the same calculation to suggest a buffer size
using the quantum-limit.
See #3744
As part of the setup for IRQ based scheduling, a period event
was installed. Not only is a timer based polling unecessary for
IRQ scheduling, depending on the state of the system, the timer
could fire far enough from the IRQ, causing alsa wakeup events
with no data in the ring buffer. Pipewire would identify these
events as an "early wakeup", adding an extra quantum of time
to the next_time estimate, skewing the clock and causing issues
with apps that depend on precise timing.
This reverts commit 49cdb468c2.
We should not do this, the nsec field should be relatable to the clock
monotonic time. If we use the estimated time, without actually using it
as a timer, we might end up with a wakeup time in the future compared to
the MONOTONIC clock time.
Instead, you can use the estimated current time simply by subtracting
the rate corrected duration from the next_nsec. This is really only
useful for some selected use cases (like in the JACK library).
This fixes some issues where in pro-audio mode, a client would try to
compare the current MONOTONIC time to nsec and find that it is in the
past.
This commit was done in an attempt to fix#3657 but it turned out the
real problem was something else.
Don't try to multiple the max_buffer_size with the frame scale or else
we might try to set a min_buffer_size larger than the max_buffer_size.
Instead, use the frame_scale only to scale the quantum_limit and then
clamp against the max_buffer size.
See #3000
We place the currently configured runtime settings in the properties but
clear the values when not negotiated. Don't do that but place the
defaults (when set) instead.
It doesn't make sense to hang these on the data loop, so let's have
these on the main loop instead. Also avoids a potential crash while
removing them (since removal happens on the main loop and the data loop
might be polling while we're doing the remove).
Don't use the current time as the nsec field in the graph clock because
it can jitter a lot. Instead, use the smoothed next_time, like we do
for timer based scheduling.
Since we track the current time against the rate converted ideal time,
lock on to the first timestamp when we reset the dll.
See #3657
Don't return the value of the last snd_pcm_resume() call because that
might be -ENOSYS when resume is not implemented for the card and then
the non-error (because we used drop/prepare later) propagates and
logs an error.
This adds an api.alsa.bind-ctls property to alsa-pcm sink and source
nodes, to bind a property to an ALSA PCM ctl. The property is an array
of ctl names that should be bound.
This can be handy, for example, to bind the Playback/Capture Rate
controls on a USB gadget, in order to track the PCM's state via a node
param.
This is currently wired to be read-only, but it should be easy enough to
make it writable.
Because we now always _drop/_prepare_/_start, the snd_pcm_recover()
before that is no longer useful.
Retry snd_pcm_resume() after suspend when -EAGAIN and fall back to
_drop/_prepare/_start when that fails.
We need to disable the resampler when there is a pitch element. This was
correctly done in setup_matching but not in check_position_config().
See #3628
We calculate the available frames in read_sync but add another
check in read_frames so that we don't attempt to read more frames
than we have available to avoid xruns.
Make a function to recalculate the headroom and call it whenever the
resample state of the node can change.
When we are IRQ based scheduling but need to resample, we are actually
not driving the graph whit IRQ and need to adjust our period size and
headroom as if we are using timers.
All linked PCMs prepare together. If we prepare the secondaries, that
action clobbers the write pointer of every PCM every time, which then
causes playback to fail to start due to lack of data.
Signed-off-by: Hector Martin <marcan@marcan.st>
When the PCM is stopped, don't check for early wakeup because if we
are early, we will never be on time in the next iteration either because the
PCM is stopped and doesn't advance.
Also don't try to align when stopped.
See #3565
Add an option to automatically use snd_pcm_link when the follower clock
is matching the driver. Only set this to true in pro-audio and when
nodes are scheduled together.
See #3556
We only start the ALSA pcm after we get our first buffer.
We still need to do the sync through (and get the number of prefilled
samples) to make sure we set our new timeout and don't keep on waking
up quickly while the graph fetches the first buffer.
Rename some variables to make it clear that we are dealing with the rate
and duration of the driver.
Set the driver rate in the clock instead of the target_rate, which we
might have rejected.
When we are using the same clock (!matching) try to link the two PCM
devices together. This starts and stops the devices at the same time and
gives better latency.
Keep track or the follower state and do the sync from the driver
wakeup.
This improves sync between devices because the sync no longer
depends on when the node was woken up in the graph and scheduled. We
would have been able to handle this difference by using the htimestamp
but that doesn't seen to work reliably on some hardware.
This is also essential for the interrupt based scheduling.