Commit graph

1296 commits

Author SHA1 Message Date
Wim Taymans
13b8c23767 Don't use SPA_AUDIO_MAX_CHANNELS directly
Make a MAX_CHANNELS define and use that one in code. This makes it
easier to change the constant later.
2025-10-21 09:43:06 +02:00
Pauli Virtanen
da2cecf074 alsa: acp: don't disable dB if negative max unless range is small
Disabling dB volumes for max_dB < 0 was added in Pulseaudio in 2021,
based on a device which had -128..-127.07 range. However, negative
max_dB is valid value for USB devices, and there are devices that have
it.

Eg. Microsoft LifeChat LX-3000 has

numid=6,iface=MIXER,name='Speaker Playback Volume'
  ; type=INTEGER,access=rw---R--,values=2,min=0,max=151,step=0
  : values=150,150
  | dBminmax-min=-28.37dB,max=-0.06dB

and the dB range seems to be OK. Web search for "The decibel volume
range for element" also gives other hits with seemingly OK looking
ranges.

Don't disable dB volume unless both the max is negative and the range is
suspiciously small. This should still disable it for the device this
check was originally added for.

Link: https://gitlab.freedesktop.org/pulseaudio/pulseaudio/-/merge_requests/447
Link: 10ac01a206
2025-10-15 21:37:06 +03:00
Pauli Virtanen
c89acd3e1c alsa: acp: fix volume rounding down causing mute
Some ALSA devices have minimum HW volume value that is muted.  ALSA
indicates it with SND_CTL_TLV_DB_GAIN_MUTE = -9999999 dB/100 volume dB.
When rounding down to HW volume, we may get this muted value.

When determining splitting of volumes to mixers and soft volume, we
don't want HW mixers to set volume to muted, unless the target volume is
actually muted.

Fix by adding element_ask_unmuted_dB_vol() that rounds up if the asked
rounding mode resulted to mute.

This fixes mic getting muted at low volume despite ALSA reporting the dB
values correctly.

Fixes #4890
2025-10-14 08:02:23 +00:00
Arun Raghavan
154ab33607 spa: alsa: Add option to use ELD-detected channels 2025-10-10 09:34:43 +00:00
Arun Raghavan
91e2f184e2 spa: alsa: Read and expose channel count and position from ELD
The next step will be to propagate this to the correct node.
2025-10-10 09:34:43 +00:00
Peter Ujfalusi
9c42c06af0 alsa: Use the minimum period size as headroom for SOF cards
Configure the headroom to be equal of the minimum allowed period size for
the configuration.

This is desirable when the ALSA driver's hw_ptr is 'jumpy' due to
underplaying hardware architecture, like SOF.
In case of SOF the DSP firmware will burst read at stream start to fill
it's host facing buffer and later settles to a constant pace. The minimal
period size is constrained by the driver to cover the initial burst and
settling time of the hw_ptr.

Guard this mode of working with a new boolean flag, which is only enabled
for SOF cards, kept it disabled for other cards to avoid any unforeseen
side effects.

Even if the use-period-size-min-as-headroom is set to true, the manual
headroom configuration will take precedence to allow experimentation.

Link: https://github.com/thesofproject/linux/issues/5284
Link: https://github.com/thesofproject/sof/issues/9695#issuecomment-2569033847
Link: https://github.com/thesofproject/sof/issues/10172
Link: https://gitlab.freedesktop.org/pipewire/pipewire/-/issues/4489
Signed-off-by: Peter Ujfalusi <peter.ujfalusi@linux.intel.com>
2025-09-25 16:30:08 +03:00
Wim Taymans
f8389cbdb7 alsa: improve force_rate handling
Replace force_rate with force_quantum. We use force_rate when we need
to play an IEC958 or a DSD format but it does not make sense to just
force the rate without also forcing the duration.

This is also what happens when doing IRQ based scheduling, we then force
both the duration and rate of the graph so we can reuse this logic.

Also when forcing a quantum, take into account the suggested duration
and rate of the graph and scale that with the currently configured rate
for the period size. This gives a quantum that will match the requested
rate better. This is important for the DSD, where rate are very high and
we want the period size to be something reasonable relative to the
selected graph rate.

For batch devices (and when using a timer) we also configure a period
size that is half the duration of the quantum, to make sure we get some
headroom. We however need to force the full duration as the quantum, so
keep track of this scaling and apply when calculating the duration.
2025-09-25 12:29:05 +02:00
Pauli Virtanen
2e2f7c9f79 alsa: don't fail if 3 periods_min fails
Some drivers (emu10k1) appear to not necessarily support more than 2
periods.

Don't fail start if snd_pcm_hw_params_set_periods_min() fails, then we
just set nearest possible periods and buffer sizes.
2025-09-23 07:21:29 +00:00
Pauli Virtanen
bf783ab08f alsa: report extra latency for FireWire drivers
Based on testing, ALSA FireWire drivers introduce additional latency
determined by the buffer size.

Report that latency.

