Always use get_avail() and then only fetch the hires timestamp when
enabled to enhance the delay reporting. This way we also recover from
errors from snd_pcm_avail() instead of ignoring them.
This should make the recover after mmap_begin obsolete but we'll leave
that just to be safe.
Since UCM doesn't perform the path lookups of alsa-mixer all UCM devices
fall back to the card's properties for e.g. icons and hence usually show
the `audio-card` icon for all ports giving a confusing UI to users as
all ports show the same icon.
As ucm names are pretty standard augment some common port names with
icons.
There are currently several issues when multiple alsa devices are
involved.
For alsa devices that are followers, all data is written via
impl_node_process(). Currently spa_alsa_write() is only called if a new
buffer was queued.
It can happen that all buffers are in the ready list (queued by previous
calls but not yet written because there was no free space in the kernel
ring buffer). In this case writing stalls indefinitely.
To fix this, also call spa_alsa_write() if no new buffer is queued but
there are still buffers in the ready list.
If the ready list of the primary device is not empty then only this
device is handled because spa_alsa_write() is called directly. The other
devices make no progress during this interval.
The clock drift calculation works by comparing the alsa delay with the
expected delay since the last wakeup. This only work if the alsa
ringbuffer was filled completly. If the ready list contains a partial
buffer then the ringbuffer is not filled and the timing calculation
during the next wakeup is incorrect.
To fix all this, remove the special case for the non-empty ready list
and just call spa_node_call_ready() every time.
If we detect Playback/Capture Pitch 1000000, we can adjust those values
to update the feedback endpoint for the host. On the capture side, this
will instruct the host to adjust the rate at which data is being sent.
On the playback side, this will adjust the amount of data the USB gadget
driver sends out in each USB tick.
Use snd_pcm_htimestamp to get both the available space and the timestamp
when this was calculated. We can then use this to get a better estimate
of the delay in the device against the graph start and get a more
reliable delay between capture and playback.
Use separate values for the number of available samples in the
ringbuffer and the delay in the device.
When using htimestamp we can use the tstamp to get a more accurate delay
value against the graph start time.
After we se the format, we negotiate the buffer size and period size.
When this fails, the period_size can be 0. Handle this case without
causing a floating point exception.
Use a separate variable to hold the maximum amount of drift we allow
between driver and follower. Ensure this value is smaller than the max_error
and period size so that we have at most 1 period of drift.
Don't reschedule a timeout when we have less samples available than the
target but only reschedule when we have less that the required amount we
need to read. This ensures that we hover around the target level and the
timeouts/rate matching adapts correctly. Previously we would only rate
match if the have at least the target amount of samples, which would
then always result in a possitive rate adjustment and cause drift.
For capture, make sure that there is at least 32 samples of headroom
when we are not using IRQ mode to handle jitter in the timer wakeup.
For capture of batch devices this results in (for a 1024 quantum) a
target buffer fill level of 1024 + 512, and we will read if there are at
least 1024 samples available.
For non-batch devices we aim for a target buffer fill level of 1024 + 32
and read if there are at least 1024 samples available.
This is a follow-up to d5390c7, where we switched to the 'PCM' mixer controls
on Sound Blaster Audigy devices, since the ones we used before only work in the
stereo-to-all-speakers mirroring mode.
It turns out we do use that mode after all, but only in a couple of profiles.
Since returning those profiles to the default mixer path yields uneven volume
steps similar to #2934, we instead add a new mixer path just for that mode.
Creative Labs Sound Blaster Audigy cards (snd_emu10k1 driver) expose
mixer controls named 'PCM Front', 'PCM Rear', etc. in addition to the
more common 'Front', 'Rear', etc. The latter seem to be intended for
a stereo-to-all-speakers mirroring mode that we do not use, and have
no effect when we adjust them.
https://docs.kernel.org/sound/cards/audigy-mixer.html
We therefore define a custom mixer path for Audigy devices, using the
PCM mixer controls.
This has been tested on an Audigy 5/Rx. Based on a brief look at the
ALSA driver, I think all Audigy devices (vendor 0x1102, device 0x0004
or 0x0008) have the same PCM controls, making this change probably safe
for our existing Audigy udev rules.
Relevant kernel files:
sound/pci/emu10k1/emu10k1_main.c
sound/pci/emu10k1/emufx.c
include/sound/emu10k1.h
Fixes#2934
For IRQ based scheduling we might otherwise be woken up after we only
added one of the fds to the poll loop and then we get an error when we
try to update it afterwards. Instead, add the fds from the data thread
to get things nicely in sync.
In IRQ mode, disable the ALSA fds while we wait for the graph to produce
data. Otherwise we will wake up very quickly over and over.
When we get more data, we activate the sources again to start the next
cycle.
Provides configuration to disable timer-based scheduling. This can be
useful at low latencies, for example, where period-based interrupts
might be more reliable than timers.
Drivers should only read the target_ values in the timeout, update the
timeout with the new duration and then update the position.
For the position we simply need to add the previous duration to the
position and then set the new duration + rate.
Otherwise, everything else should read the duration/rate and not use
the target_ values.
Place the target rate and duration in the io clock area.
The driver is meant to read these new values at the start of the cycle
and update the position rate and duration.
This used to be done by the pipewire server when it received the ready
callback from the driver but this is in fact too late. Most driver would
start processing and set the next timeout based on the old rate/duration
instead of the new pending ones.
There is still a fallback for the old behaviour (with a warning) when
the driver doesn't yet update the position.