[pulseaudio-commits] [SCM] PulseAudio Sound Server branch, master, updated. v0.9.15-test8-23-gfe8b10c

Lennart Poettering gitmailer-noreply at 0pointer.de
Mon Apr 13 13:57:17 PDT 2009


This is an automated email from the git hooks/post-receive script. It was
generated because of a push to the "PulseAudio Sound Server" repository.

The master branch has been updated
      from  6eaeaea581e730461404b5e77729d1e9476dec00 (commit)

- Log -----------------------------------------------------------------
fe8b10c core: introduce new 'reference' volume for sinks
49dcf09 alsa: include the alsa mixer control that is used in the property list
6fd8fd1 alsa: store mixer controls to use in profile data
89f74cb alsa: when passing emptry mixer control name, force sw volume
237a9e1 volume: increase dB range to -90dB
0ac038e client-conf-x11: unbreak autospawn due to stale X11 properties
0aed5ea client-conf: when  is set, disable autospawn setting
4cc4cbd client-conf: make setting a default server independant from the autospawn setting
20aba71 proplist-util: use pa_session_id() instead of accessing 7b816367b01393ed3e3e650047d78f6e-1239640487.203609-1061245823 directly
43650de client-conf: modernize a few things
a36197c print session id when starting up
1d8da03 core-util: filter utf8 in pa_machine_id()
1b4e5f1 core-util: add pa_session_id()
17f1784 cork-music-on-phone: make sure that we don't check the refcnt of pa_core when the daemon goes down
62db10c lirc: fix logic behind mute buttons
66d2184 mmkbd: get rid of support for ancient kernels
f1d3dfb mmkbd,lirc: make use of pa_assert_not_reached()
270a698 lirc, mmkbd: extend controllable volume range to PA_VOLUME_MAX
6d218e9 api: introduce PA_VOLUME_MAX
e9dd7a5 lirc: drop lirc_in_use, it's made redundant by PA_MODULE_LOAD_ONCE
d8de5d3 make sure we never overflow when calculating sleep time
-----------------------------------------------------------------------

Summary of changes:
 src/daemon/main.c                        |    5 +
 src/modules/alsa/alsa-sink.c             |   22 ++++-
 src/modules/alsa/alsa-source.c           |   20 ++++-
 src/modules/alsa/alsa-util.c             |   63 ++++++++++---
 src/modules/alsa/alsa-util.h             |   12 ++-
 src/modules/module-cork-music-on-phone.c |    1 -
 src/modules/module-device-restore.c      |    2 +-
 src/modules/module-lirc.c                |   33 +++-----
 src/modules/module-match.c               |    2 +-
 src/modules/module-mmkbd-evdev.c         |   39 +++-----
 src/modules/module-stream-restore.c      |  142 +++++++++++-------------------
 src/modules/module-x11-publish.c         |    8 ++-
 src/modules/oss/module-oss.c             |    2 +-
 src/pulse/client-conf-x11.c              |   15 +++
 src/pulse/client-conf.c                  |   31 +++----
 src/pulse/context.c                      |   24 +++---
 src/pulse/volume.c                       |    2 +-
 src/pulse/volume.h                       |    8 ++-
 src/pulsecore/cli-command.c              |    6 +-
 src/pulsecore/cli-text.c                 |   15 ++--
 src/pulsecore/core-util.c                |   18 +++-
 src/pulsecore/core-util.h                |    1 +
 src/pulsecore/proplist-util.c            |    9 +-
 src/pulsecore/protocol-esound.c          |    5 +-
 src/pulsecore/protocol-native.c          |    9 +-
 src/pulsecore/sink-input.c               |   55 +++++++-----
 src/pulsecore/sink-input.h               |    8 ++-
 src/pulsecore/sink.c                     |   42 ++++++----
 src/pulsecore/sink.h                     |   11 ++-
 29 files changed, 339 insertions(+), 271 deletions(-)

-----------------------------------------------------------------------

commit d8de5d374e0a5f438eeaa2b6c1e0771801736502
Author: Lennart Poettering <lennart at poettering.net>
Date:   Mon Apr 13 03:40:46 2009 +0200

    make sure we never overflow when calculating sleep time
    
    Issue pointed out by Jaroslav Kysela

diff --git a/src/modules/alsa/alsa-sink.c b/src/modules/alsa/alsa-sink.c
index 401b003..6ed1c3a 100644
--- a/src/modules/alsa/alsa-sink.c
+++ b/src/modules/alsa/alsa-sink.c
@@ -483,7 +483,13 @@ static int mmap_write(struct userdata *u, pa_usec_t *sleep_usec, pa_bool_t polle
         }
     }
 
-    *sleep_usec = pa_bytes_to_usec(left_to_play, &u->sink->sample_spec) - process_usec;
+    *sleep_usec = pa_bytes_to_usec(left_to_play, &u->sink->sample_spec);
+
+    if (*sleep_usec > process_usec)
+        *sleep_usec -= process_usec;
+    else
+        *sleep_usec = 0;
+
     return work_done ? 1 : 0;
 }
 
@@ -605,7 +611,13 @@ static int unix_write(struct userdata *u, pa_usec_t *sleep_usec, pa_bool_t polle
         }
     }
 
-    *sleep_usec = pa_bytes_to_usec(left_to_play, &u->sink->sample_spec) - process_usec;
+    *sleep_usec = pa_bytes_to_usec(left_to_play, &u->sink->sample_spec);
+
+    if (*sleep_usec > process_usec)
+        *sleep_usec -= process_usec;
+    else
+        *sleep_usec = 0;
+
     return work_done ? 1 : 0;
 }
 
diff --git a/src/modules/alsa/alsa-source.c b/src/modules/alsa/alsa-source.c
index 99e825c..d87ab80 100644
--- a/src/modules/alsa/alsa-source.c
+++ b/src/modules/alsa/alsa-source.c
@@ -465,7 +465,13 @@ static int mmap_read(struct userdata *u, pa_usec_t *sleep_usec, pa_bool_t polled
         }
     }
 
-    *sleep_usec = pa_bytes_to_usec(left_to_record, &u->source->sample_spec) - process_usec;
+    *sleep_usec = pa_bytes_to_usec(left_to_record, &u->source->sample_spec);
+
+    if (*sleep_usec > process_usec)
+        *sleep_usec -= process_usec;
+    else
+        *sleep_usec = 0;
+
     return work_done ? 1 : 0;
 }
 
@@ -575,7 +581,13 @@ static int unix_read(struct userdata *u, pa_usec_t *sleep_usec, pa_bool_t polled
         }
     }
 
-    *sleep_usec = pa_bytes_to_usec(left_to_record, &u->source->sample_spec) - process_usec;
+    *sleep_usec = pa_bytes_to_usec(left_to_record, &u->source->sample_spec);
+
+    if (*sleep_usec > process_usec)
+        *sleep_usec -= process_usec;
+    else
+        *sleep_usec = 0;
+
     return work_done ? 1 : 0;
 }
 

commit e9dd7a504e5495de864446ee0c4c344e10c67a41
Author: Lennart Poettering <lennart at poettering.net>
Date:   Mon Apr 13 04:38:57 2009 +0200

    lirc: drop lirc_in_use, it's made redundant by PA_MODULE_LOAD_ONCE

diff --git a/src/modules/module-lirc.c b/src/modules/module-lirc.c
index bdb8bb7..d1ee262 100644
--- a/src/modules/module-lirc.c
+++ b/src/modules/module-lirc.c
@@ -63,8 +63,6 @@ struct userdata {
     float mute_toggle_save;
 };
 
