There has been a function to get supported sample rates from alsa and an array for it in userdata of each module-alsa-sink/source. Similarly, this patch adds a function to get supported sample formats(bit depth) from alsa and an array for it to each userdata of the modules. Signed-off-by: Sangchul Lee <sc11.lee at samsung.com> --- src/modules/alsa/alsa-sink.c | 10 ++++++ src/modules/alsa/alsa-source.c | 10 ++++++ src/modules/alsa/alsa-util.c | 78 ++++++++++++++++++++++++++++++++++++++++++ src/modules/alsa/alsa-util.h | 1 + 4 files changed, 99 insertions(+) diff --git a/src/modules/alsa/alsa-sink.c b/src/modules/alsa/alsa-sink.c index 871c829..cf07393 100644 --- a/src/modules/alsa/alsa-sink.c +++ b/src/modules/alsa/alsa-sink.c @@ -111,6 +111,7 @@ struct userdata { pa_cvolume hardware_volume; + pa_sample_format_t *supported_formats; unsigned int *rates; size_t @@ -2349,6 +2350,12 @@ pa_sink *pa_alsa_sink_new(pa_module *m, pa_modargs *ma, const char*driver, pa_ca if ((is_iec958(u) || is_hdmi(u)) && ss.channels == 2) set_formats = true; + 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->rates = pa_alsa_get_supported_rates(u->pcm_handle, ss.rate); if (!u->rates) { pa_log_error("Failed to find any supported sample rates."); @@ -2629,6 +2636,9 @@ static void userdata_free(struct userdata *u) { if (u->formats) pa_idxset_free(u->formats, (pa_free_cb_t) pa_format_info_free); + if (u->supported_formats) + pa_xfree(u->supported_formats); + if (u->rates) pa_xfree(u->rates); diff --git a/src/modules/alsa/alsa-source.c b/src/modules/alsa/alsa-source.c index c32e7e9..cf8644b 100644 --- a/src/modules/alsa/alsa-source.c +++ b/src/modules/alsa/alsa-source.c @@ -99,6 +99,7 @@ struct userdata { pa_cvolume hardware_volume; + pa_sample_format_t *supported_formats; unsigned int *rates; size_t @@ -2025,6 +2026,12 @@ pa_source *pa_alsa_source_new(pa_module *m, pa_modargs *ma, const char*driver, p pa_log_info("Disabling latency range changes on overrun"); } + 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->rates = pa_alsa_get_supported_rates(u->pcm_handle, ss.rate); if (!u->rates) { pa_log_error("Failed to find any supported sample rates."); @@ -2259,6 +2266,9 @@ static void userdata_free(struct userdata *u) { if (u->smoother) pa_smoother_free(u->smoother); + if (u->supported_formats) + pa_xfree(u->supported_formats); + if (u->rates) pa_xfree(u->rates); diff --git a/src/modules/alsa/alsa-util.c b/src/modules/alsa/alsa-util.c index 41134ea..3f50aac 100644 --- a/src/modules/alsa/alsa-util.c +++ b/src/modules/alsa/alsa-util.c @@ -1430,6 +1430,84 @@ unsigned int *pa_alsa_get_supported_rates(snd_pcm_t *pcm, unsigned int fallback_ return rates; } +pa_sample_format_t *pa_alsa_get_supported_formats(snd_pcm_t *pcm, pa_sample_format_t fallback_format) { + static const snd_pcm_format_t format_trans_to_pa[] = { + [SND_PCM_FORMAT_U8] = PA_SAMPLE_U8, + [SND_PCM_FORMAT_A_LAW] = PA_SAMPLE_ALAW, + [SND_PCM_FORMAT_MU_LAW] = PA_SAMPLE_ULAW, + [SND_PCM_FORMAT_S16_LE] = PA_SAMPLE_S16LE, + [SND_PCM_FORMAT_S16_BE] = PA_SAMPLE_S16BE, + [SND_PCM_FORMAT_FLOAT_LE] = PA_SAMPLE_FLOAT32LE, + [SND_PCM_FORMAT_FLOAT_BE] = PA_SAMPLE_FLOAT32BE, + [SND_PCM_FORMAT_S32_LE] = PA_SAMPLE_S32LE, + [SND_PCM_FORMAT_S32_BE] = PA_SAMPLE_S32BE, + [SND_PCM_FORMAT_S24_3LE] = PA_SAMPLE_S24LE, + [SND_PCM_FORMAT_S24_3BE] = PA_SAMPLE_S24BE, + [SND_PCM_FORMAT_S24_LE] = PA_SAMPLE_S24_32LE, + [SND_PCM_FORMAT_S24_BE] = PA_SAMPLE_S24_32BE, + }; + static snd_pcm_format_t all_formats[] = { + SND_PCM_FORMAT_U8, + SND_PCM_FORMAT_A_LAW, + SND_PCM_FORMAT_MU_LAW, + SND_PCM_FORMAT_S16_LE, + SND_PCM_FORMAT_S16_BE, + SND_PCM_FORMAT_FLOAT_LE, + SND_PCM_FORMAT_FLOAT_BE, + SND_PCM_FORMAT_S32_LE, + SND_PCM_FORMAT_S32_BE, + SND_PCM_FORMAT_S24_3LE, + SND_PCM_FORMAT_S24_3BE, + SND_PCM_FORMAT_S24_LE, + SND_PCM_FORMAT_S24_BE, + }; + bool supported[PA_ELEMENTSOF(all_formats)] = { + false, + }; + snd_pcm_hw_params_t *hwparams; + unsigned int i, j, n; + pa_sample_format_t *formats = NULL; + int ret; + + snd_pcm_hw_params_alloca(&hwparams); + + if ((ret = snd_pcm_hw_params_any(pcm, hwparams)) < 0) { + pa_log_debug("snd_pcm_hw_params_any() failed: %s", pa_alsa_strerror(ret)); + return NULL; + } + + for (i = 0, n = 0; i < PA_ELEMENTSOF(all_formats); i++) { + if (snd_pcm_hw_params_test_format(pcm, hwparams, all_formats[i]) == 0) { + supported[i] = true; + n++; + } + } + + if (n > 0) { + formats = pa_xnew(pa_sample_format_t, n + 1); + + for (i = 0, j = 0; i < PA_ELEMENTSOF(all_formats); i++) { + if (supported[i]) + formats[j++] = format_trans_to_pa[all_formats[i]]; + } + + formats[j] = PA_SAMPLE_MAX; + } else { + formats = pa_xnew(pa_sample_format_t, 2); + + formats[0] = fallback_format; + if ((ret = snd_pcm_hw_params_set_format(pcm, hwparams, format_trans_to_pa[formats[0]])) < 0) { + pa_log_debug("snd_pcm_hw_params_set_format() failed: %s", pa_alsa_strerror(ret)); + pa_xfree(formats); + return NULL; + } + + formats[1] = PA_SAMPLE_MAX; + } + + return formats; +} + bool pa_alsa_pcm_is_hw(snd_pcm_t *pcm) { snd_pcm_info_t* info; snd_pcm_info_alloca(&info); diff --git a/src/modules/alsa/alsa-util.h b/src/modules/alsa/alsa-util.h index 8345a0b..6b27339 100644 --- a/src/modules/alsa/alsa-util.h +++ b/src/modules/alsa/alsa-util.h @@ -132,6 +132,7 @@ char *pa_alsa_get_driver_name_by_pcm(snd_pcm_t *pcm); char *pa_alsa_get_reserve_name(const char *device); unsigned int *pa_alsa_get_supported_rates(snd_pcm_t *pcm, unsigned int fallback_rate); +pa_sample_format_t *pa_alsa_get_supported_formats(snd_pcm_t *pcm, pa_sample_format_t fallback_format); bool pa_alsa_pcm_is_hw(snd_pcm_t *pcm); bool pa_alsa_pcm_is_modem(snd_pcm_t *pcm); -- 2.7.4