From aed52c507f345d0b5c4cd2b1d2c58dae2d904b53 Mon Sep 17 00:00:00 2001 From: "Igor V. Kovalenko" Date: Wed, 22 Feb 2023 01:19:24 +0300 Subject: alsa-util: Perform format and rate detection before setting HW params 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) Bug: https://gitlab.freedesktop.org/pulseaudio/pulseaudio/-/issues/1414 Bug: https://github.com/alsa-project/alsa-lib/issues/119 Part-of: --- src/modules/alsa/alsa-mixer.c | 2 +- src/modules/alsa/alsa-sink.c | 14 +++++++++----- src/modules/alsa/alsa-source.c | 8 +++----- src/modules/alsa/alsa-ucm.c | 2 +- src/modules/alsa/alsa-util.c | 24 ++++++++++++++++++++++++ src/modules/alsa/alsa-util.h | 8 ++++++++ 6 files changed, 46 insertions(+), 12 deletions(-) diff --git a/src/modules/alsa/alsa-mixer.c b/src/modules/alsa/alsa-mixer.c index 49c39687c..c272e392b 100644 --- a/src/modules/alsa/alsa-mixer.c +++ b/src/modules/alsa/alsa-mixer.c @@ -5074,7 +5074,7 @@ static snd_pcm_t* mapping_open_pcm(pa_alsa_mapping *m, handle = pa_alsa_open_by_template( m->device_strings, dev_id, NULL, &try_ss, &try_map, mode, &try_period_size, - &try_buffer_size, 0, NULL, NULL, exact_channels); + &try_buffer_size, 0, NULL, NULL, NULL, NULL, exact_channels); if (handle && !exact_channels && m->channel_map.channels != try_map.channels) { char buf[PA_CHANNEL_MAP_SNPRINT_MAX]; pa_log_debug("Channel map for mapping '%s' permanently changed to '%s'", m->name, diff --git a/src/modules/alsa/alsa-sink.c b/src/modules/alsa/alsa-sink.c index b249df680..ca22f195f 100644 --- a/src/modules/alsa/alsa-sink.c +++ b/src/modules/alsa/alsa-sink.c @@ -2527,7 +2527,9 @@ pa_sink *pa_alsa_sink_new(pa_module *m, pa_modargs *ma, const char*driver, pa_ca &ss, &map, SND_PCM_STREAM_PLAYBACK, &period_frames, &buffer_frames, tsched_frames, - &b, &d, mapping))) + &b, &d, + &u->supported_formats, &u->supported_rates, + mapping))) goto fail; } else if ((dev_id = pa_modargs_get_value(ma, "device_id", NULL))) { @@ -2541,7 +2543,9 @@ pa_sink *pa_alsa_sink_new(pa_module *m, pa_modargs *ma, const char*driver, pa_ca &ss, &map, SND_PCM_STREAM_PLAYBACK, &period_frames, &buffer_frames, tsched_frames, - &b, &d, profile_set, &mapping))) + &b, &d, + &u->supported_formats, &u->supported_rates, + profile_set, &mapping))) goto fail; } else { @@ -2552,7 +2556,9 @@ pa_sink *pa_alsa_sink_new(pa_module *m, pa_modargs *ma, const char*driver, pa_ca &ss, &map, SND_PCM_STREAM_PLAYBACK, &period_frames, &buffer_frames, tsched_frames, - &b, &d, false))) + &b, &d, + &u->supported_formats, &u->supported_rates, + false))) goto fail; } @@ -2598,13 +2604,11 @@ pa_sink *pa_alsa_sink_new(pa_module *m, pa_modargs *ma, const char*driver, pa_ca u->verified_sample_spec = ss; - u->supported_formats = pa_alsa_get_supported_formats(u->pcm_handle, ss.format); if (!u->supported_formats) { pa_log_error("Failed to find any supported sample formats."); goto fail; } - u->supported_rates = pa_alsa_get_supported_rates(u->pcm_handle, ss.rate); if (!u->supported_rates) { pa_log_error("Failed to find any supported sample rates."); goto fail; diff --git a/src/modules/alsa/alsa-source.c b/src/modules/alsa/alsa-source.c index ef8b12c32..d88c47f1f 100644 --- a/src/modules/alsa/alsa-source.c +++ b/src/modules/alsa/alsa-source.c @@ -2218,7 +2218,7 @@ pa_source *pa_alsa_source_new(pa_module *m, pa_modargs *ma, const char*driver, p &ss, &map, SND_PCM_STREAM_CAPTURE, &period_frames, &buffer_frames, tsched_frames, - &b, &d, mapping))) + &b, &d, &u->supported_formats, &u->supported_rates, mapping))) goto fail; } else if ((dev_id = pa_modargs_get_value(ma, "device_id", NULL))) { @@ -2232,7 +2232,7 @@ pa_source *pa_alsa_source_new(pa_module *m, pa_modargs *ma, const char*driver, p &ss, &map, SND_PCM_STREAM_CAPTURE, &period_frames, &buffer_frames, tsched_frames, - &b, &d, profile_set, &mapping))) + &b, &d, &u->supported_formats, &u->supported_rates, profile_set, &mapping))) goto fail; } else { @@ -2243,7 +2243,7 @@ pa_source *pa_alsa_source_new(pa_module *m, pa_modargs *ma, const char*driver, p &ss, &map, SND_PCM_STREAM_CAPTURE, &period_frames, &buffer_frames, tsched_frames, - &b, &d, false))) + &b, &d, &u->supported_formats, &u->supported_rates, false))) goto fail; } @@ -2279,13 +2279,11 @@ pa_source *pa_alsa_source_new(pa_module *m, pa_modargs *ma, const char*driver, p u->verified_sample_spec = ss; - u->supported_formats = pa_alsa_get_supported_formats(u->pcm_handle, ss.format); if (!u->supported_formats) { pa_log_error("Failed to find any supported sample formats."); goto fail; } - u->supported_rates = pa_alsa_get_supported_rates(u->pcm_handle, ss.rate); if (!u->supported_rates) { pa_log_error("Failed to find any supported sample rates."); goto fail; diff --git a/src/modules/alsa/alsa-ucm.c b/src/modules/alsa/alsa-ucm.c index e75756f53..744e7aae1 100644 --- a/src/modules/alsa/alsa-ucm.c +++ b/src/modules/alsa/alsa-ucm.c @@ -2026,7 +2026,7 @@ static snd_pcm_t* mapping_open_pcm(pa_alsa_ucm_config *ucm, pa_alsa_mapping *m, try_buffer_size = ucm->core->default_n_fragments * try_period_size; pcm = pa_alsa_open_by_device_string(m->device_strings[0], NULL, &try_ss, - &try_map, mode, &try_period_size, &try_buffer_size, 0, NULL, NULL, exact_channels); + &try_map, mode, &try_period_size, &try_buffer_size, 0, NULL, NULL, NULL, NULL, exact_channels); if (pcm) { if (!exact_channels) diff --git a/src/modules/alsa/alsa-util.c b/src/modules/alsa/alsa-util.c index fd30f18bd..b631c870c 100644 --- a/src/modules/alsa/alsa-util.c +++ b/src/modules/alsa/alsa-util.c @@ -523,6 +523,8 @@ snd_pcm_t *pa_alsa_open_by_device_id_auto( snd_pcm_uframes_t tsched_size, bool *use_mmap, bool *use_tsched, + pa_sample_format_t **query_supported_formats, + unsigned int **query_supported_rates, pa_alsa_profile_set *ps, pa_alsa_mapping **mapping) { @@ -561,6 +563,8 @@ snd_pcm_t *pa_alsa_open_by_device_id_auto( tsched_size, use_mmap, use_tsched, + query_supported_formats, + query_supported_rates, m); if (pcm_handle) { @@ -588,6 +592,8 @@ snd_pcm_t *pa_alsa_open_by_device_id_auto( tsched_size, use_mmap, use_tsched, + query_supported_formats, + query_supported_rates, m); if (pcm_handle) { @@ -612,6 +618,8 @@ snd_pcm_t *pa_alsa_open_by_device_id_auto( tsched_size, use_mmap, use_tsched, + query_supported_formats, + query_supported_rates, false); pa_xfree(d); @@ -632,6 +640,8 @@ snd_pcm_t *pa_alsa_open_by_device_id_mapping( snd_pcm_uframes_t tsched_size, bool *use_mmap, bool *use_tsched, + pa_sample_format_t **query_supported_formats, + unsigned int **query_supported_rates, pa_alsa_mapping *m) { snd_pcm_t *pcm_handle; @@ -661,6 +671,8 @@ snd_pcm_t *pa_alsa_open_by_device_id_mapping( tsched_size, use_mmap, use_tsched, + query_supported_formats, + query_supported_rates, pa_channel_map_valid(&m->channel_map) /* Query the channel count if we don't know what we want */); if (!pcm_handle) @@ -684,6 +696,8 @@ snd_pcm_t *pa_alsa_open_by_device_string( snd_pcm_uframes_t tsched_size, bool *use_mmap, bool *use_tsched, + pa_sample_format_t **query_supported_formats, + unsigned int **query_supported_rates, bool require_exact_channel_number) { int err; @@ -711,6 +725,12 @@ snd_pcm_t *pa_alsa_open_by_device_string( pa_log_debug("Managed to open %s", d); + if (query_supported_formats) + *query_supported_formats = pa_alsa_get_supported_formats(pcm_handle, ss->format); + + if (query_supported_rates) + *query_supported_rates = pa_alsa_get_supported_rates(pcm_handle, ss->rate); + if ((err = pa_alsa_set_hw_params( pcm_handle, ss, @@ -784,6 +804,8 @@ snd_pcm_t *pa_alsa_open_by_template( snd_pcm_uframes_t tsched_size, bool *use_mmap, bool *use_tsched, + pa_sample_format_t **query_supported_formats, + unsigned int **query_supported_rates, bool require_exact_channel_number) { snd_pcm_t *pcm_handle; @@ -805,6 +827,8 @@ snd_pcm_t *pa_alsa_open_by_template( tsched_size, use_mmap, use_tsched, + query_supported_formats, + query_supported_rates, require_exact_channel_number); pa_xfree(d); diff --git a/src/modules/alsa/alsa-util.h b/src/modules/alsa/alsa-util.h index 2eed3eac3..c65801104 100644 --- a/src/modules/alsa/alsa-util.h +++ b/src/modules/alsa/alsa-util.h @@ -67,6 +67,8 @@ snd_pcm_t *pa_alsa_open_by_device_id_auto( snd_pcm_uframes_t tsched_size, bool *use_mmap, /* modified at return */ bool *use_tsched, /* modified at return */ + pa_sample_format_t **query_supported_formats, /* modified at return */ + unsigned int **query_supported_rates, /* modified at return */ pa_alsa_profile_set *ps, pa_alsa_mapping **mapping); /* modified at return */ @@ -82,6 +84,8 @@ snd_pcm_t *pa_alsa_open_by_device_id_mapping( snd_pcm_uframes_t tsched_size, bool *use_mmap, /* modified at return */ bool *use_tsched, /* modified at return */ + pa_sample_format_t **query_supported_formats, /* modified at return */ + unsigned int **query_supported_rates, /* modified at return */ pa_alsa_mapping *mapping); /* Opens the explicit ALSA device */ @@ -96,6 +100,8 @@ snd_pcm_t *pa_alsa_open_by_device_string( snd_pcm_uframes_t tsched_size, bool *use_mmap, /* modified at return */ bool *use_tsched, /* modified at return */ + pa_sample_format_t **query_supported_formats, /* modified at return */ + unsigned int **query_supported_rates, /* modified at return */ bool require_exact_channel_number); /* Opens the explicit ALSA device with a fallback list */ @@ -111,6 +117,8 @@ snd_pcm_t *pa_alsa_open_by_template( snd_pcm_uframes_t tsched_size, bool *use_mmap, /* modified at return */ bool *use_tsched, /* modified at return */ + pa_sample_format_t **query_supported_formats, /* modified at return */ + unsigned int **query_supported_rates, /* modified at return */ bool require_exact_channel_number); void pa_alsa_dump(pa_log_level_t level, snd_pcm_t *pcm); -- cgit v1.2.1