-static int lirc_in_use = 0;
-
 static void io_callback(pa_mainloop_api *io, pa_io_event *e, int fd, pa_io_event_flags_t events, void*userdata) {
     struct userdata *u = userdata;
     char *name = NULL, *code = NULL;
@@ -189,11 +187,6 @@ int pa__init(pa_module*m) {
 
     pa_assert(m);
 
-    if (lirc_in_use) {
-        pa_log("module-lirc may no be loaded twice.");
-        return -1;
-    }
-
     if (!(ma = pa_modargs_new(m->argument, valid_modargs))) {
         pa_log("Failed to parse module arguments");
         goto fail;
@@ -219,8 +212,6 @@ int pa__init(pa_module*m) {
 
     u->io = m->core->mainloop->io_new(m->core->mainloop, u->lirc_fd, PA_IO_EVENT_INPUT|PA_IO_EVENT_HANGUP, io_callback, u);
 
-    lirc_in_use = 1;
-
     pa_modargs_free(ma);
 
     return 0;
@@ -252,6 +243,4 @@ void pa__done(pa_module*m) {
 
     pa_xfree(u->sink_name);
     pa_xfree(u);
-
-    lirc_in_use = 0;
 }

commit 6d218e96348b2873b20b91ef2e785333ceb65fe3
Author: Lennart Poettering <lennart at poettering.net>
Date:   Mon Apr 13 04:39:45 2009 +0200

    api: introduce PA_VOLUME_MAX

diff --git a/src/pulse/volume.h b/src/pulse/volume.h
index c3c396c..5b7e121 100644
--- a/src/pulse/volume.h
+++ b/src/pulse/volume.h
@@ -24,6 +24,7 @@
 ***/
 
 #include <inttypes.h>
+#include <limits.h>
 
 #include <pulse/cdecl.h>
 #include <pulse/gccmacro.h>
@@ -102,12 +103,15 @@ PA_C_DECL_BEGIN
  * > PA_VOLUME_NORM: increased volume */
 typedef uint32_t pa_volume_t;
 
-/** Normal volume (100%) */
+/** Normal volume (100%, 0 dB) */
 #define PA_VOLUME_NORM ((pa_volume_t) 0x10000U)
 
-/** Muted volume (0%) */
+/** Muted volume (0%, -inf dB) */
 #define PA_VOLUME_MUTED ((pa_volume_t) 0U)
 
+/** Maximum volume we can store. \since 0.9.15 */
+#define PA_VOLUME_MAX ((pa_volume_t) UINT32_MAX)
+
 /** A structure encapsulating a per-channel volume */
 typedef struct pa_cvolume {
     uint8_t channels;                     /**< Number of channels */

commit 270a6981f745a05354e09d72a7b6c3dfd4af72d3
Author: Lennart Poettering <lennart at poettering.net>
Date:   Mon Apr 13 04:41:51 2009 +0200

    lirc, mmkbd: extend controllable volume range to PA_VOLUME_MAX

diff --git a/src/modules/module-lirc.c b/src/modules/module-lirc.c
index d1ee262..1a318a5 100644
--- a/src/modules/module-lirc.c
+++ b/src/modules/module-lirc.c
@@ -127,10 +127,10 @@ static void io_callback(pa_mainloop_api *io, pa_io_event *e, int fd, pa_io_event
                     switch (volchange) {
                         case UP:
                             for (i = 0; i < cv.channels; i++) {
-                                cv.values[i] += DELTA;
-
-                                if (cv.values[i] > PA_VOLUME_NORM)
-                                    cv.values[i] = PA_VOLUME_NORM;
+                                if (cv.values[i] < PA_VOLUME_MAX - DELTA)
+                                    cv.values[i] += DELTA;
+                                else
+                                    cv.values[i] = PA_VOLUME_MAX;
                             }
 
                             pa_sink_set_volume(s, &cv, TRUE, TRUE);
@@ -138,7 +138,7 @@ static void io_callback(pa_mainloop_api *io, pa_io_event *e, int fd, pa_io_event
 
                         case DOWN:
                             for (i = 0; i < cv.channels; i++) {
-                                if (cv.values[i] >= DELTA)
+                                if (cv.values[i] > DELTA)
                                     cv.values[i] -= DELTA;
                                 else
                                     cv.values[i] = PA_VOLUME_MUTED;
diff --git a/src/modules/module-mmkbd-evdev.c b/src/modules/module-mmkbd-evdev.c
index 2f87dd2..ced3a59 100644
--- a/src/modules/module-mmkbd-evdev.c
+++ b/src/modules/module-mmkbd-evdev.c
@@ -120,10 +120,10 @@ static void io_callback(pa_mainloop_api *io, pa_io_event *e, int fd, pa_io_event
                     switch (volchange) {
                         case UP:
                             for (i = 0; i < cv.channels; i++) {
-                                cv.values[i] += DELTA;
-
-                                if (cv.values[i] > PA_VOLUME_NORM)
-                                    cv.values[i] = PA_VOLUME_NORM;
+                                if (cv.values[i] < PA_VOLUME_MAX - DELTA)
+                                    cv.values[i] += DELTA;
+                                else
+                                    cv.values[i] = PA_VOLUME_MAX;
                             }
 
                             pa_sink_set_volume(s, &cv, TRUE, TRUE);
@@ -131,7 +131,7 @@ static void io_callback(pa_mainloop_api *io, pa_io_event *e, int fd, pa_io_event
 
                         case DOWN:
                             for (i = 0; i < cv.channels; i++) {
-                                if (cv.values[i] >= DELTA)
+                                if (cv.values[i] > DELTA)
                                     cv.values[i] -= DELTA;
                                 else
                                     cv.values[i] = PA_VOLUME_MUTED;

commit f1d3dfb11873d03bd5c59aa304db3cb336711a8b
Author: Lennart Poettering <lennart at poettering.net>
Date:   Mon Apr 13 04:42:33 2009 +0200

    mmkbd,lirc: make use of pa_assert_not_reached()

diff --git a/src/modules/module-lirc.c b/src/modules/module-lirc.c
index 1a318a5..b239160 100644
--- a/src/modules/module-lirc.c
+++ b/src/modules/module-lirc.c
@@ -161,7 +161,7 @@ static void io_callback(pa_mainloop_api *io, pa_io_event *e, int fd, pa_io_event
                             break;
 
                         case INVALID:
-                            ;
+                            pa_assert_not_reached();
                     }
                 }
             }
diff --git a/src/modules/module-mmkbd-evdev.c b/src/modules/module-mmkbd-evdev.c
index ced3a59..ccee6e1 100644
--- a/src/modules/module-mmkbd-evdev.c
+++ b/src/modules/module-mmkbd-evdev.c
@@ -146,7 +146,7 @@ static void io_callback(pa_mainloop_api *io, pa_io_event *e, int fd, pa_io_event
                             break;
 
                         case INVALID:
-                            ;
+                            pa_assert_not_reached();
                     }
                 }
             }

commit 66d21849e6ca71f61997e83e754d390a4af5f550
Author: Lennart Poettering <lennart at poettering.net>
Date:   Mon Apr 13 04:43:11 2009 +0200

    mmkbd: get rid of support for ancient kernels

diff --git a/src/modules/module-mmkbd-evdev.c b/src/modules/module-mmkbd-evdev.c
index ccee6e1..c43cfda 100644
--- a/src/modules/module-mmkbd-evdev.c
+++ b/src/modules/module-mmkbd-evdev.c
@@ -52,17 +52,6 @@ PA_MODULE_USAGE("device=<evdev device> sink=<sink name>");
 
 #define DEFAULT_DEVICE "/dev/input/event0"
 
-/*
- * This isn't defined in older kernel headers and there is no way of
- * detecting it.
- */
-struct _input_id {
-    __u16 bustype;
-    __u16 vendor;
-    __u16 product;
-    __u16 version;
-};
-
 static const char* const valid_modargs[] = {
     "device",
     "sink",
@@ -169,7 +158,7 @@ int pa__init(pa_module*m) {
     pa_modargs *ma = NULL;
     struct userdata *u;
     int version;
-    struct _input_id input_id;
+    struct input_id input_id;
     char name[256];
     uint8_t evtype_bitmask[EV_MAX/8 + 1];
 
@@ -180,15 +169,15 @@ int pa__init(pa_module*m) {
         goto fail;
     }
 
-    m->userdata = u = pa_xnew(struct userdata,1);
+    m->userdata = u = pa_xnew(struct userdata, 1);
     u->module = m;
     u->io = NULL;
     u->sink_name = pa_xstrdup(pa_modargs_get_value(ma, "sink", NULL));
     u->fd = -1;
     u->fd_type = 0;
 
-    if ((u->fd = open(pa_modargs_get_value(ma, "device", DEFAULT_DEVICE), O_RDONLY)) < 0) {
-        pa_log("failed to open evdev device: %s", pa_cstrerror(errno));
+    if ((u->fd = open(pa_modargs_get_value(ma, "device", DEFAULT_DEVICE), O_RDONLY|O_NOCTTY)) < 0) {
+        pa_log("Failed to open evdev device: %s", pa_cstrerror(errno));
         goto fail;
     }
 
@@ -208,7 +197,7 @@ int pa__init(pa_module*m) {
                 input_id.vendor, input_id.product, input_id.version, input_id.bustype);
 
     memset(name, 0, sizeof(name));
-    if(ioctl(u->fd, EVIOCGNAME(sizeof(name)), name) < 0) {
+    if (ioctl(u->fd, EVIOCGNAME(sizeof(name)), name) < 0) {
         pa_log("EVIOCGNAME failed: %s", pa_cstrerror(errno));
         goto fail;
     }

commit 62db10c952232af76a7158ff20761c30f68a5c13
Author: Lennart Poettering <lennart at poettering.net>
Date:   Mon Apr 13 04:44:27 2009 +0200

    lirc: fix logic behind mute buttons

diff --git a/src/modules/module-lirc.c b/src/modules/module-lirc.c
index b239160..120b26e 100644
--- a/src/modules/module-lirc.c
+++ b/src/modules/module-lirc.c
@@ -148,11 +148,11 @@ static void io_callback(pa_mainloop_api *io, pa_io_event *e, int fd, pa_io_event
                             break;
 
                         case MUTE:
-                            pa_sink_set_mute(s, 0);
+                            pa_sink_set_mute(s, TRUE);
                             break;
 
                         case RESET:
-                            pa_sink_set_mute(s, 1);
+                            pa_sink_set_mute(s, FALSE);
                             break;
 
                         case MUTE_TOGGLE:

commit 17f1784cb7057bb8ea3da94d14dcbfc5b37ae8b7
Author: Lennart Poettering <lennart at poettering.net>
Date:   Mon Apr 13 05:12:11 2009 +0200

    cork-music-on-phone: make sure that we don't check the refcnt of pa_core when the daemon goes down

diff --git a/src/modules/module-cork-music-on-phone.c b/src/modules/module-cork-music-on-phone.c
index c0f5eea..d3a2b00 100644
--- a/src/modules/module-cork-music-on-phone.c
+++ b/src/modules/module-cork-music-on-phone.c
@@ -143,7 +143,6 @@ static pa_hook_result_t sink_input_put_cb(pa_core *core, pa_sink_input *i, struc
 }
 
 static pa_hook_result_t sink_input_unlink_cb(pa_core *core, pa_sink_input *i, struct userdata *u) {
-    pa_core_assert_ref(core);
     pa_sink_input_assert_ref(i);
 
     return process(u, i, FALSE);

commit 1b4e5f197a9bef30fc13c592cbfd65d2c9a9476a
Author: Lennart Poettering <lennart at poettering.net>
Date:   Mon Apr 13 22:20:48 2009 +0200

    core-util: add pa_session_id()

diff --git a/src/pulsecore/core-util.c b/src/pulsecore/core-util.c
index 5625339..f4776f2 100644
--- a/src/pulsecore/core-util.c
+++ b/src/pulsecore/core-util.c
@@ -2502,6 +2502,15 @@ char *pa_machine_id(void) {
     return pa_sprintf_malloc("%08lx", (unsigned long) gethostid);
 }
 
+char *pa_session_id(void) {
+    const char *e;
+
+    if (!(e = getenv("XDG_SESSION_COOKIE")))
+        return NULL;
+
+    return pa_utf8_filter(e);
+}
+
 char *pa_uname_string(void) {
     struct utsname u;
 
diff --git a/src/pulsecore/core-util.h b/src/pulsecore/core-util.h
index 0ba33f3..f96fa44 100644
--- a/src/pulsecore/core-util.h
+++ b/src/pulsecore/core-util.h
@@ -202,6 +202,7 @@ pa_bool_t pa_in_system_mode(void);
 #define pa_streq(a,b) (!strcmp((a),(b)))
 
 char *pa_machine_id(void);
+char *pa_session_id(void);
 char *pa_uname_string(void);
 
 #ifdef HAVE_VALGRIND_MEMCHECK_H

commit 1d8da03886f95c93b4e9bee45c17da377c783231
Author: Lennart Poettering <lennart at poettering.net>
Date:   Mon Apr 13 22:21:08 2009 +0200

    core-util: filter utf8 in pa_machine_id()

diff --git a/src/pulsecore/core-util.c b/src/pulsecore/core-util.c
index f4776f2..24d929d 100644
--- a/src/pulsecore/core-util.c
+++ b/src/pulsecore/core-util.c
@@ -2462,7 +2462,7 @@ char *pa_machine_id(void) {
         pa_strip_nl(ln);
 
         if (r && ln[0])
-            return pa_xstrdup(ln);
+            return pa_utf8_filter(ln);
     }
 
     /* The we fall back to the host name. It supposed to be somewhat
@@ -2480,13 +2480,16 @@ char *pa_machine_id(void) {
                 break;
 
         } else if (strlen(c) < l-1) {
+            char *u;
 
             if (*c == 0) {
                 pa_xfree(c);
                 break;
             }
 
-            return c;
+            u = pa_utf8_filter(c);
+            pa_xfree(c);
+            return u;
         }
 
         /* Hmm, the hostname is as long the space we offered the
@@ -2498,7 +2501,7 @@ char *pa_machine_id(void) {
     }
 
     /* If no hostname was set we use the POSIX hostid. It's usually
-     * the IPv4 address.  Mit not be that stable. */
+     * the IPv4 address.  Might not be that stable. */
     return pa_sprintf_malloc("%08lx", (unsigned long) gethostid);
 }
 

commit a36197c9d0654bd8011eace3e86c92b86ca93a54
Author: Lennart Poettering <lennart at poettering.net>
Date:   Mon Apr 13 22:21:26 2009 +0200

    print session id when starting up

diff --git a/src/daemon/main.c b/src/daemon/main.c
index a4f0af7..c456e6d 100644
--- a/src/daemon/main.c
+++ b/src/daemon/main.c
@@ -908,6 +908,11 @@ int main(int argc, char *argv[]) {
     pa_log_info(_("Machine ID is %s."), s);
     pa_xfree(s);
 
+    if ((s = pa_session_id())) {
+            pa_log_info(_("Session ID is %s."), s);
+            pa_xfree(s);
+    }
+
     if (!(s = pa_get_runtime_dir()))
         goto finish;
     pa_log_info(_("Using runtime directory %s."), s);

commit 43650de1abb2c3edf7e26e83cec6cf9578422c2b
Author: Lennart Poettering <lennart at poettering.net>
Date:   Mon Apr 13 22:22:22 2009 +0200

    client-conf: modernize a few things

diff --git a/src/pulse/client-conf.c b/src/pulse/client-conf.c
index 58bc3f9..fd1f471 100644
--- a/src/pulse/client-conf.c
+++ b/src/pulse/client-conf.c
@@ -92,28 +92,18 @@ int pa_client_conf_load(pa_client_conf *c, const char *filename) {
 
     /* Prepare the configuration parse table */
     pa_config_item table[] = {
-        { "daemon-binary",          pa_config_parse_string,  NULL, NULL },
-        { "extra-arguments",        pa_config_parse_string,  NULL, NULL },
-        { "default-sink",           pa_config_parse_string,  NULL, NULL },
-        { "default-source",         pa_config_parse_string,  NULL, NULL },
-        { "default-server",         pa_config_parse_string,  NULL, NULL },
-        { "autospawn",              pa_config_parse_bool,    NULL, NULL },
-        { "cookie-file",            pa_config_parse_string,  NULL, NULL },
-        { "disable-shm",            pa_config_parse_bool,    NULL, NULL },
-        { "shm-size-bytes",         pa_config_parse_size,    NULL, NULL },
+        { "daemon-binary",          pa_config_parse_string,  &c->daemon_binary, NULL },
+        { "extra-arguments",        pa_config_parse_string,  &c->extra_arguments, NULL },
+        { "default-sink",           pa_config_parse_string,  &c->default_sink, NULL },
+        { "default-source",         pa_config_parse_string,  &c->default_source, NULL },
+        { "default-server",         pa_config_parse_string,  &c->default_server, NULL },
+        { "autospawn",              pa_config_parse_bool,    &c->autospawn, NULL },
+        { "cookie-file",            pa_config_parse_string,  &c->cookie_file, NULL },
+        { "disable-shm",            pa_config_parse_bool,    &c->disable_shm, NULL },
+        { "shm-size-bytes",         pa_config_parse_size,    &c->shm_size, NULL },
         { NULL,                     NULL,                    NULL, NULL },
     };
 
-    table[0].data = &c->daemon_binary;
-    table[1].data = &c->extra_arguments;
-    table[2].data = &c->default_sink;
-    table[3].data = &c->default_source;
-    table[4].data = &c->default_server;
-    table[5].data = &c->autospawn;
-    table[6].data = &c->cookie_file;
-    table[7].data = &c->disable_shm;
-    table[8].data = &c->shm_size;
-
     if (filename) {
 
         if (!(f = fopen(filename, "r"))) {

commit 20aba71d949472bb11c44cd79e2b0c230c20b0dc
Author: Lennart Poettering <lennart at poettering.net>
Date:   Mon Apr 13 22:23:18 2009 +0200

    proplist-util: use pa_session_id() instead of accessing 7b816367b01393ed3e3e650047d78f6e-1239640487.203609-1061245823 directly

diff --git a/src/pulsecore/proplist-util.c b/src/pulsecore/proplist-util.c
index af5f0aa..eac8927 100644
--- a/src/pulsecore/proplist-util.c
+++ b/src/pulsecore/proplist-util.c
@@ -231,12 +231,11 @@ void pa_init_proplist(pa_proplist *p) {
     }
 
     if (!pa_proplist_contains(p, PA_PROP_APPLICATION_PROCESS_SESSION_ID)) {
-        const char *t;
+        char *s;
 
-        if ((t = getenv("XDG_SESSION_COOKIE"))) {
-            char *c = pa_utf8_filter(t);
-            pa_proplist_sets(p, PA_PROP_APPLICATION_PROCESS_SESSION_ID, c);
-            pa_xfree(c);
+        if ((s = pa_session_id())) {
+            pa_proplist_sets(p, PA_PROP_APPLICATION_PROCESS_SESSION_ID, s);
+            pa_xfree(s);
         }
     }
 }

commit 4cc4cbd6413b43db7704b96cb7599700acd8306d
Author: Lennart Poettering <lennart at poettering.net>
Date:   Mon Apr 13 22:25:09 2009 +0200

    client-conf: make setting a default server independant from the autospawn setting

diff --git a/src/pulse/context.c b/src/pulse/context.c
index ef36f09..4aad737 100644
--- a/src/pulse/context.c
+++ b/src/pulse/context.c
@@ -186,10 +186,10 @@ pa_context *pa_context_new_with_proplist(pa_mainloop_api *mainloop, const char *
 #endif
 
     c->conf = pa_client_conf_new();
+    pa_client_conf_load(c->conf, NULL);
 #ifdef HAVE_X11
     pa_client_conf_from_x11(c->conf, NULL);
 #endif
-    pa_client_conf_load(c->conf, NULL);
     pa_client_conf_env(c->conf);
 
     if (!(c->mempool = pa_mempool_new(!c->conf->disable_shm, c->conf->shm_size))) {
@@ -925,7 +925,9 @@ int pa_context_connect(
     PA_CHECK_VALIDITY(c, !(flags & ~(PA_CONTEXT_NOAUTOSPAWN|PA_CONTEXT_NOFAIL)), PA_ERR_INVALID);
     PA_CHECK_VALIDITY(c, !server || *server, PA_ERR_INVALID);
 
-    if (!server)
+    if (server)
+        c->conf->autospawn = FALSE;
+    else
         server = c->conf->default_server;
 
     pa_context_ref(c);
@@ -967,18 +969,18 @@ int pa_context_connect(
 
         /* The user instance via PF_LOCAL */
         c->server_list = prepend_per_user(c->server_list);
+    }
 
-        /* Set up autospawning */
-        if (!(flags & PA_CONTEXT_NOAUTOSPAWN) && c->conf->autospawn) {
+    /* Set up autospawning */
+    if (!(flags & PA_CONTEXT_NOAUTOSPAWN) && c->conf->autospawn) {
 
-            if (getuid() == 0)
-                pa_log_debug("Not doing autospawn since we are root.");
-            else {
-                c->do_autospawn = TRUE;
+        if (getuid() == 0)
+            pa_log_debug("Not doing autospawn since we are root.");
+        else {
+            c->do_autospawn = TRUE;
 
-                if (api)
-                    c->spawn_api = *api;
-            }
+            if (api)
+                c->spawn_api = *api;
         }
     }
 

commit 0aed5ea2e109e0d4b2ffdbff5f3dc944eb34d7e8
Author: Lennart Poettering <lennart at poettering.net>
Date:   Mon Apr 13 22:25:43 2009 +0200

    client-conf: when  is set, disable autospawn setting

diff --git a/src/pulse/client-conf.c b/src/pulse/client-conf.c
index fd1f471..940d0b6 100644
--- a/src/pulse/client-conf.c
+++ b/src/pulse/client-conf.c
@@ -150,6 +150,9 @@ int pa_client_conf_env(pa_client_conf *c) {
     if ((e = getenv(ENV_DEFAULT_SERVER))) {
         pa_xfree(c->default_server);
         c->default_server = pa_xstrdup(e);
+
+        /* We disable autospawning automatically if a specific server was set */
+        c->autospawn = FALSE;
     }
 
     if ((e = getenv(ENV_DAEMON_BINARY))) {

commit 0ac038e5913959910d854e9e015a9406c1976eca
Author: Lennart Poettering <lennart at poettering.net>
Date:   Mon Apr 13 22:28:35 2009 +0200

    client-conf-x11: unbreak autospawn due to stale X11 properties
    
    If the X11 property data is from the same session than the client the
    client may do autospawning in case the X11 property data is stale.
    
    Closes #518.

diff --git a/src/modules/module-x11-publish.c b/src/modules/module-x11-publish.c
index 83e69d1..2c7fdc1 100644
--- a/src/modules/module-x11-publish.c
+++ b/src/modules/module-x11-publish.c
@@ -136,7 +136,7 @@ static void x11_kill_cb(pa_x11_wrapper *w, void *userdata) {
 int pa__init(pa_module*m) {
     struct userdata *u;
     pa_modargs *ma = NULL;
-    char *mid;
+    char *mid, *sid;
     char hx[PA_NATIVE_COOKIE_LENGTH*2+1];
     const char *t;
 
@@ -170,6 +170,11 @@ int pa__init(pa_module*m) {
 
     pa_x11_set_prop(pa_x11_wrapper_get_display(u->x11_wrapper), "PULSE_ID", u->id);
 
+    if ((sid = pa_session_id())) {
+        pa_x11_set_prop(pa_x11_wrapper_get_display(u->x11_wrapper), "PULSE_SESSION_ID", sid);
+        pa_xfree(sid);
+    }
+
     publish_servers(u, pa_native_protocol_servers(u->protocol));
 
     if ((t = pa_modargs_get_value(ma, "source", NULL)))
@@ -219,6 +224,7 @@ void pa__done(pa_module*m) {
             pa_x11_del_prop(pa_x11_wrapper_get_display(u->x11_wrapper), "PULSE_SINK");
             pa_x11_del_prop(pa_x11_wrapper_get_display(u->x11_wrapper), "PULSE_SOURCE");
             pa_x11_del_prop(pa_x11_wrapper_get_display(u->x11_wrapper), "PULSE_COOKIE");
+            pa_x11_del_prop(pa_x11_wrapper_get_display(u->x11_wrapper), "PULSE_SESSION_ID");
             XSync(pa_x11_wrapper_get_display(u->x11_wrapper), False);
         }
 
diff --git a/src/pulse/client-conf-x11.c b/src/pulse/client-conf-x11.c
index 3bec742..4970363 100644
--- a/src/pulse/client-conf-x11.c
+++ b/src/pulse/client-conf-x11.c
@@ -57,8 +57,23 @@ int pa_client_conf_from_x11(pa_client_conf *c, const char *dname) {
     }
 
     if (pa_x11_get_prop(d, "PULSE_SERVER", t, sizeof(t))) {
+        pa_bool_t disable_autospawn = TRUE;
+
         pa_xfree(c->default_server);
         c->default_server = pa_xstrdup(t);
+
+        if (pa_x11_get_prop(d, "PULSE_SESSION_ID", t, sizeof(t))) {
+            char *id;
+
+            if ((id = pa_session_id())) {
+                if (pa_streq(t, id))
+                    disable_autospawn = FALSE;
+                pa_xfree(id);
+            }
+        }
+
+        if (disable_autospawn)
+            c->autospawn = FALSE;
     }
 
     if (pa_x11_get_prop(d, "PULSE_SINK", t, sizeof(t))) {

commit 237a9e12f8ee17cfec40e4c4df61a3db0c57ce81
Author: Lennart Poettering <lennart at poettering.net>
Date:   Mon Apr 13 22:41:38 2009 +0200

    volume: increase dB range to -90dB
    
    Increasing the volume range to -90dB has the benefit of corresponding
    with a volume decrease from the full 16 bit signal to 0.
    
    This also makes us a bit more like traditional stereos

diff --git a/src/pulse/volume.c b/src/pulse/volume.c
index ad3b3a4..6848771 100644
--- a/src/pulse/volume.c
+++ b/src/pulse/volume.c
@@ -120,7 +120,7 @@ pa_volume_t pa_sw_volume_divide(pa_volume_t a, pa_volume_t b) {
     return pa_sw_volume_from_linear(pa_sw_volume_to_linear(a) / v);
 }
 
-#define USER_DECIBEL_RANGE 60
+#define USER_DECIBEL_RANGE 90
 
 pa_volume_t pa_sw_volume_from_dB(double dB) {
     if (isinf(dB) < 0 || dB <= -USER_DECIBEL_RANGE)

commit 89f74cb85867a8eb1bb609006212453405583132
Author: Lennart Poettering <lennart at poettering.net>
Date:   Mon Apr 13 22:45:31 2009 +0200

    alsa: when passing emptry mixer control name, force sw volume

diff --git a/src/modules/alsa/alsa-util.c b/src/modules/alsa/alsa-util.c
index fbf88b0..8da07b2 100644
--- a/src/modules/alsa/alsa-util.c
+++ b/src/modules/alsa/alsa-util.c
@@ -1107,6 +1107,11 @@ int pa_alsa_find_mixer_and_elem(
     pa_assert(_m);
     pa_assert(_e);
 
+    if (control_name && *control_name == 0) {
+        pa_log_debug("Hardware mixer usage disabled because empty control name passed");
+        return -1;
+    }
+
     if ((err = snd_mixer_open(&m, 0)) < 0) {
         pa_log("Error opening mixer: %s", snd_strerror(err));
         return -1;

commit 6fd8fd18c2916f650a220b0c09c26e39f31a7655
Author: Lennart Poettering <lennart at poettering.net>
Date:   Mon Apr 13 22:46:39 2009 +0200

    alsa: store mixer controls to use in profile data
    
    This allows us to easily use different mixer controls for analog and
    spdif output.

diff --git a/src/modules/alsa/alsa-sink.c b/src/modules/alsa/alsa-sink.c
index 6ed1c3a..99172a6 100644
--- a/src/modules/alsa/alsa-sink.c
+++ b/src/modules/alsa/alsa-sink.c
@@ -1664,7 +1664,7 @@ pa_sink *pa_alsa_sink_new(pa_module *m, pa_modargs *ma, const char*driver, pa_ca
     /* ALSA might tweak the sample spec, so recalculate the frame size */
     frame_size = pa_frame_size(&ss);
 
-    pa_alsa_find_mixer_and_elem(u->pcm_handle, &u->mixer_handle, &u->mixer_elem, pa_modargs_get_value(ma, "control", NULL));
+    pa_alsa_find_mixer_and_elem(u->pcm_handle, &u->mixer_handle, &u->mixer_elem, pa_modargs_get_value(ma, "control", NULL), profile);
 
     pa_sink_new_data_init(&data);
     data.driver = driver;
diff --git a/src/modules/alsa/alsa-source.c b/src/modules/alsa/alsa-source.c
index d87ab80..f06c0a7 100644
--- a/src/modules/alsa/alsa-source.c
+++ b/src/modules/alsa/alsa-source.c
@@ -1519,7 +1519,7 @@ pa_source *pa_alsa_source_new(pa_module *m, pa_modargs *ma, const char*driver, p
     /* ALSA might tweak the sample spec, so recalculate the frame size */
     frame_size = pa_frame_size(&ss);
 
-    pa_alsa_find_mixer_and_elem(u->pcm_handle, &u->mixer_handle, &u->mixer_elem, pa_modargs_get_value(ma, "control", NULL));
+    pa_alsa_find_mixer_and_elem(u->pcm_handle, &u->mixer_handle, &u->mixer_elem, pa_modargs_get_value(ma, "control", NULL), profile);
 
     pa_source_new_data_init(&data);
     data.driver = driver;
diff --git a/src/modules/alsa/alsa-util.c b/src/modules/alsa/alsa-util.c
index 8da07b2..2a8694b 100644
--- a/src/modules/alsa/alsa-util.c
+++ b/src/modules/alsa/alsa-util.c
@@ -529,39 +529,51 @@ static const struct pa_alsa_profile_info device_table[] = {
      "hw",
      N_("Analog Mono"),
      "analog-mono",
-     1 },
+     1,
+     "Master", "PCM",
+     "Capture", "Mic" },
 
     {{ 2, { PA_CHANNEL_POSITION_LEFT, PA_CHANNEL_POSITION_RIGHT }},
      "front",
      N_("Analog Stereo"),
      "analog-stereo",
-     10 },
+     10,
+     "Master", "PCM",
+     "Capture", "Mic" },
 
     {{ 2, { PA_CHANNEL_POSITION_LEFT, PA_CHANNEL_POSITION_RIGHT }},
      "iec958",
      N_("Digital Stereo (IEC958)"),
      "iec958-stereo",
-     5 },
+     5,
+     "IEC958", NULL,
+     "IEC958 In", NULL },
 
     {{ 2, { PA_CHANNEL_POSITION_LEFT, PA_CHANNEL_POSITION_RIGHT }},
      "hdmi",
      N_("Digital Stereo (HDMI)"),
      "hdmi-stereo",
-     4 },
+     4,
+     "IEC958", NULL,
+     "IEC958 In", NULL },
 
     {{ 4, { PA_CHANNEL_POSITION_FRONT_LEFT, PA_CHANNEL_POSITION_FRONT_RIGHT,
             PA_CHANNEL_POSITION_REAR_LEFT, PA_CHANNEL_POSITION_REAR_RIGHT }},
      "surround40",
      N_("Analog Surround 4.0"),
      "analog-surround-40",
-     7 },
+     7,
+     "Master", "PCM",
+     "Capture", "Mic" },
 
     {{ 4, { PA_CHANNEL_POSITION_FRONT_LEFT, PA_CHANNEL_POSITION_FRONT_RIGHT,
             PA_CHANNEL_POSITION_REAR_LEFT, PA_CHANNEL_POSITION_REAR_RIGHT }},
      "a52",
      N_("Digital Surround 4.0 (IEC958/AC3)"),
      "iec958-ac3-surround-40",
-     2 },
+     2,
+     "Master", "PCM",
+     "Capture", "Mic" },
 
     {{ 5, { PA_CHANNEL_POSITION_FRONT_LEFT, PA_CHANNEL_POSITION_FRONT_RIGHT,
             PA_CHANNEL_POSITION_REAR_LEFT, PA_CHANNEL_POSITION_REAR_RIGHT,
@@ -569,7 +581,9 @@ static const struct pa_alsa_profile_info device_table[] = {
      "surround41",
      N_("Analog Surround 4.1"),
      "analog-surround-41",
-     7 },
+     7,
+     "Master", "PCM",
+     "Capture", "Mic" },
 
     {{ 5, { PA_CHANNEL_POSITION_FRONT_LEFT, PA_CHANNEL_POSITION_FRONT_RIGHT,
             PA_CHANNEL_POSITION_REAR_LEFT, PA_CHANNEL_POSITION_REAR_RIGHT,
@@ -577,7 +591,9 @@ static const struct pa_alsa_profile_info device_table[] = {
      "surround50",
      N_("Analog Surround 5.0"),
      "analog-surround-50",
-     7 },
+     7,
+     "Master", "PCM",
+     "Capture", "Mic" },
 
     {{ 6, { PA_CHANNEL_POSITION_FRONT_LEFT, PA_CHANNEL_POSITION_FRONT_RIGHT,
             PA_CHANNEL_POSITION_REAR_LEFT, PA_CHANNEL_POSITION_REAR_RIGHT,
@@ -585,7 +601,9 @@ static const struct pa_alsa_profile_info device_table[] = {
      "surround51",
      N_("Analog Surround 5.1"),
      "analog-surround-51",
-     8 },
+     8,
+     "Master", "PCM",
+     "Capture", "Mic" },
 
     {{ 6, { PA_CHANNEL_POSITION_FRONT_LEFT, PA_CHANNEL_POSITION_FRONT_RIGHT,
             PA_CHANNEL_POSITION_REAR_LEFT, PA_CHANNEL_POSITION_REAR_RIGHT,
@@ -593,7 +611,9 @@ static const struct pa_alsa_profile_info device_table[] = {
      "a52",
      N_("Digital Surround 5.1 (IEC958/AC3)"),
      "iec958-ac3-surround-51",
-     3 },
+     3,
+     "IEC958", NULL,
+     "IEC958 In", NULL },
 
     {{ 8, { PA_CHANNEL_POSITION_FRONT_LEFT, PA_CHANNEL_POSITION_FRONT_RIGHT,
             PA_CHANNEL_POSITION_REAR_LEFT, PA_CHANNEL_POSITION_REAR_RIGHT,
@@ -602,9 +622,11 @@ static const struct pa_alsa_profile_info device_table[] = {
      "surround71",
      N_("Analog Surround 7.1"),
      "analog-surround-71",
-     7 },
+     7,
+     "Master", "PCM",
+     "Capture", "Mic" },
 
-    {{ 0, { 0 }}, NULL, NULL, NULL, 0 }
+    {{ 0, { 0 }}, NULL, NULL, NULL, 0, NULL, NULL, NULL, NULL }
 };
 
 snd_pcm_t *pa_alsa_open_by_device_id_auto(
@@ -1095,7 +1117,8 @@ int pa_alsa_find_mixer_and_elem(
         snd_pcm_t *pcm,
         snd_mixer_t **_m,
         snd_mixer_elem_t **_e,
-        const char *control_name) {
+        const char *control_name,
+        const pa_alsa_profile_info *profile) {
 
     int err;
     snd_mixer_t *m;
@@ -1154,6 +1177,8 @@ int pa_alsa_find_mixer_and_elem(
         case SND_PCM_STREAM_PLAYBACK:
             if (control_name)
                 e = pa_alsa_find_elem(m, control_name, NULL, TRUE);
+            else if (profile)
+                e = pa_alsa_find_elem(m, profile->playback_control_name, profile->playback_control_fallback, TRUE);
             else
                 e = pa_alsa_find_elem(m, "Master", "PCM", TRUE);
             break;
@@ -1161,6 +1186,8 @@ int pa_alsa_find_mixer_and_elem(
         case SND_PCM_STREAM_CAPTURE:
             if (control_name)
                 e = pa_alsa_find_elem(m, control_name, NULL, FALSE);
+            else if (profile)
+                e = pa_alsa_find_elem(m, profile->record_control_name, profile->record_control_fallback, FALSE);
             else
                 e = pa_alsa_find_elem(m, "Capture", "Mic", FALSE);
             break;
diff --git a/src/modules/alsa/alsa-util.h b/src/modules/alsa/alsa-util.h
index 9fce6da..e7b2de8 100644
--- a/src/modules/alsa/alsa-util.h
+++ b/src/modules/alsa/alsa-util.h
@@ -53,18 +53,20 @@ int pa_alsa_set_hw_params(
 
 int pa_alsa_set_sw_params(snd_pcm_t *pcm, snd_pcm_uframes_t avail_min);
 
-int pa_alsa_prepare_mixer(snd_mixer_t *mixer, const char *dev);
-snd_mixer_elem_t *pa_alsa_find_elem(snd_mixer_t *mixer, const char *name, const char *fallback, pa_bool_t playback);
-int pa_alsa_find_mixer_and_elem(snd_pcm_t *pcm, snd_mixer_t **_m, snd_mixer_elem_t **_e, const char *control_name);
-
 typedef struct pa_alsa_profile_info {
     pa_channel_map map;
     const char *alsa_name;
     const char *description; /* internationalized */
     const char *name;
     unsigned priority;
+    const char *playback_control_name, *playback_control_fallback;
+    const char *record_control_name, *record_control_fallback;
 } pa_alsa_profile_info;
 
+int pa_alsa_prepare_mixer(snd_mixer_t *mixer, const char *dev);
+snd_mixer_elem_t *pa_alsa_find_elem(snd_mixer_t *mixer, const char *name, const char *fallback, pa_bool_t playback);
+int pa_alsa_find_mixer_and_elem(snd_pcm_t *pcm, snd_mixer_t **_m, snd_mixer_elem_t **_e, const char *control_name, const pa_alsa_profile_info*profile);
+
 /* Picks a working profile based on the specified ss/map */
 snd_pcm_t *pa_alsa_open_by_device_id_auto(
         const char *dev_id,

commit 49dcf0940e6024f788eeaaf33012eb8b48c3d8ae
Author: Lennart Poettering <lennart at poettering.net>
Date:   Mon Apr 13 22:48:29 2009 +0200

    alsa: include the alsa mixer control that is used in the property list

diff --git a/src/modules/alsa/alsa-sink.c b/src/modules/alsa/alsa-sink.c
index 99172a6..3e5c219 100644
--- a/src/modules/alsa/alsa-sink.c
+++ b/src/modules/alsa/alsa-sink.c
@@ -1674,7 +1674,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_alsa_init_proplist_pcm(m->core, data.proplist, u->pcm_handle);
+    pa_alsa_init_proplist_pcm(m->core, data.proplist, u->pcm_handle, u->mixer_elem);
     pa_proplist_sets(data.proplist, PA_PROP_DEVICE_STRING, u->device_name);
     pa_proplist_setf(data.proplist, PA_PROP_DEVICE_BUFFERING_BUFFER_SIZE, "%lu", (unsigned long) (period_frames * frame_size * nfrags));
     pa_proplist_setf(data.proplist, PA_PROP_DEVICE_BUFFERING_FRAGMENT_SIZE, "%lu", (unsigned long) (period_frames * frame_size));
diff --git a/src/modules/alsa/alsa-source.c b/src/modules/alsa/alsa-source.c
index f06c0a7..c59fc75 100644
--- a/src/modules/alsa/alsa-source.c
+++ b/src/modules/alsa/alsa-source.c
@@ -1529,7 +1529,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_alsa_init_proplist_pcm(m->core, data.proplist, u->pcm_handle);
+    pa_alsa_init_proplist_pcm(m->core, data.proplist, u->pcm_handle, u->mixer_elem);
     pa_proplist_sets(data.proplist, PA_PROP_DEVICE_STRING, u->device_name);
     pa_proplist_setf(data.proplist, PA_PROP_DEVICE_BUFFERING_BUFFER_SIZE, "%lu", (unsigned long) (period_frames * frame_size * nfrags));
     pa_proplist_setf(data.proplist, PA_PROP_DEVICE_BUFFERING_FRAGMENT_SIZE, "%lu", (unsigned long) (period_frames * frame_size));
diff --git a/src/modules/alsa/alsa-util.c b/src/modules/alsa/alsa-util.c
index 2a8694b..d2dc6e8 100644
--- a/src/modules/alsa/alsa-util.c
+++ b/src/modules/alsa/alsa-util.c
@@ -1515,7 +1515,7 @@ void pa_alsa_init_proplist_pcm_info(pa_core *c, pa_proplist *p, snd_pcm_info_t *
         pa_alsa_init_proplist_card(c, p, card);
 }
 
-void pa_alsa_init_proplist_pcm(pa_core *c, pa_proplist *p, snd_pcm_t *pcm) {
+void pa_alsa_init_proplist_pcm(pa_core *c, pa_proplist *p, snd_pcm_t *pcm, snd_mixer_elem_t *elem) {
     snd_pcm_hw_params_t *hwparams;
     snd_pcm_info_t *info;
     int bits, err;
@@ -1531,6 +1531,9 @@ void pa_alsa_init_proplist_pcm(pa_core *c, pa_proplist *p, snd_pcm_t *pcm) {
             pa_proplist_setf(p, "alsa.resolution_bits", "%i", bits);
     }
 
+    if (elem)
+        pa_proplist_sets(p, "alsa.mixer_element", snd_mixer_selem_get_name(elem));
+
     if ((err = snd_pcm_info(pcm, info)) < 0)
         pa_log_warn("Error fetching PCM info: %s", snd_strerror(err));
     else
diff --git a/src/modules/alsa/alsa-util.h b/src/modules/alsa/alsa-util.h
index e7b2de8..c8acc7c 100644
--- a/src/modules/alsa/alsa-util.h
+++ b/src/modules/alsa/alsa-util.h
@@ -125,7 +125,7 @@ void pa_alsa_redirect_errors_dec(void);
 
 void pa_alsa_init_proplist_pcm_info(pa_core *c, pa_proplist *p, snd_pcm_info_t *pcm_info);
 void pa_alsa_init_proplist_card(pa_core *c, pa_proplist *p, int card);
-void pa_alsa_init_proplist_pcm(pa_core *c, pa_proplist *p, snd_pcm_t *pcm);
+void pa_alsa_init_proplist_pcm(pa_core *c, pa_proplist *p, snd_pcm_t *pcm, snd_mixer_elem_t *elem);
 pa_bool_t pa_alsa_init_description(pa_proplist *p);
 
 int pa_alsa_recover_from_poll(snd_pcm_t *pcm, int revents);

commit fe8b10cc05b3b8e8633ffaff30e73a40a30c8bf8
Author: Lennart Poettering <lennart at poettering.net>
Date:   Mon Apr 13 22:50:24 2009 +0200

    core: introduce new 'reference' volume for sinks
    
    The reference volume is to be used as reference volume for stored stream
    volumes. Previously if a new stream was created the relative volume was
    taken relatively to the virtual device volume. Due to the flat volume
    logic this could then be fed back to the virtual device volume.
    Repeating the whole story over and over would result in a device volume
    that would go lower, and lower and lower.
    
    This patch introduces a 'reference' volume for each sink which stays
    unmodified by stream volume changes even if flat volumes are used. It is
    only modified if the sink volumes are modified directly by the user.
    
    For further explanations see http://pulseaudio.org/wiki/InternalVolumes

diff --git a/src/modules/alsa/alsa-sink.c b/src/modules/alsa/alsa-sink.c
index 3e5c219..2fbcd7b 100644
--- a/src/modules/alsa/alsa-sink.c
+++ b/src/modules/alsa/alsa-sink.c
@@ -931,7 +931,7 @@ static int mixer_callback(snd_mixer_elem_t *elem, unsigned int mask) {
         return 0;
 
     if (mask & SND_CTL_EVENT_MASK_VALUE) {
-        pa_sink_get_volume(u->sink, TRUE);
+        pa_sink_get_volume(u->sink, TRUE, FALSE);
         pa_sink_get_mute(u->sink, TRUE);
     }
 
diff --git a/src/modules/module-device-restore.c b/src/modules/module-device-restore.c
index 0ca3dd8..7d87ca0 100644
--- a/src/modules/module-device-restore.c
+++ b/src/modules/module-device-restore.c
@@ -191,7 +191,7 @@ static void subscribe_callback(pa_core *c, pa_subscription_event_type_t t, uint3
 
         name = pa_sprintf_malloc("sink:%s", sink->name);
         entry.channel_map = sink->channel_map;
-        entry.volume = *pa_sink_get_volume(sink, FALSE);
+        entry.volume = *pa_sink_get_volume(sink, FALSE, TRUE);
         entry.muted = pa_sink_get_mute(sink, FALSE);
 
     } else {
diff --git a/src/modules/module-lirc.c b/src/modules/module-lirc.c
index 120b26e..a1a8726 100644
--- a/src/modules/module-lirc.c
+++ b/src/modules/module-lirc.c
@@ -120,7 +120,7 @@ static void io_callback(pa_mainloop_api *io, pa_io_event *e, int fd, pa_io_event
                     pa_log("Failed to get sink '%s'", u->sink_name);
                 else {
                     int i;
-                    pa_cvolume cv = *pa_sink_get_volume(s, FALSE);
+                    pa_cvolume cv = *pa_sink_get_volume(s, FALSE, FALSE);
 
 #define DELTA (PA_VOLUME_NORM/20)
 
@@ -133,7 +133,7 @@ static void io_callback(pa_mainloop_api *io, pa_io_event *e, int fd, pa_io_event
                                     cv.values[i] = PA_VOLUME_MAX;
                             }
 
-                            pa_sink_set_volume(s, &cv, TRUE, TRUE);
+                            pa_sink_set_volume(s, &cv, TRUE, TRUE, TRUE);
                             break;
 
                         case DOWN:
@@ -144,7 +144,7 @@ static void io_callback(pa_mainloop_api *io, pa_io_event *e, int fd, pa_io_event
                                     cv.values[i] = PA_VOLUME_MUTED;
                             }
 
-                            pa_sink_set_volume(s, &cv, TRUE, TRUE);
+                            pa_sink_set_volume(s, &cv, TRUE, TRUE, TRUE);
                             break;
 
                         case MUTE:
diff --git a/src/modules/module-match.c b/src/modules/module-match.c
index d7365ca..625f2a8 100644
--- a/src/modules/module-match.c
+++ b/src/modules/module-match.c
@@ -216,7 +216,7 @@ static void callback(pa_core *c, pa_subscription_event_type_t t, uint32_t idx, v
                 pa_cvolume cv;
                 pa_log_debug("changing volume of sink input '%s' to 0x%03x", n, r->volume);
                 pa_cvolume_set(&cv, si->sample_spec.channels, r->volume);
-                pa_sink_input_set_volume(si, &cv, TRUE);
+                pa_sink_input_set_volume(si, &cv, TRUE, TRUE);
             }
         }
     }
diff --git a/src/modules/module-mmkbd-evdev.c b/src/modules/module-mmkbd-evdev.c
index c43cfda..d8b9c79 100644
--- a/src/modules/module-mmkbd-evdev.c
+++ b/src/modules/module-mmkbd-evdev.c
@@ -102,7 +102,7 @@ static void io_callback(pa_mainloop_api *io, pa_io_event *e, int fd, pa_io_event
                     pa_log("Failed to get sink '%s'", u->sink_name);
                 else {
                     int i;
-                    pa_cvolume cv = *pa_sink_get_volume(s, FALSE);
+                    pa_cvolume cv = *pa_sink_get_volume(s, FALSE, FALSE);
 
 #define DELTA (PA_VOLUME_NORM/20)
 
@@ -115,7 +115,7 @@ static void io_callback(pa_mainloop_api *io, pa_io_event *e, int fd, pa_io_event
                                     cv.values[i] = PA_VOLUME_MAX;
                             }
 
-                            pa_sink_set_volume(s, &cv, TRUE, TRUE);
+                            pa_sink_set_volume(s, &cv, TRUE, TRUE, TRUE);
                             break;
 
                         case DOWN:
@@ -126,7 +126,7 @@ static void io_callback(pa_mainloop_api *io, pa_io_event *e, int fd, pa_io_event
                                     cv.values[i] = PA_VOLUME_MUTED;
                             }
 
-                            pa_sink_set_volume(s, &cv, TRUE, TRUE);
+                            pa_sink_set_volume(s, &cv, TRUE, TRUE, TRUE);
                             break;
 
                         case MUTE_TOGGLE:
diff --git a/src/modules/module-stream-restore.c b/src/modules/module-stream-restore.c
index 2c90e72..70cd89a 100644
--- a/src/modules/module-stream-restore.c
+++ b/src/modules/module-stream-restore.c
@@ -91,15 +91,14 @@ struct userdata {
     pa_idxset *subscribed;
 };
 
-#define ENTRY_VERSION 1
+#define ENTRY_VERSION 2
 
 struct entry {
     uint8_t version;
-    pa_bool_t muted_valid:1, relative_volume_valid:1, absolute_volume_valid:1, device_valid:1;
+    pa_bool_t muted_valid:1, volume_valid:1, device_valid:1;
     pa_bool_t muted:1;
     pa_channel_map channel_map;
-    pa_cvolume relative_volume;
-    pa_cvolume absolute_volume;
+    pa_cvolume volume;
     char device[PA_NAME_MAX];
 } PA_GCC_PACKED;
 
@@ -192,13 +191,12 @@ static struct entry* read_entry(struct userdata *u, const char *name) {
         goto fail;
     }
 
-    if ((e->relative_volume_valid || e->absolute_volume_valid) && !pa_channel_map_valid(&e->channel_map)) {
+    if (e->volume_valid && !pa_channel_map_valid(&e->channel_map)) {
         pa_log_warn("Invalid channel map stored in database for stream %s", name);
         goto fail;
     }
 
-    if ((e->relative_volume_valid && (!pa_cvolume_valid(&e->relative_volume) || e->relative_volume.channels != e->channel_map.channels)) ||
-        (e->absolute_volume_valid && (!pa_cvolume_valid(&e->absolute_volume) || e->absolute_volume.channels != e->channel_map.channels))) {
+    if (e->volume_valid && (!pa_cvolume_valid(&e->volume) || !pa_cvolume_compatible_with_channel_map(&e->volume, &e->channel_map))) {
         pa_log_warn("Invalid volume stored in database for stream %s", name);
         goto fail;
     }
@@ -251,14 +249,9 @@ static pa_bool_t entries_equal(const struct entry *a, const struct entry *b) {
         (a->muted_valid && (a->muted != b->muted)))
         return FALSE;
 
-    t = b->relative_volume;
-    if (a->relative_volume_valid != b->relative_volume_valid ||
-        (a->relative_volume_valid && !pa_cvolume_equal(pa_cvolume_remap(&t, &b->channel_map, &a->channel_map), &a->relative_volume)))
-        return FALSE;
-
-    t = b->absolute_volume;
-    if (a->absolute_volume_valid != b->absolute_volume_valid ||
-        (a->absolute_volume_valid && !pa_cvolume_equal(pa_cvolume_remap(&t, &b->channel_map, &a->channel_map), &a->absolute_volume)))
+    t = b->volume;
+    if (a->volume_valid != b->volume_valid ||
+        (a->volume_valid && !pa_cvolume_equal(pa_cvolume_remap(&t, &b->channel_map, &a->channel_map), &a->volume)))
         return FALSE;
 
     return TRUE;
@@ -291,22 +284,24 @@ static void subscribe_callback(pa_core *c, pa_subscription_event_type_t t, uint3
         if (!(name = get_name(sink_input->proplist, "sink-input")))
             return;
 
-        entry.channel_map = sink_input->channel_map;
-
-        pa_sink_input_get_relative_volume(sink_input, &entry.relative_volume);
-        entry.relative_volume_valid = sink_input->save_volume;
+        if ((old = read_entry(u, name)))
+            entry = *old;
 
-        if (sink_input->sink->flags & PA_SINK_FLAT_VOLUME) {
-            entry.absolute_volume = *pa_sink_input_get_volume(sink_input);
-            entry.absolute_volume_valid = sink_input->save_volume;
-        } else
-            entry.absolute_volume_valid = FALSE;
+        if (sink_input->save_volume) {
+            entry.channel_map = sink_input->channel_map;
+            pa_sink_input_get_volume(sink_input, &entry.volume, FALSE);
+            entry.volume_valid = TRUE;
+        }
 
-        entry.muted = pa_sink_input_get_mute(sink_input);
-        entry.muted_valid = sink_input->save_muted;
+        if (sink_input->save_muted) {
+            entry.muted = pa_sink_input_get_mute(sink_input);
+            entry.muted_valid = TRUE;
+        }
 
-        pa_strlcpy(entry.device, sink_input->sink->name, sizeof(entry.device));
-        entry.device_valid = sink_input->save_sink;
+        if (sink_input->save_sink) {
+            pa_strlcpy(entry.device, sink_input->sink->name, sizeof(entry.device));
+            entry.device_valid = TRUE;
+        }
 
     } else {
         pa_source_output *source_output;
@@ -319,13 +314,16 @@ static void subscribe_callback(pa_core *c, pa_subscription_event_type_t t, uint3
         if (!(name = get_name(source_output->proplist, "source-output")))
             return;
 
-        entry.channel_map = source_output->channel_map;
+        if ((old = read_entry(u, name)))
+            entry = *old;
 
-        pa_strlcpy(entry.device, source_output->source->name, sizeof(entry.device));
-        entry.device_valid = source_output->save_source;
+        if (source_output->save_source) {
+            pa_strlcpy(entry.device, source_output->source->name, sizeof(entry.device));
+            entry.device_valid = source_output->save_source;
+        }
     }
 
-    if ((old = read_entry(u, name))) {
+    if (old) {
 
         if (entries_equal(old, &entry)) {
             pa_xfree(old);
@@ -400,42 +398,24 @@ static pa_hook_result_t sink_input_fixate_hook_callback(pa_core *c, pa_sink_inpu
 
     if ((e = read_entry(u, name))) {
 
-        if (u->restore_volume) {
+        if (u->restore_volume && e->volume_valid) {
 
             if (!new_data->volume_is_set) {
                 pa_cvolume v;
-                pa_cvolume_init(&v);
-
-                if (new_data->sink->flags & PA_SINK_FLAT_VOLUME) {
-
-                    /* We don't check for e->device_valid here because
-                    that bit marks whether it is a good choice for
-                    restoring, not just if the data is filled in. */
-                    if (e->absolute_volume_valid &&
-                        (e->device[0] == 0 || pa_streq(new_data->sink->name, e->device))) {
-
-                        v = e->absolute_volume;
-                        new_data->volume_is_absolute = TRUE;
-                    } else if (e->relative_volume_valid) {
-                        v = e->relative_volume;
-                        new_data->volume_is_absolute = FALSE;
-                    }
-
-                } else if (e->relative_volume_valid) {
-                    v = e->relative_volume;
-                    new_data->volume_is_absolute = FALSE;
-                }
 
-                if (v.channels > 0) {
-                    pa_log_info("Restoring volume for sink input %s.", name);
-                    pa_sink_input_new_data_set_volume(new_data, pa_cvolume_remap(&v, &e->channel_map, &new_data->channel_map));
-                    new_data->save_volume = TRUE;
-                }
+                pa_log_info("Restoring volume for sink input %s.", name);
+                v = e->volume;
+                pa_cvolume_remap(&v, &e->channel_map, &new_data->channel_map);
+                pa_sink_input_new_data_set_volume(new_data, &v);
+
+                new_data->volume_is_absolute = FALSE;
+                new_data->save_volume = FALSE;
             } else
                 pa_log_debug("Not restoring volume for sink input %s, because already set.", name);
         }
 
         if (u->restore_muted && e->muted_valid) {
+
             if (!new_data->muted_is_set) {
                 pa_log_info("Restoring mute state for sink input %s.", name);
                 pa_sink_input_new_data_set_muted(new_data, e->muted);
@@ -532,30 +512,15 @@ static void apply_entry(struct userdata *u, const char *name, struct entry *e) {
         }
         pa_xfree(n);
 
-        if (u->restore_volume) {
+        if (u->restore_volume && e->volume_valid) {
             pa_cvolume v;
-            pa_cvolume_init(&v);
 
-            if (si->sink->flags & PA_SINK_FLAT_VOLUME) {
-
-                if (e->absolute_volume_valid &&
-                    (e->device[0] == 0 || pa_streq(e->device, si->sink->name)))
-                    v = e->absolute_volume;
-                else if (e->relative_volume_valid) {
-                    pa_cvolume t = *pa_sink_get_volume(si->sink, FALSE);
-                    pa_sw_cvolume_multiply(&v, &e->relative_volume, pa_cvolume_remap(&t, &si->sink->channel_map, &e->channel_map));
-                }
-            } else if (e->relative_volume_valid)
-                v = e->relative_volume;
-
-            if (v.channels > 0) {
-                pa_log_info("Restoring volume for sink input %s.", name);
-                pa_sink_input_set_volume(si, pa_cvolume_remap(&v, &e->channel_map, &si->channel_map), TRUE);
-            }
+            v = e->volume;
+            pa_log_info("Restoring volume for sink input %s.", name);
+            pa_sink_input_set_volume(si, pa_cvolume_remap(&v, &e->channel_map, &si->channel_map), FALSE, FALSE);
         }
 
-        if (u->restore_muted &&
-            e->muted_valid) {
+        if (u->restore_muted && e->muted_valid) {
             pa_log_info("Restoring mute state for sink input %s.", name);
             pa_sink_input_set_mute(si, e->muted, TRUE);
         }
@@ -610,10 +575,10 @@ static void dump_database(struct userdata *u) {
         if ((e = read_entry(u, name))) {
             char t[256];
             pa_log("name=%s", name);
-            pa_log("device=%s", e->device);
+            pa_log("device=%s %s", e->device, pa_yes_no(e->device_valid));
             pa_log("channel_map=%s", pa_channel_map_snprint(t, sizeof(t), &e->channel_map));
-            pa_log("volume=%s", pa_cvolume_snprint(t, sizeof(t), &e->volume));
-            pa_log("mute=%s", pa_yes_no(e->muted));
+            pa_log("volume=%s %s", pa_cvolume_snprint(t, sizeof(t), &e->volume), pa_yes_no(e->volume_valid));
+            pa_log("mute=%s %s", pa_yes_no(e->muted), pa_yes_no(e->volume_valid));
             pa_xfree(e);
         }
 
@@ -674,8 +639,8 @@ static int extension_cb(pa_native_protocol *p, pa_module *m, pa_native_connectio
                     pa_channel_map cm;
 
                     pa_tagstruct_puts(reply, name);
-                    pa_tagstruct_put_channel_map(reply, (e->relative_volume_valid || e->absolute_volume_valid) ? &e->channel_map : pa_channel_map_init(&cm));
-                    pa_tagstruct_put_cvolume(reply, e->absolute_volume_valid ? &e->absolute_volume : (e->relative_volume_valid ? &e->relative_volume : pa_cvolume_init(&r)));
+                    pa_tagstruct_put_channel_map(reply, e->volume_valid ? &e->channel_map : pa_channel_map_init(&cm));
+                    pa_tagstruct_put_cvolume(reply, e->volume_valid ? &e->volume : pa_cvolume_init(&r));
                     pa_tagstruct_puts(reply, e->device_valid ? e->device : NULL);
                     pa_tagstruct_put_boolean(reply, e->muted_valid ? e->muted : FALSE);
 
@@ -718,7 +683,7 @@ static int extension_cb(pa_native_protocol *p, pa_module *m, pa_native_connectio
 
                 if (pa_tagstruct_gets(t, &name) < 0 ||
                     pa_tagstruct_get_channel_map(t, &entry.channel_map) ||
-                    pa_tagstruct_get_cvolume(t, &entry.absolute_volume) < 0 ||
+                    pa_tagstruct_get_cvolume(t, &entry.volume) < 0 ||
                     pa_tagstruct_gets(t, &device) < 0 ||
                     pa_tagstruct_get_boolean(t, &muted) < 0)
                     goto fail;
@@ -726,11 +691,10 @@ static int extension_cb(pa_native_protocol *p, pa_module *m, pa_native_connectio
                 if (!name || !*name)
                     goto fail;
 
-                entry.relative_volume = entry.absolute_volume;
-                entry.absolute_volume_valid = entry.relative_volume_valid = entry.relative_volume.channels > 0;
+                entry.volume_valid = entry.volume.channels > 0;
 
-                if (entry.relative_volume_valid)
-                    if (!pa_cvolume_compatible_with_channel_map(&entry.relative_volume, &entry.channel_map))
+                if (entry.volume_valid)
+                    if (!pa_cvolume_compatible_with_channel_map(&entry.volume, &entry.channel_map))
                         goto fail;
 
                 entry.muted = muted;
diff --git a/src/modules/oss/module-oss.c b/src/modules/oss/module-oss.c
index 855e8a3..9f7863f 100644
--- a/src/modules/oss/module-oss.c
+++ b/src/modules/oss/module-oss.c
@@ -617,7 +617,7 @@ static int unsuspend(struct userdata *u) {
     build_pollfd(u);
 
     if (u->sink)
-        pa_sink_get_volume(u->sink, TRUE);
+        pa_sink_get_volume(u->sink, TRUE, FALSE);
     if (u->source)
         pa_source_get_volume(u->source, TRUE);
 
diff --git a/src/pulsecore/cli-command.c b/src/pulsecore/cli-command.c
index 3ea1dca..15fe525 100644
--- a/src/pulsecore/cli-command.c
+++ b/src/pulsecore/cli-command.c
@@ -524,7 +524,7 @@ static int pa_cli_command_sink_volume(pa_core *c, pa_tokenizer *t, pa_strbuf *bu
     }
 
     pa_cvolume_set(&cvolume, sink->sample_spec.channels, volume);
-    pa_sink_set_volume(sink, &cvolume, TRUE, TRUE);
+    pa_sink_set_volume(sink, &cvolume, TRUE, TRUE, TRUE);
     return 0;
 }
 
@@ -566,7 +566,7 @@ static int pa_cli_command_sink_input_volume(pa_core *c, pa_tokenizer *t, pa_strb
     }
 
     pa_cvolume_set(&cvolume, si->sample_spec.channels, volume);
-    pa_sink_input_set_volume(si, &cvolume, TRUE);
+    pa_sink_input_set_volume(si, &cvolume, TRUE, TRUE);
     return 0;
 }
 
@@ -1516,7 +1516,7 @@ static int pa_cli_command_dump(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, pa_b
             nl = 1;
         }
 
-        pa_strbuf_printf(buf, "set-sink-volume %s 0x%03x\n", sink->name, pa_cvolume_avg(pa_sink_get_volume(sink, FALSE)));
+        pa_strbuf_printf(buf, "set-sink-volume %s 0x%03x\n", sink->name, pa_cvolume_avg(pa_sink_get_volume(sink, FALSE, TRUE)));
         pa_strbuf_printf(buf, "set-sink-mute %s %s\n", sink->name, pa_yes_no(pa_sink_get_mute(sink, FALSE)));
         pa_strbuf_printf(buf, "suspend-sink %s %s\n", sink->name, pa_yes_no(pa_sink_get_state(sink) == PA_SINK_SUSPENDED));
     }
diff --git a/src/pulsecore/cli-text.c b/src/pulsecore/cli-text.c
index b0911ef..604678b 100644
--- a/src/pulsecore/cli-text.c
+++ b/src/pulsecore/cli-text.c
@@ -258,10 +258,10 @@ char *pa_sink_list_to_string(pa_core *c) {
             sink->flags & PA_SINK_FLAT_VOLUME ? "FLAT_VOLUME " : "",
             sink->flags & PA_SINK_DYNAMIC_LATENCY ? "DYNAMIC_LATENCY" : "",
             sink_state_to_string(pa_sink_get_state(sink)),
-            pa_cvolume_snprint(cv, sizeof(cv), pa_sink_get_volume(sink, FALSE)),
+            pa_cvolume_snprint(cv, sizeof(cv), pa_sink_get_volume(sink, FALSE, FALSE)),
             sink->flags & PA_SINK_DECIBEL_VOLUME ? "\n\t        " : "",
-            sink->flags & PA_SINK_DECIBEL_VOLUME ? pa_sw_cvolume_snprint_dB(cvdb, sizeof(cvdb), pa_sink_get_volume(sink, FALSE)) : "",
-            pa_cvolume_get_balance(pa_sink_get_volume(sink, FALSE), &sink->channel_map),
+            sink->flags & PA_SINK_DECIBEL_VOLUME ? pa_sw_cvolume_snprint_dB(cvdb, sizeof(cvdb), pa_sink_get_volume(sink, FALSE, FALSE)) : "",
+            pa_cvolume_get_balance(pa_sink_get_volume(sink, FALSE, FALSE), &sink->channel_map),
             pa_volume_snprint(v, sizeof(v), sink->base_volume),
             sink->flags & PA_SINK_DECIBEL_VOLUME ? "\n\t             " : "",
             sink->flags & PA_SINK_DECIBEL_VOLUME ? pa_sw_volume_snprint_dB(vdb, sizeof(vdb), sink->base_volume) : "",
@@ -507,6 +507,9 @@ char *pa_sink_input_list_to_string(pa_core *c) {
         char ss[PA_SAMPLE_SPEC_SNPRINT_MAX], cvdb[PA_SW_CVOLUME_SNPRINT_DB_MAX], cv[PA_CVOLUME_SNPRINT_MAX], cm[PA_CHANNEL_MAP_SNPRINT_MAX], *t, clt[28];
         pa_usec_t cl;
         const char *cmn;
+        pa_cvolume v;
+
+        pa_sink_input_get_volume(i, &v, TRUE);
 
         cmn = pa_channel_map_to_pretty_name(&i->channel_map);
 
@@ -547,9 +550,9 @@ char *pa_sink_input_list_to_string(pa_core *c) {
             i->flags & PA_SINK_INPUT_FAIL_ON_SUSPEND ? "FAIL_ON_SUSPEND " : "",
             state_table[pa_sink_input_get_state(i)],
             i->sink->index, i->sink->name,
-            pa_cvolume_snprint(cv, sizeof(cv), pa_sink_input_get_volume(i)),
-            pa_sw_cvolume_snprint_dB(cvdb, sizeof(cvdb), pa_sink_input_get_volume(i)),
-            pa_cvolume_get_balance(pa_sink_input_get_volume(i), &i->channel_map),
+            pa_cvolume_snprint(cv, sizeof(cv), &v),
+            pa_sw_cvolume_snprint_dB(cvdb, sizeof(cvdb), &v),
+            pa_cvolume_get_balance(&v, &i->channel_map),
             pa_yes_no(pa_sink_input_get_mute(i)),
             (double) pa_sink_input_get_latency(i, NULL) / PA_USEC_PER_MSEC,
             clt,
diff --git a/src/pulsecore/protocol-esound.c b/src/pulsecore/protocol-esound.c
index a024471..7e7126e 100644
--- a/src/pulsecore/protocol-esound.c
+++ b/src/pulsecore/protocol-esound.c
@@ -638,7 +638,8 @@ static int esd_proto_all_info(connection *c, esd_proto_t request, const void *da
         pa_assert(t >= k*2+s);
 
         if (conn->sink_input) {
-            pa_cvolume volume = *pa_sink_input_get_volume(conn->sink_input);
+            pa_cvolume volume;
+            pa_sink_input_get_volume(conn->sink_input, &volume, TRUE);
             rate = (int32_t) conn->sink_input->sample_spec.rate;
             lvolume = (int32_t) ((volume.values[0]*ESD_VOLUME_BASE)/PA_VOLUME_NORM);
             rvolume = (int32_t) ((volume.values[volume.channels == 2 ? 1 : 0]*ESD_VOLUME_BASE)/PA_VOLUME_NORM);
@@ -778,7 +779,7 @@ static int esd_proto_stream_pan(connection *c, esd_proto_t request, const void *
         volume.values[1] = (rvolume*PA_VOLUME_NORM)/ESD_VOLUME_BASE;
         volume.channels = conn->sink_input->sample_spec.channels;
 
-        pa_sink_input_set_volume(conn->sink_input, &volume, TRUE);
+        pa_sink_input_set_volume(conn->sink_input, &volume, TRUE, TRUE);
         ok = 1;
     } else
         ok = 0;
diff --git a/src/pulsecore/protocol-native.c b/src/pulsecore/protocol-native.c
index 7c2183d..aecaf71 100644
--- a/src/pulsecore/protocol-native.c
+++ b/src/pulsecore/protocol-native.c
@@ -2819,7 +2819,7 @@ static void sink_fill_tagstruct(pa_native_connection *c, pa_tagstruct *t, pa_sin
         PA_TAG_SAMPLE_SPEC, &fixed_ss,
         PA_TAG_CHANNEL_MAP, &sink->channel_map,
         PA_TAG_U32, sink->module ? sink->module->index : PA_INVALID_INDEX,
-        PA_TAG_CVOLUME, pa_sink_get_volume(sink, FALSE),
+        PA_TAG_CVOLUME, pa_sink_get_volume(sink, FALSE, FALSE),
         PA_TAG_BOOLEAN, pa_sink_get_mute(sink, FALSE),
         PA_TAG_U32, sink->monitor_source ? sink->monitor_source->index : PA_INVALID_INDEX,
         PA_TAG_STRING, sink->monitor_source ? sink->monitor_source->name : NULL,
@@ -2943,6 +2943,7 @@ static void module_fill_tagstruct(pa_native_connection *c, pa_tagstruct *t, pa_m
 static void sink_input_fill_tagstruct(pa_native_connection *c, pa_tagstruct *t, pa_sink_input *s) {
     pa_sample_spec fixed_ss;
     pa_usec_t sink_latency;
+    pa_cvolume v;
 
     pa_assert(t);
     pa_sink_input_assert_ref(s);
@@ -2956,7 +2957,7 @@ static void sink_input_fill_tagstruct(pa_native_connection *c, pa_tagstruct *t,
     pa_tagstruct_putu32(t, s->sink->index);
     pa_tagstruct_put_sample_spec(t, &fixed_ss);
     pa_tagstruct_put_channel_map(t, &s->channel_map);
-    pa_tagstruct_put_cvolume(t, pa_sink_input_get_volume(s));
+    pa_tagstruct_put_cvolume(t, pa_sink_input_get_volume(s, &v, TRUE));
     pa_tagstruct_put_usec(t, pa_sink_input_get_latency(s, &sink_latency));
     pa_tagstruct_put_usec(t, sink_latency);
     pa_tagstruct_puts(t, pa_resample_method_to_string(pa_sink_input_get_resample_method(s)));
@@ -3321,11 +3322,11 @@ static void command_set_volume(
     CHECK_VALIDITY(c->pstream, si || sink || source, tag, PA_ERR_NOENTITY);
 
     if (sink)
-        pa_sink_set_volume(sink, &volume, TRUE, TRUE);
+        pa_sink_set_volume(sink, &volume, TRUE, TRUE, TRUE);
     else if (source)
         pa_source_set_volume(source, &volume);
     else if (si)
-        pa_sink_input_set_volume(si, &volume, TRUE);
+        pa_sink_input_set_volume(si, &volume, TRUE, TRUE);
 
     pa_pstream_send_simple_ack(c->pstream, tag);
 }
diff --git a/src/pulsecore/sink-input.c b/src/pulsecore/sink-input.c
index b1b9fb5..65f1fd5 100644
--- a/src/pulsecore/sink-input.c
+++ b/src/pulsecore/sink-input.c
@@ -176,16 +176,8 @@ int pa_sink_input_new(
     pa_return_val_if_fail(pa_channel_map_compatible(&data->channel_map, &data->sample_spec), -PA_ERR_INVALID);
 
     if (!data->volume_is_set) {
-
-        if (data->sink->flags & PA_SINK_FLAT_VOLUME) {
-            data->volume = *pa_sink_get_volume(data->sink, FALSE);
-            pa_cvolume_remap(&data->volume, &data->sink->channel_map, &data->channel_map);
-            data->volume_is_absolute = TRUE;
-        } else {
-            pa_cvolume_reset(&data->volume, data->sample_spec.channels);
-            data->volume_is_absolute = FALSE;
-        }
-
+        pa_cvolume_reset(&data->volume, data->sample_spec.channels);
+        data->volume_is_absolute = FALSE;
         data->save_volume = FALSE;
     }
 
@@ -279,10 +271,9 @@ int pa_sink_input_new(
         /* When the 'absolute' bool is not set then we'll treat the volume
          * as relative to the sink volume even in flat volume mode */
 
-        pa_cvolume t = *pa_sink_get_volume(data->sink, FALSE);
-        pa_cvolume_remap(&t, &data->sink->channel_map, &data->channel_map);
-
-        pa_sw_cvolume_multiply(&i->virtual_volume, &data->volume, &t);
+        pa_cvolume v = data->sink->reference_volume;
+        pa_cvolume_remap(&v, &data->sink->channel_map, &data->channel_map);
+        pa_sw_cvolume_multiply(&i->virtual_volume, &data->volume, &v);
     } else
         i->virtual_volume = data->volume;
 
@@ -451,7 +442,7 @@ void pa_sink_input_unlink(pa_sink_input *i) {
         if (i->sink->flags & PA_SINK_FLAT_VOLUME) {
             pa_cvolume new_volume;
             pa_sink_update_flat_volume(i->sink, &new_volume);
-            pa_sink_set_volume(i->sink, &new_volume, FALSE, FALSE);
+            pa_sink_set_volume(i->sink, &new_volume, FALSE, FALSE, FALSE);
         }
 
         if (i->sink->asyncmsgq)
@@ -529,7 +520,7 @@ void pa_sink_input_put(pa_sink_input *i) {
     if (i->sink->flags & PA_SINK_FLAT_VOLUME) {
         pa_cvolume new_volume;
         pa_sink_update_flat_volume(i->sink, &new_volume);
-        pa_sink_set_volume(i->sink, &new_volume, FALSE, FALSE);
+        pa_sink_set_volume(i->sink, &new_volume, FALSE, FALSE, FALSE);
     } else
         pa_sink_input_set_relative_volume(i, &i->virtual_volume);
 
@@ -881,13 +872,21 @@ pa_usec_t pa_sink_input_get_requested_latency(pa_sink_input *i) {
 }
 
 /* Called from main context */
-void pa_sink_input_set_volume(pa_sink_input *i, const pa_cvolume *volume, pa_bool_t save) {
+void pa_sink_input_set_volume(pa_sink_input *i, const pa_cvolume *volume, pa_bool_t save, pa_bool_t absolute) {
+    pa_cvolume v;
+
     pa_sink_input_assert_ref(i);
     pa_assert(PA_SINK_INPUT_IS_LINKED(i->state));
     pa_assert(volume);
     pa_assert(pa_cvolume_valid(volume));
     pa_assert(pa_cvolume_compatible(volume, &i->sample_spec));
 
+    if ((i->sink->flags & PA_SINK_FLAT_VOLUME) && !absolute) {
+        v = i->sink->reference_volume;
+        pa_cvolume_remap(&v, &i->sink->channel_map, &i->channel_map);
+        volume = pa_sw_cvolume_multiply(&v, &v, volume);
+    }
+
     if (pa_cvolume_equal(volume, &i->virtual_volume))
         return;
 
@@ -901,7 +900,7 @@ void pa_sink_input_set_volume(pa_sink_input *i, const pa_cvolume *volume, pa_boo
          * volumes and update the flat volume of the sink */
 
         pa_sink_update_flat_volume(i->sink, &new_volume);
-        pa_sink_set_volume(i->sink, &new_volume, FALSE, TRUE);
+        pa_sink_set_volume(i->sink, &new_volume, FALSE, TRUE, FALSE);
 
     } else {
 
@@ -921,11 +920,18 @@ void pa_sink_input_set_volume(pa_sink_input *i, const pa_cvolume *volume, pa_boo
 }
 
 /* Called from main context */
-const pa_cvolume *pa_sink_input_get_volume(pa_sink_input *i) {
+pa_cvolume *pa_sink_input_get_volume(pa_sink_input *i, pa_cvolume *volume, pa_bool_t absolute) {
     pa_sink_input_assert_ref(i);
     pa_assert(PA_SINK_INPUT_IS_LINKED(i->state));
 
-    return &i->virtual_volume;
+    if ((i->sink->flags & PA_SINK_FLAT_VOLUME) && !absolute) {
+        pa_cvolume v = i->sink->reference_volume;
+        pa_cvolume_remap(&v, &i->sink->channel_map, &i->channel_map);
+        pa_sw_cvolume_divide(volume, &i->virtual_volume, &v);
+    } else
+        *volume = i->virtual_volume;
+
+    return volume;
 }
 
 /* Called from main context */
@@ -936,7 +942,8 @@ pa_cvolume *pa_sink_input_get_relative_volume(pa_sink_input *i, pa_cvolume *v) {
     pa_assert(v);
     pa_assert(PA_SINK_INPUT_IS_LINKED(i->state));
 
-    /* This always returns a relative volume, even in flat volume mode */
+    /* This always returns the relative volume. Converts the float
+     * version into a pa_cvolume */
 
     v->channels = i->sample_spec.channels;
 
@@ -1152,7 +1159,7 @@ int pa_sink_input_start_move(pa_sink_input *i) {
         /* We might need to update the sink's volume if we are in flat
          * volume mode. */
         pa_sink_update_flat_volume(i->sink, &new_volume);
-        pa_sink_set_volume(i->sink, &new_volume, FALSE, FALSE);
+        pa_sink_set_volume(i->sink, &new_volume, FALSE, FALSE, FALSE);
     }
 
     pa_assert_se(pa_asyncmsgq_send(i->sink->asyncmsgq, PA_MSGOBJECT(i->sink), PA_SINK_MESSAGE_START_MOVE, i, 0, NULL) == 0);
@@ -1239,13 +1246,13 @@ int pa_sink_input_finish_move(pa_sink_input *i, pa_sink *dest, pa_bool_t save) {
         pa_cvolume new_volume;
 
         /* Make relative volume absolute again */
-        pa_cvolume t = dest->virtual_volume;
+        pa_cvolume t = dest->reference_volume;
         pa_cvolume_remap(&t, &dest->channel_map, &i->channel_map);
         pa_sw_cvolume_multiply(&i->virtual_volume, &i->virtual_volume, &t);
 
         /* We might need to update the sink's volume if we are in flat volume mode. */
         pa_sink_update_flat_volume(i->sink, &new_volume);
-        pa_sink_set_volume(i->sink, &new_volume, FALSE, FALSE);
+        pa_sink_set_volume(i->sink, &new_volume, FALSE, FALSE, FALSE);
     }
 
     pa_assert_se(pa_asyncmsgq_send(i->sink->asyncmsgq, PA_MSGOBJECT(i->sink), PA_SINK_MESSAGE_FINISH_MOVE, i, 0, NULL) == 0);
diff --git a/src/pulsecore/sink-input.h b/src/pulsecore/sink-input.h
index 96ad2ba..98144d4 100644
--- a/src/pulsecore/sink-input.h
+++ b/src/pulsecore/sink-input.h
@@ -91,6 +91,7 @@ struct pa_sink_input {
 
     pa_sink_input *sync_prev, *sync_next;
 
+    /* Also see http://pulseaudio.org/wiki/InternalVolumes */
     pa_cvolume virtual_volume;  /* The volume clients are informed about */
     pa_cvolume volume_factor;   /* An internally used volume factor that can be used by modules to apply effects and suchlike without having that visible to the outside */
     double relative_volume[PA_CHANNELS_MAX]; /* The calculated volume relative to the sink volume as linear factors. */
@@ -309,11 +310,14 @@ void pa_sink_input_kill(pa_sink_input*i);
 
 pa_usec_t pa_sink_input_get_latency(pa_sink_input *i, pa_usec_t *sink_latency);
 
-void pa_sink_input_set_volume(pa_sink_input *i, const pa_cvolume *volume, pa_bool_t save);
-const pa_cvolume *pa_sink_input_get_volume(pa_sink_input *i);
+void pa_sink_input_set_volume(pa_sink_input *i, const pa_cvolume *volume, pa_bool_t save, pa_bool_t absolute);
+pa_cvolume *pa_sink_input_get_volume(pa_sink_input *i, pa_cvolume *volume, pa_bool_t absolute);
+
 pa_cvolume *pa_sink_input_get_relative_volume(pa_sink_input *i, pa_cvolume *v);
+
 void pa_sink_input_set_mute(pa_sink_input *i, pa_bool_t mute, pa_bool_t save);
 pa_bool_t pa_sink_input_get_mute(pa_sink_input *i);
+
 void pa_sink_input_update_proplist(pa_sink_input *i, pa_update_mode_t mode, pa_proplist *p);
 
 pa_resample_method_t pa_sink_input_get_resample_method(pa_sink_input *i);
diff --git a/src/pulsecore/sink.c b/src/pulsecore/sink.c
index 93800d1..30fa557 100644
--- a/src/pulsecore/sink.c
+++ b/src/pulsecore/sink.c
@@ -202,7 +202,7 @@ pa_sink* pa_sink_new(
     s->inputs = pa_idxset_new(NULL, NULL);
     s->n_corked = 0;
 
-    s->virtual_volume = data->volume;
+    s->reference_volume = s->virtual_volume = data->volume;
     pa_cvolume_reset(&s->soft_volume, s->sample_spec.channels);
     s->base_volume = PA_VOLUME_NORM;
     s->n_volume_steps = PA_VOLUME_NORM+1;
@@ -351,11 +351,12 @@ void pa_sink_put(pa_sink* s) {
 
     if (!(s->flags & PA_SINK_HW_VOLUME_CTRL)) {
         s->flags |= PA_SINK_DECIBEL_VOLUME;
-
-        s->thread_info.soft_volume = s->soft_volume;
-        s->thread_info.soft_muted = s->muted;
+        s->base_volume = PA_VOLUME_NORM;
     }
 
+    s->thread_info.soft_volume = s->soft_volume;
+    s->thread_info.soft_muted = s->muted;
+
     if (s->flags & PA_SINK_DECIBEL_VOLUME)
         s->n_volume_steps = PA_VOLUME_NORM+1;
 
@@ -1046,16 +1047,16 @@ void pa_sink_update_flat_volume(pa_sink *s, pa_cvolume *new_volume) {
     pa_assert(PA_SINK_IS_LINKED(s->state));
     pa_assert(s->flags & PA_SINK_FLAT_VOLUME);
 
-    /* This is called whenever a sink input volume changes and we
-     * might need to fix up the sink volume accordingly. Please note
-     * that we don't actually update the sinks volume here, we only
-     * return how it needs to be updated. The caller should then call
-     * pa_sink_set_volume().*/
+    /* This is called whenever a sink input volume changes or a sink
+     * input is added/removed and we might need to fix up the sink
+     * volume accordingly. Please note that we don't actually update
+     * the sinks volume here, we only return how it needs to be
+     * updated. The caller should then call pa_sink_set_volume().*/
 
     if (pa_idxset_isempty(s->inputs)) {
         /* In the special case that we have no sink input we leave the
          * volume unmodified. */
-        *new_volume = s->virtual_volume;
+        *new_volume = s->reference_volume;
         return;
     }
 
@@ -1142,7 +1143,7 @@ void pa_sink_propagate_flat_volume(pa_sink *s) {
 }
 
 /* Called from main thread */
-void pa_sink_set_volume(pa_sink *s, const pa_cvolume *volume, pa_bool_t propagate, pa_bool_t sendmsg) {
+void pa_sink_set_volume(pa_sink *s, const pa_cvolume *volume, pa_bool_t propagate, pa_bool_t sendmsg, pa_bool_t become_reference) {
     pa_bool_t virtual_volume_changed;
 
     pa_sink_assert_ref(s);
@@ -1154,6 +1155,9 @@ void pa_sink_set_volume(pa_sink *s, const pa_cvolume *volume, pa_bool_t propagat
     virtual_volume_changed = !pa_cvolume_equal(volume, &s->virtual_volume);
     s->virtual_volume = *volume;
 
+    if (become_reference)
+        s->reference_volume = s->virtual_volume;
+
     /* Propagate this volume change back to the inputs */
     if (virtual_volume_changed)
         if (propagate && (s->flags & PA_SINK_FLAT_VOLUME))
@@ -1161,8 +1165,8 @@ void pa_sink_set_volume(pa_sink *s, const pa_cvolume *volume, pa_bool_t propagat
 
     if (s->set_volume) {
         /* If we have a function set_volume(), then we do not apply a
-         * soft volume by default. However, set_volume() is apply one
-         * to s->soft_volume */
+         * soft volume by default. However, set_volume() is free to
+         * apply one to s->soft_volume */
 
         pa_cvolume_reset(&s->soft_volume, s->sample_spec.channels);
         s->set_volume(s);
@@ -1194,7 +1198,7 @@ void pa_sink_set_soft_volume(pa_sink *s, const pa_cvolume *volume) {
 }
 
 /* Called from main thread */
-const pa_cvolume *pa_sink_get_volume(pa_sink *s, pa_bool_t force_refresh) {
+const pa_cvolume *pa_sink_get_volume(pa_sink *s, pa_bool_t force_refresh, pa_bool_t reference) {
     pa_sink_assert_ref(s);
 
     if (s->refresh_volume || force_refresh) {
@@ -1207,6 +1211,8 @@ const pa_cvolume *pa_sink_get_volume(pa_sink *s, pa_bool_t force_refresh) {
 
         if (!pa_cvolume_equal(&old_virtual_volume, &s->virtual_volume)) {
 
+            s->reference_volume = s->virtual_volume;
+
             if (s->flags & PA_SINK_FLAT_VOLUME)
                 pa_sink_propagate_flat_volume(s);
 
@@ -1214,7 +1220,7 @@ const pa_cvolume *pa_sink_get_volume(pa_sink *s, pa_bool_t force_refresh) {
         }
     }
 
-    return &s->virtual_volume;
+    return reference ? &s->reference_volume : &s->virtual_volume;
 }
 
 /* Called from main thread */
@@ -1226,7 +1232,11 @@ void pa_sink_volume_changed(pa_sink *s, const pa_cvolume *new_volume) {
     if (pa_cvolume_equal(&s->virtual_volume, new_volume))
         return;
 
-    s->virtual_volume = *new_volume;
+    s->reference_volume = s->virtual_volume = *new_volume;
+
+    if (s->flags & PA_SINK_FLAT_VOLUME)
+        pa_sink_propagate_flat_volume(s);
+
     pa_subscription_post(s->core, PA_SUBSCRIPTION_EVENT_SINK|PA_SUBSCRIPTION_EVENT_CHANGE, s->index);
 }
 
diff --git a/src/pulsecore/sink.h b/src/pulsecore/sink.h
index cb4697f..352282b 100644
--- a/src/pulsecore/sink.h
+++ b/src/pulsecore/sink.h
@@ -74,8 +74,10 @@ struct pa_sink {
     pa_volume_t base_volume; /* shall be constant */
     unsigned n_volume_steps; /* shall be constant */
 
-    pa_cvolume virtual_volume; /* The volume clients are informed about */
-    pa_cvolume soft_volume;    /* The internal software volume we apply to all PCM data while it passes through */
+    /* Also see http://pulseaudio.org/wiki/InternalVolumes */
+    pa_cvolume virtual_volume;   /* The volume clients are informed about */
+    pa_cvolume reference_volume; /* The volume taken as refernce base for relative sink input volumes */
+    pa_cvolume soft_volume;      /* The internal software volume we apply to all PCM data while it passes through */
     pa_bool_t muted:1;
 
     pa_bool_t refresh_volume:1;
@@ -255,8 +257,9 @@ int pa_sink_suspend_all(pa_core *c, pa_bool_t suspend);
 void pa_sink_update_flat_volume(pa_sink *s, pa_cvolume *new_volume);
 void pa_sink_propagate_flat_volume(pa_sink *s);
 
-void pa_sink_set_volume(pa_sink *sink, const pa_cvolume *volume, pa_bool_t propagate, pa_bool_t sendmsg);
-const pa_cvolume *pa_sink_get_volume(pa_sink *sink, pa_bool_t force_refresh);
+void pa_sink_set_volume(pa_sink *sink, const pa_cvolume *volume, pa_bool_t propagate, pa_bool_t sendmsg, pa_bool_t become_reference);
+const pa_cvolume *pa_sink_get_volume(pa_sink *sink, pa_bool_t force_refresh, pa_bool_t reference);
+
 void pa_sink_set_mute(pa_sink *sink, pa_bool_t mute);
 pa_bool_t pa_sink_get_mute(pa_sink *sink, pa_bool_t force_refresh);
 

-- 
hooks/post-receive
PulseAudio Sound Server



More information about the pulseaudio-commits mailing list