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);