Bug 211941 - USB audio stuck hardware params
Summary: USB audio stuck hardware params
Status: RESOLVED CODE_FIX
Alias: None
Product: Drivers
Classification: Unclassified
Component: Sound(ALSA) (show other bugs)
Hardware: All Linux
: P1 normal
Assignee: Jaroslav Kysela
URL:
Keywords:
Depends on:
Blocks:
 
Reported: 2021-02-26 08:17 UTC by Michael Forney
Modified: 2021-02-28 08:03 UTC (History)
1 user (show)

See Also:
Kernel Version: 5.11
Subsystem:
Regression: Yes
Bisected commit-id:


Attachments
USB descriptors (12.02 KB, text/plain)
2021-02-26 08:17 UTC, Michael Forney
Details
5.10 dmesg output (7.58 KB, text/plain)
2021-02-26 08:18 UTC, Michael Forney
Details
5.11 dmesg output (6.97 KB, text/plain)
2021-02-26 08:19 UTC, Michael Forney
Details
Test hw_params program (1.17 KB, text/x-csrc)
2021-02-26 08:26 UTC, Michael Forney
Details
/proc/asound/S3/stream0 (1.19 KB, text/plain)
2021-02-26 10:38 UTC, Michael Forney
Details
Test fix patch (677 bytes, patch)
2021-02-27 17:44 UTC, Takashi Iwai
Details | Diff
Revised test patch (693 bytes, patch)
2021-02-27 18:49 UTC, Takashi Iwai
Details | Diff

Description Michael Forney 2021-02-26 08:17:39 UTC
Created attachment 295453 [details]
USB descriptors

After upgrading to linux 5.11, I noticed some strange behavior with setting hw_params on my USB audio device (Schiit Modi 3 DAC).

If the parameters are set to some rate or period size, I can't change them later on to new values. I attached a test program to demonstrate the issue. On linux 5.10, the second hw_params can be set successfully:

rate=48000 dir=0
period=4800 dir=0
rate=44100 dir=0
period=441 dir=0

but on linux 5.11, it prints:

rate=48000 dir=0
period=4800 dir=0
rate=48000 dir=0
period=4800 dir=0

It seems the rate and period are getting stuck at the previous settings.

I see there was quite a bit of refactoring of USB audio in 5.11. I bisected the issue to commit e4ea77f8e5 (ALSA: usb-audio: Always apply the hw constraints for implicit fb sync). This seems suspicious since the device does not have any implicit feedback endpoints; it has one asynchronous endpoint with explicit feedback. I attached a dump of the device descriptors.

I also attached some snippets from dmesg with debug messages for 5.10 and 5.11. It shows that on 5.11, the second snd_pcm_hw_params triggers hw_rule_*_implicit_fb, which locks down the parameters to the previous values. I believe this is unexpected.

I noticed this bug when using sndio, since it sets an initially large period size when the device is opened, before the application chooses its desired size, but it was getting stuck at 4800. This was causing firefox to play videos with reduced framerate.
Comment 1 Michael Forney 2021-02-26 08:18:31 UTC
Created attachment 295455 [details]
5.10 dmesg output
Comment 2 Michael Forney 2021-02-26 08:19:00 UTC
Created attachment 295457 [details]
5.11 dmesg output
Comment 3 Michael Forney 2021-02-26 08:26:59 UTC
Created attachment 295459 [details]
Test hw_params program
Comment 4 Takashi Iwai 2021-02-26 09:44:17 UTC
Assuming that your device is running in the implicit feedback mode (that's what commit affects), it's the right behavior.  In the implicit fb mode, both full-duplex streams (or the streams sharing the same endpoint) have to be aligned with the same parameters, and that's the side-effect.  See the LKML thread:
  https://lore.kernel.org/lkml/YDfYAYCaC9KDc1F0@fritha.org/
Comment 5 Takashi Iwai 2021-02-26 09:56:17 UTC
OK, now looking at the test program, I understood about the situation.

I'd say that it's an application bug.  If the application calls snd_pcm_hw_free() before re-setting the hw_params, it should work with the latest driver.

The multiple hw_params calls work in most cases, but it essentially means to apply on top of the previous setup, hence such a side-effect can happen.  If you redo the whole set up, you'd need to clear the setup at first.
Comment 6 Michael Forney 2021-02-26 10:35:45 UTC
Thanks for taking a look.

> Assuming that your device is running in the implicit feedback mode (that's
> what commit affects), it's the right behavior.  In the implicit fb mode, both
> full-duplex streams (or the streams sharing the same endpoint) have to be
> aligned with the same parameters, and that's the side-effect.

I don't think this is the case. The device has only one output endpoint (half-duplex) with *explicit* feedback. It is not in implicit feedback mode. I will attach the /proc/asound/S3/stream0 file.

I believe the reason why this commit introduces the behavior change is that get_sync_ep_from_substream can return an endpoint if cur_rate is non-zero, even if it is not implicit_fb. Previously, the code to detect the sync endpoint would run only once during setup_hw_info, but now it is run every time the hw_rule_*_implicit_fb functions are called. On the second configuration, the endpoint already has a cur_rate, so the implicit_fb rules begin to run, even though it is not implicit_fb (I hope I'm explaining well enough).

> I'd say that it's an application bug.  If the application calls
> snd_pcm_hw_free() before re-setting the hw_params, it should work with the
> latest driver.

Thanks for the tip, adding snd_pcm_hw_free does seem to solve the problem. I will report this to the sndio developers.
Comment 7 Michael Forney 2021-02-26 10:38:13 UTC
Created attachment 295473 [details]
/proc/asound/S3/stream0
Comment 8 Takashi Iwai 2021-02-26 11:12:20 UTC
Yes, that's another case where the cur_rate is evaluated, indeed.  But essentially that's the same issue -- the endpoint is being used already by else (or itself without releasing), hence it cannot change the parameter since the endpoint setup is exclusive.  In that sense, the driver behavior is correct.
Comment 9 Michael Forney 2021-02-27 00:37:08 UTC
I see, thanks for the explanation.

In that case, it seems like the hw_rule_*_implicit_fb functions are misnamed, since they apply to all endpoints, not just implicit feedback endpoints.

Also, I think the alsa-lib documentation could be improved to prevent this type of issue in the future. snd_pcm_hw_params says that the configuration can't be changed once the stream is running, which implies that it *can* be changed before that. However, it does not mention that snd_pcm_hw_free is needed in between.

I have sent a patch to the sndio mailing list:
https://sndio.org/arch/0134.html
Comment 10 Takashi Iwai 2021-02-27 17:44:13 UTC
Thinking of this problem again, this could be also worked around in the kernel side, too, although the behavior itself is basically an application bug.

Below is the test patch.  Could you check it without fixing the application side?
Comment 11 Takashi Iwai 2021-02-27 17:44:34 UTC
Created attachment 295513 [details]
Test fix patch
Comment 12 Takashi Iwai 2021-02-27 18:49:52 UTC
Created attachment 295515 [details]
Revised test patch
Comment 13 Michael Forney 2021-02-28 00:26:52 UTC
> Could you check it without fixing the application side?

Yep, it fixes the issue with unpatched sndio.
Comment 14 Takashi Iwai 2021-02-28 08:03:43 UTC
OK, now I submitted and merge the fix for the upstream.
The commit 5f5e6a3e8b1df52f79122e447855cffbf1710540 in sound git tree.
    ALSA: usb-audio: Allow modifying parameters with succeeding hw_params calls

Note You need to log in before you can comment on or make changes to this bug.