Pass device.bus to the node, so it can recognize firewire.
2025-09-07 18:23:31 +00:00
Pauli Virtanen
916896c1cc alsa: force IRQ scheduling for firewire in pro-audio profile
FireWire ALSA driver latency is determined by the buffer size and not the
period. Timer-based scheduling is then not really useful on these devices as
the latency is fixed.

In pro-audio profile, enable IRQ scheduling unconditionally for these
devices, so that controlling the latency works properly.

See #4785
2025-09-07 18:23:31 +00:00
Pauli Virtanen
64aaf8a832 alsa: set minimum period count before automatic period size
Some devices (FireWire) fail to produce audio if period count is < 3,
and also have small buffer size. When quantum is too large, we might
then get too few periods and broken sound.

Set minimum for the period count in ALSA, to determine the maximum
period size we can use. If smaller than what we were going to use, round
down to power-of-2.

See #4785
2025-09-07 18:23:31 +00:00
Wim Taymans
0f6aae914f alsa: don't add MAX_LATENCY when using IRQ scheduling
The Max latency property only works for timer based scheduling so that
we don't select a quantum larger than we can handle in our buffer.

With IRQ based scheduling this does not make sense because we will
reconfigure the buffer completely when we change quantums and so the
currently selected buffer size does not limit the latency in any way.

Fixes #4877
2025-09-02 18:52:38 +02:00
Wim Taymans
9606b37776 alsa: use 3 periods in IRQ mode by default
3 seems to work better as a default for Firewire. It does not actually
add latency because we only keep 1 period filled with data at all times.
2025-09-02 17:29:26 +02:00
Wim Taymans
0095d79ef8 alsa: use 2 (or 3 for batch) periods in IRQ mode
Some drivers (Firewire) have a latency depending on the ALSA buffer size
instead of the period size.

In IRQ mode, we can safely use 2 (or 3 for batch devices) periods
because we always need to reconfigure the hardware when we want to
change the period and so we don't need to keep some headroom like we do
for timer based scheduling.

See #4785
2025-09-02 14:13:19 +02:00
alexdlm
b0b6b1fcc5 Map Razer BlackShark v3 ACP 2025-08-27 15:55:02 +00:00
Wim Taymans
e35a8554f8 control: improve UMP to Midi conversiom
Improve the spa_ump_to_midi function so that it can consume multiple UMP
messages and produce multiple midi messages.

Some UMP messages (like program changes) need to be translated into up
to 3 midi messages. Do this byt adding a state to the function and by
making it consume the input bytes, just like the spa_ump_from_midi
function.

Adapt code to this new world. This is a little API break..
2025-08-19 18:33:59 +02:00
Wim Taymans
f562394596 alsa-seq: improve debug
Make it easier to change the event debug. Also add some more context
to the event debug.
2025-08-19 18:33:58 +02:00
Pauli Virtanen
618d60a1f2 alsa: show correct value in api.alsa.period-num 2025-08-09 12:53:41 +03:00
Wim Taymans
c9c7552fed alsa: clear port before adding to free list
If we clear the port after adding, we will destroy the links into the
list and cause crashes later.
2025-08-04 11:02:02 +02:00
Wim Taymans
4715e36a5c spa: don't free the mix_list ports
We can't move the mix_list ports to the free_list like that because the
elements in the list use a different list to link together. Also, we
don't need to free those ports at all because they will be freed when we
move the port_list to the free_list.
2025-07-31 10:20:59 +02:00
Wim Taymans
a3da53f66e alsa: fix seq compilation 2025-07-30 18:54:16 +02:00
Wim Taymans
7f7b4be82d alsa: use the safer pod parser for control events 2025-07-30 18:43:34 +02:00
Wim Taymans
6d07eaea1f seq: rework port handling
Dynamically allocate ports as we need them.
Use port lists to iterate active ports.
2025-07-30 17:32:02 +02:00
Wim Taymans
685aed1de2 alsa: update resampler requested size before reading
spa_alsa_read is called from the source process function when we are a
follower and no buffer is ready yet.

Part of the rate correction was performed by the ALSA driver when it
woke up but now, the resampler has updated the requested size and we
need to requery it before we can start reading samples.

Otherwise, we end up with requested samples from before the rate update
and we might not give enough samples to the resampler. In that case, the
adapter will call us again and we will again try to produce a buffer
worth of the requested samples, which will xrun.
2025-07-22 16:48:43 +02:00
Karl Relton
9189b1d8b7 Add ACP for Logitech 407 USB PC Speaker set 2025-07-21 12:25:26 +00:00
Karl Relton
eac495f0e7 Option of analog or iec958 stereo output, both merging volume switches 2025-07-21 12:19:13 +00:00
Karl Relton
47e8984450 Upload New File 2025-07-21 12:17:40 +00:00
Wim Taymans
f2fb0b0aa5 alsa: update resample state in all cases
We need to manually recheck the resample state when the matching state
got updated.
2025-07-18 19:20:00 +02:00
Wim Taymans
ce2989891d alsa: init the bw_max value
Otherwise, rate matching doesn't work when it's left to 0.0.
2025-07-18 18:21:18 +02:00
Carlos Rafael Giani
c504851dca alsa-compress-offload-sink: Improve write_queued_output_buffers comments 2025-07-18 10:53:59 +02:00
Carlos Rafael Giani
48716a72b1 alsa-compress-offload-sink: Remove unused variable 2025-07-18 10:53:52 +02:00
Wim Taymans
328e101f37 alsa: don't try to activate resampling with unknown rates
If the driver or our rate is not known yet, don't assume we will need to
resample.
2025-07-15 15:06:24 +02:00
Wim Taymans
0be61add02 Revert "spa: alsa: Try to get driver rate before setting up matching"
This reverts commit 019b53ace8.

