From: Arun Raghavan Date: Mon, 17 Oct 2011 17:16:06 +0000 (+0530) Subject: alsa: Probe sink/source sample rates X-Git-Tag: 1.0_branch~287 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=e67440e2208fb8182916493b57b75e91013510e7;p=profile%2Fivi%2Fpulseaudio.git alsa: Probe sink/source sample rates This probes sink and source sample rates and uses this information to validate rate changes and check incoming passthrough formats. --- diff --git a/src/modules/alsa/alsa-sink.c b/src/modules/alsa/alsa-sink.c index e77b331..7b31b1b 100644 --- a/src/modules/alsa/alsa-sink.c +++ b/src/modules/alsa/alsa-sink.c @@ -109,6 +109,8 @@ struct userdata { pa_cvolume hardware_volume; + unsigned int *rates; + size_t frame_size, fragment_size, @@ -1509,8 +1511,8 @@ static pa_idxset* sink_get_formats(pa_sink *s) { static pa_bool_t sink_set_formats(pa_sink *s, pa_idxset *formats) { struct userdata *u = s->userdata; - pa_format_info *f; - uint32_t idx; + pa_format_info *f, *g; + uint32_t idx, n; pa_assert(u); @@ -1528,16 +1530,26 @@ static pa_bool_t sink_set_formats(pa_sink *s, pa_idxset *formats) { * This is fine for now since we don't support that via the passthrough * framework, but this must be changed if we do. */ + /* Count how many sample rates we support */ + for (idx = 0, n = 0; u->rates[idx]; idx++) + n++; + /* First insert non-PCM formats since we prefer those. */ PA_IDXSET_FOREACH(f, formats, idx) { - if (!pa_format_info_is_pcm(f)) - pa_idxset_put(u->formats, pa_format_info_copy(f), NULL); + if (!pa_format_info_is_pcm(f)) { + g = pa_format_info_copy(f); + pa_format_info_set_prop_int_array(g, PA_PROP_FORMAT_RATE, (int *) u->rates, n); + pa_idxset_put(u->formats, g, NULL); + } } /* Now add any PCM formats */ PA_IDXSET_FOREACH(f, formats, idx) { - if (pa_format_info_is_pcm(f)) + if (pa_format_info_is_pcm(f)) { + /* We don't set rates here since we'll just tack on a resampler for + * unsupported rates */ pa_idxset_put(u->formats, pa_format_info_copy(f), NULL); + } } return TRUE; @@ -1546,13 +1558,29 @@ static pa_bool_t sink_set_formats(pa_sink *s, pa_idxset *formats) { static pa_bool_t sink_update_rate_cb(pa_sink *s, uint32_t rate) { struct userdata *u = s->userdata; + int i; + pa_bool_t supported = FALSE; + pa_assert(u); + for (i = 0; u->rates[i]; i++) { + if (u->rates[i] == rate) { + supported = TRUE; + break; + } + } + + if (!supported) { + pa_log_info("Sink does not support sample rate of %d Hz", rate); + return FALSE; + } + if (!PA_SINK_IS_OPENED(s->state)) { pa_log_info("Updating rate for device %s, new rate is %d",u->device_name, rate); u->sink->sample_spec.rate = rate; return TRUE; } + return FALSE; } @@ -2121,6 +2149,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)) set_formats = TRUE; + u->rates = pa_alsa_get_supported_rates(u->pcm_handle); + if (!u->rates) { + pa_log_error("Failed to find any supported sample rates."); + goto fail; + } + /* ALSA might tweak the sample spec, so recalculate the frame size */ frame_size = pa_frame_size(&ss); @@ -2350,6 +2384,9 @@ static void userdata_free(struct userdata *u) { if (u->formats) pa_idxset_free(u->formats, (pa_free2_cb_t) pa_format_info_free2, NULL); + if (u->rates) + pa_xfree(u->rates); + reserve_done(u); monitor_done(u); diff --git a/src/modules/alsa/alsa-source.c b/src/modules/alsa/alsa-source.c index 180baca..7a51572 100644 --- a/src/modules/alsa/alsa-source.c +++ b/src/modules/alsa/alsa-source.c @@ -99,6 +99,8 @@ struct userdata { pa_cvolume hardware_volume; + unsigned int *rates; + size_t frame_size, fragment_size, @@ -1385,13 +1387,29 @@ static void source_update_requested_latency_cb(pa_source *s) { static pa_bool_t source_update_rate_cb(pa_source *s, uint32_t rate) { struct userdata *u = s->userdata; + int i; + pa_bool_t supported = FALSE; + pa_assert(u); + for (i = 0; u->rates[i]; i++) { + if (u->rates[i] == rate) { + supported = TRUE; + break; + } + } + + if (!supported) { + pa_log_info("Sink does not support sample rate of %d Hz", rate); + return FALSE; + } + if (!PA_SOURCE_IS_OPENED(s->state)) { pa_log_info("Updating rate for device %s, new rate is %d", u->device_name, rate); u->source->sample_spec.rate = rate; return TRUE; } + return FALSE; } @@ -1862,6 +1880,12 @@ pa_source *pa_alsa_source_new(pa_module *m, pa_modargs *ma, const char*driver, p if (u->use_tsched) pa_log_info("Successfully enabled timer-based scheduling mode."); + u->rates = pa_alsa_get_supported_rates(u->pcm_handle); + if (!u->rates) { + pa_log_error("Failed to find any supported sample rates."); + goto fail; + } + /* ALSA might tweak the sample spec, so recalculate the frame size */ frame_size = pa_frame_size(&ss); @@ -2062,6 +2086,9 @@ static void userdata_free(struct userdata *u) { if (u->smoother) pa_smoother_free(u->smoother); + if (u->rates) + pa_xfree(u->rates); + reserve_done(u); monitor_done(u); diff --git a/src/modules/alsa/alsa-util.c b/src/modules/alsa/alsa-util.c index 602e9a3..b9de050 100644 --- a/src/modules/alsa/alsa-util.c +++ b/src/modules/alsa/alsa-util.c @@ -1327,6 +1327,42 @@ char *pa_alsa_get_reserve_name(const char *device) { return pa_sprintf_malloc("Audio%i", i); } +unsigned int *pa_alsa_get_supported_rates(snd_pcm_t *pcm) { + static unsigned int all_rates[] = { 8000, 11025, 16000, 22050, 32000, 44100, 48000, 88200, 96000, 176400, 192000, 384000 }; + pa_bool_t supported[PA_ELEMENTSOF(all_rates)] = { FALSE, }; + snd_pcm_hw_params_t *hwparams; + unsigned int i, j, n, *rates = 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_rates); i++) { + if (snd_pcm_hw_params_test_rate(pcm, hwparams, all_rates[i], 0) == 0) { + supported[i] = TRUE; + n++; + } + } + + if (n == 0) + return NULL; + + rates = pa_xnew(unsigned int, n + 1); + + for (i = 0, j = 0; i < PA_ELEMENTSOF(all_rates); i++) { + if (supported[i]) + rates[j++] = all_rates[i]; + } + + rates[j] = 0; + + return rates; +} + pa_bool_t 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 ee5e781..f8d0518 100644 --- a/src/modules/alsa/alsa-util.h +++ b/src/modules/alsa/alsa-util.h @@ -133,6 +133,8 @@ 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); + pa_bool_t pa_alsa_pcm_is_hw(snd_pcm_t *pcm); pa_bool_t pa_alsa_pcm_is_modem(snd_pcm_t *pcm);