alsa-lib icon indicating copy to clipboard operation
alsa-lib copied to clipboard

What is the semantics of snd_pcm_hw_params_any?

Open jpalus opened this issue 3 years ago • 11 comments

It is not really a bug report but rather a request for clarification in attempt to figure out who is to blame for incorrect pulseaudio behavior.

I've got two different cards -- one internal and one USB -- which behave quite differently for this simple high level code:

snd_pcm_open()
snd_pcm_hw_params_any()
iterate snd_pcm_hw_params_test_rate() to check for supported rates
snd_pcm_hw_params_set_rate_near(44100)
snd_pcm_hw_params()
snd_pcm_hw_params_any()
iterate snd_pcm_hw_params_test_rate() to check for supported rates

In essence supported sample rates are queried twice, always with snd_pcm_hw_params_any() before them, but separated by snd_pcm_hw_params_set_rate_near().

Now with internal card both iterations report 7 supported rates while for USB first iteration reports 4 rates and second only one (44100). Is that expected or is snd_pcm_hw_params_any() supposed to provide configuration which would result in all rates reported again?

jpalus avatar Feb 19 '21 23:02 jpalus

If you set the params - snd_pcm_hw_params(), the driver may restrict the future configuration space depending on this settings (for example to lock the playback and capture rates to identical value). Do you see this behaviour without snd_pcm_hw_params() in the chain?

perexg avatar Feb 20 '21 17:02 perexg

Without snd_pcm_hw_params() both calls report all supported rates.

High level code in first comment is what pulseaudio basically does. Card initialization ends with snd_pcm_hw_params() while supported rates are queried later on. For some cards all rates are returned while for USB audio only one rate is returned. But as I understand that's something to be expected.

jpalus avatar Feb 20 '21 17:02 jpalus

Yes, the configuration space is dynamic and it may change when the hw params are set.

perexg avatar Feb 20 '21 18:02 perexg

Is there a way to leave this state and go back to unrestricted configuration?

jpalus avatar Feb 20 '21 21:02 jpalus

Yes, snd_pcm_hw_free() call after snd_pcm_hw_params(). The PCM stream should be put back to the "open" state.

I don't follow the "set params" -> "query params" operation in PA. The query should be first...

perexg avatar Feb 21 '21 20:02 perexg

I can't really tell why pulseaudio is doing things like this, but it seems to be in current shape for years. For some reason "set params" is part of initialization and capabilities query is done only once initialization is successful. I'm in the process of creating workaround but I'm still not sure about guarantees that alsa provides. I'd like to do something like:

snd_pcm_hw_params_alloca(&orig_hwparams); snd_pcm_hw_params_current(pcm, orig_hwparams); snd_pcm_hw_free(pcm); <query rates> snd_pcm_hw_params(pcm, orig_hwparams);

but not sure if orig_hwparams is still valid after snd_pcm_hw_free()? Or should I snd_pcm_hw_params_copy() it first?

Just in case it's about issue: https://gitlab.freedesktop.org/pulseaudio/pulseaudio/-/issues/1145

and initialization process I mentioned is here: https://gitlab.freedesktop.org/pulseaudio/pulseaudio/-/blob/v14.2/src/modules/alsa/alsa-util.c#L675

jpalus avatar Feb 22 '21 10:02 jpalus

Seems that no matter what I do params retrieved with snd_pcm_hw_params_current() never succeed if passed to snd_pcm_hw_params().

jpalus avatar Mar 05 '21 00:03 jpalus

You may use snd_pcm_dump() to check the set / current params.

perexg avatar Mar 05 '21 12:03 perexg

Another pulseaudio issue with seemingly same outcome https://gitlab.freedesktop.org/pulseaudio/pulseaudio/-/issues/1414

With my C-Media Unitek Y-247A I do not see this issue, all supported rates are detected by pulseaudio. Guess this still could be kernel driver change causing different behavior for devices with programmable clock source stuff.

I'm trying to fetch one of the modern dongles to confirm findings here regarding pulseaudio rate probing procedure.

i-garrison avatar Feb 05 '23 17:02 i-garrison

Yes, snd_pcm_hw_free() call after snd_pcm_hw_params(). The PCM stream should be put back to the "open" state.

I don't follow the "set params" -> "query params" operation in PA. The query should be first...

Hi @perexg here is the pulseaudio sample rate probe routine since year 2011 https://gitlab.freedesktop.org/pulseaudio/pulseaudio/-/blob/master/src/modules/alsa/alsa-util.c#L1440-1452 Note this currently runs after snd_pcm_hw_param() is already called with default sample rate.

I can reproduce this issue now with UAC2 hardware. Looks like this always worked before (and now with e.g. UAC1 or HDMI hardware that I have) because nothing was restricting sample rates.

I'll try to experiment with calling snd_pcm_hw_free before starting probe or moving probe routine to happen before snd_pcm_hw_param() is called for the first time.

i-garrison avatar Feb 21 '23 19:02 i-garrison

Hi @jpalus could you please test pulseaudio with this change https://gitlab.freedesktop.org/pulseaudio/pulseaudio/-/merge_requests/782 ? I moved rate detection code to be just after snd_pcm_open() which seems to fix the issue with UAC2 device that I have.

i-garrison avatar Feb 21 '23 23:02 i-garrison