[pulseaudio-commits] 10 commits - man/pulse-daemon.conf.5.xml.in src/daemon src/Makefile.am src/modules src/pulse src/pulsecore
Arun Raghavan
arun at kemper.freedesktop.org
Mon Oct 17 21:00:37 PDT 2011
man/pulse-daemon.conf.5.xml.in | 10 ++
src/Makefile.am | 2
src/daemon/daemon-conf.c | 25 ++++++-
src/daemon/daemon-conf.h | 1
src/daemon/daemon.conf.in | 1
src/daemon/main.c | 1
src/modules/alsa/alsa-sink.c | 120 ++++++++++++++++++----------------
src/modules/alsa/alsa-source.c | 50 ++++++++++++++
src/modules/alsa/alsa-util.c | 41 +++++++++++
src/modules/alsa/alsa-util.h | 2
src/modules/alsa/module-alsa-sink.c | 2
src/modules/alsa/module-alsa-source.c | 2
src/modules/dbus/iface-core.c | 45 ++++++++++++
src/pulse/def.h | 10 ++
src/pulsecore/core.h | 1
src/pulsecore/modargs.c | 13 +++
src/pulsecore/modargs.h | 3
src/pulsecore/sink-input.c | 28 +++++++
src/pulsecore/sink.c | 88 ++++++++++++++++++++++++
src/pulsecore/sink.h | 11 +++
src/pulsecore/source-output.c | 28 +++++++
src/pulsecore/source.c | 77 +++++++++++++++++++++
src/pulsecore/source.h | 10 ++
23 files changed, 513 insertions(+), 58 deletions(-)
New commits:
commit 72377fcad50a8b3917ba086f9d3d62670b53b87f
Author: Pierre-Louis Bossart <pierre-louis.bossart at linux.intel.com>
Date: Mon Oct 17 14:43:50 2011 -0500
alsa: fix list of sampling rates
add all standard audio rates
Signed-off-by: Pierre-Louis Bossart <pierre-louis.bossart at linux.intel.com>
diff --git a/src/modules/alsa/alsa-util.c b/src/modules/alsa/alsa-util.c
index b9de050..f054178 100644
--- a/src/modules/alsa/alsa-util.c
+++ b/src/modules/alsa/alsa-util.c
@@ -1328,7 +1328,12 @@ char *pa_alsa_get_reserve_name(const char *device) {
}
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 };
+ static unsigned int all_rates[] = { 8000, 11025, 12000,
+ 16000, 22050, 24000,
+ 32000, 44100, 48000,
+ 64000, 88200, 96000,
+ 128000, 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;
commit e67440e2208fb8182916493b57b75e91013510e7
Author: Arun Raghavan <arun.raghavan at collabora.co.uk>
Date: Mon Oct 17 22:46:06 2011 +0530
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);
commit 3555634e6eeee593fb736d9ba8cd34d25526319c
Author: Arun Raghavan <arun.raghavan at collabora.co.uk>
Date: Mon Oct 17 21:16:23 2011 +0530
alsa: Remove unused variable
diff --git a/src/modules/alsa/alsa-sink.c b/src/modules/alsa/alsa-sink.c
index 8ce4ed7..e77b331 100644
--- a/src/modules/alsa/alsa-sink.c
+++ b/src/modules/alsa/alsa-sink.c
@@ -109,8 +109,6 @@ struct userdata {
pa_cvolume hardware_volume;
- uint32_t old_rate;
-
size_t
frame_size,
fragment_size,
commit 59d058dea4600f0987202e0ef4b50ab925f756d7
Author: Arun Raghavan <arun.raghavan at collabora.co.uk>
Date: Mon Oct 17 20:03:52 2011 +0530
sink,source: Handle equal default and alternate sample rates
diff --git a/src/pulsecore/sink.c b/src/pulsecore/sink.c
index f3b78a5..5ca2453 100644
--- a/src/pulsecore/sink.c
+++ b/src/pulsecore/sink.c
@@ -285,11 +285,17 @@ pa_sink* pa_sink_new(
s->sample_spec = data->sample_spec;
s->channel_map = data->channel_map;
+ s->default_sample_rate = s->sample_spec.rate;
+
if (data->alternate_sample_rate_is_set)
s->alternate_sample_rate = data->alternate_sample_rate;
else
s->alternate_sample_rate = s->core->alternate_sample_rate;
- s->default_sample_rate = s->sample_spec.rate;
+
+ if (s->sample_spec.rate == s->alternate_sample_rate) {
+ pa_log_warn("Default and alternate sample rates are the same.");
+ s->alternate_sample_rate = 0;
+ }
s->inputs = pa_idxset_new(NULL, NULL);
s->n_corked = 0;
@@ -1335,6 +1341,11 @@ pa_bool_t pa_sink_update_rate(pa_sink *s, uint32_t rate, pa_bool_t passthrough)
uint32_t alternate_rate = s->alternate_sample_rate;
pa_bool_t use_alternate = FALSE;
+ if (PA_UNLIKELY(default_rate == alternate_rate)) {
+ pa_log_warn("Default and alternate sample rates are the same.");
+ return FALSE;
+ }
+
if (PA_SINK_IS_RUNNING(s->state)) {
pa_log_info("Cannot update rate, SINK_IS_RUNNING, will keep using %u kHz",
s->sample_spec.rate);
diff --git a/src/pulsecore/source.c b/src/pulsecore/source.c
index 444d587..e70e446 100644
--- a/src/pulsecore/source.c
+++ b/src/pulsecore/source.c
@@ -251,11 +251,17 @@ pa_source* pa_source_new(
s->sample_spec = data->sample_spec;
s->channel_map = data->channel_map;
+ s->default_sample_rate = s->sample_spec.rate;
+
if (data->alternate_sample_rate_is_set)
s->alternate_sample_rate = data->alternate_sample_rate;
else
s->alternate_sample_rate = s->core->alternate_sample_rate;
- s->default_sample_rate = s->sample_spec.rate;
+
+ if (s->sample_spec.rate == s->alternate_sample_rate) {
+ pa_log_warn("Default and alternate sample rates are the same.");
+ s->alternate_sample_rate = 0;
+ }
s->outputs = pa_idxset_new(NULL, NULL);
s->n_corked = 0;
@@ -929,6 +935,11 @@ pa_bool_t pa_source_update_rate(pa_source *s, uint32_t rate, pa_bool_t passthrou
uint32_t alternate_rate = s->alternate_sample_rate;
pa_bool_t use_alternate = FALSE;
+ if (PA_UNLIKELY(default_rate == alternate_rate)) {
+ pa_log_warn("Default and alternate sample rates are the same.");
+ return FALSE;
+ }
+
if (PA_SOURCE_IS_RUNNING(s->state)) {
pa_log_info("Cannot update rate, SOURCE_IS_RUNNING, will keep using %u kHz",
s->sample_spec.rate);
commit ac469a25c04c206c2483159b07deaa9b7c9d5f7c
Author: Arun Raghavan <arun.raghavan at collabora.co.uk>
Date: Mon Oct 17 20:01:03 2011 +0530
sink,source: Add the ability to disable alternat sample rate switching
Setting the alternate sample rate to 0 in config disables this feature.
diff --git a/man/pulse-daemon.conf.5.xml.in b/man/pulse-daemon.conf.5.xml.in
index 33ea792..2c42f8c 100644
--- a/man/pulse-daemon.conf.5.xml.in
+++ b/man/pulse-daemon.conf.5.xml.in
@@ -420,7 +420,8 @@ USA.
default-rate-rate value or this alternate value, typically 44.1
or 48kHz. Switching between default and alternate values is
enabled only when the sinks/sources are suspended. This option
- is ignored in passthrough mode where the stream rate will be used.</p>
+ is ignored in passthrough mode where the stream rate will be used.
+ If set to zero, this feature is disabled.</p>
</option>
</section>
diff --git a/src/modules/alsa/alsa-sink.c b/src/modules/alsa/alsa-sink.c
index 0b7bbe0..8ce4ed7 100644
--- a/src/modules/alsa/alsa-sink.c
+++ b/src/modules/alsa/alsa-sink.c
@@ -2201,7 +2201,8 @@ pa_sink *pa_alsa_sink_new(pa_module *m, pa_modargs *ma, const char*driver, pa_ca
u->sink->update_requested_latency = sink_update_requested_latency_cb;
u->sink->set_state = sink_set_state_cb;
u->sink->set_port = sink_set_port_cb;
- u->sink->update_rate = sink_update_rate_cb;
+ if (u->sink->alternate_sample_rate)
+ u->sink->update_rate = sink_update_rate_cb;
u->sink->userdata = u;
pa_sink_set_asyncmsgq(u->sink, u->thread_mq.inq);
diff --git a/src/modules/alsa/alsa-source.c b/src/modules/alsa/alsa-source.c
index c279429..180baca 100644
--- a/src/modules/alsa/alsa-source.c
+++ b/src/modules/alsa/alsa-source.c
@@ -1939,7 +1939,8 @@ pa_source *pa_alsa_source_new(pa_module *m, pa_modargs *ma, const char*driver, p
u->source->update_requested_latency = source_update_requested_latency_cb;
u->source->set_state = source_set_state_cb;
u->source->set_port = source_set_port_cb;
- u->source->update_rate = source_update_rate_cb;
+ if (u->source->alternate_sample_rate)
+ u->source->update_rate = source_update_rate_cb;
u->source->userdata = u;
pa_source_set_asyncmsgq(u->source, u->thread_mq.inq);
commit b9ff90fef856be80a299b7ce41ab8cebfe3c6bc5
Author: Arun Raghavan <arun.raghavan at collabora.co.uk>
Date: Tue Oct 11 00:47:56 2011 +0530
source: Bring rate update code in sync with sink code
Basically adds code to handle passthrough sources. This isn't a tested
path at the moment, but in the future, when we do wish to support these,
it'll save us the trouble of having to sync all the code again.
diff --git a/src/pulsecore/sink.c b/src/pulsecore/sink.c
index 6b5a385..f3b78a5 100644
--- a/src/pulsecore/sink.c
+++ b/src/pulsecore/sink.c
@@ -1380,8 +1380,8 @@ pa_bool_t pa_sink_update_rate(pa_sink *s, uint32_t rate, pa_bool_t passthrough)
if (s->update_rate(s, desired_rate) == TRUE) {
/* update monitor source as well */
- if (s->monitor_source)
- pa_source_update_rate(s->monitor_source, desired_rate);
+ if (s->monitor_source && !passthrough)
+ pa_source_update_rate(s->monitor_source, desired_rate, FALSE);
pa_log_info("Changed sampling rate successfully");
return TRUE;
}
diff --git a/src/pulsecore/source-output.c b/src/pulsecore/source-output.c
index 46a95a7..21e8da9 100644
--- a/src/pulsecore/source-output.c
+++ b/src/pulsecore/source-output.c
@@ -354,7 +354,11 @@ int pa_source_output_new(
module-suspend-on-idle can resume a source */
pa_log_info("Trying to change sample rate");
- pa_source_update_rate(data->source, data->sample_spec.rate);
+ if (pa_source_update_rate(data->source, data->sample_spec.rate, pa_source_output_new_data_is_passthrough(data)) == TRUE)
+ pa_log_info("Rate changed to %u kHz",
+ data->source->sample_spec.rate);
+ else
+ pa_log_info("Resampling enabled to %u kHz", data->source->sample_spec.rate);
}
if (data->resample_method == PA_RESAMPLER_INVALID)
@@ -1401,7 +1405,7 @@ int pa_source_output_finish_move(pa_source_output *o, pa_source *dest, pa_bool_t
SOURCE_OUTPUT_MOVE_FINISH hook */
pa_log_info("Trying to change sample rate");
- if (pa_source_update_rate(dest, o->sample_spec.rate) == TRUE)
+ if (pa_source_update_rate(dest, o->sample_spec.rate, pa_source_output_is_passthrough(o)) == TRUE)
pa_log_info("Rate changed to %u kHz",
dest->sample_spec.rate);
else
diff --git a/src/pulsecore/source.c b/src/pulsecore/source.c
index 508fb4a..444d587 100644
--- a/src/pulsecore/source.c
+++ b/src/pulsecore/source.c
@@ -921,9 +921,8 @@ void pa_source_post_direct(pa_source*s, pa_source_output *o, const pa_memchunk *
}
/* Called from main thread */
-pa_bool_t pa_source_update_rate(pa_source *s, uint32_t rate)
+pa_bool_t pa_source_update_rate(pa_source *s, uint32_t rate, pa_bool_t passthrough)
{
-
if (s->update_rate) {
uint32_t desired_rate = rate;
uint32_t default_rate = s->default_sample_rate;
@@ -933,30 +932,38 @@ pa_bool_t pa_source_update_rate(pa_source *s, uint32_t rate)
if (PA_SOURCE_IS_RUNNING(s->state)) {
pa_log_info("Cannot update rate, SOURCE_IS_RUNNING, will keep using %u kHz",
s->sample_spec.rate);
- return FALSE; /* cannot reconfigure a RUNNING source without glitches */
+ return FALSE;
}
if (PA_UNLIKELY (desired_rate < 8000 ||
desired_rate > PA_RATE_MAX))
return FALSE;
- pa_assert(default_rate % 4000 || default_rate % 11025);
- pa_assert(alternate_rate % 4000 || alternate_rate % 11025);
+ if (!passthrough) {
+ pa_assert(default_rate % 4000 || default_rate % 11025);
+ pa_assert(alternate_rate % 4000 || alternate_rate % 11025);
+
+ if (default_rate % 4000) {
+ /* default is a 11025 multiple */
+ if ((alternate_rate % 4000 == 0) && (desired_rate % 4000 == 0))
+ use_alternate=TRUE;
+ } else {
+ /* default is 4000 multiple */
+ if ((alternate_rate % 11025 == 0) && (desired_rate % 11025 == 0))
+ use_alternate=TRUE;
+ }
- if (default_rate % 4000) {
- /* default is a 11025 multiple */
- if ((alternate_rate % 4000 == 0) && (desired_rate % 4000 == 0))
- use_alternate=TRUE;
+ if (use_alternate)
+ desired_rate = alternate_rate;
+ else
+ desired_rate = default_rate;
} else {
- /* default is 4000 multiple */
- if ((alternate_rate % 11025 == 0) && (desired_rate % 11025 == 0))
- use_alternate=TRUE;
+ desired_rate = rate; /* use stream sampling rate, discard default/alternate settings */
}
- if (use_alternate)
- desired_rate = alternate_rate;
- else
- desired_rate = default_rate;
+ if (passthrough || pa_source_used_by(s) == 0) {
+ pa_source_suspend(s, TRUE, PA_SUSPEND_IDLE); /* needed before rate update, will be resumed automatically */
+ }
if (s->update_rate(s, desired_rate) == TRUE) {
pa_log_info("Changed sampling rate successfully ");
diff --git a/src/pulsecore/source.h b/src/pulsecore/source.h
index 8adc5f1..c5cfb39 100644
--- a/src/pulsecore/source.h
+++ b/src/pulsecore/source.h
@@ -367,7 +367,7 @@ pa_bool_t pa_source_get_mute(pa_source *source, pa_bool_t force_refresh);
pa_bool_t pa_source_update_proplist(pa_source *s, pa_update_mode_t mode, pa_proplist *p);
int pa_source_set_port(pa_source *s, const char *name, pa_bool_t save);
-pa_bool_t pa_source_update_rate(pa_source *s, uint32_t rate);
+pa_bool_t pa_source_update_rate(pa_source *s, uint32_t rate, pa_bool_t passthrough);
unsigned pa_source_linked_by(pa_source *s); /* Number of connected streams */
unsigned pa_source_used_by(pa_source *s); /* Number of connected streams that are not corked */
commit b232fbd8f8afa5881d483e2fa72e06206f1da861
Author: Pierre-Louis Bossart <pierre-louis.bossart at linux.intel.com>
Date: Tue Aug 2 18:37:29 2011 -0500
alsa: support for alternate sampling rate
This is where the actual changes happen.
Some additional checks would be required to make sure the
rate is actually supported
Tested with both PCM and passthrough streams
Signed-off-by: Pierre-Louis Bossart <pierre-louis.bossart at linux.intel.com>
diff --git a/src/modules/alsa/alsa-sink.c b/src/modules/alsa/alsa-sink.c
index bcc6e51..0b7bbe0 100644
--- a/src/modules/alsa/alsa-sink.c
+++ b/src/modules/alsa/alsa-sink.c
@@ -1121,56 +1121,6 @@ static int sink_process_msg(pa_msgobject *o, int code, void *data, int64_t offse
switch (code) {
- case PA_SINK_MESSAGE_FINISH_MOVE:
- case PA_SINK_MESSAGE_ADD_INPUT: {
- pa_sink_input *i = PA_SINK_INPUT(data);
- int r = 0;
-
- if (PA_LIKELY(!pa_sink_input_is_passthrough(i)))
- break;
-
- u->old_rate = u->sink->sample_spec.rate;
-
- /* Passthrough format, see if we need to reset sink sample rate */
- if (u->sink->sample_spec.rate == i->thread_info.sample_spec.rate)
- break;
-
- /* .. we do */
- if ((r = suspend(u)) < 0)
- return r;
-
- u->sink->sample_spec.rate = i->thread_info.sample_spec.rate;
-
- if ((r = unsuspend(u)) < 0)
- return r;
-
- break;
- }
-
- case PA_SINK_MESSAGE_START_MOVE:
- case PA_SINK_MESSAGE_REMOVE_INPUT: {
- pa_sink_input *i = PA_SINK_INPUT(data);
- int r = 0;
-
- if (PA_LIKELY(!pa_sink_input_is_passthrough(i)))
- break;
-
- /* Passthrough format, see if we need to reset sink sample rate */
- if (u->sink->sample_spec.rate == u->old_rate)
- break;
-
- /* .. we do */
- if (PA_SINK_IS_OPENED(u->sink->thread_info.state) && ((r = suspend(u)) < 0))
- return r;
-
- u->sink->sample_spec.rate = u->old_rate;
-
- if (PA_SINK_IS_OPENED(u->sink->thread_info.state) && ((r = unsuspend(u)) < 0))
- return r;
-
- break;
- }
-
case PA_SINK_MESSAGE_GET_LATENCY: {
pa_usec_t r = 0;
@@ -1595,6 +1545,19 @@ static pa_bool_t sink_set_formats(pa_sink *s, pa_idxset *formats) {
return TRUE;
}
+static pa_bool_t sink_update_rate_cb(pa_sink *s, uint32_t rate)
+{
+ struct userdata *u = s->userdata;
+ pa_assert(u);
+
+ 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;
+}
+
static int process_rewind(struct userdata *u) {
snd_pcm_sframes_t unused;
size_t rewind_nbytes, unused_nbytes, limit_nbytes;
@@ -1975,6 +1938,7 @@ pa_sink *pa_alsa_sink_new(pa_module *m, pa_modargs *ma, const char*driver, pa_ca
struct userdata *u = NULL;
const char *dev_id = NULL;
pa_sample_spec ss;
+ uint32_t alternate_sample_rate;
pa_channel_map map;
uint32_t nfrags, frag_size, buffer_size, tsched_size, tsched_watermark, rewind_safeguard;
snd_pcm_uframes_t period_frames, buffer_frames, tsched_frames;
@@ -1993,6 +1957,12 @@ pa_sink *pa_alsa_sink_new(pa_module *m, pa_modargs *ma, const char*driver, pa_ca
goto fail;
}
+ alternate_sample_rate = m->core->alternate_sample_rate;
+ if (pa_modargs_get_alternate_sample_rate(ma, &alternate_sample_rate) < 0) {
+ pa_log("Failed to parse alternate sample rate");
+ goto fail;
+ }
+
frame_size = pa_frame_size(&ss);
nfrags = m->core->default_n_fragments;
@@ -2178,6 +2148,7 @@ pa_sink *pa_alsa_sink_new(pa_module *m, pa_modargs *ma, const char*driver, pa_ca
pa_sink_new_data_set_sample_spec(&data, &ss);
pa_sink_new_data_set_channel_map(&data, &map);
+ pa_sink_new_data_set_alternate_sample_rate(&data, alternate_sample_rate);
pa_alsa_init_proplist_pcm(m->core, data.proplist, u->pcm_handle);
pa_proplist_sets(data.proplist, PA_PROP_DEVICE_STRING, u->device_name);
@@ -2230,6 +2201,7 @@ pa_sink *pa_alsa_sink_new(pa_module *m, pa_modargs *ma, const char*driver, pa_ca
u->sink->update_requested_latency = sink_update_requested_latency_cb;
u->sink->set_state = sink_set_state_cb;
u->sink->set_port = sink_set_port_cb;
+ u->sink->update_rate = sink_update_rate_cb;
u->sink->userdata = u;
pa_sink_set_asyncmsgq(u->sink, u->thread_mq.inq);
diff --git a/src/modules/alsa/alsa-source.c b/src/modules/alsa/alsa-source.c
index 0766e11..c279429 100644
--- a/src/modules/alsa/alsa-source.c
+++ b/src/modules/alsa/alsa-source.c
@@ -1382,6 +1382,19 @@ static void source_update_requested_latency_cb(pa_source *s) {
update_sw_params(u);
}
+static pa_bool_t source_update_rate_cb(pa_source *s, uint32_t rate)
+{
+ struct userdata *u = s->userdata;
+ pa_assert(u);
+
+ 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;
+}
+
static void thread_func(void *userdata) {
struct userdata *u = userdata;
unsigned short revents = 0;
@@ -1674,6 +1687,7 @@ pa_source *pa_alsa_source_new(pa_module *m, pa_modargs *ma, const char*driver, p
struct userdata *u = NULL;
const char *dev_id = NULL;
pa_sample_spec ss;
+ uint32_t alternate_sample_rate;
pa_channel_map map;
uint32_t nfrags, frag_size, buffer_size, tsched_size, tsched_watermark;
snd_pcm_uframes_t period_frames, buffer_frames, tsched_frames;
@@ -1692,6 +1706,12 @@ pa_source *pa_alsa_source_new(pa_module *m, pa_modargs *ma, const char*driver, p
goto fail;
}
+ alternate_sample_rate = m->core->alternate_sample_rate;
+ if (pa_modargs_get_alternate_sample_rate(ma, &alternate_sample_rate) < 0) {
+ pa_log("Failed to parse alternate sample rate");
+ goto fail;
+ }
+
frame_size = pa_frame_size(&ss);
nfrags = m->core->default_n_fragments;
@@ -1867,6 +1887,7 @@ pa_source *pa_alsa_source_new(pa_module *m, pa_modargs *ma, const char*driver, p
pa_source_new_data_set_sample_spec(&data, &ss);
pa_source_new_data_set_channel_map(&data, &map);
+ pa_source_new_data_set_alternate_sample_rate(&data, alternate_sample_rate);
pa_alsa_init_proplist_pcm(m->core, data.proplist, u->pcm_handle);
pa_proplist_sets(data.proplist, PA_PROP_DEVICE_STRING, u->device_name);
@@ -1918,6 +1939,7 @@ pa_source *pa_alsa_source_new(pa_module *m, pa_modargs *ma, const char*driver, p
u->source->update_requested_latency = source_update_requested_latency_cb;
u->source->set_state = source_set_state_cb;
u->source->set_port = source_set_port_cb;
+ u->source->update_rate = source_update_rate_cb;
u->source->userdata = u;
pa_source_set_asyncmsgq(u->source, u->thread_mq.inq);
diff --git a/src/modules/alsa/module-alsa-sink.c b/src/modules/alsa/module-alsa-sink.c
index 2a558a1..019ccf0 100644
--- a/src/modules/alsa/module-alsa-sink.c
+++ b/src/modules/alsa/module-alsa-sink.c
@@ -45,6 +45,7 @@ PA_MODULE_USAGE(
"device_id=<ALSA card index> "
"format=<sample format> "
"rate=<sample rate> "
+ "alternate_rate=<alternate sample rate> "
"channels=<number of channels> "
"channel_map=<channel map> "
"fragments=<number of fragments> "
@@ -69,6 +70,7 @@ static const char* const valid_modargs[] = {
"device_id",
"format",
"rate",
+ "alternate_rate",
"channels",
"channel_map",
"fragments",
diff --git a/src/modules/alsa/module-alsa-source.c b/src/modules/alsa/module-alsa-source.c
index 628e631..2d2c8b6 100644
--- a/src/modules/alsa/module-alsa-source.c
+++ b/src/modules/alsa/module-alsa-source.c
@@ -54,6 +54,7 @@ PA_MODULE_USAGE(
"device_id=<ALSA card index> "
"format=<sample format> "
"rate=<sample rate> "
+ "alternate_rate=<alternate sample rate> "
"channels=<number of channels> "
"channel_map=<channel map> "
"fragments=<number of fragments> "
@@ -77,6 +78,7 @@ static const char* const valid_modargs[] = {
"device_id",
"format",
"rate",
+ "alternate_rate",
"channels",
"channel_map",
"fragments",
commit f0ec495938cf0adbee820aec126ece99eb31a1af
Author: Pierre-Louis Bossart <pierre-louis.bossart at linux.intel.com>
Date: Tue Aug 2 18:37:28 2011 -0500
sink,source: support for rate update
Avoid resampling or use integer resampling when supported by the
sinks/sources
Signed-off-by: Pierre-Louis Bossart <pierre-louis.bossart at linux.intel.com>
diff --git a/src/pulse/def.h b/src/pulse/def.h
index f43e864..49e4fdc 100644
--- a/src/pulse/def.h
+++ b/src/pulse/def.h
@@ -826,6 +826,11 @@ static inline int PA_SINK_IS_OPENED(pa_sink_state_t x) {
return x == PA_SINK_RUNNING || x == PA_SINK_IDLE;
}
+/** Returns non-zero if sink is running. \since 1.0 */
+static inline int PA_SINK_IS_RUNNING(pa_sink_state_t x) {
+ return x == PA_SINK_RUNNING;
+}
+
/** \cond fulldocs */
#define PA_SINK_INVALID_STATE PA_SINK_INVALID_STATE
#define PA_SINK_RUNNING PA_SINK_RUNNING
@@ -937,6 +942,11 @@ static inline int PA_SOURCE_IS_OPENED(pa_source_state_t x) {
return x == PA_SOURCE_RUNNING || x == PA_SOURCE_IDLE;
}
+/** Returns non-zero if source is running \since 1.0 */
+static inline int PA_SOURCE_IS_RUNNING(pa_source_state_t x) {
+ return x == PA_SOURCE_RUNNING;
+}
+
/** \cond fulldocs */
#define PA_SOURCE_INVALID_STATE PA_SOURCE_INVALID_STATE
#define PA_SOURCE_RUNNING PA_SOURCE_RUNNING
diff --git a/src/pulsecore/sink-input.c b/src/pulsecore/sink-input.c
index 5146a9d..a64defa 100644
--- a/src/pulsecore/sink-input.c
+++ b/src/pulsecore/sink-input.c
@@ -367,6 +367,19 @@ int pa_sink_input_new(
pa_assert(pa_sample_spec_valid(&data->sample_spec));
pa_assert(pa_channel_map_valid(&data->channel_map));
+ if (!(data->flags & PA_SINK_INPUT_VARIABLE_RATE) &&
+ !pa_sample_spec_equal(&data->sample_spec, &data->sink->sample_spec)) {
+ /* try to change sink rate. This is done before the FIXATE hook since
+ module-suspend-on-idle can resume a sink */
+
+ pa_log_info("Trying to change sample rate");
+ if (pa_sink_update_rate(data->sink, data->sample_spec.rate, pa_sink_input_new_data_is_passthrough(data)) == TRUE)
+ pa_log_info("Rate changed to %u kHz",
+ data->sink->sample_spec.rate);
+ else
+ pa_log_info("Resampling enabled to %u kHz", data->sink->sample_spec.rate);
+ }
+
/* Due to the fixing of the sample spec the volume might not match anymore */
pa_cvolume_remap(&data->volume, &original_cm, &data->channel_map);
@@ -1605,6 +1618,21 @@ int pa_sink_input_finish_move(pa_sink_input *i, pa_sink *dest, pa_bool_t save) {
return -PA_ERR_NOTSUPPORTED;
}
+ if (!(i->flags & PA_SINK_INPUT_VARIABLE_RATE) &&
+ !pa_sample_spec_equal(&i->sample_spec, &dest->sample_spec)) {
+ /* try to change dest sink rate if possible without glitches.
+ module-suspend-on-idle resumes destination sink with
+ SINK_INPUT_MOVE_FINISH hook */
+
+ pa_log_info("Trying to change sample rate");
+ if (pa_sink_update_rate(dest, i->sample_spec.rate, pa_sink_input_is_passthrough(i)) == TRUE)
+ pa_log_info("Rate changed to %u kHz",
+ dest->sample_spec.rate);
+ else
+ pa_log_info("Resampling enabled to %u kHz",
+ dest->sample_spec.rate);
+ }
+
if (i->thread_info.resampler &&
pa_sample_spec_equal(pa_resampler_output_sample_spec(i->thread_info.resampler), &dest->sample_spec) &&
pa_channel_map_equal(pa_resampler_output_channel_map(i->thread_info.resampler), &dest->channel_map))
diff --git a/src/pulsecore/sink.c b/src/pulsecore/sink.c
index 53cab32..6b5a385 100644
--- a/src/pulsecore/sink.c
+++ b/src/pulsecore/sink.c
@@ -106,6 +106,13 @@ void pa_sink_new_data_set_channel_map(pa_sink_new_data *data, const pa_channel_m
data->channel_map = *map;
}
+void pa_sink_new_data_set_alternate_sample_rate(pa_sink_new_data *data, const uint32_t alternate_sample_rate) {
+ pa_assert(data);
+
+ data->alternate_sample_rate_is_set = TRUE;
+ data->alternate_sample_rate = alternate_sample_rate;
+}
+
void pa_sink_new_data_set_volume(pa_sink_new_data *data, const pa_cvolume *volume) {
pa_assert(data);
@@ -182,6 +189,7 @@ static void reset_callbacks(pa_sink *s) {
s->set_port = NULL;
s->get_formats = NULL;
s->set_formats = NULL;
+ s->update_rate = NULL;
}
/* Called from main context */
@@ -277,6 +285,11 @@ pa_sink* pa_sink_new(
s->sample_spec = data->sample_spec;
s->channel_map = data->channel_map;
+ if (data->alternate_sample_rate_is_set)
+ s->alternate_sample_rate = data->alternate_sample_rate;
+ else
+ s->alternate_sample_rate = s->core->alternate_sample_rate;
+ s->default_sample_rate = s->sample_spec.rate;
s->inputs = pa_idxset_new(NULL, NULL);
s->n_corked = 0;
@@ -364,6 +377,7 @@ pa_sink* pa_sink_new(
pa_source_new_data_init(&source_data);
pa_source_new_data_set_sample_spec(&source_data, &s->sample_spec);
pa_source_new_data_set_channel_map(&source_data, &s->channel_map);
+ pa_source_new_data_set_alternate_sample_rate(&source_data, s->alternate_sample_rate);
source_data.name = pa_sprintf_malloc("%s.monitor", name);
source_data.driver = data->driver;
source_data.module = data->module;
@@ -1313,6 +1327,69 @@ void pa_sink_render_full(pa_sink *s, size_t length, pa_memchunk *result) {
}
/* Called from main thread */
+pa_bool_t pa_sink_update_rate(pa_sink *s, uint32_t rate, pa_bool_t passthrough)
+{
+ if (s->update_rate) {
+ uint32_t desired_rate = rate;
+ uint32_t default_rate = s->default_sample_rate;
+ uint32_t alternate_rate = s->alternate_sample_rate;
+ pa_bool_t use_alternate = FALSE;
+
+ if (PA_SINK_IS_RUNNING(s->state)) {
+ pa_log_info("Cannot update rate, SINK_IS_RUNNING, will keep using %u kHz",
+ s->sample_spec.rate);
+ return FALSE;
+ }
+
+ if (s->monitor_source) {
+ if (PA_SOURCE_IS_RUNNING(s->monitor_source->state) == TRUE) {
+ pa_log_info("Cannot update rate, monitor source is RUNNING");
+ return FALSE;
+ }
+ }
+
+ if (PA_UNLIKELY (desired_rate < 8000 ||
+ desired_rate > PA_RATE_MAX))
+ return FALSE;
+
+ if (!passthrough) {
+ pa_assert(default_rate % 4000 || default_rate % 11025);
+ pa_assert(alternate_rate % 4000 || alternate_rate % 11025);
+
+ if (default_rate % 4000) {
+ /* default is a 11025 multiple */
+ if ((alternate_rate % 4000 == 0) && (desired_rate % 4000 == 0))
+ use_alternate=TRUE;
+ } else {
+ /* default is 4000 multiple */
+ if ((alternate_rate % 11025 == 0) && (desired_rate % 11025 == 0))
+ use_alternate=TRUE;
+ }
+
+ if (use_alternate)
+ desired_rate = alternate_rate;
+ else
+ desired_rate = default_rate;
+ } else {
+ desired_rate = rate; /* use stream sampling rate, discard default/alternate settings */
+ }
+
+ if (passthrough || pa_sink_used_by(s) == 0) {
+ pa_sink_suspend(s, TRUE, PA_SUSPEND_IDLE); /* needed before rate update, will be resumed automatically */
+ }
+
+ if (s->update_rate(s, desired_rate) == TRUE) {
+ /* update monitor source as well */
+ if (s->monitor_source)
+ pa_source_update_rate(s->monitor_source, desired_rate);
+ pa_log_info("Changed sampling rate successfully");
+ return TRUE;
+ }
+ }
+ return FALSE;
+}
+
+/* Called from main thread */
pa_usec_t pa_sink_get_latency(pa_sink *s) {
pa_usec_t usec = 0;
diff --git a/src/pulsecore/sink.h b/src/pulsecore/sink.h
index 7f639e2..a88ac58 100644
--- a/src/pulsecore/sink.h
+++ b/src/pulsecore/sink.h
@@ -88,6 +88,8 @@ struct pa_sink {
pa_sample_spec sample_spec;
pa_channel_map channel_map;
+ uint32_t default_sample_rate;
+ uint32_t alternate_sample_rate;
pa_idxset *inputs;
unsigned n_corked;
@@ -233,6 +235,10 @@ struct pa_sink {
* set). Makes a copy of the formats passed in. */
pa_bool_t (*set_formats)(pa_sink *s, pa_idxset *formats); /* may be NULL */
+ /* Called whenever the sampling frequency shall be changed. Called from
+ * main thread. */
+ pa_bool_t (*update_rate)(pa_sink *s, uint32_t rate);
+
/* Contains copies of the above data so that the real-time worker
* thread can work without access locking */
struct {
@@ -337,11 +343,13 @@ typedef struct pa_sink_new_data {
pa_sample_spec sample_spec;
pa_channel_map channel_map;
+ uint32_t alternate_sample_rate;
pa_cvolume volume;
pa_bool_t muted :1;
pa_bool_t sample_spec_is_set:1;
pa_bool_t channel_map_is_set:1;
+ pa_bool_t alternate_sample_rate_is_set:1;
pa_bool_t volume_is_set:1;
pa_bool_t muted_is_set:1;
@@ -356,6 +364,7 @@ pa_sink_new_data* pa_sink_new_data_init(pa_sink_new_data *data);
void pa_sink_new_data_set_name(pa_sink_new_data *data, const char *name);
void pa_sink_new_data_set_sample_spec(pa_sink_new_data *data, const pa_sample_spec *spec);
void pa_sink_new_data_set_channel_map(pa_sink_new_data *data, const pa_channel_map *map);
+void pa_sink_new_data_set_alternate_sample_rate(pa_sink_new_data *data, const uint32_t alternate_sample_rate);
void pa_sink_new_data_set_volume(pa_sink_new_data *data, const pa_cvolume *volume);
void pa_sink_new_data_set_muted(pa_sink_new_data *data, pa_bool_t mute);
void pa_sink_new_data_set_port(pa_sink_new_data *data, const char *port);
@@ -403,6 +412,8 @@ unsigned pa_device_init_priority(pa_proplist *p);
/**** May be called by everyone, from main context */
+pa_bool_t pa_sink_update_rate(pa_sink *s, uint32_t rate, pa_bool_t passthrough);
+
/* The returned value is supposed to be in the time domain of the sound card! */
pa_usec_t pa_sink_get_latency(pa_sink *s);
pa_usec_t pa_sink_get_requested_latency(pa_sink *s);
diff --git a/src/pulsecore/source-output.c b/src/pulsecore/source-output.c
index f6ad009..46a95a7 100644
--- a/src/pulsecore/source-output.c
+++ b/src/pulsecore/source-output.c
@@ -348,6 +348,15 @@ int pa_source_output_new(
/* Due to the fixing of the sample spec the volume might not match anymore */
pa_cvolume_remap(&data->volume, &original_cm, &data->channel_map);
+ if (!(data->flags & PA_SOURCE_OUTPUT_VARIABLE_RATE) &&
+ !pa_sample_spec_equal(&data->sample_spec, &data->source->sample_spec)){
+ /* try to change source rate. This is done before the FIXATE hook since
+ module-suspend-on-idle can resume a source */
+
+ pa_log_info("Trying to change sample rate");
+ pa_source_update_rate(data->source, data->sample_spec.rate);
+ }
+
if (data->resample_method == PA_RESAMPLER_INVALID)
data->resample_method = core->resample_method;
@@ -1385,6 +1394,21 @@ int pa_source_output_finish_move(pa_source_output *o, pa_source *dest, pa_bool_t
return -PA_ERR_NOTSUPPORTED;
}
+ if (!(o->flags & PA_SOURCE_OUTPUT_VARIABLE_RATE) &&
+ !pa_sample_spec_equal(&o->sample_spec, &dest->sample_spec)){
+ /* try to change dest sink rate if possible without glitches.
+ module-suspend-on-idle resumes destination source with
+ SOURCE_OUTPUT_MOVE_FINISH hook */
+
+ pa_log_info("Trying to change sample rate");
+ if (pa_source_update_rate(dest, o->sample_spec.rate) == TRUE)
+ pa_log_info("Rate changed to %u kHz",
+ dest->sample_spec.rate);
+ else
+ pa_log_info("Resampling enabled to %u kHz",
+ dest->sample_spec.rate);
+ }
+
if (o->thread_info.resampler &&
pa_sample_spec_equal(pa_resampler_input_sample_spec(o->thread_info.resampler), &dest->sample_spec) &&
pa_channel_map_equal(pa_resampler_input_channel_map(o->thread_info.resampler), &dest->channel_map))
diff --git a/src/pulsecore/source.c b/src/pulsecore/source.c
index d47280c..508fb4a 100644
--- a/src/pulsecore/source.c
+++ b/src/pulsecore/source.c
@@ -98,6 +98,13 @@ void pa_source_new_data_set_channel_map(pa_source_new_data *data, const pa_chann
data->channel_map = *map;
}
+void pa_source_new_data_set_alternate_sample_rate(pa_source_new_data *data, const uint32_t alternate_sample_rate) {
+ pa_assert(data);
+
+ data->alternate_sample_rate_is_set = TRUE;
+ data->alternate_sample_rate = alternate_sample_rate;
+}
+
void pa_source_new_data_set_volume(pa_source_new_data *data, const pa_cvolume *volume) {
pa_assert(data);
@@ -150,6 +157,7 @@ static void reset_callbacks(pa_source *s) {
s->update_requested_latency = NULL;
s->set_port = NULL;
s->get_formats = NULL;
+ s->update_rate = NULL;
}
/* Called from main context */
@@ -243,6 +251,11 @@ pa_source* pa_source_new(
s->sample_spec = data->sample_spec;
s->channel_map = data->channel_map;
+ if (data->alternate_sample_rate_is_set)
+ s->alternate_sample_rate = data->alternate_sample_rate;
+ else
+ s->alternate_sample_rate = s->core->alternate_sample_rate;
+ s->default_sample_rate = s->sample_spec.rate;
s->outputs = pa_idxset_new(NULL, NULL);
s->n_corked = 0;
@@ -908,6 +921,52 @@ void pa_source_post_direct(pa_source*s, pa_source_output *o, const pa_memchunk *
}
/* Called from main thread */
+pa_bool_t pa_source_update_rate(pa_source *s, uint32_t rate)
+{
+
+ if (s->update_rate) {
+ uint32_t desired_rate = rate;
+ uint32_t default_rate = s->default_sample_rate;
+ uint32_t alternate_rate = s->alternate_sample_rate;
+ pa_bool_t use_alternate = FALSE;
+
+ if (PA_SOURCE_IS_RUNNING(s->state)) {
+ pa_log_info("Cannot update rate, SOURCE_IS_RUNNING, will keep using %u kHz",
+ s->sample_spec.rate);
+ return FALSE; /* cannot reconfigure a RUNNING source without glitches */
+ }
+
+ if (PA_UNLIKELY (desired_rate < 8000 ||
+ desired_rate > PA_RATE_MAX))
+ return FALSE;
+
+ pa_assert(default_rate % 4000 || default_rate % 11025);
+ pa_assert(alternate_rate % 4000 || alternate_rate % 11025);
+
+ if (default_rate % 4000) {
+ /* default is a 11025 multiple */
+ if ((alternate_rate % 4000 == 0) && (desired_rate % 4000 == 0))
+ use_alternate=TRUE;
+ } else {
+ /* default is 4000 multiple */
+ if ((alternate_rate % 11025 == 0) && (desired_rate % 11025 == 0))
+ use_alternate=TRUE;
+ }
+
+ if (use_alternate)
+ desired_rate = alternate_rate;
+ else
+ desired_rate = default_rate;
+
+ if (s->update_rate(s, desired_rate) == TRUE) {
+ pa_log_info("Changed sampling rate successfully ");
+ return TRUE;
+ }
+ }
+ return FALSE;
+}
+
+/* Called from main thread */
pa_usec_t pa_source_get_latency(pa_source *s) {
pa_usec_t usec;
diff --git a/src/pulsecore/source.h b/src/pulsecore/source.h
index 949ae48..8adc5f1 100644
--- a/src/pulsecore/source.h
+++ b/src/pulsecore/source.h
@@ -76,6 +76,8 @@ struct pa_source {
pa_sample_spec sample_spec;
pa_channel_map channel_map;
+ uint32_t default_sample_rate;
+ uint32_t alternate_sample_rate;
pa_idxset *outputs;
unsigned n_corked;
@@ -178,6 +180,10 @@ struct pa_source {
* in descending order of preference. */
pa_idxset* (*get_formats)(pa_source *s); /* ditto */
+ /* Called whenever the sampling frequency shall be changed. Called from
+ * main thread. */
+ pa_bool_t (*update_rate)(pa_source *s, uint32_t rate);
+
/* Contains copies of the above data so that the real-time worker
* thread can work without access locking */
struct {
@@ -262,6 +268,7 @@ typedef struct pa_source_new_data {
pa_sample_spec sample_spec;
pa_channel_map channel_map;
+ uint32_t alternate_sample_rate;
pa_cvolume volume;
pa_bool_t muted:1;
@@ -269,6 +276,7 @@ typedef struct pa_source_new_data {
pa_bool_t muted_is_set:1;
pa_bool_t sample_spec_is_set:1;
pa_bool_t channel_map_is_set:1;
+ pa_bool_t alternate_sample_rate_is_set:1;
pa_bool_t namereg_fail:1;
@@ -281,6 +289,7 @@ pa_source_new_data* pa_source_new_data_init(pa_source_new_data *data);
void pa_source_new_data_set_name(pa_source_new_data *data, const char *name);
void pa_source_new_data_set_sample_spec(pa_source_new_data *data, const pa_sample_spec *spec);
void pa_source_new_data_set_channel_map(pa_source_new_data *data, const pa_channel_map *map);
+void pa_source_new_data_set_alternate_sample_rate(pa_source_new_data *data, const uint32_t alternate_sample_rate);
void pa_source_new_data_set_volume(pa_source_new_data *data, const pa_cvolume *volume);
void pa_source_new_data_set_muted(pa_source_new_data *data, pa_bool_t mute);
void pa_source_new_data_set_port(pa_source_new_data *data, const char *port);
@@ -358,6 +367,7 @@ pa_bool_t pa_source_get_mute(pa_source *source, pa_bool_t force_refresh);
pa_bool_t pa_source_update_proplist(pa_source *s, pa_update_mode_t mode, pa_proplist *p);
int pa_source_set_port(pa_source *s, const char *name, pa_bool_t save);
+pa_bool_t pa_source_update_rate(pa_source *s, uint32_t rate);
unsigned pa_source_linked_by(pa_source *s); /* Number of connected streams */
unsigned pa_source_used_by(pa_source *s); /* Number of connected streams that are not corked */
commit 5bcfd2b630ae56c97348edc93c4c237f71b24283
Author: Pierre-Louis Bossart <pierre-louis.bossart at linux.intel.com>
Date: Tue Aug 2 18:37:27 2011 -0500
core: infrastructure for alternate sampling rate
New parameter to avoid resampling. BIG power savings here...
Signed-off-by: Pierre-Louis Bossart <pierre-louis.bossart at linux.intel.com>
diff --git a/man/pulse-daemon.conf.5.xml.in b/man/pulse-daemon.conf.5.xml.in
index b5ef09c..33ea792 100644
--- a/man/pulse-daemon.conf.5.xml.in
+++ b/man/pulse-daemon.conf.5.xml.in
@@ -414,6 +414,15 @@ USA.
<p><opt>default-channel-map</opt> The default channel map.</p>
</option>
+ <option>
+ <p><opt>alternate-sample-rate</opt> The alternate sample
+ frequency. Sinks and sources will use either the
+ default-rate-rate value or this alternate value, typically 44.1
+ or 48kHz. Switching between default and alternate values is
+ enabled only when the sinks/sources are suspended. This option
+ is ignored in passthrough mode where the stream rate will be used.</p>
+ </option>
+
</section>
<section name="Default Fragment Settings">
diff --git a/src/daemon/daemon-conf.c b/src/daemon/daemon-conf.c
index 3619fb5..3ef7f81 100644
--- a/src/daemon/daemon-conf.c
+++ b/src/daemon/daemon-conf.c
@@ -101,6 +101,7 @@ static const pa_daemon_conf default_conf = {
.deferred_volume_safety_margin_usec = 8000,
.deferred_volume_extra_delay_usec = 0,
.default_sample_spec = { .format = PA_SAMPLE_S16NE, .rate = 44100, .channels = 2 },
+ .alternate_sample_rate = 48000,
.default_channel_map = { .channels = 2, .map = { PA_CHANNEL_POSITION_LEFT, PA_CHANNEL_POSITION_RIGHT } },
.shm_size = 0
#ifdef HAVE_SYS_RESOURCE_H
@@ -364,7 +365,8 @@ static int parse_sample_rate(const char *filename, unsigned line, const char *se
pa_assert(rvalue);
pa_assert(data);
- if (pa_atou(rvalue, &r) < 0 || r > (uint32_t) PA_RATE_MAX || r <= 0) {
+ if (pa_atou(rvalue, &r) < 0 || r > (uint32_t) PA_RATE_MAX || r <= 0 ||
+ !((r % 4000 == 0) || (r % 11025 == 0))) {
pa_log(_("[%s:%u] Invalid sample rate '%s'."), filename, line, rvalue);
return -1;
}
@@ -373,6 +375,25 @@ static int parse_sample_rate(const char *filename, unsigned line, const char *se
return 0;
}
+static int parse_alternate_sample_rate(const char *filename, unsigned line, const char *section, const char *lvalue, const char *rvalue, void *data, void *userdata) {
+ pa_daemon_conf *c = data;
+ uint32_t r;
+
+ pa_assert(filename);
+ pa_assert(lvalue);
+ pa_assert(rvalue);
+ pa_assert(data);
+
+ if (pa_atou(rvalue, &r) < 0 || r > (uint32_t) PA_RATE_MAX || r <= 0 ||
+ !((r % 4000==0) || (r % 11025 == 0))) {
+ pa_log(_("[%s:%u] Invalid sample rate '%s'."), filename, line, rvalue);
+ return -1;
+ }
+
+ c->alternate_sample_rate = r;
+ return 0;
+}
+
struct channel_conf_info {
pa_daemon_conf *conf;
pa_bool_t default_sample_spec_set;
@@ -548,6 +569,7 @@ int pa_daemon_conf_load(pa_daemon_conf *c, const char *filename) {
{ "resample-method", parse_resample_method, c, NULL },
{ "default-sample-format", parse_sample_format, c, NULL },
{ "default-sample-rate", parse_sample_rate, c, NULL },
+ { "alternate-sample-rate", parse_alternate_sample_rate, c, NULL },
{ "default-sample-channels", parse_sample_channels, &ci, NULL },
{ "default-channel-map", parse_channel_map, &ci, NULL },
{ "default-fragments", parse_fragments, c, NULL },
@@ -751,6 +773,7 @@ char *pa_daemon_conf_dump(pa_daemon_conf *c) {
pa_strbuf_printf(s, "enable-lfe-remixing = %s\n", pa_yes_no(!c->disable_lfe_remixing));
pa_strbuf_printf(s, "default-sample-format = %s\n", pa_sample_format_to_string(c->default_sample_spec.format));
pa_strbuf_printf(s, "default-sample-rate = %u\n", c->default_sample_spec.rate);
+ pa_strbuf_printf(s, "alternate-sample-rate = %u\n", c->alternate_sample_rate);
pa_strbuf_printf(s, "default-sample-channels = %u\n", c->default_sample_spec.channels);
pa_strbuf_printf(s, "default-channel-map = %s\n", pa_channel_map_snprint(cm, sizeof(cm), &c->default_channel_map));
pa_strbuf_printf(s, "default-fragments = %u\n", c->default_n_fragments);
diff --git a/src/daemon/daemon-conf.h b/src/daemon/daemon-conf.h
index 600bcec..faf2540 100644
--- a/src/daemon/daemon-conf.h
+++ b/src/daemon/daemon-conf.h
@@ -131,6 +131,7 @@ typedef struct pa_daemon_conf {
unsigned deferred_volume_safety_margin_usec;
int deferred_volume_extra_delay_usec;
pa_sample_spec default_sample_spec;
+ uint32_t alternate_sample_rate;
pa_channel_map default_channel_map;
size_t shm_size;
} pa_daemon_conf;
diff --git a/src/daemon/daemon.conf.in b/src/daemon/daemon.conf.in
index b13ede7..dff97ae 100644
--- a/src/daemon/daemon.conf.in
+++ b/src/daemon/daemon.conf.in
@@ -80,6 +80,7 @@ ifelse(@HAVE_SYS_RESOURCE_H@, 1, [dnl
; default-sample-format = s16le
; default-sample-rate = 44100
+; alternate-sample-rate = 48000
; default-sample-channels = 2
; default-channel-map = front-left,front-right
diff --git a/src/daemon/main.c b/src/daemon/main.c
index c32f7c7..19933e3 100644
--- a/src/daemon/main.c
+++ b/src/daemon/main.c
@@ -1013,6 +1013,7 @@ int main(int argc, char *argv[]) {
}
c->default_sample_spec = conf->default_sample_spec;
+ c->alternate_sample_rate = conf->alternate_sample_rate;
c->default_channel_map = conf->default_channel_map;
c->default_n_fragments = conf->default_n_fragments;
c->default_fragment_size_msec = conf->default_fragment_size_msec;
diff --git a/src/modules/dbus/iface-core.c b/src/modules/dbus/iface-core.c
index f2e3468..58abcb9 100644
--- a/src/modules/dbus/iface-core.c
+++ b/src/modules/dbus/iface-core.c
@@ -62,6 +62,8 @@ static void handle_get_default_sample_format(DBusConnection *conn, DBusMessage *
static void handle_set_default_sample_format(DBusConnection *conn, DBusMessage *msg, DBusMessageIter *iter, void *userdata);
static void handle_get_default_sample_rate(DBusConnection *conn, DBusMessage *msg, void *userdata);
static void handle_set_default_sample_rate(DBusConnection *conn, DBusMessage *msg, DBusMessageIter *iter, void *userdata);
+static void handle_get_alternate_sample_rate(DBusConnection *conn, DBusMessage *msg, void *userdata);
+static void handle_set_alternate_sample_rate(DBusConnection *conn, DBusMessage *msg, DBusMessageIter *iter, void *userdata);
static void handle_get_cards(DBusConnection *conn, DBusMessage *msg, void *userdata);
static void handle_get_sinks(DBusConnection *conn, DBusMessage *msg, void *userdata);
static void handle_get_fallback_sink(DBusConnection *conn, DBusMessage *msg, void *userdata);
@@ -129,6 +131,7 @@ enum property_handler_index {
PROPERTY_HANDLER_DEFAULT_CHANNELS,
PROPERTY_HANDLER_DEFAULT_SAMPLE_FORMAT,
PROPERTY_HANDLER_DEFAULT_SAMPLE_RATE,
+ PROPERTY_HANDLER_ALTERNATE_SAMPLE_RATE,
PROPERTY_HANDLER_CARDS,
PROPERTY_HANDLER_SINKS,
PROPERTY_HANDLER_FALLBACK_SINK,
@@ -154,6 +157,7 @@ static pa_dbus_property_handler property_handlers[PROPERTY_HANDLER_MAX] = {
[PROPERTY_HANDLER_DEFAULT_CHANNELS] = { .property_name = "DefaultChannels", .type = "au", .get_cb = handle_get_default_channels, .set_cb = handle_set_default_channels },
[PROPERTY_HANDLER_DEFAULT_SAMPLE_FORMAT] = { .property_name = "DefaultSampleFormat", .type = "u", .get_cb = handle_get_default_sample_format, .set_cb = handle_set_default_sample_format },
[PROPERTY_HANDLER_DEFAULT_SAMPLE_RATE] = { .property_name = "DefaultSampleRate", .type = "u", .get_cb = handle_get_default_sample_rate, .set_cb = handle_set_default_sample_rate },
+ [PROPERTY_HANDLER_ALTERNATE_SAMPLE_RATE] = { .property_name = "AlternateSampleRate", .type = "u", .get_cb = handle_get_alternate_sample_rate, .set_cb = handle_set_alternate_sample_rate },
[PROPERTY_HANDLER_CARDS] = { .property_name = "Cards", .type = "ao", .get_cb = handle_get_cards, .set_cb = NULL },
[PROPERTY_HANDLER_SINKS] = { .property_name = "Sinks", .type = "ao", .get_cb = handle_get_sinks, .set_cb = NULL },
[PROPERTY_HANDLER_FALLBACK_SINK] = { .property_name = "FallbackSink", .type = "o", .get_cb = handle_get_fallback_sink, .set_cb = handle_set_fallback_sink },
@@ -540,7 +544,8 @@ static void handle_set_default_sample_rate(DBusConnection *conn, DBusMessage *ms
dbus_message_iter_get_basic(iter, &default_sample_rate);
- if (default_sample_rate <= 0 || default_sample_rate > PA_RATE_MAX) {
+ if (default_sample_rate <= 0 || default_sample_rate > PA_RATE_MAX ||
+ !((default_sample_rate % 4000 == 0) || (default_sample_rate % 11025 == 0))) {
pa_dbus_send_error(conn, msg, DBUS_ERROR_INVALID_ARGS, "Invalid sample rate.");
return;
}
@@ -550,6 +555,41 @@ static void handle_set_default_sample_rate(DBusConnection *conn, DBusMessage *ms
pa_dbus_send_empty_reply(conn, msg);
}
+static void handle_get_alternate_sample_rate(DBusConnection *conn, DBusMessage *msg, void *userdata) {
+ pa_dbusiface_core *c = userdata;
+ dbus_uint32_t alternate_sample_rate;
+
+ pa_assert(conn);
+ pa_assert(msg);
+ pa_assert(c);
+
+ alternate_sample_rate = c->core->alternate_sample_rate;
+
+ pa_dbus_send_basic_variant_reply(conn, msg, DBUS_TYPE_UINT32, &alternate_sample_rate);
+}
+
+static void handle_set_alternate_sample_rate(DBusConnection *conn, DBusMessage *msg, DBusMessageIter *iter, void *userdata) {
+ pa_dbusiface_core *c = userdata;
+ dbus_uint32_t alternate_sample_rate;
+
+ pa_assert(conn);
+ pa_assert(msg);
+ pa_assert(iter);
+ pa_assert(c);
+
+ dbus_message_iter_get_basic(iter, &alternate_sample_rate);
+
+ if (alternate_sample_rate <= 0 || alternate_sample_rate > PA_RATE_MAX ||
+ !((alternate_sample_rate % 4000 == 0) || (alternate_sample_rate % 11025 == 0))) {
+ pa_dbus_send_error(conn, msg, DBUS_ERROR_INVALID_ARGS, "Invalid sample rate.");
+ return;
+ }
+
+ c->core->alternate_sample_rate = alternate_sample_rate;
+
+ pa_dbus_send_empty_reply(conn, msg);
+}
+
/* The caller frees the array, but not the strings. */
static const char **get_cards(pa_dbusiface_core *c, unsigned *n) {
const char **cards;
@@ -1015,6 +1055,7 @@ static void handle_get_all(DBusConnection *conn, DBusMessage *msg, void *userdat
unsigned n_default_channels;
dbus_uint32_t default_sample_format;
dbus_uint32_t default_sample_rate;
+ dbus_uint32_t alternate_sample_rate;
const char **cards;
unsigned n_cards;
const char **sinks;
@@ -1050,6 +1091,7 @@ static void handle_get_all(DBusConnection *conn, DBusMessage *msg, void *userdat
default_channels = get_default_channels(c, &n_default_channels);
default_sample_format = c->core->default_sample_spec.format;
default_sample_rate = c->core->default_sample_spec.rate;
+ alternate_sample_rate = c->core->alternate_sample_rate;
cards = get_cards(c, &n_cards);
sinks = get_sinks(c, &n_sinks);
fallback_sink = c->fallback_sink
@@ -1082,6 +1124,7 @@ static void handle_get_all(DBusConnection *conn, DBusMessage *msg, void *userdat
pa_dbus_append_basic_array_variant_dict_entry(&dict_iter, property_handlers[PROPERTY_HANDLER_DEFAULT_CHANNELS].property_name, DBUS_TYPE_UINT32, default_channels, n_default_channels);
pa_dbus_append_basic_variant_dict_entry(&dict_iter, property_handlers[PROPERTY_HANDLER_DEFAULT_SAMPLE_FORMAT].property_name, DBUS_TYPE_UINT32, &default_sample_format);
pa_dbus_append_basic_variant_dict_entry(&dict_iter, property_handlers[PROPERTY_HANDLER_DEFAULT_SAMPLE_RATE].property_name, DBUS_TYPE_UINT32, &default_sample_rate);
+ pa_dbus_append_basic_variant_dict_entry(&dict_iter, property_handlers[PROPERTY_HANDLER_ALTERNATE_SAMPLE_RATE].property_name, DBUS_TYPE_UINT32, &alternate_sample_rate);
pa_dbus_append_basic_array_variant_dict_entry(&dict_iter, property_handlers[PROPERTY_HANDLER_CARDS].property_name, DBUS_TYPE_OBJECT_PATH, cards, n_cards);
pa_dbus_append_basic_array_variant_dict_entry(&dict_iter, property_handlers[PROPERTY_HANDLER_SINKS].property_name, DBUS_TYPE_OBJECT_PATH, sinks, n_sinks);
diff --git a/src/pulsecore/core.h b/src/pulsecore/core.h
index ef51b8c..d0641cf 100644
--- a/src/pulsecore/core.h
+++ b/src/pulsecore/core.h
@@ -143,6 +143,7 @@ struct pa_core {
pa_channel_map default_channel_map;
pa_sample_spec default_sample_spec;
+ uint32_t alternate_sample_rate;
unsigned default_n_fragments, default_fragment_size_msec;
unsigned deferred_volume_safety_margin_usec;
int deferred_volume_extra_delay_usec;
diff --git a/src/pulsecore/modargs.c b/src/pulsecore/modargs.c
index 2211cba..555c4d0 100644
--- a/src/pulsecore/modargs.c
+++ b/src/pulsecore/modargs.c
@@ -368,6 +368,19 @@ int pa_modargs_get_sample_spec(pa_modargs *ma, pa_sample_spec *rss) {
return 0;
}
+int pa_modargs_get_alternate_sample_rate(pa_modargs *ma, uint32_t *alternate_rate) {
+ pa_assert(ma);
+ pa_assert(alternate_rate);
+
+ if ((pa_modargs_get_value_u32(ma, "alternate_rate", alternate_rate)) < 0 ||
+ *alternate_rate <= 0 ||
+ *alternate_rate > PA_RATE_MAX ||
+ !((*alternate_rate % 4000 == 0) || (*alternate_rate % 11025 == 0)))
+ return -1;
+
+ return 0;
+}
+
int pa_modargs_get_channel_map(pa_modargs *ma, const char *name, pa_channel_map *rmap) {
pa_channel_map map;
const char *cm;
diff --git a/src/pulsecore/modargs.h b/src/pulsecore/modargs.h
index 1dea4ff..f6e1861 100644
--- a/src/pulsecore/modargs.h
+++ b/src/pulsecore/modargs.h
@@ -58,6 +58,9 @@ structure if no channel_map is found, using pa_channel_map_init_auto() */
int pa_modargs_get_sample_spec_and_channel_map(pa_modargs *ma, pa_sample_spec *ss, pa_channel_map *map, pa_channel_map_def_t def);
+/* Return alternate sample rate from "alternate_sample_rate" parameter */
+int pa_modargs_get_alternate_sample_rate(pa_modargs *ma, uint32_t *alternate_rate);
+
int pa_modargs_get_proplist(pa_modargs *ma, const char *name, pa_proplist *p, pa_update_mode_t m);
/* Iterate through the module argument list. The user should allocate a
commit 31a9f195fa6d8f35d1821a1b082ee929b9689e1f
Author: Arun Raghavan <arun.raghavan at collabora.co.uk>
Date: Mon Oct 17 17:09:24 2011 +0530
build-sys: Minor CXXFLAGS fix
Set it on echo-cancel-test only if webrtc support is enabled.
diff --git a/src/Makefile.am b/src/Makefile.am
index 5f8a9bb..43c600c 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -524,7 +524,9 @@ echo_cancel_test_SOURCES = $(module_echo_cancel_la_SOURCES)
nodist_echo_cancel_test_SOURCES = $(nodist_module_echo_cancel_la_SOURCES)
echo_cancel_test_LDADD = $(module_echo_cancel_la_LIBADD)
echo_cancel_test_CFLAGS = $(module_echo_cancel_la_CFLAGS) -DECHO_CANCEL_TEST=1
+if HAVE_WEBRTC
echo_cancel_test_CXXFLAGS = $(module_echo_cancel_la_CXXFLAGS) -DECHO_CANCEL_TEST=1
+endif
echo_cancel_test_LDFLAGS = $(AM_LDFLAGS) $(BINLDFLAGS)
###################################
More information about the pulseaudio-commits
mailing list