[pulseaudio-discuss] [PATCH] volumes: Implement options to bypass the base volume system.

David Henningsson david.henningsson at canonical.com
Thu Sep 8 20:58:41 PDT 2011


On 09/08/2011 10:30 PM, Colin Guthrie wrote:
> When the underlying hardware (typically ALSA) reports that the dB
> volume ranges to to a value>0dB, a 'base volume' is automatically
> added. This system allows the user to utilise the full range of the
> underlying hardware controls (ranging from PA_VOLUME_MIN to
> PA_VOLUME_NORM) but still get informed, via UI clues, as to the point
> the hardware reports as 0dB (i.e. the point at which your sound should
> be unmodified).
>
> Sadly, this system does not work for some users. Sometimes the range
> where the volume remains below the underlying 0dB point is very small
> (e.g. from 0 to 20%). In this scenario, things are made very awkward for
> users as the active range they typically want to adjust is so small.

Hm. If I understand the problem correctly, the problem is that the user 
does not want to see the volume slider ranging from PA_VOLUME_MIN to
PA_VOLUME_NORM, but something different. This sounds very much like the 
PA_VOLUME_UI_MAX thing.

Let me suggest a different solution. Drop both this and 
PA_VOLUME_UI_MAX, and replace it with something more configurable. For 
every port, let the user configure the range they want to be able to 
set, so that they can set an arbitrarily range, both within and outside 
the limits of what the hardware volume supports.

I'm not sure exactly how to best store this information (udev rules? 
gconf? per-user volume database?) but my point is to have this 
information on Port level rather than card level or global level.

> Added to the above scenario, if the user has flat volumes enabled they
> will also get this limited range within application volume controls.
>
> This particular scenario has prompted some applications to implement
> their own work arounds to this problem and scale the whole volume range
> they expose to the base volume when flat volumes are enabled. This
> means that the scale the user sees inside the application will be
> different to e.g. the scale given by panel applet volume controls,
> OSD displays+volume keys and full blown mixers GUIs.
>
> This inconsistency in applications is what has prompted this feature.
> It allows users to choose whether or not they want to expose the base
> volume and get the full range of h/w control (as currently), or whether
> they would prefer to honour the 0dB of the underlying h/w and set
> that to our 0dB point (aka 100%). UIs which honour PA_VOLUME_UI_MAX will
> still offer the user some of the additional range their h/w supports
>> 0dB.
>
> The behaviour remains unchanged by default and users will have to set
> the feature manually in daemon.conf. The option is split so the user can
> choose to apply it separately for sinks (where the problem is most
> visible) and sources.

For sources, in particular microphone inputs, the base volume is usually 
very low. On a typical HDA the volume might range between -30dB to +60 
dB and usually you want to set it to something like +20 dB. My USB 
headset actually ranges from +16 dB to +29 dB, so 0 dB is not even 
settable through hw controls.

