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.
The code that removes the mixer path if probing fails can be called in
the path that sets a non-off device profile on hotplug *before*
card->active_profile is updated, which results in spuriously removing
the mixer path. By this point, context->ucm->active_verb would be set
to the same as the profile name, so we can use that instead to avoid
the issue.
On Apple Silicon machines with the UCM profiles in the Asahi Linux repo,
this manifests as the headphones jack having hardware volume controls
*only* if PA is started with headphones connected and until they are
disconnected. Hotplugs end up triggering the bad codepath, and it falls
back to software volume (which is particularly a problem when the
hardware volume happens to be very low or 0 at that point).
Fixes: a9cc1373e2a7 ("alsa: ucm - update the mixer path also after volume probe")
Signed-off-by: Hector Martin <marcan@marcan.st>
The ucm_get_device_property() function adds to each UCM device's
playback_volumes (or capture_volumes) hash map an associated volume
mixer keyed with the UCM verb. These key-value pairs are then iterated
over in various places which assume the key is a profile name. This
assumption is no longer true since we can generate multiple profiles to
use conflicting devices.
A previous commit 45278904167f ("alsa-ucm: Stop conflating profile name
with UCM verb name") fixes some instances of this assumption, but misses
the relation explained above. Fix more instances of misleading
"profile"s where the UCM verb name is actually meant.
Fixes: 45278904167f ("alsa-ucm: Stop conflating profile name with UCM verb name")
Signed-off-by: Alper Nebi Yasak <alpernebiyasak@gmail.com>
Although it's a valid UCM configuration to have multiple devices using
the same PlaybackPCM or CapturePCM, it's unclear how PulseAudio should
handle the cases where multiple of these devices are enabled. Some
options I can think of are:
- Merge all devices sharing the same PCM into the same mapping, open
only one PCM substream for this mapping, and add 'combination ports'
that enable combinations of the devices. This has been the case until
recently, although the combination port logic was broken. A problem
with this is that we can't independently control device volumes. We
most likely cannot use hardware volumes either.
- Have one mapping for each device in the same profile, and open one PCM
substream for each mapping. This is the current state, and it fails
when there are fewer substreams than devices. Otherwise it works, but
it's still confusing, as sound directed to a device-specific mapping
might end up playing at multiple devices.
- Make multiple profiles each with combinations of upto-substream-count
devices, and have one mapping/substream per device. This still causes
the confusion mentioned above. And it's likely that the substream
count will almost always be one, where this case degenerates into the
last one.
- Have one mapping for each device in the same profile, but open only
one PCM substream. I assume this is possible with software mixing, but
it is still confusing like the above, and probably less performant.
- Generate multiple profiles each with one of the shared-PCM devices,
again with one mapping/substream for that one device. The trade-off
with this is that we can't use multiple of these devices at the same
time. However, this doesn't have the output device confusion,
combination port's volume problems, or the substream count limitation.
This patch takes a short-cut to achieve the last option, by considering
shared-PCM devices implicitly conflicting with each other.
Signed-off-by: Alper Nebi Yasak <alpernebiyasak@gmail.com>
While switching profiles of the same UCM verb, existing code first
disables devices that are only on the first profile to avoid conflicts.
However, it only disables devices, not modifiers. Even worse, modifiers
which have PlaybackPCM/CapturePCM are incorrectly treated as devices and
result in a segmentation fault.
Check what we are disabling, and call the appropriate disable function
for both devices and modifiers. Modifiers are disabled before devices,
because _dismod calls fail when the modifier's supported devices are
disabled.
Signed-off-by: Alper Nebi Yasak <alpernebiyasak@gmail.com>
These are mostly the same as the device helpers added in c83b34516929
("alsa-ucm: Add enable, disable, status helpers for devices"), but for
modifiers instead.
Signed-off-by: Alper Nebi Yasak <alpernebiyasak@gmail.com>
Looks like original intention was to scan over sample formats supported by PA,
but code does the scan by list of alsa formats. Reverse the map and adjust
fallback case which now can use the same map.
Perform detection of supported sample format and rates just after device is
opened, before `snd_pcm_hw_params()` is called for the first time. This fixes a
problem where device restricts available sample rates after HW params are set
preventing sample rate detection (seen with UAC2 devices and kernel 6.1.9)
The full identifier check must be executed for the new melem
creation, otherwise the duplicate control element code check
is reached.
Example (using the snd-aloop driver):
numid=56,iface=PCM,name='PCM Notify',device=1,subdevice=1
numid=62,iface=PCM,name='PCM Notify',device=1,subdevice=2
Signed-off-by: Jaroslav Kysela <perex@perex.cz>
The new helem must be tracked and old helem must be cleared
to make the code work properly. Introduce the pointer to helem
as the private value for melem and add the necessary code.
Also, add a check for the duplicate mixer elements. The duplicate
mixer element invokes the abort check in alsa-lib. Print a warning
instead and handle the exit gracefully.
Fixes: def8eb074 ("alsa-mixer: allow to re-attach the mixer control element")
Signed-off-by: Jaroslav Kysela <perex@perex.cz>
Right now we try to add all UCM devices of a verb to a single profile.
But if some devices using different PCMs are configured as conflicting
with one another, we will only be able to utilize one of them, chosen
seemingly based on the order in the UCM config file.
This is not a problem with conflicting devices sharing a PCM, as they
are assigned to the same mapping and the ports mechanism only enables
one of them to be active at a time.
To utilize all devices in a UCM verb even when there are conflicting
devices using different PCMs, calculate subsets of devices which
can be simultaneously used and create a profile for each such set.
Signed-off-by: Alper Nebi Yasak <alpernebiyasak@gmail.com>
While switching profiles, it was enough to switch UCM verbs since that
disables all enabled UCM devices and every profile had a distinct verb.
However, switching to the current verb does not disable any devices.
To support multiple profiles for a verb we need to explicitly disable
the old profile's devices, since they might be conflicting with the new
profile's devices and will prevent them from being enabled. Compare both
profiles' mappings, and disable the devices not in the new mappings.
Signed-off-by: Alper Nebi Yasak <alpernebiyasak@gmail.com>
After previous patches, we should be generating no combination ports, so
we don't need to store multiple modifiers per mapping. Simplify the code
based on this.
Signed-off-by: Alper Nebi Yasak <alpernebiyasak@gmail.com>
After previous patches, we should be generating no combination ports, so
we don't need to store multiple devices per mapping. Simplify the code
based on this.
Signed-off-by: Alper Nebi Yasak <alpernebiyasak@gmail.com>