From cc021c73305023a113f78190fb1b995528d003ae Mon Sep 17 00:00:00 2001
From: Arun Raghavan
Date: Sat, 28 Jan 2017 13:19:08 +0530
Subject: [PATCH] sink, source: Add a mode to avoid resampling if possible
This adds an "avoid-resampling" option to daemon.conf that makes the
daemon try to use the stream sample rate if possible (the device needs
to support it, which currently only ALSA does), and there should not be
any other stream connected).
This should enable some of the "audiophile" use-cases where users wish
to play high sample rate audio files without resampling.
We still will do conversion if sample formats don't match, though. This
means that if you want to play 96 kHz/24 bit audio without any
modification the default format will need to be set to be 24-bit as
well. This will force all streams to be upconverted, which, other than
the wasted resources, should be relatively harmless.
---
man/pulse-daemon.conf.5.xml.in | 9 +++++++++
src/daemon/daemon-conf.c | 3 +++
src/daemon/daemon-conf.h | 1 +
src/daemon/daemon.conf.in | 1 +
src/daemon/main.c | 1 +
src/pulsecore/core.h | 1 +
src/pulsecore/sink.c | 9 +++++++--
src/pulsecore/source.c | 9 +++++++--
8 files changed, 30 insertions(+), 4 deletions(-)
diff --git a/man/pulse-daemon.conf.5.xml.in b/man/pulse-daemon.conf.5.xml.in
index b81a5493f..f0550f3b1 100644
--- a/man/pulse-daemon.conf.5.xml.in
+++ b/man/pulse-daemon.conf.5.xml.in
@@ -123,6 +123,15 @@ License along with PulseAudio; if not, see .
resampler to use.
+
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 31e4b144e..988312672 100644
--- a/src/daemon/daemon-conf.c
+++ b/src/daemon/daemon-conf.c
@@ -81,6 +81,7 @@ static const pa_daemon_conf default_conf = {
.log_meta = false,
.log_time = false,
.resample_method = PA_RESAMPLER_AUTO,
+ .avoid_resampling = false,
.disable_remixing = false,
.remixing_use_all_sink_channels = true,
.disable_lfe_remixing = true,
@@ -553,6 +554,7 @@ int pa_daemon_conf_load(pa_daemon_conf *c, const char *filename) {
{ "deferred-volume-extra-delay-usec",
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 },
{ "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",
@@ -750,6 +752,7 @@ char *pa_daemon_conf_dump(pa_daemon_conf *c) {
pa_strbuf_printf(s, "log-target = %s\n", pa_strempty(log_target));
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, "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, "enable-lfe-remixing = %s\n", pa_yes_no(!c->disable_lfe_remixing));
diff --git a/src/daemon/daemon-conf.h b/src/daemon/daemon-conf.h
index e61f67fa9..953ea33af 100644
--- a/src/daemon/daemon-conf.h
+++ b/src/daemon/daemon-conf.h
@@ -67,6 +67,7 @@ typedef struct pa_daemon_conf {
no_cpu_limit,
disable_shm,
disable_memfd,
+ avoid_resampling,
disable_remixing,
remixing_use_all_sink_channels,
disable_lfe_remixing,
diff --git a/src/daemon/daemon.conf.in b/src/daemon/daemon.conf.in
index 2d74afaed..a95552382 100644
--- a/src/daemon/daemon.conf.in
+++ b/src/daemon/daemon.conf.in
@@ -54,6 +54,7 @@ ifelse(@HAVE_DBUS@, 1, [dnl
; log-backtrace = 0
; resample-method = speex-float-1
+; avoid-resampling = false
; enable-remixing = yes
; remixing-use-all-sink-channels = yes
; enable-lfe-remixing = no
diff --git a/src/daemon/main.c b/src/daemon/main.c
index 280252ace..f35252d06 100644
--- a/src/daemon/main.c
+++ b/src/daemon/main.c
@@ -1036,6 +1036,7 @@ int main(int argc, char *argv[]) {
c->resample_method = conf->resample_method;
c->realtime_priority = conf->realtime_priority;
c->realtime_scheduling = conf->realtime_scheduling;
+ c->avoid_resampling = conf->avoid_resampling;
c->disable_remixing = conf->disable_remixing;
c->remixing_use_all_sink_channels = conf->remixing_use_all_sink_channels;
c->disable_lfe_remixing = conf->disable_lfe_remixing;
diff --git a/src/pulsecore/core.h b/src/pulsecore/core.h
index d2fe887cb..212f6f711 100644
--- a/src/pulsecore/core.h
+++ b/src/pulsecore/core.h
@@ -199,6 +199,7 @@ struct pa_core {
bool disallow_exit:1;
bool running_as_daemon:1;
bool realtime_scheduling:1;
+ bool avoid_resampling:1;
bool disable_remixing:1;
bool remixing_use_all_sink_channels:1;
bool disable_lfe_remixing:1;
diff --git a/src/pulsecore/sink.c b/src/pulsecore/sink.c
index aa2182220..1a968f355 100644
--- a/src/pulsecore/sink.c
+++ b/src/pulsecore/sink.c
@@ -1414,6 +1414,7 @@ int pa_sink_update_rate(pa_sink *s, uint32_t rate, bool passthrough) {
pa_sink_input *i;
bool default_rate_is_usable = false;
bool alternate_rate_is_usable = false;
+ bool avoid_resampling = s->core->avoid_resampling;
if (rate == s->sample_spec.rate)
return 0;
@@ -1421,7 +1422,7 @@ int pa_sink_update_rate(pa_sink *s, uint32_t rate, bool passthrough) {
if (!s->update_rate)
return -1;
- if (PA_UNLIKELY(default_rate == alternate_rate && !passthrough)) {
+ if (PA_UNLIKELY(default_rate == alternate_rate && !passthrough && !avoid_resampling)) {
pa_log_debug("Default and alternate sample rates are the same, so there is no point in switching.");
return -1;
}
@@ -1442,7 +1443,11 @@ int pa_sink_update_rate(pa_sink *s, uint32_t rate, bool passthrough) {
if (PA_UNLIKELY(!pa_sample_rate_valid(desired_rate)))
return -1;
- if (!passthrough && default_rate != desired_rate && alternate_rate != desired_rate) {
+ if (avoid_resampling && (rate >= default_rate || rate >= alternate_rate)) {
+ /* We just try to set the sink input's sample rate if it's not too low */
+ desired_rate = rate;
+
+ } else if (!passthrough && default_rate != desired_rate && alternate_rate != desired_rate) {
if (default_rate % 11025 == 0 && desired_rate % 11025 == 0)
default_rate_is_usable = true;
if (default_rate % 4000 == 0 && desired_rate % 4000 == 0)
diff --git a/src/pulsecore/source.c b/src/pulsecore/source.c
index 8ce781804..72aae4796 100644
--- a/src/pulsecore/source.c
+++ b/src/pulsecore/source.c
@@ -982,6 +982,7 @@ int pa_source_update_rate(pa_source *s, uint32_t rate, bool passthrough) {
uint32_t alternate_rate = s->alternate_sample_rate;
bool default_rate_is_usable = false;
bool alternate_rate_is_usable = false;
+ bool avoid_resampling = s->core->avoid_resampling;
if (rate == s->sample_spec.rate)
return 0;
@@ -989,7 +990,7 @@ int pa_source_update_rate(pa_source *s, uint32_t rate, bool passthrough) {
if (!s->update_rate && !s->monitor_of)
return -1;
- if (PA_UNLIKELY(default_rate == alternate_rate && !passthrough)) {
+ if (PA_UNLIKELY(default_rate == alternate_rate && !passthrough && !avoid_resampling)) {
pa_log_debug("Default and alternate sample rates are the same, so there is no point in switching.");
return -1;
}
@@ -1010,7 +1011,11 @@ int pa_source_update_rate(pa_source *s, uint32_t rate, bool passthrough) {
if (PA_UNLIKELY(!pa_sample_rate_valid(desired_rate)))
return -1;
- if (!passthrough && default_rate != desired_rate && alternate_rate != desired_rate) {
+ if (avoid_resampling && (rate >= default_rate || rate >= alternate_rate)) {
+ /* We just try to set the source output's sample rate if it's not too low */
+ desired_rate = rate;
+
+ } else if (!passthrough && default_rate != desired_rate && alternate_rate != desired_rate) {
if (default_rate % 11025 == 0 && desired_rate % 11025 == 0)
default_rate_is_usable = true;
if (default_rate % 4000 == 0 && desired_rate % 4000 == 0)