pa_cvolume hardware_volume;
+ unsigned int *rates;
+
size_t
frame_size,
fragment_size,
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);
* 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;
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;
}
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);
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);
pa_cvolume hardware_volume;
+ unsigned int *rates;
+
size_t
frame_size,
fragment_size,
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;
}
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);
if (u->smoother)
pa_smoother_free(u->smoother);
+ if (u->rates)
+ pa_xfree(u->rates);
+
reserve_done(u);
monitor_done(u);
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);
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);