From 01c26546fa4ca4c89d0ca850e2b50a847c3a70f4 Mon Sep 17 00:00:00 2001
From: Arun Raghavan
Date: Mon, 24 Sep 2018 13:51:23 +0530
Subject: [PATCH] sink, source: Add an avoid-processing mode
This generalises the avoid-resampling concept (don't resample for any
rate above the default/alternate sample rate) to include channel count
and sample format as well. The rationale for this is that users who wish
to send out their data untouched by processing in PulseAudio can do so.
In addition to this, there are opportunities for certain hardware (such
as systems with a DSP connected to a codec) to offload processing to the
DSP (providing potential cost savings).
Finally, this also enables modules that might be able to perform
transformations of (ANY -> sink format), and this allows us to implement
such transformations.
---
man/pulse-daemon.conf.5.xml.in | 10 +++++++++
src/daemon/daemon-conf.c | 3 +++
src/daemon/daemon-conf.h | 1 +
src/daemon/daemon.conf.in | 1 +
src/daemon/main.c | 1 +
src/modules/alsa/alsa-sink.c | 9 ++++++++
src/modules/alsa/alsa-source.c | 9 ++++++++
src/modules/alsa/module-alsa-card.c | 2 ++
src/modules/module-udev-detect.c | 17 ++++++++++++--
src/pulsecore/core.h | 1 +
src/pulsecore/sink.c | 35 ++++++++++++++++++++++++-----
src/pulsecore/sink.h | 6 ++++-
src/pulsecore/source.c | 34 +++++++++++++++++++++++-----
src/pulsecore/source.h | 6 ++++-
14 files changed, 121 insertions(+), 14 deletions(-)
diff --git a/man/pulse-daemon.conf.5.xml.in b/man/pulse-daemon.conf.5.xml.in
index 52223fb8c..b6e2c9c14 100644
--- a/man/pulse-daemon.conf.5.xml.in
+++ b/man/pulse-daemon.conf.5.xml.in
@@ -132,6 +132,16 @@ License along with PulseAudio; if not, see .
rates.
+
enable-remixing= If disabled never upmix or
downmix channels to different channel maps. Instead, do a simple
diff --git a/src/daemon/daemon-conf.c b/src/daemon/daemon-conf.c
index ffef554be..7a75be04e 100644
--- a/src/daemon/daemon-conf.c
+++ b/src/daemon/daemon-conf.c
@@ -83,6 +83,7 @@ static const pa_daemon_conf default_conf = {
.log_time = false,
.resample_method = PA_RESAMPLER_AUTO,
.avoid_resampling = false,
+ .avoid_processing = false,
.disable_remixing = false,
.remixing_use_all_sink_channels = true,
.remixing_produce_lfe = false,
@@ -606,6 +607,7 @@ int pa_daemon_conf_load(pa_daemon_conf *c, const char *filename) {
pa_config_parse_int, &c->deferred_volume_extra_delay_usec, NULL },
{ "nice-level", parse_nice_level, c, NULL },
{ "avoid-resampling", pa_config_parse_bool, &c->avoid_resampling, NULL },
+ { "avoid-processing", pa_config_parse_bool, &c->avoid_processing, NULL },
{ "disable-remixing", pa_config_parse_bool, &c->disable_remixing, NULL },
{ "enable-remixing", pa_config_parse_not_bool, &c->disable_remixing, NULL },
{ "remixing-use-all-sink-channels",
@@ -819,6 +821,7 @@ char *pa_daemon_conf_dump(pa_daemon_conf *c) {
pa_strbuf_printf(s, "log-level = %s\n", log_level_to_string[c->log_level]);
pa_strbuf_printf(s, "resample-method = %s\n", pa_resample_method_to_string(c->resample_method));
pa_strbuf_printf(s, "avoid-resampling = %s\n", pa_yes_no(c->avoid_resampling));
+ pa_strbuf_printf(s, "avoid-processing = %s\n", pa_yes_no(c->avoid_processing));
pa_strbuf_printf(s, "enable-remixing = %s\n", pa_yes_no(!c->disable_remixing));
pa_strbuf_printf(s, "remixing-use-all-sink-channels = %s\n", pa_yes_no(c->remixing_use_all_sink_channels));
pa_strbuf_printf(s, "remixing-produce-lfe = %s\n", pa_yes_no(c->remixing_produce_lfe));
diff --git a/src/daemon/daemon-conf.h b/src/daemon/daemon-conf.h
index fa713b95d..31a5a8821 100644
--- a/src/daemon/daemon-conf.h
+++ b/src/daemon/daemon-conf.h
@@ -68,6 +68,7 @@ typedef struct pa_daemon_conf {
disable_shm,
disable_memfd,
avoid_resampling,
+ avoid_processing,
disable_remixing,
remixing_use_all_sink_channels,
remixing_produce_lfe,
diff --git a/src/daemon/daemon.conf.in b/src/daemon/daemon.conf.in
index 7409976d1..c8e0bbaae 100644
--- a/src/daemon/daemon.conf.in
+++ b/src/daemon/daemon.conf.in
@@ -55,6 +55,7 @@ ifelse(@HAVE_DBUS@, 1, [dnl
; resample-method = speex-float-1
; avoid-resampling = false
+; avoid-processing = false
; enable-remixing = yes
; remixing-use-all-sink-channels = yes
; remixing-produce-lfe = no
diff --git a/src/daemon/main.c b/src/daemon/main.c
index 924a4d4aa..775cf2cde 100644
--- a/src/daemon/main.c
+++ b/src/daemon/main.c
@@ -1208,6 +1208,7 @@ int main(int argc, char *argv[]) {
c->realtime_priority = conf->realtime_priority;
c->realtime_scheduling = conf->realtime_scheduling;
c->avoid_resampling = conf->avoid_resampling;
+ c->avoid_processing = conf->avoid_processing;
c->disable_remixing = conf->disable_remixing;
c->remixing_use_all_sink_channels = conf->remixing_use_all_sink_channels;
c->remixing_produce_lfe = conf->remixing_produce_lfe;
diff --git a/src/modules/alsa/alsa-sink.c b/src/modules/alsa/alsa-sink.c
index b2c142bf3..6ffdf6ea7 100644
--- a/src/modules/alsa/alsa-sink.c
+++ b/src/modules/alsa/alsa-sink.c
@@ -2348,6 +2348,7 @@ pa_sink *pa_alsa_sink_new(pa_module *m, pa_modargs *ma, const char*driver, pa_ca
bool b;
bool d;
bool avoid_resampling;
+ bool avoid_processing;
pa_sink_new_data data;
bool volume_is_set;
bool mute_is_set;
@@ -2364,6 +2365,7 @@ pa_sink *pa_alsa_sink_new(pa_module *m, pa_modargs *ma, const char*driver, pa_ca
ss = m->core->default_sample_spec;
map = m->core->default_channel_map;
avoid_resampling = m->core->avoid_resampling;
+ avoid_processing = m->core->avoid_processing;
/* Pick sample spec overrides from the mapping, if any */
if (mapping) {
@@ -2640,6 +2642,13 @@ pa_sink *pa_alsa_sink_new(pa_module *m, pa_modargs *ma, const char*driver, pa_ca
}
pa_sink_new_data_set_avoid_resampling(&data, avoid_resampling);
+ if (pa_modargs_get_value_boolean(ma, "avoid_processing", &avoid_processing) < 0) {
+ pa_log("Failed to parse avoid_processing argument.");
+ pa_sink_new_data_done(&data);
+ goto fail;
+ }
+ pa_sink_new_data_set_avoid_processing(&data, avoid_processing);
+
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);
diff --git a/src/modules/alsa/alsa-source.c b/src/modules/alsa/alsa-source.c
index 24fae97c0..ee2d04d9a 100644
--- a/src/modules/alsa/alsa-source.c
+++ b/src/modules/alsa/alsa-source.c
@@ -2050,6 +2050,7 @@ pa_source *pa_alsa_source_new(pa_module *m, pa_modargs *ma, const char*driver, p
bool b;
bool d;
bool avoid_resampling;
+ bool avoid_processing;
pa_source_new_data data;
bool volume_is_set;
bool mute_is_set;
@@ -2062,6 +2063,7 @@ pa_source *pa_alsa_source_new(pa_module *m, pa_modargs *ma, const char*driver, p
ss = m->core->default_sample_spec;
map = m->core->default_channel_map;
avoid_resampling = m->core->avoid_resampling;
+ avoid_processing = m->core->avoid_processing;
/* Pick sample spec overrides from the mapping, if any */
if (mapping) {
@@ -2320,6 +2322,13 @@ pa_source *pa_alsa_source_new(pa_module *m, pa_modargs *ma, const char*driver, p
}
pa_source_new_data_set_avoid_resampling(&data, avoid_resampling);
+ if (pa_modargs_get_value_boolean(ma, "avoid_processing", &avoid_processing) < 0) {
+ pa_log("Failed to parse avoid_processing argument.");
+ pa_source_new_data_done(&data);
+ goto fail;
+ }
+ pa_source_new_data_set_avoid_processing(&data, avoid_processing);
+
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);
diff --git a/src/modules/alsa/module-alsa-card.c b/src/modules/alsa/module-alsa-card.c
index 05c87c6bb..4d53bc0de 100644
--- a/src/modules/alsa/module-alsa-card.c
+++ b/src/modules/alsa/module-alsa-card.c
@@ -69,6 +69,7 @@ PA_MODULE_USAGE(
"paths_dir= "
"use_ucm= "
"avoid_resampling= "
+ "avoid_processing= "
"control= "
);
@@ -98,6 +99,7 @@ static const char* const valid_modargs[] = {
"paths_dir",
"use_ucm",
"avoid_resampling",
+ "avoid_processing",
"control",
NULL
};
diff --git a/src/modules/module-udev-detect.c b/src/modules/module-udev-detect.c
index 7a107c44d..72b431d4d 100644
--- a/src/modules/module-udev-detect.c
+++ b/src/modules/module-udev-detect.c
@@ -47,7 +47,8 @@ PA_MODULE_USAGE(
"ignore_dB= "
"deferred_volume= "
"use_ucm= "
- "avoid_resampling=");
+ "avoid_resampling= "
+ "avoid_processing=");
struct device {
char *path;
@@ -70,6 +71,7 @@ struct userdata {
bool deferred_volume:1;
bool use_ucm:1;
bool avoid_resampling:1;
+ bool avoid_processing:1;
uint32_t tsched_buffer_size;
@@ -89,6 +91,7 @@ static const char* const valid_modargs[] = {
"deferred_volume",
"use_ucm",
"avoid_resampling",
+ "avoid_processing",
NULL
};
@@ -415,6 +418,7 @@ static void card_changed(struct userdata *u, struct udev_device *dev) {
"deferred_volume=%s "
"use_ucm=%s "
"avoid_resampling=%s "
+ "avoid_processing=%s "
"card_properties=\"module-udev-detect.discovered=1\"",
path_get_card_id(path),
n,
@@ -424,7 +428,8 @@ static void card_changed(struct userdata *u, struct udev_device *dev) {
pa_yes_no(u->ignore_dB),
pa_yes_no(u->deferred_volume),
pa_yes_no(u->use_ucm),
- pa_yes_no(u->avoid_resampling));
+ pa_yes_no(u->avoid_resampling),
+ pa_yes_no(u->avoid_processing));
pa_xfree(n);
if (u->tsched_buffer_size_valid)
@@ -698,6 +703,7 @@ int pa__init(pa_module *m) {
bool use_tsched = true, fixed_latency_range = false, ignore_dB = false, deferred_volume = m->core->deferred_volume;
bool use_ucm = true;
bool avoid_resampling;
+ bool avoid_processing;
pa_assert(m);
@@ -757,6 +763,13 @@ int pa__init(pa_module *m) {
}
u->avoid_resampling = avoid_resampling;
+ avoid_processing = m->core->avoid_processing;
+ if (pa_modargs_get_value_boolean(ma, "avoid_processing", &avoid_processing) < 0) {
+ pa_log("Failed to parse avoid_processing= argument.");
+ goto fail;
+ }
+ u->avoid_processing = avoid_processing;
+
if (!(u->udev = udev_new())) {
pa_log("Failed to initialize udev library.");
goto fail;
diff --git a/src/pulsecore/core.h b/src/pulsecore/core.h
index 118dcf291..00ed08297 100644
--- a/src/pulsecore/core.h
+++ b/src/pulsecore/core.h
@@ -221,6 +221,7 @@ struct pa_core {
bool running_as_daemon:1;
bool realtime_scheduling:1;
bool avoid_resampling:1;
+ bool avoid_processing:1;
bool disable_remixing:1;
bool remixing_use_all_sink_channels:1;
bool remixing_produce_lfe:1;
diff --git a/src/pulsecore/sink.c b/src/pulsecore/sink.c
index d4011f9e3..9231cf9d6 100644
--- a/src/pulsecore/sink.c
+++ b/src/pulsecore/sink.c
@@ -121,6 +121,13 @@ void pa_sink_new_data_set_avoid_resampling(pa_sink_new_data *data, bool avoid_re
data->avoid_resampling = avoid_resampling;
}
+void pa_sink_new_data_set_avoid_processing(pa_sink_new_data *data, bool avoid_processing) {
+ pa_assert(data);
+
+ data->avoid_processing_is_set = true;
+ data->avoid_processing = avoid_processing;
+}
+
void pa_sink_new_data_set_volume(pa_sink_new_data *data, const pa_cvolume *volume) {
pa_assert(data);
@@ -272,7 +279,7 @@ 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;
+ s->default_sample_spec = s->sample_spec;
pa_sample_spec_init(&s->saved_spec);
pa_channel_map_init(&s->saved_map);
@@ -286,6 +293,11 @@ pa_sink* pa_sink_new(
else
s->avoid_resampling = s->core->avoid_resampling;
+ if (data->avoid_processing_is_set)
+ s->avoid_processing = data->avoid_processing;
+ else
+ s->avoid_processing = s->core->avoid_processing;
+
s->inputs = pa_idxset_new(NULL, NULL);
s->n_corked = 0;
s->input_to_master = NULL;
@@ -378,6 +390,7 @@ pa_sink* pa_sink_new(
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);
pa_source_new_data_set_avoid_resampling(&source_data, s->avoid_resampling);
+ pa_source_new_data_set_avoid_processing(&source_data, s->avoid_processing);
source_data.name = pa_sprintf_malloc("%s.monitor", name);
source_data.driver = data->driver;
source_data.module = data->module;
@@ -1484,13 +1497,16 @@ void pa_sink_render_full(pa_sink *s, size_t length, pa_memchunk *result) {
int pa_sink_reconfigure(pa_sink *s, pa_sample_spec *spec, pa_channel_map *map, bool passthrough, bool restore) {
int ret = -1;
pa_sample_spec desired_spec;
- uint32_t default_rate = s->default_sample_rate;
+ pa_sample_format_t default_format = s->default_sample_spec.format;
+ uint32_t default_rate = s->default_sample_spec.rate;
uint32_t alternate_rate = s->alternate_sample_rate;
+ uint8_t default_channels = s->default_sample_spec.channels;
uint32_t idx;
pa_sink_input *i;
bool default_rate_is_usable = false;
bool alternate_rate_is_usable = false;
bool avoid_resampling = s->avoid_resampling;
+ bool avoid_processing = s->avoid_processing;
pa_channel_map old_map, *new_map;
pa_assert(restore || (spec != NULL));
@@ -1502,7 +1518,7 @@ int pa_sink_reconfigure(pa_sink *s, pa_sample_spec *spec, pa_channel_map *map, b
if (!s->reconfigure)
return -1;
- if (PA_UNLIKELY(default_rate == alternate_rate && !passthrough && !restore && !avoid_resampling)) {
+ if (PA_UNLIKELY(default_rate == alternate_rate && !passthrough && !restore && !avoid_resampling && !avoid_processing)) {
pa_log_debug("Default and alternate sample rates are the same, so there is no point in switching.");
return -1;
}
@@ -1541,13 +1557,22 @@ int pa_sink_reconfigure(pa_sink *s, pa_sample_spec *spec, pa_channel_map *map, b
/* We have to try to use the sink input spec */
desired_spec = *spec;
+ } else if (avoid_processing) {
+ desired_spec = s->sample_spec;
+
+ if (spec->rate >= default_rate || spec->rate >= alternate_rate)
+ desired_spec.rate = spec->rate;
+ if (spec->channels >= default_channels)
+ desired_spec.channels = spec->channels;
+ if (pa_sample_size_of_format(spec->format) >= pa_sample_size_of_format(default_format))
+ desired_spec.format = spec->format;
+
} else if (avoid_resampling) {
/* We just try to set the sink input's sample rate if it's not too low */
desired_spec = s->sample_spec;
+
if (spec->rate >= default_rate || spec->rate >= alternate_rate)
desired_spec.rate = spec->rate;
- /* FIXME: don't set this if it's too low */
- desired_spec.format = spec->format;
} else if (default_rate == spec->rate || alternate_rate == spec->rate) {
/* We can directly try to use this rate */
diff --git a/src/pulsecore/sink.h b/src/pulsecore/sink.h
index 8a15415d1..e83477761 100644
--- a/src/pulsecore/sink.h
+++ b/src/pulsecore/sink.h
@@ -81,9 +81,10 @@ struct pa_sink {
pa_sample_spec sample_spec;
pa_channel_map channel_map;
- uint32_t default_sample_rate;
+ pa_sample_spec default_sample_spec;
uint32_t alternate_sample_rate;
bool avoid_resampling:1;
+ bool avoid_processing:1;
pa_idxset *inputs;
unsigned n_corked;
@@ -385,6 +386,7 @@ typedef struct pa_sink_new_data {
pa_channel_map channel_map;
uint32_t alternate_sample_rate;
bool avoid_resampling:1;
+ bool avoid_processing:1;
pa_cvolume volume;
bool muted:1;
@@ -392,6 +394,7 @@ typedef struct pa_sink_new_data {
bool channel_map_is_set:1;
bool alternate_sample_rate_is_set:1;
bool avoid_resampling_is_set:1;
+ bool avoid_processing_is_set:1;
bool volume_is_set:1;
bool muted_is_set:1;
@@ -408,6 +411,7 @@ void pa_sink_new_data_set_sample_spec(pa_sink_new_data *data, const pa_sample_sp
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_avoid_resampling(pa_sink_new_data *data, bool avoid_resampling);
+void pa_sink_new_data_set_avoid_processing(pa_sink_new_data *data, bool avoid_processing);
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, bool mute);
void pa_sink_new_data_set_port(pa_sink_new_data *data, const char *port);
diff --git a/src/pulsecore/source.c b/src/pulsecore/source.c
index c46879828..2e62a8593 100644
--- a/src/pulsecore/source.c
+++ b/src/pulsecore/source.c
@@ -111,6 +111,13 @@ void pa_source_new_data_set_avoid_resampling(pa_source_new_data *data, bool avoi
data->avoid_resampling = avoid_resampling;
}
+void pa_source_new_data_set_avoid_processing(pa_source_new_data *data, bool avoid_processing) {
+ pa_assert(data);
+
+ data->avoid_processing_is_set = true;
+ data->avoid_processing = avoid_processing;
+}
+
void pa_source_new_data_set_volume(pa_source_new_data *data, const pa_cvolume *volume) {
pa_assert(data);
@@ -258,7 +265,7 @@ 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;
+ s->default_sample_spec = s->sample_spec;
pa_sample_spec_init(&s->saved_spec);
pa_channel_map_init(&s->saved_map);
@@ -272,6 +279,11 @@ pa_source* pa_source_new(
else
s->avoid_resampling = s->core->avoid_resampling;
+ if (data->avoid_processing_is_set)
+ s->avoid_processing = data->avoid_processing;
+ else
+ s->avoid_processing = s->core->avoid_processing;
+
s->outputs = pa_idxset_new(NULL, NULL);
s->n_corked = 0;
s->monitor_of = NULL;
@@ -1050,11 +1062,14 @@ void pa_source_post_direct(pa_source*s, pa_source_output *o, const pa_memchunk *
int pa_source_reconfigure(pa_source *s, pa_sample_spec *spec, pa_channel_map *map, bool passthrough, bool restore) {
int ret;
pa_sample_spec desired_spec;
- uint32_t default_rate = s->default_sample_rate;
+ pa_sample_format_t default_format = s->default_sample_spec.format;
+ uint32_t default_rate = s->default_sample_spec.rate;
uint32_t alternate_rate = s->alternate_sample_rate;
+ uint8_t default_channels = s->default_sample_spec.channels;
bool default_rate_is_usable = false;
bool alternate_rate_is_usable = false;
bool avoid_resampling = s->avoid_resampling;
+ bool avoid_processing = s->avoid_processing;
pa_channel_map old_map, *new_map;
pa_assert(restore || (spec != NULL));
@@ -1066,7 +1081,7 @@ int pa_source_reconfigure(pa_source *s, pa_sample_spec *spec, pa_channel_map *ma
if (!s->reconfigure && !s->monitor_of)
return -1;
- if (PA_UNLIKELY(default_rate == alternate_rate && !passthrough && !restore && !avoid_resampling)) {
+ if (PA_UNLIKELY(default_rate == alternate_rate && !passthrough && !restore && !avoid_resampling && !avoid_processing)) {
pa_log_debug("Default and alternate sample rates are the same, so there is no point in switching.");
return -1;
}
@@ -1105,13 +1120,22 @@ int pa_source_reconfigure(pa_source *s, pa_sample_spec *spec, pa_channel_map *ma
/* We have to try to use the source output spec */
desired_spec = *spec;
+ } else if (avoid_processing) {
+ desired_spec = s->sample_spec;
+
+ if (spec->rate >= default_rate || spec->rate >= alternate_rate)
+ desired_spec.rate = spec->rate;
+ if (spec->channels >= default_channels)
+ desired_spec.channels = spec->channels;
+ if (pa_sample_size_of_format(spec->format) >= pa_sample_size_of_format(default_format))
+ desired_spec.format = spec->format;
+
} else if (avoid_resampling) {
/* We just try to set the source output's sample rate if it's not too low */
desired_spec = s->sample_spec;
+
if (spec->rate >= default_rate || spec->rate >= alternate_rate)
desired_spec.rate = spec->rate;
- /* FIXME: don't set this if it's too low */
- desired_spec.format = spec->format;
} else if (default_rate == spec->rate || alternate_rate == spec->rate) {
/* We can directly try to use this rate */
diff --git a/src/pulsecore/source.h b/src/pulsecore/source.h
index 64f534b1b..daaa4c6d8 100644
--- a/src/pulsecore/source.h
+++ b/src/pulsecore/source.h
@@ -82,9 +82,10 @@ struct pa_source {
pa_sample_spec sample_spec;
pa_channel_map channel_map;
- uint32_t default_sample_rate;
+ pa_sample_spec default_sample_spec;
uint32_t alternate_sample_rate;
bool avoid_resampling:1;
+ bool avoid_processing:1;
pa_idxset *outputs;
unsigned n_corked;
@@ -319,6 +320,7 @@ typedef struct pa_source_new_data {
pa_channel_map channel_map;
uint32_t alternate_sample_rate;
bool avoid_resampling:1;
+ bool avoid_processing:1;
pa_cvolume volume;
bool muted:1;
@@ -328,6 +330,7 @@ typedef struct pa_source_new_data {
bool channel_map_is_set:1;
bool alternate_sample_rate_is_set:1;
bool avoid_resampling_is_set:1;
+ bool avoid_processing_is_set:1;
bool namereg_fail:1;
@@ -342,6 +345,7 @@ void pa_source_new_data_set_sample_spec(pa_source_new_data *data, const pa_sampl
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_avoid_resampling(pa_source_new_data *data, bool avoid_resampling);
+void pa_source_new_data_set_avoid_processing(pa_source_new_data *data, bool avoid_processing);
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, bool mute);
void pa_source_new_data_set_port(pa_source_new_data *data, const char *port);