This is a result of a different problem, that the rates are compared
when they are unset.
2025-07-15 14:52:31 +02:00
Julien Massot
8aa836d588 alsa-pcm: add support for api.alsa.dll-bandwidth-max
In USB Audio Class 2 (UAC2) setups, pitch control is handled by
feedback endpoints. The host adjusts its data rate accordingly.

When pitch control is active (pitch_elem), applying the default
delay-locked loop (DLL) bandwidth can lead to instability and
oscillations around the target rate.

This patch adds a new parameter, api.alsa.dll-bandwidth-max, to
configure the maximum DLL bandwidth. It introduces a new field
in the ALSA state to store this value.

By default, it uses SPA_DLL_BW_MAX, but when pitch control is in
use, setting it to a lower value (e.g. 0.02) helps ensure better
stability, based on empirical testing.
2025-07-07 10:40:11 +00:00
Arun Raghavan
019b53ace8 spa: alsa: Try to get driver rate before setting up matching
In some cases, it is possible that the follower shares a clock with the
driver, but the driver rate is not known when the follower is assigned
to the driver. If this happens, then state->driver_rate is 0, and when
setting the format, we might think that we need to resample (because
follower rate != driver rate). This can cause us to incorrectly halve
the period size for the node.

This was introduced in commit 0b67c10a9c,
which forces reevaluation of matching status on driver change.

To avoid this, let us also probe for the driver rate when updating the
matching status, so we can make the update more accurate.
2025-07-03 19:02:02 +00:00
Julian Bouzas
a8b9ce2050 alsa: add option to disable pro-audio profiles
Some devices might have nonfunctional 'Pro Audio' sound. This patch adds a
new 'api.acp.disable-pro-audio' option to disable pro-audio profile entirely.
2025-07-02 08:11:48 -04:00
Harald Sitter
1541ce3368 Revert "alsa: add Teufel Cage Pro mapping"
This reverts commit b57b87abbb.

It turns out this device is subtily different and doesn't work with the
current profile configurations. A UCM profile was added to alsa-ucm-conf
instead.
2025-06-26 09:19:09 +00:00
Wim Taymans
f3ff25c936 alsa: don't log unknown events with info
Debug is good enough
2025-06-20 15:49:17 +02:00
Wim Taymans
54923bf5bd alsa: remove UMP negotiation constraint
Otherwise we won't be able to negotiate with a port that only wants old
style midi.

Instead just negotiate the control link, conversion to old style midi
will be done in the control mixer for the old client.

Fixes #4759
2025-06-18 10:10:10 +02:00
Harald Sitter
b57b87abbb alsa: add Teufel Cage Pro mapping 2025-06-17 11:33:38 +00:00
Wim Taymans
f2905c74ed alsa-udev: support alsa.use-ucm
Make a new alsa.use-ucm option that sets api.alsa.use-ucm on the device
it creates (when set).

There is some documentation floating around (thr arch wiki) with this
property.

See #4755
2025-06-17 12:54:39 +02:00
Pauli Virtanen
3539374ba7 spa: alsa: fix some coverity warnings
NULL checks.

Change pa_x* malloc functions act like the pulseaudio ones: assert on
failure, as code assumes that.
2025-06-14 14:38:26 +03:00
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
Sam James
2cec77e7df *: unify config.h handling
config.h needs to be consistently included before any standard headers
if we ever want to set feature test macros (like _GNU_SOURCE or whatever)
inside. It can lead to hard-to-debug issues without that.

It can also be problematic just for our own HAVE_* that it may define
if it's not consistently made available before our own headers. Just
always include it first, before everything.

We already did this in many files, just not consistently.
2025-05-30 10:24:13 +00:00
Sam James
b943c31fd8
*: don't include standard C headers inside of extern "C"
Including C headers inside of `extern "C"` breaks use from C++. Hoist
the includes of standard C headers above the block so we don't try
to mangle the stdlib.

I initially tried to scope this with a targeted change but it's too
hard to do correctly that way. This way, we avoid whack-a-mole.

Firefox is working around this in their e21461b7b8b39cc31ba53c47d4f6f310c673ff2f
commit.

Bug: https://bugzilla.mozilla.org/1953080
2025-05-30 09:48:28 +01:00