> ---
>   src/daemon/daemon-conf.c       |    6 ++++++
>   src/daemon/daemon-conf.h       |    2 ++
>   src/daemon/daemon.conf.in      |    2 ++
>   src/daemon/main.c              |    2 ++
>   src/modules/alsa/alsa-sink.c   |   17 ++++++++++++-----
>   src/modules/alsa/alsa-source.c |   17 ++++++++++++-----
>   src/pulsecore/core.h           |    2 ++
>   7 files changed, 38 insertions(+), 10 deletions(-)
>
> diff --git a/src/daemon/daemon-conf.c b/src/daemon/daemon-conf.c
> index c4ee544..5fb10a0 100644
> --- a/src/daemon/daemon-conf.c
> +++ b/src/daemon/daemon-conf.c
> @@ -71,6 +71,8 @@ static const pa_daemon_conf default_conf = {
>       .disallow_module_loading = FALSE,
>       .disallow_exit = FALSE,
>       .flat_volumes = TRUE,
> +    .sink_use_base_volume = TRUE,
> +    .source_use_base_volume = TRUE,
>       .exit_idle_time = 20,
>       .scache_idle_time = 20,
>       .auto_log_target = 1,
> @@ -535,6 +537,8 @@ int pa_daemon_conf_load(pa_daemon_conf *c, const char *filename) {
>           { "disable-shm",                pa_config_parse_bool,&c->disable_shm, NULL },
>           { "enable-shm",                 pa_config_parse_not_bool,&c->disable_shm, NULL },
>           { "flat-volumes",               pa_config_parse_bool,&c->flat_volumes, NULL },
> +        { "sink-use-base-volume",       pa_config_parse_bool,&c->sink_use_base_volume, NULL },
> +        { "source-use-base-volume",     pa_config_parse_bool,&c->source_use_base_volume, NULL },
>           { "lock-memory",                pa_config_parse_bool,&c->lock_memory, NULL },
>           { "enable-sync-volume",         pa_config_parse_bool,&c->sync_volume, NULL },
>           { "exit-idle-time",             pa_config_parse_int,&c->exit_idle_time, NULL },
> @@ -736,6 +740,8 @@ char *pa_daemon_conf_dump(pa_daemon_conf *c) {
>       pa_strbuf_printf(s, "cpu-limit = %s\n", pa_yes_no(!c->no_cpu_limit));
>       pa_strbuf_printf(s, "enable-shm = %s\n", pa_yes_no(!c->disable_shm));
>       pa_strbuf_printf(s, "flat-volumes = %s\n", pa_yes_no(c->flat_volumes));
> +    pa_strbuf_printf(s, "sink-use-base-volume = %s\n", pa_yes_no(c->sink_use_base_volume));
> +    pa_strbuf_printf(s, "source-use-base-volume = %s\n", pa_yes_no(c->source_use_base_volume));
>       pa_strbuf_printf(s, "lock-memory = %s\n", pa_yes_no(c->lock_memory));
>       pa_strbuf_printf(s, "enable-sync-volume = %s\n", pa_yes_no(c->sync_volume));
>       pa_strbuf_printf(s, "exit-idle-time = %i\n", c->exit_idle_time);
> diff --git a/src/daemon/daemon-conf.h b/src/daemon/daemon-conf.h
> index 9fd6aba..e1b7804 100644
> --- a/src/daemon/daemon-conf.h
> +++ b/src/daemon/daemon-conf.h
> @@ -75,6 +75,8 @@ typedef struct pa_daemon_conf {
>           log_meta,
>           log_time,
>           flat_volumes,
> +        sink_use_base_volume,
> +        source_use_base_volume,
>           lock_memory,
>           sync_volume;
>       pa_server_type_t local_server_type;
> diff --git a/src/daemon/daemon.conf.in b/src/daemon/daemon.conf.in
> index 6437f8f..dd80cce 100644
> --- a/src/daemon/daemon.conf.in
> +++ b/src/daemon/daemon.conf.in
> @@ -59,6 +59,8 @@ ifelse(@HAVE_DBUS@, 1, [dnl
>   ; enable-lfe-remixing = no
>
>   ; flat-volumes = yes
> +; sink-use-base-volume = yes
> +; source-use-base-volume = yes
>
>   ifelse(@HAVE_SYS_RESOURCE_H@, 1, [dnl
>   ; rlimit-fsize = -1
> diff --git a/src/daemon/main.c b/src/daemon/main.c
> index e7e5238..bcd879e 100644
> --- a/src/daemon/main.c
> +++ b/src/daemon/main.c
> @@ -1029,6 +1029,8 @@ int main(int argc, char *argv[]) {
>       c->running_as_daemon = !!conf->daemonize;
>       c->disallow_exit = conf->disallow_exit;
>       c->flat_volumes = conf->flat_volumes;
> +    c->sink_use_base_volume = conf->sink_use_base_volume;
> +    c->source_use_base_volume = conf->source_use_base_volume;
>   #ifdef HAVE_DBUS
>       c->server_type = conf->local_server_type;
>   #endif
> diff --git a/src/modules/alsa/alsa-sink.c b/src/modules/alsa/alsa-sink.c
> index 7d205bf..dc4bd52 100644
> --- a/src/modules/alsa/alsa-sink.c
> +++ b/src/modules/alsa/alsa-sink.c
> @@ -1284,14 +1284,18 @@ static void sink_set_volume_cb(pa_sink *s) {
>       pa_assert(u->mixer_path);
>       pa_assert(u->mixer_handle);
>
> -    /* Shift up by the base volume */
> -    pa_sw_cvolume_divide_scalar(&r,&s->real_volume, s->base_volume);
> +    if (u->core->sink_use_base_volume)
> +        /* Shift up by the base volume */
> +        pa_sw_cvolume_divide_scalar(&r,&s->real_volume, s->base_volume);
> +    else
> +        r = s->real_volume;
>
>       if (pa_alsa_path_set_volume(u->mixer_path, u->mixer_handle,&s->channel_map,&r, sync_volume, !sync_volume)<  0)
>           return;
>
> -    /* Shift down by the base volume, so that 0dB becomes maximum volume */
> -    pa_sw_cvolume_multiply_scalar(&r,&r, s->base_volume);
> +    if (u->core->sink_use_base_volume)
> +        /* Shift down by the base volume, so that 0dB becomes maximum volume */
> +        pa_sw_cvolume_multiply_scalar(&r,&r, s->base_volume);
>
>       u->hardware_volume = r;
>
> @@ -1421,7 +1425,10 @@ static void mixer_volume_init(struct userdata *u) {
>               pa_sink_enable_decibel_volume(u->sink, TRUE);
>               pa_log_info("Hardware volume ranges from %0.2f dB to %0.2f dB.", u->mixer_path->min_dB, u->mixer_path->max_dB);
>
> -            u->sink->base_volume = pa_sw_volume_from_dB(-u->mixer_path->max_dB);
> +            if (u->core->sink_use_base_volume)
> +                u->sink->base_volume = pa_sw_volume_from_dB(-u->mixer_path->max_dB);
> +            else
> +                u->sink->base_volume = PA_VOLUME_NORM;
>               u->sink->n_volume_steps = PA_VOLUME_NORM+1;
>
>               pa_log_info("Fixing base volume to %0.2f dB", pa_sw_volume_to_dB(u->sink->base_volume));
> diff --git a/src/modules/alsa/alsa-source.c b/src/modules/alsa/alsa-source.c
> index fa500a1..932db4e 100644
> --- a/src/modules/alsa/alsa-source.c
> +++ b/src/modules/alsa/alsa-source.c
> @@ -1135,14 +1135,18 @@ static void source_set_volume_cb(pa_source *s) {
>       pa_assert(u->mixer_path);
>       pa_assert(u->mixer_handle);
>
> -    /* Shift up by the base volume */
> -    pa_sw_cvolume_divide_scalar(&r,&s->real_volume, s->base_volume);
> +    if (u->core->source_use_base_volume)
> +        /* Shift up by the base volume */
> +        pa_sw_cvolume_divide_scalar(&r,&s->real_volume, s->base_volume);
> +    else
> +        r = s->real_volume;
>
>       if (pa_alsa_path_set_volume(u->mixer_path, u->mixer_handle,&s->channel_map,&r, sync_volume, !sync_volume)<  0)
>           return;
>
> -    /* Shift down by the base volume, so that 0dB becomes maximum volume */
> -    pa_sw_cvolume_multiply_scalar(&r,&r, s->base_volume);
> +    if (u->core->source_use_base_volume)
> +        /* Shift down by the base volume, so that 0dB becomes maximum volume */
> +        pa_sw_cvolume_multiply_scalar(&r,&r, s->base_volume);
>
>       u->hardware_volume = r;
>
> @@ -1272,7 +1276,10 @@ static void mixer_volume_init(struct userdata *u) {
>               pa_source_enable_decibel_volume(u->source, TRUE);
>               pa_log_info("Hardware volume ranges from %0.2f dB to %0.2f dB.", u->mixer_path->min_dB, u->mixer_path->max_dB);
>
> -            u->source->base_volume = pa_sw_volume_from_dB(-u->mixer_path->max_dB);
> +            if (u->core->source_use_base_volume)
> +                u->source->base_volume = pa_sw_volume_from_dB(-u->mixer_path->max_dB);
> +            else
> +                u->source->base_volume = PA_VOLUME_NORM;
>               u->source->n_volume_steps = PA_VOLUME_NORM+1;
>
>               pa_log_info("Fixing base volume to %0.2f dB", pa_sw_volume_to_dB(u->source->base_volume));
> diff --git a/src/pulsecore/core.h b/src/pulsecore/core.h
> index d4639e0..1e93f0d 100644
> --- a/src/pulsecore/core.h
> +++ b/src/pulsecore/core.h
> @@ -163,6 +163,8 @@ struct pa_core {
>       int exit_idle_time, scache_idle_time;
>
>       pa_bool_t flat_volumes:1;
> +    pa_bool_t sink_use_base_volume:1;
> +    pa_bool_t source_use_base_volume:1;
>       pa_bool_t disallow_module_loading:1;
>       pa_bool_t disallow_exit:1;
>       pa_bool_t running_as_daemon:1;



-- 
David Henningsson, Canonical Ltd.
http://launchpad.net/~diwic


More information about the pulseaudio-discuss mailing list