[pulseaudio-commits] [SCM] PulseAudio Sound Server branch, master, updated. v1.0-dev-116-gbed4b73

Colin Guthrie gitmailer-noreply at 0pointer.de
Mon Feb 28 03:37:30 PST 2011


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  f51889c6f64f11221caba3615bf779fc19d0dd15 (commit)

- Log -----------------------------------------------------------------
bed4b73 Add src/*-symdef.h to .gitignore.
59f2b44 sink: Add casts to some printf arguments to get rid of compiler warnings.
0d8bbaf sink: Don't send unnecessary PA_SINK_MESSAGE_SET_SHARED_VOLUME messages.
6bd3415 virtual-sink: Fix a crash when moving the sink to a new master right after setup.
b3644c1 virtual-sink/source: Remove an unused variable.
1fda23c virtual-sink/source: Use a more descriptive stream name.
d2d36be virtual-sink: Add a modarg for forcing flat volume.
8702d15 virtual-sink: Add a modarg for enabling volume sharing.
c9c88fb Implement the "volume sharing" feature.
dbdb460 alsa-mixer: Make sure capture source and input source use right path
65317c8 alsa-mixer: Fixup "Mic"/"Line"/"analog-input" paths to work with the new paths
3618268 alsa-mixer: Add new paths for Internal Mic, Front Mic, Rear Mic and Dock Mic
ade0a6f alsa-mixer: always round towards 0 dB
b0f7231 alsa-mixer: add required-any and required-* for enum options
0ce3017 alsa-mixer: Add a few well-known descriptions
624152d alsa-card: Add a new modarg "profile_set" for giving the card a custom profile set configuration file.
4635904 alsa-mixer: Fix path set building when using the element-output or element-input mapping options in profile set configuration.
3153b60 core: Add a new hook PA_CORE_HOOK_CARD_PROFILE_CHANGED
9379d40 core: Added new hooks: PA_CORE_HOOK_SOURCE_PORT_CHANGED and PA_CORE_HOOK_SINK_PORT_CHANGED
6bd32ee Support for multichannel DSP processing in module-ladspa-sink
a3dbdb0 Merge remote-tracking branch 'mkbosmans/mingw32-build'
821562b Use pa_read, pa_write and pa_poll instead of system functions
30c7c95 tests/rtstutter: Use pa_rtclock
aebf66b Use pa_* instead of generic functions to improve portability
f2a9fd7 Give module-waveout a configure switch
110b14e module-waveout: Adapted to updated API
5205e6a win32: Implement pa_random
a39a836 win32: Implement rtclock based on QueryPerformanceCounter
5699954 win32: flush stderr after log output
d6d4336 Implement some functions for win32
7b90e3b Repair some typos
5815ec6 Add AM_LDFLAGS more consistently to all commands
2de2c73 Fix dependencies and include necessary headers
a951c77 Use PCRE if POSIX regex.h is not available
bb12ff8 Apply #ifdefs around functionality not available on win32
0ac0479 Adapt win32 specific code to current API
4f1d404 Use <pulsecore/socket.h> instead of <sys/socket.h>
d6d9fb2 Clean up <poll.h> includes
8d12ab9 Use setenv instead of putenv
-----------------------------------------------------------------------

Summary of changes:
 configure.ac                                       |   56 ++-
 src/.gitignore                                     |    1 +
 src/Makefile.am                                    |   89 ++--
 src/daemon/cpulimit.c                              |    2 +-
 src/daemon/daemon-conf.c                           |    5 +
 src/daemon/dumpmodules.c                           |    2 +
 src/daemon/ltdl-bind-now.c                         |    4 +
 src/daemon/main.c                                  |   14 +-
 src/modules/.gitignore                             |    1 -
 src/modules/alsa/alsa-mixer.c                      |  117 ++++-
 src/modules/alsa/alsa-mixer.h                      |    8 +
 ...nternal-mic.conf => analog-input-dock-mic.conf} |   56 ++-
 ...ternal-mic.conf => analog-input-front-mic.conf} |   54 ++-
 .../mixer/paths/analog-input-internal-mic.conf     |   84 +++-
 .../alsa/mixer/paths/analog-input-linein.conf      |   25 +-
 src/modules/alsa/mixer/paths/analog-input-mic.conf |   75 ++-
 .../alsa/mixer/paths/analog-input-mic.conf.common  |   77 +--
 ...nternal-mic.conf => analog-input-rear-mic.conf} |   56 ++-
 src/modules/alsa/mixer/paths/analog-input.conf     |   28 +-
 .../alsa/mixer/paths/analog-input.conf.common      |   45 --
 .../alsa/mixer/paths/analog-output.conf.common     |    5 +
 src/modules/alsa/mixer/profile-sets/default.conf   |    4 +-
 src/modules/alsa/module-alsa-card.c                |    9 +-
 src/modules/bluetooth/module-bluetooth-device.c    |    3 +-
 src/modules/module-augment-properties.c            |    2 +
 src/modules/module-cli.c                           |    6 +-
 src/modules/module-esound-sink.c                   |   14 +-
 src/modules/module-ladspa-sink.c                   |  384 ++++++++-----
 src/modules/module-match.c                         |    7 +-
 src/modules/module-pipe-sink.c                     |    2 +-
 src/modules/module-pipe-source.c                   |    2 +-
 src/modules/module-protocol-stub.c                 |    5 +-
 src/modules/module-sine-source.c                   |    2 -
 src/modules/module-virtual-sink.c                  |   48 ++-
 src/modules/module-virtual-source.c                |    7 +-
 src/modules/module-waveout.c                       |  395 ++++++++------
 src/modules/oss/module-oss.c                       |    2 +-
 src/modules/rtp/module-rtp-recv.c                  |    2 +-
 src/modules/rtp/rtp.h                              |    3 +
 src/pulse/context.c                                |   12 +-
 src/pulse/def.h                                    |   12 +-
 src/pulse/mainloop-api.h                           |    1 -
 src/pulse/mainloop.c                               |    2 +-
 src/pulse/rtclock.c                                |    2 +-
 src/pulse/thread-mainloop.c                        |    9 +-
 src/pulse/timeval.c                                |   16 +-
 src/pulse/util.c                                   |   30 +-
 src/pulsecore/authkey.c                            |    3 +-
 src/pulsecore/card.c                               |    2 +
 src/pulsecore/core-rtclock.c                       |   32 ++
 src/pulsecore/core-rtclock.h                       |    2 +
 src/pulsecore/core-util.c                          |  126 ++++-
 src/pulsecore/core-util.h                          |    2 +-
 src/pulsecore/core.h                               |    3 +
 src/pulsecore/creds.h                              |    4 +-
 src/pulsecore/fdsem.c                              |   18 +-
 src/pulsecore/inet_ntop.c                          |   11 +-
 src/pulsecore/inet_ntop.h                          |    8 +-
 src/pulsecore/inet_pton.c                          |   10 +-
 src/pulsecore/inet_pton.h                          |    8 +-
 src/pulsecore/iochannel.c                          |    7 +-
 src/pulsecore/ioline.c                             |    2 +-
 src/pulsecore/ipacl.c                              |    7 +-
 src/pulsecore/lock-autospawn.c                     |   13 +-
 src/pulsecore/log.c                                |    3 +
 src/pulsecore/memblockq.c                          |    2 -
 src/pulsecore/memtrap.c                            |    7 +
 src/pulsecore/mutex-win32.c                        |   25 +-
 src/pulsecore/parseaddr.c                          |    5 +-
 src/pulsecore/pipe.c                               |    7 +-
 src/pulsecore/play-memblockq.c                     |    6 +
 src/pulsecore/poll.c                               |   11 +-
 src/pulsecore/proplist-util.c                      |    2 +-
 src/pulsecore/protocol-native.c                    |    2 +-
 src/pulsecore/pstream.c                            |    6 +-
 src/pulsecore/random.c                             |   17 +-
 src/pulsecore/rtpoll.c                             |    1 -
 src/pulsecore/sink-input.c                         |  204 ++++++-
 src/pulsecore/sink.c                               |  570 ++++++++++++++------
 src/pulsecore/sink.h                               |    4 +
 src/pulsecore/socket-client.c                      |    9 +-
 src/pulsecore/socket-server.c                      |   11 +-
 src/pulsecore/socket-util.c                        |    8 +-
 src/pulsecore/socket-util.h                        |    2 +-
 src/pulsecore/{winsock.h => socket.h}              |    9 +-
 src/pulsecore/source.c                             |    2 +
 src/pulsecore/start-child.c                        |    3 +
 src/pulsecore/tagstruct.c                          |    2 +-
 src/pulsecore/tagstruct.h                          |    1 -
 src/pulsecore/thread-mq.h                          |    2 +-
 src/pulsecore/thread-win32.c                       |    5 +-
 src/pulsecore/thread.h                             |    2 +-
 src/tests/asyncq-test.c                            |    2 +-
 src/tests/ipacl-test.c                             |    9 +-
 src/tests/rtstutter.c                              |   62 +--
 95 files changed, 2018 insertions(+), 1026 deletions(-)
 delete mode 100644 src/modules/.gitignore
 copy src/modules/alsa/mixer/paths/{analog-input-internal-mic.conf => analog-input-dock-mic.conf} (63%)
 copy src/modules/alsa/mixer/paths/{analog-input-internal-mic.conf => analog-input-front-mic.conf} (63%)
 copy src/modules/alsa/mixer/paths/{analog-input-internal-mic.conf => analog-input-rear-mic.conf} (63%)
 rename src/pulsecore/{winsock.h => socket.h} (77%)

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

commit 8d12ab9e632420864fa024909c66863de2452987
Author: Maarten Bosmans <mkbosmans at gmail.com>
Date:   Wed Jan 12 08:15:44 2011 +0100

    Use setenv instead of putenv
    
    In theory putenv could be used to handle freeing of strings yourself, but this
    was not done in PulseAudio.  That leaves no advantages in using putenv.  With
    setenv you're at the mercy of the implementation whether the strings leak, but
    at least that is better then a certain leak, as it was before.

diff --git a/src/pulsecore/core-util.c b/src/pulsecore/core-util.c
index 4e7d0d7..ec0b338 100644
--- a/src/pulsecore/core-util.c
+++ b/src/pulsecore/core-util.c
@@ -2501,7 +2501,7 @@ void pa_set_env(const char *key, const char *value) {
 
     /* This is not thread-safe */
 
-    putenv(pa_sprintf_malloc("%s=%s", key, value));
+    setenv(key, value, 1);
 }
 
 void pa_set_env_and_record(const char *key, const char *value) {

commit d6d9fb295d03a411974a148e469465e0f7c59891
Author: Maarten Bosmans <mkbosmans at gmail.com>
Date:   Tue Jan 4 11:17:53 2011 +0100

    Clean up <poll.h> includes
    
    Instead <pulsecore/poll.h> should be included.  That file includes poll.h on
    platform where it is appropriate.  Also remove some unnecessary <ioctl.h>
    includes.

diff --git a/src/daemon/main.c b/src/daemon/main.c
index cad6f70..0db794b 100644
--- a/src/daemon/main.c
+++ b/src/daemon/main.c
@@ -43,10 +43,6 @@
 #include <sys/mman.h>
 #endif
 
-#ifdef HAVE_SYS_IOCTL_H
-#include <sys/ioctl.h>
-#endif
-
 #ifdef HAVE_PWD_H
 #include <pwd.h>
 #endif
diff --git a/src/modules/bluetooth/module-bluetooth-device.c b/src/modules/bluetooth/module-bluetooth-device.c
index 6d31c1e..dc09ffc 100644
--- a/src/modules/bluetooth/module-bluetooth-device.c
+++ b/src/modules/bluetooth/module-bluetooth-device.c
@@ -25,8 +25,6 @@
 
 #include <string.h>
 #include <errno.h>
-#include <poll.h>
-#include <sys/ioctl.h>
 #include <linux/sockios.h>
 #include <arpa/inet.h>
 
@@ -44,6 +42,7 @@
 #include <pulsecore/socket-util.h>
 #include <pulsecore/thread.h>
 #include <pulsecore/thread-mq.h>
+#include <pulsecore/poll.h>
 #include <pulsecore/rtpoll.h>
 #include <pulsecore/time-smoother.h>
 #include <pulsecore/namereg.h>
diff --git a/src/modules/module-esound-sink.c b/src/modules/module-esound-sink.c
index 02541e6..0d04fff 100644
--- a/src/modules/module-esound-sink.c
+++ b/src/modules/module-esound-sink.c
@@ -31,7 +31,6 @@
 #include <fcntl.h>
 #include <unistd.h>
 #include <limits.h>
-#include <poll.h>
 #include <sys/socket.h>
 #include <netinet/in.h>
 #include <netinet/tcp.h>
@@ -60,6 +59,8 @@
 #include <pulsecore/thread.h>
 #include <pulsecore/time-smoother.h>
 #include <pulsecore/socket-util.h>
+#include <pulsecore/rtpoll.h>
+#include <pulsecore/poll.h>
 
 #include "module-esound-sink-symdef.h"
 
diff --git a/src/modules/module-pipe-sink.c b/src/modules/module-pipe-sink.c
index e26cbf6..4ed91aa 100644
--- a/src/modules/module-pipe-sink.c
+++ b/src/modules/module-pipe-sink.c
@@ -32,7 +32,6 @@
 #include <unistd.h>
 #include <limits.h>
 #include <sys/ioctl.h>
-#include <poll.h>
 
 #ifdef HAVE_SYS_FILIO_H
 #include <sys/filio.h>
@@ -49,6 +48,7 @@
 #include <pulsecore/thread.h>
 #include <pulsecore/thread-mq.h>
 #include <pulsecore/rtpoll.h>
+#include <pulsecore/poll.h>
 
 #include "module-pipe-sink-symdef.h"
 
diff --git a/src/modules/module-pipe-source.c b/src/modules/module-pipe-source.c
index 1a6607d..c50536e 100644
--- a/src/modules/module-pipe-source.c
+++ b/src/modules/module-pipe-source.c
@@ -32,7 +32,6 @@
 #include <unistd.h>
 #include <limits.h>
 #include <sys/ioctl.h>
-#include <sys/poll.h>
 
 #ifdef HAVE_SYS_FILIO_H
 #include <sys/filio.h>
@@ -49,6 +48,7 @@
 #include <pulsecore/thread.h>
 #include <pulsecore/thread-mq.h>
 #include <pulsecore/rtpoll.h>
+#include <pulsecore/poll.h>
 
 #include "module-pipe-source-symdef.h"
 
diff --git a/src/modules/module-sine-source.c b/src/modules/module-sine-source.c
index c66099c..955834f 100644
--- a/src/modules/module-sine-source.c
+++ b/src/modules/module-sine-source.c
@@ -31,7 +31,6 @@
 #include <fcntl.h>
 #include <unistd.h>
 #include <limits.h>
-#include <sys/ioctl.h>
 
 #include <pulse/rtclock.h>
 #include <pulse/timeval.h>
@@ -47,7 +46,6 @@
 #include <pulsecore/thread.h>
 #include <pulsecore/thread-mq.h>
 #include <pulsecore/rtpoll.h>
-#include <pulsecore/poll.h>
 
 #include "module-sine-source-symdef.h"
 
diff --git a/src/modules/oss/module-oss.c b/src/modules/oss/module-oss.c
index ba9b99e..c9dc4e7 100644
--- a/src/modules/oss/module-oss.c
+++ b/src/modules/oss/module-oss.c
@@ -53,7 +53,6 @@
 #include <unistd.h>
 #include <limits.h>
 #include <signal.h>
-#include <poll.h>
 
 #include <pulse/xmalloc.h>
 #include <pulse/util.h>
@@ -70,6 +69,7 @@
 #include <pulsecore/macro.h>
 #include <pulsecore/thread-mq.h>
 #include <pulsecore/rtpoll.h>
+#include <pulsecore/poll.h>
 
 #if defined(__NetBSD__) && !defined(SNDCTL_DSP_GETODELAY)
 #include <sys/audioio.h>
diff --git a/src/modules/rtp/module-rtp-recv.c b/src/modules/rtp/module-rtp-recv.c
index b59519f..a920e66 100644
--- a/src/modules/rtp/module-rtp-recv.c
+++ b/src/modules/rtp/module-rtp-recv.c
@@ -31,7 +31,6 @@
 #include <errno.h>
 #include <string.h>
 #include <unistd.h>
-#include <poll.h>
 
 #include <pulse/rtclock.h>
 #include <pulse/timeval.h>
@@ -54,6 +53,7 @@
 #include <pulsecore/atomic.h>
 #include <pulsecore/socket-util.h>
 #include <pulsecore/once.h>
+#include <pulsecore/poll.h>
 
 #include "module-rtp-recv-symdef.h"
 
diff --git a/src/pulse/thread-mainloop.c b/src/pulse/thread-mainloop.c
index c3cf49c..d8c82c8 100644
--- a/src/pulse/thread-mainloop.c
+++ b/src/pulse/thread-mainloop.c
@@ -31,12 +31,6 @@
 #include <signal.h>
 #include <stdio.h>
 
-#ifdef HAVE_POLL_H
-#include <poll.h>
-#else
-#include <pulsecore/poll.h>
-#endif
-
 #include <pulse/xmalloc.h>
 #include <pulse/mainloop.h>
 #include <pulse/i18n.h>
@@ -46,6 +40,7 @@
 #include <pulsecore/thread.h>
 #include <pulsecore/mutex.h>
 #include <pulsecore/macro.h>
+#include <pulsecore/poll.h>
 
 #include "thread-mainloop.h"
 
diff --git a/src/pulsecore/lock-autospawn.c b/src/pulsecore/lock-autospawn.c
index 422f5eb..b515057 100644
--- a/src/pulsecore/lock-autospawn.c
+++ b/src/pulsecore/lock-autospawn.c
@@ -26,7 +26,6 @@
 #include <fcntl.h>
 #include <errno.h>
 #include <string.h>
-#include <sys/poll.h>
 #include <signal.h>
 #include <pthread.h>
 

commit 4f1d4044f8409ff29eeb7f97324daba496e40714
Author: Maarten Bosmans <mkbosmans at gmail.com>
Date:   Tue Jan 4 17:03:13 2011 +0100

    Use <pulsecore/socket.h> instead of <sys/socket.h>
    
    The check whether POSIX socket.h or WIN32 winsock2.h must be included can be
    made centrally.  The downside is that some functionality of e.g. arpa/inet.h is
    also implemented in winsock.h, so that some files that don't use socket
    functions, but do use inet.h functions, must also include pulsecore/socket.h.
    (as well as arpa/inet.h)

diff --git a/src/Makefile.am b/src/Makefile.am
index 0687e40..baba9c5 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -617,7 +617,7 @@ libpulsecommon_ at PA_MAJORMINOR@_la_SOURCES = \
 		pulsecore/tokenizer.c pulsecore/tokenizer.h \
 		pulsecore/usergroup.c pulsecore/usergroup.h \
 		pulsecore/sndfile-util.c pulsecore/sndfile-util.h \
-		pulsecore/winsock.h
+		pulsecore/socket.h
 
 libpulsecommon_ at PA_MAJORMINOR@_la_CFLAGS = $(AM_CFLAGS) $(LIBSAMPLERATE_CFLAGS) $(LIBSNDFILE_CFLAGS)
 libpulsecommon_ at PA_MAJORMINOR@_la_LDFLAGS = $(AM_LDFLAGS) -avoid-version
diff --git a/src/daemon/main.c b/src/daemon/main.c
index 0db794b..de809b1 100644
--- a/src/daemon/main.c
+++ b/src/daemon/main.c
@@ -70,7 +70,7 @@
 #include <pulse/i18n.h>
 
 #include <pulsecore/lock-autospawn.h>
-#include <pulsecore/winsock.h>
+#include <pulsecore/socket.h>
 #include <pulsecore/core-error.h>
 #include <pulsecore/core-rtclock.h>
 #include <pulsecore/core.h>
diff --git a/src/modules/module-esound-sink.c b/src/modules/module-esound-sink.c
index 0d04fff..9eba8ac 100644
--- a/src/modules/module-esound-sink.c
+++ b/src/modules/module-esound-sink.c
@@ -31,7 +31,6 @@
 #include <fcntl.h>
 #include <unistd.h>
 #include <limits.h>
-#include <sys/socket.h>
 #include <netinet/in.h>
 #include <netinet/tcp.h>
 #include <sys/ioctl.h>
@@ -44,6 +43,7 @@
 #include <pulse/timeval.h>
 #include <pulse/xmalloc.h>
 
+#include <pulsecore/socket.h>
 #include <pulsecore/core-error.h>
 #include <pulsecore/iochannel.h>
 #include <pulsecore/sink.h>
diff --git a/src/modules/module-protocol-stub.c b/src/modules/module-protocol-stub.c
index e21186b..7ba5405 100644
--- a/src/modules/module-protocol-stub.c
+++ b/src/modules/module-protocol-stub.c
@@ -30,9 +30,6 @@
 #include <unistd.h>
 #include <limits.h>
 
-#ifdef HAVE_SYS_SOCKET_H
-#include <sys/socket.h>
-#endif
 #ifdef HAVE_ARPA_INET_H
 #include <arpa/inet.h>
 #endif
@@ -42,9 +39,9 @@
 
 #include <pulse/xmalloc.h>
 
-#include <pulsecore/winsock.h>
 #include <pulsecore/core-error.h>
 #include <pulsecore/module.h>
+#include <pulsecore/socket.h>
 #include <pulsecore/socket-server.h>
 #include <pulsecore/socket-util.h>
 #include <pulsecore/core-util.h>
diff --git a/src/pulse/context.c b/src/pulse/context.c
index 7a539b4..ca81650 100644
--- a/src/pulse/context.c
+++ b/src/pulse/context.c
@@ -39,9 +39,6 @@
 #include <sys/wait.h>
 #endif
 
-#ifdef HAVE_SYS_SOCKET_H
-#include <sys/socket.h>
-#endif
 #ifdef HAVE_SYS_UN_H
 #include <sys/un.h>
 #endif
@@ -57,9 +54,7 @@
 #include <pulse/mainloop.h>
 #include <pulse/timeval.h>
 
-#include <pulsecore/winsock.h>
 #include <pulsecore/core-error.h>
-
 #include <pulsecore/native-common.h>
 #include <pulsecore/pdispatch.h>
 #include <pulsecore/pstream.h>
@@ -69,6 +64,7 @@
 #include <pulsecore/core-rtclock.h>
 #include <pulsecore/core-util.h>
 #include <pulsecore/log.h>
+#include <pulsecore/socket.h>
 #include <pulsecore/socket-util.h>
 #include <pulsecore/creds.h>
 #include <pulsecore/macro.h>
diff --git a/src/pulse/mainloop.c b/src/pulse/mainloop.c
index 8f743ec..8c26138 100644
--- a/src/pulse/mainloop.c
+++ b/src/pulse/mainloop.c
@@ -47,7 +47,7 @@
 #include <pulsecore/llist.h>
 #include <pulsecore/log.h>
 #include <pulsecore/core-error.h>
-#include <pulsecore/winsock.h>
+#include <pulsecore/socket.h>
 #include <pulsecore/macro.h>
 
 #include "mainloop.h"
diff --git a/src/pulse/timeval.c b/src/pulse/timeval.c
index cde4417..c4a0841 100644
--- a/src/pulse/timeval.c
+++ b/src/pulse/timeval.c
@@ -31,7 +31,6 @@
 #include <windows.h>
 #endif
 
-#include <pulsecore/winsock.h>
 #include <pulsecore/macro.h>
 #include <pulsecore/core-util.h>
 
diff --git a/src/pulse/util.c b/src/pulse/util.c
index ca766da..3206e94 100644
--- a/src/pulse/util.c
+++ b/src/pulse/util.c
@@ -37,10 +37,6 @@
 #include <pwd.h>
 #endif
 
-#ifdef HAVE_SYS_SOCKET_H
-#include <sys/socket.h>
-#endif
-
 #ifdef HAVE_NETDB_H
 #include <netdb.h>
 #endif
@@ -56,7 +52,7 @@
 #include <pulse/xmalloc.h>
 #include <pulse/timeval.h>
 
-#include <pulsecore/winsock.h>
+#include <pulsecore/socket.h>
 #include <pulsecore/core-error.h>
 #include <pulsecore/log.h>
 #include <pulsecore/core-util.h>
@@ -195,11 +191,11 @@ char *pa_get_binary_name(char *s, size_t l) {
     {
         char *rp;
 
-	if ((rp = pa_readlink("/proc/curproc/file"))) {
-	    pa_strlcpy(s, pa_path_get_filename(rp), l);
-	    pa_xfree(rp);
-	    return s;
-	}
+        if ((rp = pa_readlink("/proc/curproc/file"))) {
+            pa_strlcpy(s, pa_path_get_filename(rp), l);
+            pa_xfree(rp);
+            return s;
+        }
     }
 #endif
 
diff --git a/src/pulsecore/core-util.c b/src/pulsecore/core-util.c
index ec0b338..3ce5edb 100644
--- a/src/pulsecore/core-util.c
+++ b/src/pulsecore/core-util.c
@@ -43,7 +43,6 @@
 #include <regex.h>
 #include <langinfo.h>
 #include <sys/utsname.h>
-#include <sys/socket.h>
 
 #ifdef HAVE_STRTOF_L
 #include <locale.h>
@@ -110,7 +109,7 @@
 #include <pulse/utf8.h>
 
 #include <pulsecore/core-error.h>
-#include <pulsecore/winsock.h>
+#include <pulsecore/socket.h>
 #include <pulsecore/log.h>
 #include <pulsecore/macro.h>
 #include <pulsecore/thread.h>
diff --git a/src/pulsecore/core-util.h b/src/pulsecore/core-util.h
index 0d63cfc..8619330 100644
--- a/src/pulsecore/core-util.h
+++ b/src/pulsecore/core-util.h
@@ -28,7 +28,6 @@
 #include <stdarg.h>
 #include <stdio.h>
 #include <string.h>
-#include <sys/socket.h>
 
 #ifdef HAVE_SYS_RESOURCE_H
 #include <sys/resource.h>
@@ -36,6 +35,7 @@
 
 #include <pulse/gccmacro.h>
 #include <pulsecore/macro.h>
+#include <pulsecore/socket.h>
 
 #ifndef PACKAGE
 #error "Please include config.h before including this file!"
diff --git a/src/pulsecore/creds.h b/src/pulsecore/creds.h
index c15c469..9e6fb12 100644
--- a/src/pulsecore/creds.h
+++ b/src/pulsecore/creds.h
@@ -28,9 +28,7 @@
 #error "Please include config.h before including this file!"
 #endif
 
-#ifdef HAVE_SYS_SOCKET_H
-#include <sys/socket.h>
-#endif
+#include <pulsecore/socket.h>
 
 #ifdef HAVE_SYS_UN_H
 #include <sys/un.h>
diff --git a/src/pulsecore/inet_ntop.c b/src/pulsecore/inet_ntop.c
index 012a1a0..e283a67 100644
--- a/src/pulsecore/inet_ntop.c
+++ b/src/pulsecore/inet_ntop.c
@@ -28,11 +28,7 @@
 
 #ifndef HAVE_INET_NTOP
 
-#ifdef HAVE_SYS_SOCKET_H
-#include <sys/socket.h>
-#endif
-
-#include "winsock.h"
+#include <pulsecore/socket.h>
 
 #include "inet_ntop.h"
 
diff --git a/src/pulsecore/inet_ntop.h b/src/pulsecore/inet_ntop.h
index 7fb67b4..7e1b203 100644
--- a/src/pulsecore/inet_ntop.h
+++ b/src/pulsecore/inet_ntop.h
@@ -1,11 +1,7 @@
 #ifndef fooinet_ntophfoo
 #define fooinet_ntophfoo
 
-#ifdef HAVE_SYS_SOCKET_H
-#include <sys/socket.h>
-#endif
-
-#include "winsock.h"
+#include <pulsecore/socket.h>
 
 const char *inet_ntop(int af, const void *src, char *dst, socklen_t cnt);
 
diff --git a/src/pulsecore/inet_pton.c b/src/pulsecore/inet_pton.c
index abdfa46..198d1a0 100644
--- a/src/pulsecore/inet_pton.c
+++ b/src/pulsecore/inet_pton.c
@@ -28,11 +28,7 @@
 
 #ifndef HAVE_INET_PTON
 
-#ifdef HAVE_SYS_SOCKET_H
-#include <sys/socket.h>
-#endif
-
-#include "winsock.h"
+#include <pulsecore/socket.h>
 
 #include "inet_pton.h"
 
diff --git a/src/pulsecore/inet_pton.h b/src/pulsecore/inet_pton.h
index 111b4a0..9d9c476 100644
--- a/src/pulsecore/inet_pton.h
+++ b/src/pulsecore/inet_pton.h
@@ -1,11 +1,7 @@
 #ifndef fooinet_ptonhfoo
 #define fooinet_ptonhfoo
 
-#ifdef HAVE_SYS_SOCKET_H
-#include <sys/socket.h>
-#endif
-
-#include "winsock.h"
+#include <pulsecore/socket.h>
 
 int inet_pton(int af, const char *src, void *dst);
 
diff --git a/src/pulsecore/iochannel.c b/src/pulsecore/iochannel.c
index f85c989..f89b067 100644
--- a/src/pulsecore/iochannel.c
+++ b/src/pulsecore/iochannel.c
@@ -28,19 +28,16 @@
 #include <fcntl.h>
 #include <unistd.h>
 #include <errno.h>
-#ifdef HAVE_SYS_SOCKET_H
-#include <sys/socket.h>
-#endif
+
 #ifdef HAVE_SYS_UN_H
 #include <sys/un.h>
 #endif
 
-#include "winsock.h"
-
 #include <pulse/xmalloc.h>
 
 #include <pulsecore/core-error.h>
 #include <pulsecore/core-util.h>
+#include <pulsecore/socket.h>
 #include <pulsecore/socket-util.h>
 #include <pulsecore/log.h>
 #include <pulsecore/macro.h>
diff --git a/src/pulsecore/ioline.c b/src/pulsecore/ioline.c
index 7afdb08..963f7d2 100644
--- a/src/pulsecore/ioline.c
+++ b/src/pulsecore/ioline.c
@@ -30,7 +30,7 @@
 
 #include <pulse/xmalloc.h>
 
-#include <pulsecore/winsock.h>
+#include <pulsecore/socket.h>
 #include <pulsecore/core-error.h>
 #include <pulsecore/log.h>
 #include <pulsecore/macro.h>
diff --git a/src/pulsecore/ipacl.c b/src/pulsecore/ipacl.c
index 312e040..0cbe34a 100644
--- a/src/pulsecore/ipacl.c
+++ b/src/pulsecore/ipacl.c
@@ -28,9 +28,6 @@
 #include <sys/types.h>
 #include <string.h>
 
-#ifdef HAVE_SYS_SOCKET_H
-#include <sys/socket.h>
-#endif
 #ifdef HAVE_NETINET_IN_H
 #include <netinet/in.h>
 #endif
@@ -50,10 +47,10 @@
 #include <pulsecore/llist.h>
 #include <pulsecore/log.h>
 #include <pulsecore/macro.h>
-#include <pulsecore/winsock.h>
+#include <pulsecore/socket.h>
 
 #ifndef HAVE_INET_PTON
-#include "inet_pton.h"
+#include <pulsecore/inet_pton.h>
 #endif
 
 #include "ipacl.h"
diff --git a/src/pulsecore/parseaddr.c b/src/pulsecore/parseaddr.c
index 44cd9a0..7f6cd90 100644
--- a/src/pulsecore/parseaddr.c
+++ b/src/pulsecore/parseaddr.c
@@ -25,8 +25,10 @@
 
 #include <string.h>
 #include <stdlib.h>
+
+#ifdef HAVE_ARPA_INET_H
 #include <arpa/inet.h>
-#include <sys/socket.h>
+#endif
 
 #include <pulse/xmalloc.h>
 #include <pulse/util.h>
diff --git a/src/pulsecore/pipe.c b/src/pulsecore/pipe.c
index c21e4b1..db8e16f 100644
--- a/src/pulsecore/pipe.c
+++ b/src/pulsecore/pipe.c
@@ -29,11 +29,7 @@
 
 #include <sys/types.h>
 
-#ifdef HAVE_SYS_SOCKET_H
-#include <sys/socket.h>
-#endif
-
-#include "winsock.h"
+#include <pulsecore/socket.h>
 
 #include "pipe.h"
 
diff --git a/src/pulsecore/poll.c b/src/pulsecore/poll.c
index b98fb16..b993c47 100644
--- a/src/pulsecore/poll.c
+++ b/src/pulsecore/poll.c
@@ -45,8 +45,7 @@
 #include <sys/select.h>
 #endif
 
-#include "winsock.h"
-
+#include <pulsecore/socket.h>
 #include <pulsecore/core-util.h>
 #include <pulse/util.h>
 
@@ -187,11 +186,11 @@ int pa_poll (struct pollfd *fds, unsigned long int nfds, int timeout) {
                      * connected socket, a server socket, or something else using a
                      * 0-byte recv, and use ioctl(2) to detect POLLHUP.  */
                     r = recv(f->fd, NULL, 0, MSG_PEEK);
-		    if (r == 0 || (r < 0 && errno == ENOTSOCK))
-		        ioctl(f->fd, FIONREAD, &r);
+                    if (r == 0 || (r < 0 && errno == ENOTSOCK))
+                        ioctl(f->fd, FIONREAD, &r);
 
-		    if (r == 0)
-		        f->revents |= POLLHUP;
+                    if (r == 0)
+                        f->revents |= POLLHUP;
 #else /* !OS_IS_DARWIN */
                     if (recv (f->fd, data, 64, MSG_PEEK) == -1) {
                         if (errno == ESHUTDOWN || errno == ECONNRESET ||
diff --git a/src/pulsecore/pstream.c b/src/pulsecore/pstream.c
index 3e0bfa3..369e22c 100644
--- a/src/pulsecore/pstream.c
+++ b/src/pulsecore/pstream.c
@@ -28,9 +28,6 @@
 #include <stdlib.h>
 #include <unistd.h>
 
-#ifdef HAVE_SYS_SOCKET_H
-#include <sys/socket.h>
-#endif
 #ifdef HAVE_SYS_UN_H
 #include <sys/un.h>
 #endif
@@ -38,10 +35,9 @@
 #include <netinet/in.h>
 #endif
 
-
 #include <pulse/xmalloc.h>
 
-#include <pulsecore/winsock.h>
+#include <pulsecore/socket.h>
 #include <pulsecore/queue.h>
 #include <pulsecore/log.h>
 #include <pulsecore/core-scache.h>
diff --git a/src/pulsecore/rtpoll.c b/src/pulsecore/rtpoll.c
index 2ef7873..98d7d62 100644
--- a/src/pulsecore/rtpoll.c
+++ b/src/pulsecore/rtpoll.c
@@ -40,7 +40,6 @@
 #include <pulsecore/llist.h>
 #include <pulsecore/flist.h>
 #include <pulsecore/core-util.h>
-#include <pulsecore/winsock.h>
 #include <pulsecore/ratelimit.h>
 #include <pulse/rtclock.h>
 
diff --git a/src/pulsecore/socket-client.c b/src/pulsecore/socket-client.c
index 7c449be..31acfd2 100644
--- a/src/pulsecore/socket-client.c
+++ b/src/pulsecore/socket-client.c
@@ -32,9 +32,6 @@
 #include <string.h>
 #include <stdlib.h>
 
-#ifdef HAVE_SYS_SOCKET_H
-#include <sys/socket.h>
-#endif
 #ifdef HAVE_SYS_UN_H
 #include <sys/un.h>
 #endif
@@ -56,9 +53,9 @@
 #include <pulse/timeval.h>
 #include <pulse/xmalloc.h>
 
-#include <pulsecore/winsock.h>
-#include <pulsecore/core-error.h>
+#include <pulsecore/socket.h>
 #include <pulsecore/socket-util.h>
+#include <pulsecore/core-error.h>
 #include <pulsecore/core-rtclock.h>
 #include <pulsecore/core-util.h>
 #include <pulsecore/socket-util.h>
diff --git a/src/pulsecore/socket-server.c b/src/pulsecore/socket-server.c
index 3b7c697..e45ded0 100644
--- a/src/pulsecore/socket-server.c
+++ b/src/pulsecore/socket-server.c
@@ -32,9 +32,6 @@
 #include <unistd.h>
 #include <sys/stat.h>
 
-#ifdef HAVE_SYS_SOCKET_H
-#include <sys/socket.h>
-#endif
 #ifdef HAVE_SYS_UN_H
 #include <sys/un.h>
 #ifndef SUN_LEN
@@ -54,18 +51,16 @@
 #endif
 
 #ifndef HAVE_INET_NTOP
-#include "inet_ntop.h"
+#include <pulsecore/inet_ntop.h>
 #endif
-
 #ifndef HAVE_INET_PTON
-#include "inet_pton.h"
+#include <pulsecore/inet_pton.h>
 #endif
 
-#include "winsock.h"
-
 #include <pulse/xmalloc.h>
 #include <pulse/util.h>
 
+#include <pulsecore/socket.h>
 #include <pulsecore/socket-util.h>
 #include <pulsecore/core-util.h>
 #include <pulsecore/log.h>
diff --git a/src/pulsecore/socket-util.c b/src/pulsecore/socket-util.c
index 2cc9882..0b16e0f 100644
--- a/src/pulsecore/socket-util.c
+++ b/src/pulsecore/socket-util.c
@@ -36,9 +36,6 @@
 #include <unistd.h>
 #include <sys/stat.h>
 
-#ifdef HAVE_SYS_SOCKET_H
-#include <sys/socket.h>
-#endif
 #ifdef HAVE_SYS_UN_H
 #include <sys/un.h>
 #endif
@@ -62,17 +59,16 @@
 #endif
 
 #ifndef HAVE_INET_NTOP
-#include "inet_ntop.h"
+#include <pulsecore/inet_ntop.h>
 #endif
 
-#include "winsock.h"
-
 #include <pulse/xmalloc.h>
 
 #include <pulsecore/core-error.h>
 #include <pulsecore/core-util.h>
 #include <pulsecore/log.h>
 #include <pulsecore/macro.h>
+#include <pulsecore/socket.h>
 
 #include "socket-util.h"
 
diff --git a/src/pulsecore/socket-util.h b/src/pulsecore/socket-util.h
index f6d1637..154afd4 100644
--- a/src/pulsecore/socket-util.h
+++ b/src/pulsecore/socket-util.h
@@ -24,8 +24,8 @@
 ***/
 
 #include <sys/types.h>
-#include <sys/socket.h>
 
+#include <pulsecore/socket.h>
 #include <pulsecore/macro.h>
 
 void pa_socket_peer_to_string(int fd, char *c, size_t l);
diff --git a/src/pulsecore/socket.h b/src/pulsecore/socket.h
new file mode 100644
index 0000000..0d38bee
--- /dev/null
+++ b/src/pulsecore/socket.h
@@ -0,0 +1,31 @@
+#ifndef foopulsecoresockethfoo
+#define foopulsecoresockethfoo
+
+#ifdef HAVE_SYS_SOCKET_H
+#include <sys/socket.h>
+#endif
+
+#ifdef HAVE_WINSOCK2_H
+#include <winsock2.h>
+
+#define ESHUTDOWN       WSAESHUTDOWN
+#define ECONNRESET      WSAECONNRESET
+#define ECONNABORTED    WSAECONNABORTED
+#define ENETRESET       WSAENETRESET
+#define EINPROGRESS     WSAEINPROGRESS
+#define EAFNOSUPPORT    WSAEAFNOSUPPORT
+#define ETIMEDOUT       WSAETIMEDOUT
+#define ECONNREFUSED    WSAECONNREFUSED
+#define EHOSTUNREACH    WSAEHOSTUNREACH
+#define EWOULDBLOCK     WSAEWOULDBLOCK
+#define EADDRINUSE      WSAEADDRINUSE
+
+typedef long suseconds_t;
+
+#endif
+
+#ifdef HAVE_WS2TCPIP_H
+#include <ws2tcpip.h>
+#endif
+
+#endif
diff --git a/src/pulsecore/tagstruct.c b/src/pulsecore/tagstruct.c
index 330b759..804b9f9 100644
--- a/src/pulsecore/tagstruct.c
+++ b/src/pulsecore/tagstruct.c
@@ -35,7 +35,7 @@
 
 #include <pulse/xmalloc.h>
 
-#include <pulsecore/winsock.h>
+#include <pulsecore/socket.h>
 #include <pulsecore/macro.h>
 
 #include "tagstruct.h"
diff --git a/src/pulsecore/winsock.h b/src/pulsecore/winsock.h
deleted file mode 100644
index 0352bf4..0000000
--- a/src/pulsecore/winsock.h
+++ /dev/null
@@ -1,26 +0,0 @@
-#ifndef foowinsockhfoo
-#define foowinsockhfoo
-
-#ifdef HAVE_WINSOCK2_H
-#include <winsock2.h>
-
-#define ESHUTDOWN       WSAESHUTDOWN
-#define ECONNRESET      WSAECONNRESET
-#define ECONNABORTED    WSAECONNABORTED
-#define ENETRESET       WSAENETRESET
-#define EINPROGRESS     WSAEINPROGRESS
-#define EAFNOSUPPORT    WSAEAFNOSUPPORT
-#define ETIMEDOUT       WSAETIMEDOUT
-#define ECONNREFUSED    WSAECONNREFUSED
-#define EHOSTUNREACH    WSAEHOSTUNREACH
-#define EWOULDBLOCK     WSAEWOULDBLOCK
-
-typedef long suseconds_t;
-
-#endif
-
-#ifdef HAVE_WS2TCPIP_H
-#include <ws2tcpip.h>
-#endif
-
-#endif
diff --git a/src/tests/ipacl-test.c b/src/tests/ipacl-test.c
index 57b7068..88bd6c6 100644
--- a/src/tests/ipacl-test.c
+++ b/src/tests/ipacl-test.c
@@ -8,9 +8,6 @@
 #include <assert.h>
 #include <string.h>
 
-#ifdef HAVE_SYS_SOCKET_H
-#include <sys/socket.h>
-#endif
 #ifdef HAVE_NETINET_IN_H
 #include <netinet/in.h>
 #endif
@@ -24,9 +21,8 @@
 #include <arpa/inet.h>
 #endif
 
-#include "../pulsecore/winsock.h"
-#include "../pulsecore/macro.h"
-
+#include <pulsecore/socket.h>
+#include <pulsecore/macro.h>
 #include <pulsecore/ipacl.h>
 
 int main(int argc, char *argv[]) {

commit 0ac0479534d9cb6e4ef734eeb3a663f33a4f8ef3
Author: Maarten Bosmans <mkbosmans at gmail.com>
Date:   Tue Jan 4 17:07:50 2011 +0100

    Adapt win32 specific code to current API

diff --git a/src/daemon/main.c b/src/daemon/main.c
index de809b1..cab275f 100644
--- a/src/daemon/main.c
+++ b/src/daemon/main.c
@@ -133,7 +133,7 @@ static void message_cb(pa_mainloop_api*a, pa_time_event*e, const struct timeval
     }
 
     pa_timeval_add(pa_gettimeofday(&tvnext), 100000);
-    a->rtclock_time_restart(e, &tvnext);
+    a->time_restart(e, &tvnext);
 }
 
 #endif
@@ -980,7 +980,7 @@ int main(int argc, char *argv[]) {
 #endif
 
 #ifdef OS_IS_WIN32
-    win32_timer = pa_mainloop_get_api(mainloop)->rtclock_time_new(pa_mainloop_get_api(mainloop), pa_gettimeofday(&win32_tv), message_cb, NULL);
+    win32_timer = pa_mainloop_get_api(mainloop)->time_new(pa_mainloop_get_api(mainloop), pa_gettimeofday(&win32_tv), message_cb, NULL);
 #endif
 
     if (!conf->no_cpu_limit)
diff --git a/src/pulsecore/mutex-win32.c b/src/pulsecore/mutex-win32.c
index 3a910b0..f4652a9 100644
--- a/src/pulsecore/mutex-win32.c
+++ b/src/pulsecore/mutex-win32.c
@@ -91,7 +91,7 @@ void pa_cond_signal(pa_cond *c, int broadcast) {
         return;
 
     if (broadcast)
-        SetEvent(pa_hashmap_get_first(c->wait_events));
+        SetEvent(pa_hashmap_first(c->wait_events));
     else {
         void *iter;
         const void *key;
@@ -131,3 +131,26 @@ int pa_cond_wait(pa_cond *c, pa_mutex *m) {
 
     return 0;
 }
+
+/* This is a copy of the function in mutex-posix.c */
+pa_mutex* pa_static_mutex_get(pa_static_mutex *s, pa_bool_t recursive, pa_bool_t inherit_priority) {
+    pa_mutex *m;
+
+    pa_assert(s);
+
+    /* First, check if already initialized and short cut */
+    if ((m = pa_atomic_ptr_load(&s->ptr)))
+        return m;
+
+    /* OK, not initialized, so let's allocate, and fill in */
+    m = pa_mutex_new(recursive, inherit_priority);
+    if ((pa_atomic_ptr_cmpxchg(&s->ptr, NULL, m)))
+        return m;
+
+    pa_mutex_free(m);
+
+    /* Him, filling in failed, so someone else must have filled in
+     * already */
+    pa_assert_se(m = pa_atomic_ptr_load(&s->ptr));
+    return m;
+}
diff --git a/src/pulsecore/thread-win32.c b/src/pulsecore/thread-win32.c
index 0a1baa5..7d458b9 100644
--- a/src/pulsecore/thread-win32.c
+++ b/src/pulsecore/thread-win32.c
@@ -71,8 +71,9 @@ static DWORD WINAPI internal_thread_func(LPVOID param) {
     return 0;
 }
 
-pa_thread* pa_thread_new(pa_thread_func_t thread_func, void *userdata) {
+pa_thread* pa_thread_new(const char *name, pa_thread_func_t thread_func, void *userdata) {
     pa_thread *t;
+    DWORD thread_id;
 
     assert(thread_func);
 
@@ -80,7 +81,7 @@ pa_thread* pa_thread_new(pa_thread_func_t thread_func, void *userdata) {
     t->thread_func = thread_func;
     t->userdata = userdata;
 
-    t->thread = CreateThread(NULL, 0, internal_thread_func, t, 0, NULL);
+    t->thread = CreateThread(NULL, 0, internal_thread_func, t, 0, &thread_id);
 
     if (!t->thread) {
         pa_xfree(t);

commit bb12ff83564d43566089dd979639c6993ba76665
Author: Maarten Bosmans <mkbosmans at gmail.com>
Date:   Thu Jan 6 00:51:33 2011 +0100

    Apply #ifdefs around functionality not available on win32
    
    And also the reverse: around some win32 specific functionality

diff --git a/configure.ac b/configure.ac
index 08c947a..42d9c3b 100644
--- a/configure.ac
+++ b/configure.ac
@@ -390,6 +390,7 @@ AC_CHECK_HEADERS_ONCE([byteswap.h])
 AC_CHECK_HEADERS_ONCE([sys/syscall.h])
 AC_CHECK_HEADERS_ONCE([sys/eventfd.h])
 AC_CHECK_HEADERS_ONCE([execinfo.h])
+AC_CHECK_HEADERS_ONCE([langinfo.h])
 
 #### Typdefs, structures, etc. ####
 
@@ -470,7 +471,7 @@ AC_FUNC_SELECT_ARGTYPES
 AC_CHECK_FUNCS_ONCE([chmod chown fstat fchown fchmod clock_gettime getaddrinfo getgrgid_r getgrnam_r \
     getpwnam_r getpwuid_r gettimeofday getuid inet_ntop inet_pton mlock nanosleep \
     pipe posix_fadvise posix_madvise posix_memalign setpgid setsid shm_open \
-    sigaction sleep sysconf pthread_setaffinity_np])
+    sigaction sleep symlink sysconf uname pthread_setaffinity_np])
 AC_CHECK_FUNCS([mkfifo], [HAVE_MKFIFO=1], [HAVE_MKFIFO=0])
 
 AM_CONDITIONAL(HAVE_MKFIFO, test "x$HAVE_MKFIFO" = "x1")
diff --git a/src/daemon/daemon-conf.c b/src/daemon/daemon-conf.c
index 74e8135..3339f3b 100644
--- a/src/daemon/daemon-conf.c
+++ b/src/daemon/daemon-conf.c
@@ -28,7 +28,10 @@
 #include <stdio.h>
 #include <string.h>
 #include <unistd.h>
+
+#ifdef HAVE_SCHED_H
 #include <sched.h>
+#endif
 
 #include <pulse/xmalloc.h>
 #include <pulse/timeval.h>
@@ -460,10 +463,12 @@ static int parse_rtprio(const char *filename, unsigned line, const char *section
     pa_assert(rvalue);
     pa_assert(data);
 
+#ifdef HAVE_SCHED_H
     if (pa_atoi(rvalue, &rtprio) < 0 || rtprio < sched_get_priority_min(SCHED_FIFO) || rtprio > sched_get_priority_max(SCHED_FIFO)) {
         pa_log("[%s:%u] Invalid realtime priority '%s'.", filename, line, rvalue);
         return -1;
     }
+#endif
 
     c->realtime_priority = (int) rtprio;
     return 0;
diff --git a/src/daemon/dumpmodules.c b/src/daemon/dumpmodules.c
index 92470b4..d0504dc 100644
--- a/src/daemon/dumpmodules.c
+++ b/src/daemon/dumpmodules.c
@@ -90,7 +90,9 @@ static void show_info(const char *name, const char *path, void (*info)(const cha
     }
 }
 
+#ifndef OS_IS_WIN32
 extern const lt_dlsymlist lt_preloaded_symbols[];
+#endif
 
 static int is_preloaded(const char *name) {
     const lt_dlsymlist *l;
diff --git a/src/daemon/ltdl-bind-now.c b/src/daemon/ltdl-bind-now.c
index 276b2a0..2ba73ce 100644
--- a/src/daemon/ltdl-bind-now.c
+++ b/src/daemon/ltdl-bind-now.c
@@ -51,6 +51,10 @@
 #undef PA_BIND_NOW
 #endif
 
+#ifdef OS_IS_WIN32
+#undef PA_BIND_NOW
+#endif
+
 #ifdef PA_BIND_NOW
 
 /*
diff --git a/src/daemon/main.c b/src/daemon/main.c
index cab275f..5aeb9bc 100644
--- a/src/daemon/main.c
+++ b/src/daemon/main.c
@@ -654,6 +654,7 @@ int main(int argc, char *argv[]) {
         goto finish;
     }
 
+#ifdef HAVE_GETUID
     if (getuid() == 0 && !conf->system_instance)
         pa_log_warn(_("This program is not intended to be run as root (unless --system is specified)."));
 #ifndef HAVE_DBUS /* A similar, only a notice worthy check was done earlier, if D-Bus is enabled. */
@@ -662,6 +663,7 @@ int main(int argc, char *argv[]) {
         goto finish;
     }
 #endif
+#endif  /* HAVE_GETUID */
 
     if (conf->cmd == PA_CMD_START && conf->system_instance) {
         pa_log(_("--start not supported for system instances."));
diff --git a/src/modules/module-augment-properties.c b/src/modules/module-augment-properties.c
index 30df69d..bdeee29 100644
--- a/src/modules/module-augment-properties.c
+++ b/src/modules/module-augment-properties.c
@@ -180,6 +180,7 @@ static void update_rule(struct rule *r) {
         DIR *desktopfiles_dir;
         struct dirent *dir;
 
+#ifdef DT_DIR
         /* Let's try a more aggressive search, but only one level */
         if ((desktopfiles_dir = opendir(DESKTOPFILEDIR))) {
             while ((dir = readdir(desktopfiles_dir))) {
@@ -200,6 +201,7 @@ static void update_rule(struct rule *r) {
             }
             closedir(desktopfiles_dir);
         }
+#endif
     }
     if (!found) {
         r->good = FALSE;
diff --git a/src/modules/module-cli.c b/src/modules/module-cli.c
index c5ff456..90ce3b6 100644
--- a/src/modules/module-cli.c
+++ b/src/modules/module-cli.c
@@ -105,10 +105,14 @@ int pa__init(pa_module*m) {
      * of log messages, particularly because if stdout and stderr are
      * dup'ed they share the same O_NDELAY, too. */
 
+#ifndef OS_IS_WIN32
     if ((fd = pa_open_cloexec("/dev/tty", O_RDWR|O_NONBLOCK, 0)) >= 0) {
         io = pa_iochannel_new(m->core->mainloop, fd, fd);
         pa_log_debug("Managed to open /dev/tty.");
-    } else {
+    }
+    else
+#endif
+    {
         io = pa_iochannel_new(m->core->mainloop, STDIN_FILENO, STDOUT_FILENO);
         pa_iochannel_set_noclose(io, TRUE);
         pa_log_debug("Failed to open /dev/tty, using stdin/stdout fds instead.");
diff --git a/src/modules/module-esound-sink.c b/src/modules/module-esound-sink.c
index 9eba8ac..5a1391d 100644
--- a/src/modules/module-esound-sink.c
+++ b/src/modules/module-esound-sink.c
@@ -31,9 +31,18 @@
 #include <fcntl.h>
 #include <unistd.h>
 #include <limits.h>
+
+#ifdef HAVE_NETINET_IN_H
 #include <netinet/in.h>
+#endif
+
+#ifdef HAVE_NETINET_TCP_H
 #include <netinet/tcp.h>
+#endif
+
+#ifdef HAVE_SYS_IOCTL_H
 #include <sys/ioctl.h>
+#endif
 
 #ifdef HAVE_LINUX_SOCKIOS_H
 #include <linux/sockios.h>
diff --git a/src/pulse/context.c b/src/pulse/context.c
index ca81650..8f632b5 100644
--- a/src/pulse/context.c
+++ b/src/pulse/context.c
@@ -585,10 +585,12 @@ static char *get_old_legacy_runtime_dir(void) {
         return NULL;
     }
 
+#ifdef HAVE_GETUID
     if (st.st_uid != getuid()) {
         pa_xfree(p);
         return NULL;
     }
+#endif
 
     return p;
 }
@@ -607,10 +609,12 @@ static char *get_very_old_legacy_runtime_dir(void) {
         return NULL;
     }
 
+#ifdef HAVE_GETUID
     if (st.st_uid != getuid()) {
         pa_xfree(p);
         return NULL;
     }
+#endif
 
     return p;
 }
@@ -997,6 +1001,7 @@ int pa_context_connect(
     /* Set up autospawning */
     if (!(flags & PA_CONTEXT_NOAUTOSPAWN) && c->conf->autospawn) {
 
+#ifdef HAVE_GETUID
         if (getuid() == 0)
             pa_log_debug("Not doing autospawn since we are root.");
         else {
@@ -1005,6 +1010,7 @@ int pa_context_connect(
             if (api)
                 c->spawn_api = *api;
         }
+#endif
     }
 
     pa_context_set_state(c, PA_CONTEXT_CONNECTING);
diff --git a/src/pulse/util.c b/src/pulse/util.c
index 3206e94..c5cfc8c 100644
--- a/src/pulse/util.c
+++ b/src/pulse/util.c
@@ -75,11 +75,15 @@ char *pa_get_user_name(char *s, size_t l) {
     pa_assert(s);
     pa_assert(l > 0);
 
-    if ((p = (getuid() == 0 ? "root" : NULL)) ||
-        (p = getenv("USER")) ||
-        (p = getenv("LOGNAME")) ||
-        (p = getenv("USERNAME")))
-    {
+    p = NULL;
+#ifdef HAVE_GETUID
+    p = getuid() == 0 ? "root" : NULL;
+#endif
+    if (!p) p = getenv("USER");
+    if (!p) p = getenv("LOGNAME");
+    if (!p) p = getenv("USERNAME");
+
+    if (p) {
         name = pa_strlcpy(s, p, l);
     } else {
 #ifdef HAVE_PWD_H
diff --git a/src/pulsecore/core-rtclock.c b/src/pulsecore/core-rtclock.c
index 110158b..a69b466 100644
--- a/src/pulsecore/core-rtclock.c
+++ b/src/pulsecore/core-rtclock.c
@@ -174,6 +174,7 @@ struct timeval* pa_rtclock_from_wallclock(struct timeval *tv) {
     return tv;
 }
 
+#ifdef HAVE_CLOCK_GETTIME
 pa_usec_t pa_timespec_load(const struct timespec *ts) {
 
     if (PA_UNLIKELY(!ts))
@@ -198,6 +199,7 @@ struct timespec* pa_timespec_store(struct timespec *ts, pa_usec_t v) {
 
     return ts;
 }
+#endif
 
 static struct timeval* wallclock_from_rtclock(struct timeval *tv) {
 
diff --git a/src/pulsecore/core-rtclock.h b/src/pulsecore/core-rtclock.h
index 3b393ed..6253536 100644
--- a/src/pulsecore/core-rtclock.h
+++ b/src/pulsecore/core-rtclock.h
@@ -43,8 +43,10 @@ void pa_rtclock_hrtimer_enable(void);
 
 struct timeval* pa_rtclock_from_wallclock(struct timeval *tv);
 
+#ifdef HAVE_CLOCK_GETTIME
 pa_usec_t pa_timespec_load(const struct timespec *ts);
 struct timespec* pa_timespec_store(struct timespec *ts, pa_usec_t v);
+#endif
 
 struct timeval* pa_timeval_rtstore(struct timeval *tv, pa_usec_t v, pa_bool_t rtclock);
 
diff --git a/src/pulsecore/core-util.c b/src/pulsecore/core-util.c
index 3ce5edb..4c4fbfe 100644
--- a/src/pulsecore/core-util.c
+++ b/src/pulsecore/core-util.c
@@ -41,8 +41,14 @@
 #include <sys/time.h>
 #include <dirent.h>
 #include <regex.h>
+
+#ifdef HAVE_LANGINFO_H
 #include <langinfo.h>
+#endif
+
+#ifdef HAVE_UNAME
 #include <sys/utsname.h>
+#endif
 
 #ifdef HAVE_STRTOF_L
 #include <locale.h>
@@ -216,7 +222,7 @@ int pa_make_secure_dir(const char* dir, mode_t m, uid_t uid, gid_t gid) {
     if (r < 0 && errno != EEXIST)
         return -1;
 
-#ifdef HAVE_FSTAT
+#if defined(HAVE_FSTAT) && !defined(OS_IS_WIN32)
     if ((fd = open(dir,
 #ifdef O_CLOEXEC
                    O_CLOEXEC|
@@ -254,7 +260,6 @@ int pa_make_secure_dir(const char* dir, mode_t m, uid_t uid, gid_t gid) {
 #endif
 
     pa_assert_se(pa_close(fd) >= 0);
-
 #endif
 
 #ifdef HAVE_LSTAT
@@ -610,6 +615,7 @@ char *pa_strlcpy(char *b, const char *s, size_t l) {
 }
 
 static int set_scheduler(int rtprio) {
+#ifdef HAVE_SCHED_H
     struct sched_param sp;
 #ifdef HAVE_DBUS
     int r;
@@ -633,6 +639,7 @@ static int set_scheduler(int rtprio) {
         pa_log_debug("SCHED_RR worked.");
         return 0;
     }
+#endif  /* HAVE_SCHED_H */
 
 #ifdef HAVE_DBUS
     /* Try to talk to RealtimeKit */
@@ -702,10 +709,12 @@ static int set_nice(int nice_level) {
     dbus_error_init(&error);
 #endif
 
+#ifdef HAVE_SYS_RESOURCE_H
     if (setpriority(PRIO_PROCESS, 0, nice_level) >= 0) {
         pa_log_debug("setpriority() worked.");
         return 0;
     }
+#endif
 
 #ifdef HAVE_DBUS
     /* Try to talk to RealtimeKit */
@@ -826,6 +835,7 @@ int pa_parse_boolean(const char *v) {
     else if (!strcmp(v, "0") || v[0] == 'n' || v[0] == 'N' || v[0] == 'f' || v[0] == 'F' || !strcasecmp(v, "off"))
         return 0;
 
+#ifdef HAVE_LANGINFO_H
     /* And then we check language dependant */
     if ((expr = nl_langinfo(YESEXPR)))
         if (expr[0])
@@ -836,6 +846,7 @@ int pa_parse_boolean(const char *v) {
         if (expr[0])
             if (pa_match(expr, v) > 0)
                 return 0;
+#endif
 
     errno = EINVAL;
     return -1;
@@ -1338,11 +1349,13 @@ static char *get_pulse_home(void) {
         goto finish;
     }
 
+#ifdef HAVE_GETUID
     if (st.st_uid != getuid()) {
         pa_log_error("Home directory %s not ours.", h);
         errno = EACCES;
         goto finish;
     }
+#endif
 
     ret = pa_sprintf_malloc("%s" PA_PATH_SEP ".pulse", h);
 
@@ -1440,7 +1453,11 @@ static char* make_random_dir(mode_t m) {
             fn[i] = table[rand() % (sizeof(table)-1)];
 
         u = umask((~m) & 0777);
+#ifndef OS_IS_WIN32
         r = mkdir(fn, m);
+#else
+        r = mkdir(fn);
+#endif
 
         saved_errno = errno;
         umask(u);
@@ -1463,6 +1480,7 @@ static int make_random_dir_and_link(mode_t m, const char *k) {
     if (!(p = make_random_dir(m)))
         return -1;
 
+#ifdef HAVE_SYMLINK
     if (symlink(p, k) < 0) {
         int saved_errno = errno;
 
@@ -1475,6 +1493,7 @@ static int make_random_dir_and_link(mode_t m, const char *k) {
         errno = saved_errno;
         return -1;
     }
+#endif
 
     pa_xfree(p);
     return 0;
@@ -1559,6 +1578,7 @@ char *pa_get_runtime_dir(void) {
         /* Hmm, so this symlink is still around, make sure nobody fools
          * us */
 
+#ifdef HAVE_LSTAT
         if (lstat(p, &st) < 0) {
 
             if (errno != ENOENT) {
@@ -1578,6 +1598,7 @@ char *pa_get_runtime_dir(void) {
 
             pa_log_info("Hmm, runtime path exists, but points to an invalid directory. Changing runtime directory.");
         }
+#endif
 
         pa_xfree(p);
         p = NULL;
@@ -2217,6 +2238,7 @@ void pa_close_pipe(int fds[2]) {
 }
 
 char *pa_readlink(const char *p) {
+#ifdef HAVE_READLINK
     size_t l = 100;
 
     for (;;) {
@@ -2238,6 +2260,9 @@ char *pa_readlink(const char *p) {
         pa_xfree(c);
         l *= 2;
     }
+#else
+    return NULL;
+#endif
 }
 
 int pa_close_all(int except_fd, ...) {
@@ -2276,6 +2301,7 @@ int pa_close_all(int except_fd, ...) {
 }
 
 int pa_close_allv(const int except_fds[]) {
+#ifndef OS_IS_WIN32
     struct rlimit rl;
     int maxfd, fd;
 
@@ -2365,6 +2391,7 @@ int pa_close_allv(const int except_fds[]) {
         if (pa_close(fd) < 0 && errno != EBADF)
             return -1;
     }
+#endif  /* !OS_IS_WIN32 */
 
     return 0;
 }
@@ -2405,6 +2432,7 @@ int pa_unblock_sigs(int except, ...) {
 }
 
 int pa_unblock_sigsv(const int except[]) {
+#ifndef OS_IS_WIN32
     int i;
     sigset_t ss;
 
@@ -2416,6 +2444,9 @@ int pa_unblock_sigsv(const int except[]) {
             return -1;
 
     return sigprocmask(SIG_SETMASK, &ss, NULL);
+#else
+    return 0;
+#endif
 }
 
 int pa_reset_sigs(int except, ...) {
@@ -2454,6 +2485,7 @@ int pa_reset_sigs(int except, ...) {
 }
 
 int pa_reset_sigsv(const int except[]) {
+#ifndef OS_IS_WIN32
     int sig;
 
     for (sig = 1; sig < NSIG; sig++) {
@@ -2490,6 +2522,7 @@ int pa_reset_sigsv(const int except[]) {
                     return -1;
         }
     }
+#endif
 
     return 0;
 }
@@ -2624,9 +2657,13 @@ char *pa_machine_id(void) {
     if ((h = pa_get_host_name_malloc()))
         return h;
 
+#ifndef OS_IS_WIN32
     /* If no hostname was set we use the POSIX hostid. It's usually
      * the IPv4 address.  Might not be that stable. */
     return pa_sprintf_malloc("%08lx", (unsigned long) gethostid);
+#else
+    return NULL;
+#endif
 }
 
 char *pa_session_id(void) {
diff --git a/src/pulsecore/inet_ntop.h b/src/pulsecore/inet_ntop.h
index 7e1b203..77ace6a 100644
--- a/src/pulsecore/inet_ntop.h
+++ b/src/pulsecore/inet_ntop.h
@@ -1,8 +1,12 @@
 #ifndef fooinet_ntophfoo
 #define fooinet_ntophfoo
 
+#ifndef HAVE_INET_NTOP
+
 #include <pulsecore/socket.h>
 
 const char *inet_ntop(int af, const void *src, char *dst, socklen_t cnt);
 
 #endif
+
+#endif
diff --git a/src/pulsecore/inet_pton.h b/src/pulsecore/inet_pton.h
index 9d9c476..913efc4 100644
--- a/src/pulsecore/inet_pton.h
+++ b/src/pulsecore/inet_pton.h
@@ -1,8 +1,12 @@
 #ifndef fooinet_ptonhfoo
 #define fooinet_ptonhfoo
 
+#ifndef HAVE_INET_PTON
+
 #include <pulsecore/socket.h>
 
 int inet_pton(int af, const char *src, void *dst);
 
 #endif
+
+#endif
diff --git a/src/pulsecore/lock-autospawn.c b/src/pulsecore/lock-autospawn.c
index b515057..1a082db 100644
--- a/src/pulsecore/lock-autospawn.c
+++ b/src/pulsecore/lock-autospawn.c
@@ -27,7 +27,10 @@
 #include <errno.h>
 #include <string.h>
 #include <signal.h>
+
+#ifdef HAVE_PTHREAD
 #include <pthread.h>
+#endif
 
 #include <pulse/i18n.h>
 #include <pulse/xmalloc.h>
@@ -206,11 +209,14 @@ static void empty_pipe(void) {
 static void thread_func(void *u) {
     int fd;
     char *lf;
+
+#ifdef HAVE_PTHREAD
     sigset_t fullset;
 
     /* No signals in this thread please */
     sigfillset(&fullset);
     pthread_sigmask(SIG_BLOCK, &fullset, NULL);
+#endif
 
     if (!(lf = pa_runtime_path(AUTOSPAWN_LOCK))) {
         pa_log_warn(_("Cannot access autospawn lock."));
diff --git a/src/pulsecore/memtrap.c b/src/pulsecore/memtrap.c
index 4fc1821..b56d806 100644
--- a/src/pulsecore/memtrap.c
+++ b/src/pulsecore/memtrap.c
@@ -24,7 +24,10 @@
 #endif
 
 #include <signal.h>
+
+#ifdef HAVE_SYS_MMAN_H
 #include <sys/mman.h>
+#endif
 
 /* This is deprecated on glibc but is still used by FreeBSD */
 #if !defined(MAP_ANONYMOUS) && defined(MAP_ANON)
@@ -68,6 +71,7 @@ static void sigsafe_error(const char *s) {
     (void) write(STDERR_FILENO, s, strlen(s));
 }
 
+#ifdef HAVE_SIGACTION
 static void signal_handler(int sig, siginfo_t* si, void *data) {
     unsigned j;
     pa_memtrap *m;
@@ -102,6 +106,7 @@ fail:
     sigsafe_error("Failed to handle SIGBUS.\n");
     abort();
 }
+#endif
 
 static void memtrap_link(pa_memtrap *m, unsigned j) {
     pa_assert(m);
@@ -221,6 +226,7 @@ unlock:
 }
 
 void pa_memtrap_install(void) {
+#ifdef HAVE_SIGACTION
     struct sigaction sa;
 
     allocate_aupdate();
@@ -230,4 +236,5 @@ void pa_memtrap_install(void) {
     sa.sa_flags = SA_RESTART|SA_SIGINFO;
 
     pa_assert_se(sigaction(SIGBUS, &sa, NULL) == 0);
+#endif
 }
diff --git a/src/pulsecore/start-child.c b/src/pulsecore/start-child.c
index 4a70aea..dabcfa5 100644
--- a/src/pulsecore/start-child.c
+++ b/src/pulsecore/start-child.c
@@ -47,6 +47,7 @@ int pa_start_child_for_read(const char *name, const char *argv1, pid_t *pid) {
     pid_t child;
     int pipe_fds[2] = { -1, -1 };
 
+#ifdef HAVE_FORK
     if (pipe(pipe_fds) < 0) {
         pa_log("pipe() failed: %s", pa_cstrerror(errno));
         goto fail;
@@ -104,6 +105,7 @@ int pa_start_child_for_read(const char *name, const char *argv1, pid_t *pid) {
         execl(name, name, argv1, NULL);
         _exit(1);
     }
+#endif
 
 fail:
     pa_close_pipe(pipe_fds);
diff --git a/src/pulsecore/thread.h b/src/pulsecore/thread.h
index aea0276..79b61ae 100644
--- a/src/pulsecore/thread.h
+++ b/src/pulsecore/thread.h
@@ -92,7 +92,7 @@ void *pa_tls_set(pa_tls *t, void *userdata);
     }                                                                   \
     struct __stupid_useless_struct_to_allow_trailing_semicolon
 
-#ifdef SUPPORT_TLS___THREAD
+#if defined(SUPPORT_TLS___THREAD) && !defined(OS_IS_WIN32)
 /* An optimized version of the above that requires no dynamic
  * allocation if the compiler supports __thread */
 #define PA_STATIC_TLS_DECLARE_NO_FREE(name)                             \
diff --git a/src/tests/rtstutter.c b/src/tests/rtstutter.c
index c93fee9..21f33bf 100644
--- a/src/tests/rtstutter.c
+++ b/src/tests/rtstutter.c
@@ -29,7 +29,10 @@
 #include <sched.h>
 #include <inttypes.h>
 #include <string.h>
+
+#ifdef HAVE_PTHREAD
 #include <pthread.h>
+#endif
 
 #include <pulse/timeval.h>
 #include <pulse/gccmacro.h>
@@ -43,9 +46,6 @@ static int msec_lower, msec_upper;
 static void* work(void *p) PA_GCC_NORETURN;
 
 static void* work(void *p) {
-#ifdef HAVE_PTHREAD_SETAFFINITY_NP
-    cpu_set_t mask;
-#endif
     struct sched_param param;
 
     pa_log_notice("CPU%i: Created thread.", PA_PTR_TO_UINT(p));
@@ -55,9 +55,13 @@ static void* work(void *p) {
     pa_assert_se(pthread_setschedparam(pthread_self(), SCHED_FIFO, &param) == 0);
 
 #ifdef HAVE_PTHREAD_SETAFFINITY_NP
+{
+    cpu_set_t mask;
+
     CPU_ZERO(&mask);
     CPU_SET((size_t) PA_PTR_TO_UINT(p), &mask);
     pa_assert_se(pthread_setaffinity_np(pthread_self(), sizeof(mask), &mask) == 0);
+}
 #endif
 
     for (;;) {

commit a951c779c6fe0705f75c1dfbe090deb78485b4e8
Author: Maarten Bosmans <mkbosmans at gmail.com>
Date:   Tue Jan 4 16:48:06 2011 +0100

    Use PCRE if POSIX regex.h is not available

diff --git a/configure.ac b/configure.ac
index 42d9c3b..a2657c0 100644
--- a/configure.ac
+++ b/configure.ac
@@ -362,10 +362,7 @@ AC_CHECK_HEADERS([netinet/ip.h], [], [],
                   # include <netinet/in_systm.h>
                   #endif
                  ])
-AC_CHECK_HEADERS([regex.h], [HAVE_REGEX=1], [HAVE_REGEX=0])
 AC_CHECK_HEADERS([sys/un.h], [HAVE_AF_UNIX=1], [HAVE_AF_UNIX=0])
-
-AM_CONDITIONAL(HAVE_REGEX, test "x$HAVE_REGEX" = "x1")
 AM_CONDITIONAL(HAVE_AF_UNIX, test "x$HAVE_AF_UNIX" = "x1")
 
 # Linux
@@ -391,6 +388,7 @@ AC_CHECK_HEADERS_ONCE([sys/syscall.h])
 AC_CHECK_HEADERS_ONCE([sys/eventfd.h])
 AC_CHECK_HEADERS_ONCE([execinfo.h])
 AC_CHECK_HEADERS_ONCE([langinfo.h])
+AC_CHECK_HEADERS_ONCE([regex.h pcreposix.h])
 
 #### Typdefs, structures, etc. ####
 
@@ -459,6 +457,8 @@ fi
 AC_SUBST(HAVE_BONJOUR)
 AM_CONDITIONAL([HAVE_BONJOUR], [test "x$HAVE_BONJOUR" = x1])
 
+AC_SEARCH_LIBS([regexec], [pcreposix])
+
 #### Check for functions ####
 
 # ISO
@@ -518,6 +518,9 @@ AS_IF([test "$pulseaudio_cv_PTHREAD_PRIO_INHERIT" = "yes"], [
 
 AC_DEFINE_UNQUOTED(PA_CFLAGS,"$CFLAGS", [The CFLAGS used during compilation])
 
+AC_CHECK_FUNCS([regexec], [HAVE_REGEX=1], [HAVE_REGEX=0])
+AM_CONDITIONAL(HAVE_REGEX, [test "x$HAVE_REGEX" = "x1"])
+
 #### Large File-Support (LFS) ####
 
 AC_SYS_LARGEFILE
diff --git a/src/modules/module-match.c b/src/modules/module-match.c
index d83c86c..f9f36fd 100644
--- a/src/modules/module-match.c
+++ b/src/modules/module-match.c
@@ -27,10 +27,15 @@
 #include <string.h>
 #include <errno.h>
 #include <sys/types.h>
-#include <regex.h>
 #include <stdio.h>
 #include <stdlib.h>
 
+#if defined(HAVE_REGEX_H)
+#include <regex.h>
+#elif defined(HAVE_PCREPOSIX_H)
+#include <pcreposix.h>
+#endif
+
 #include <pulse/xmalloc.h>
 
 #include <pulsecore/core-error.h>
diff --git a/src/pulsecore/core-util.c b/src/pulsecore/core-util.c
index 4c4fbfe..ba9e820 100644
--- a/src/pulsecore/core-util.c
+++ b/src/pulsecore/core-util.c
@@ -40,7 +40,6 @@
 #include <sys/stat.h>
 #include <sys/time.h>
 #include <dirent.h>
-#include <regex.h>
 
 #ifdef HAVE_LANGINFO_H
 #include <langinfo.h>
@@ -50,6 +49,12 @@
 #include <sys/utsname.h>
 #endif
 
+#if defined(HAVE_REGEX_H)
+#include <regex.h>
+#elif defined(HAVE_PCREPOSIX_H)
+#include <pcreposix.h>
+#endif
+
 #ifdef HAVE_STRTOF_L
 #include <locale.h>
 #endif

commit 2de2c735c937c6724c14656acf01ce90f122b903
Author: Maarten Bosmans <mkbosmans at gmail.com>
Date:   Thu Jan 6 01:35:27 2011 +0100

    Fix dependencies and include necessary headers

diff --git a/src/Makefile.am b/src/Makefile.am
index baba9c5..89377a6 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -562,6 +562,14 @@ libpulsecommon_ at PA_MAJORMINOR@_la_SOURCES = \
 		pulse/client-conf.c pulse/client-conf.h \
 		pulse/i18n.c pulse/i18n.h \
 		pulse/fork-detect.c pulse/fork-detect.h \
+		pulse/xmalloc.c pulse/xmalloc.h \
+		pulse/proplist.c pulse/proplist.h \
+		pulse/utf8.c pulse/utf8.h \
+		pulse/channelmap.c pulse/channelmap.h \
+		pulse/sample.c pulse/sample.h \
+		pulse/util.c pulse/util.h \
+		pulse/timeval.c pulse/timeval.h \
+		pulse/rtclock.c pulse/rtclock.h \
 		pulsecore/atomic.h \
 		pulsecore/authkey.c pulsecore/authkey.h \
 		pulsecore/conf-parser.c pulsecore/conf-parser.h \
diff --git a/src/pulsecore/core-util.c b/src/pulsecore/core-util.c
index ba9e820..49cd01a 100644
--- a/src/pulsecore/core-util.c
+++ b/src/pulsecore/core-util.c
@@ -128,6 +128,7 @@
 #include <pulsecore/usergroup.h>
 #include <pulsecore/strlist.h>
 #include <pulsecore/cpu-x86.h>
+#include <pulsecore/pipe.h>
 
 #include "core-util.h"
 
diff --git a/src/pulsecore/inet_ntop.c b/src/pulsecore/inet_ntop.c
index e283a67..64c28ed 100644
--- a/src/pulsecore/inet_ntop.c
+++ b/src/pulsecore/inet_ntop.c
@@ -28,6 +28,7 @@
 
 #ifndef HAVE_INET_NTOP
 
+#include <pulsecore/core-util.h>
 #include <pulsecore/socket.h>
 
 #include "inet_ntop.h"
diff --git a/src/pulsecore/parseaddr.c b/src/pulsecore/parseaddr.c
index 7f6cd90..99fdcbf 100644
--- a/src/pulsecore/parseaddr.c
+++ b/src/pulsecore/parseaddr.c
@@ -35,6 +35,7 @@
 
 #include <pulsecore/core-util.h>
 #include <pulsecore/macro.h>
+#include <pulsecore/inet_pton.h>
 
 #include "parseaddr.h"
 
diff --git a/src/pulsecore/pipe.c b/src/pulsecore/pipe.c
index db8e16f..f873ef6 100644
--- a/src/pulsecore/pipe.c
+++ b/src/pulsecore/pipe.c
@@ -30,6 +30,7 @@
 #include <sys/types.h>
 
 #include <pulsecore/socket.h>
+#include <pulsecore/core-util.h>
 
 #include "pipe.h"
 
diff --git a/src/pulsecore/proplist-util.c b/src/pulsecore/proplist-util.c
index 23864bc..642c498 100644
--- a/src/pulsecore/proplist-util.c
+++ b/src/pulsecore/proplist-util.c
@@ -25,7 +25,7 @@
 
 #include <string.h>
 #include <locale.h>
-#include <dlfcn.h>
+#include <libintl.h>
 
 #ifdef __APPLE__
 #include <crt_externs.h>
diff --git a/src/pulsecore/start-child.c b/src/pulsecore/start-child.c
index dabcfa5..fd1baeb 100644
--- a/src/pulsecore/start-child.c
+++ b/src/pulsecore/start-child.c
@@ -40,6 +40,7 @@
 
 #include <pulsecore/core-util.h>
 #include <pulsecore/core-error.h>
+#include <pulsecore/pipe.h>
 
 #include "start-child.h"
 
diff --git a/src/tests/ipacl-test.c b/src/tests/ipacl-test.c
index 88bd6c6..5866346 100644
--- a/src/tests/ipacl-test.c
+++ b/src/tests/ipacl-test.c
@@ -24,6 +24,7 @@
 #include <pulsecore/socket.h>
 #include <pulsecore/macro.h>
 #include <pulsecore/ipacl.h>
+#include <pulsecore/inet_pton.h>
 
 int main(int argc, char *argv[]) {
     struct sockaddr_in sa;

commit 5815ec6f3ec7d138e9dd2d28d442ad1059ecb020
Author: Maarten Bosmans <mkbosmans at gmail.com>
Date:   Thu Jan 6 01:39:29 2011 +0100

    Add AM_LDFLAGS more consistently to all commands

diff --git a/src/Makefile.am b/src/Makefile.am
index 89377a6..55e6322 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -74,12 +74,12 @@ BINLDFLAGS = -static
 endif
 
 if OS_IS_WIN32
-AM_LDFLAGS+=-Wl,--export-all-symbols
+AM_LDFLAGS+=-Wl,--export-all-symbols,--enable-auto-import -no-undefined
 WINSOCK_LIBS=-lwsock32 -lws2_32 -lwininet
 endif
 
 FOREIGN_CFLAGS = -w
-MODULE_LDFLAGS = -module -disable-static -avoid-version $(LDFLAGS_NOUNDEFINED)
+MODULE_LDFLAGS = $(AM_LDFLAGS) -module -disable-static -avoid-version $(LDFLAGS_NOUNDEFINED)
 MODULE_LIBADD = $(AM_LIBADD) libpulsecore- at PA_MAJORMINOR@.la libpulsecommon- at PA_MAJORMINOR@.la libpulse.la
 
 ###################################
@@ -866,7 +866,7 @@ libpulsecore_ at PA_MAJORMINOR@_la_SOURCES = \
 		pulsecore/database.h
 
 libpulsecore_ at PA_MAJORMINOR@_la_CFLAGS = $(AM_CFLAGS) $(LIBSAMPLERATE_CFLAGS) $(LIBSPEEX_CFLAGS) $(LIBSNDFILE_CFLAGS) $(WINSOCK_CFLAGS)
-libpulsecore_ at PA_MAJORMINOR@_la_LDFLAGS = -avoid-version
+libpulsecore_ at PA_MAJORMINOR@_la_LDFLAGS = $(AM_LDFLAGS) -avoid-version
 libpulsecore_ at PA_MAJORMINOR@_la_LIBADD = $(AM_LIBADD) $(LIBLTDL) $(LIBSAMPLERATE_LIBS) $(LIBSPEEX_LIBS) $(LIBSNDFILE_LIBS) $(WINSOCK_LIBS) $(LTLIBICONV) libpulsecommon- at PA_MAJORMINOR@.la libpulse.la libpulsecore-foreign.la
 
 if HAVE_X11
@@ -936,27 +936,27 @@ modlibexec_LTLIBRARIES += \
 endif
 
 libprotocol_simple_la_SOURCES = pulsecore/protocol-simple.c pulsecore/protocol-simple.h
-libprotocol_simple_la_LDFLAGS = -avoid-version
+libprotocol_simple_la_LDFLAGS = $(AM_LDFLAGS) -avoid-version
 libprotocol_simple_la_LIBADD = $(AM_LIBADD) libpulsecore- at PA_MAJORMINOR@.la libpulsecommon- at PA_MAJORMINOR@.la libpulse.la
 
 libcli_la_SOURCES = pulsecore/cli.c pulsecore/cli.h
-libcli_la_LDFLAGS = -avoid-version
+libcli_la_LDFLAGS = $(AM_LDFLAGS) -avoid-version
 libcli_la_LIBADD = $(AM_LIBADD) libpulsecore- at PA_MAJORMINOR@.la libpulsecommon- at PA_MAJORMINOR@.la libpulse.la
 
 libprotocol_cli_la_SOURCES = pulsecore/protocol-cli.c pulsecore/protocol-cli.h
-libprotocol_cli_la_LDFLAGS = -avoid-version
+libprotocol_cli_la_LDFLAGS = $(AM_LDFLAGS) -avoid-version
 libprotocol_cli_la_LIBADD = $(AM_LIBADD) libpulsecore- at PA_MAJORMINOR@.la libpulsecommon- at PA_MAJORMINOR@.la libpulse.la libcli.la
 
 libprotocol_http_la_SOURCES = pulsecore/protocol-http.c pulsecore/protocol-http.h pulsecore/mime-type.c pulsecore/mime-type.h
-libprotocol_http_la_LDFLAGS = -avoid-version
+libprotocol_http_la_LDFLAGS = $(AM_LDFLAGS) -avoid-version
 libprotocol_http_la_LIBADD = $(AM_LIBADD) libpulsecore- at PA_MAJORMINOR@.la libpulsecommon- at PA_MAJORMINOR@.la libpulse.la
 
 libprotocol_native_la_SOURCES = pulsecore/protocol-native.c pulsecore/protocol-native.h pulsecore/native-common.h
-libprotocol_native_la_LDFLAGS = -avoid-version
+libprotocol_native_la_LDFLAGS = $(AM_LDFLAGS) -avoid-version
 libprotocol_native_la_LIBADD = $(AM_LIBADD) libpulsecore- at PA_MAJORMINOR@.la libpulsecommon- at PA_MAJORMINOR@.la libpulse.la
 
 libprotocol_esound_la_SOURCES = pulsecore/protocol-esound.c pulsecore/protocol-esound.h pulsecore/esound.h
-libprotocol_esound_la_LDFLAGS = -avoid-version
+libprotocol_esound_la_LDFLAGS = $(AM_LDFLAGS) -avoid-version
 libprotocol_esound_la_LIBADD = $(AM_LIBADD) libpulsecore- at PA_MAJORMINOR@.la libpulsecommon- at PA_MAJORMINOR@.la libpulse.la
 
 librtp_la_SOURCES = \
@@ -965,19 +965,19 @@ librtp_la_SOURCES = \
 		modules/rtp/sap.c modules/rtp/sap.h \
 		modules/rtp/rtsp_client.c modules/rtp/rtsp_client.h \
 		modules/rtp/headerlist.c modules/rtp/headerlist.h
-librtp_la_LDFLAGS = -avoid-version
+librtp_la_LDFLAGS = $(AM_LDFLAGS) -avoid-version
 librtp_la_LIBADD = $(AM_LIBADD) libpulsecore- at PA_MAJORMINOR@.la libpulsecommon- at PA_MAJORMINOR@.la libpulse.la
 
 libraop_la_SOURCES = \
         modules/raop/raop_client.c modules/raop/raop_client.h \
         modules/raop/base64.c modules/raop/base64.h
 libraop_la_CFLAGS = $(AM_CFLAGS) $(OPENSSL_CFLAGS) -I$(top_srcdir)/src/modules/rtp
-libraop_la_LDFLAGS = -avoid-version
+libraop_la_LDFLAGS = $(AM_LDFLAGS) -avoid-version
 libraop_la_LIBADD = $(AM_LIBADD) $(OPENSSL_LIBS) libpulsecore- at PA_MAJORMINOR@.la librtp.la libpulsecommon- at PA_MAJORMINOR@.la libpulse.la
 
 # Avahi
 libavahi_wrap_la_SOURCES = pulsecore/avahi-wrap.c pulsecore/avahi-wrap.h
-libavahi_wrap_la_LDFLAGS = -avoid-version
+libavahi_wrap_la_LDFLAGS = $(AM_LDFLAGS) -avoid-version
 libavahi_wrap_la_CFLAGS = $(AM_CFLAGS) $(AVAHI_CFLAGS)
 libavahi_wrap_la_LIBADD = $(AM_LIBADD) $(AVAHI_CFLAGS) libpulsecore- at PA_MAJORMINOR@.la libpulsecommon- at PA_MAJORMINOR@.la libpulse.la
 
@@ -1416,7 +1416,7 @@ module_esound_compat_spawnpid_la_LDFLAGS = $(MODULE_LDFLAGS)
 module_esound_compat_spawnpid_la_LIBADD = $(MODULE_LIBADD)
 
 module_esound_sink_la_SOURCES = modules/module-esound-sink.c
-module_esound_sink_la_LDFLAGS = $(MODULE_LDFLAGS)
+module_esound_sink_la_LDFLAGS = $(MODULE_LDFLAGS) $(WINSOCK_LIBS)
 module_esound_sink_la_LIBADD = $(MODULE_LIBADD)
 
 # Pipes
@@ -1440,7 +1440,7 @@ module_null_sink_la_LDFLAGS = $(MODULE_LDFLAGS)
 module_null_sink_la_LIBADD = $(MODULE_LIBADD)
 
 module_sine_source_la_SOURCES = modules/module-sine-source.c
-module_sine_source_la_LDFLAGS = -module -avoid-version
+module_sine_source_la_LDFLAGS = $(MODULE_LDFLAGS)
 module_sine_source_la_LIBADD = $(MODULE_LIBADD)
 
 # Couplings

commit 7b90e3b942b43521e4ed6b9f07b14ee3ae156cf3
Author: Maarten Bosmans <mkbosmans at gmail.com>
Date:   Tue Jan 4 17:12:09 2011 +0100

    Repair some typos

diff --git a/src/pulsecore/core-util.c b/src/pulsecore/core-util.c
index 49cd01a..f2a0946 100644
--- a/src/pulsecore/core-util.c
+++ b/src/pulsecore/core-util.c
@@ -1166,23 +1166,23 @@ int pa_check_in_group(gid_t g) {
 #else /* HAVE_GRP_H */
 
 int pa_own_uid_in_group(const char *name, gid_t *gid) {
-    errno = ENOSUP;
+    errno = ENOTSUP;
     return -1;
 
 }
 
 int pa_uid_in_group(uid_t uid, const char *name) {
-    errno = ENOSUP;
+    errno = ENOTSUP;
     return -1;
 }
 
 gid_t pa_get_gid_of_group(const char *name) {
-    errno = ENOSUP;
+    errno = ENOTSUP;
     return (gid_t) -1;
 }
 
 int pa_check_in_group(gid_t g) {
-    errno = ENOSUP;
+    errno = ENOTSUP;
     return -1;
 }
 
diff --git a/src/pulsecore/socket-client.c b/src/pulsecore/socket-client.c
index 31acfd2..ae7abc9 100644
--- a/src/pulsecore/socket-client.c
+++ b/src/pulsecore/socket-client.c
@@ -522,7 +522,7 @@ pa_socket_client* pa_socket_client_new_string(pa_mainloop_api *m, pa_bool_t use_
                 if (!host)
                     goto finish;
 
-                pa_zero(sa);
+                pa_zero(s);
                 s.sin_family = AF_INET;
                 memcpy(&s.sin_addr, host->h_addr, sizeof(struct in_addr));
                 s.sin_port = htons(a.port);
diff --git a/src/pulsecore/thread-mq.h b/src/pulsecore/thread-mq.h
index 96839d2..a1f4b3f 100644
--- a/src/pulsecore/thread-mq.h
+++ b/src/pulsecore/thread-mq.h
@@ -27,7 +27,7 @@
 #include <pulsecore/rtpoll.h>
 
 /* Two way communication between a thread and a mainloop. Before the
- * thread is started a pa_pthread_mq should be initialized and than
+ * thread is started a pa_thread_mq should be initialized and than
  * attached to the thread using pa_thread_mq_install(). */
 
 typedef struct pa_thread_mq {

commit d6d43367053bbc0d99acd7a21a21e15a5aaae659
Author: Maarten Bosmans <mkbosmans at gmail.com>
Date:   Thu Jan 6 02:10:45 2011 +0100

    Implement some functions for win32
    
    And disable building binaries for win32 that make no sense there

diff --git a/src/Makefile.am b/src/Makefile.am
index 55e6322..c17c225 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -177,8 +177,11 @@ endif
 
 bin_PROGRAMS += \
 		pacat \
-		pactl \
-		pasuspender
+		pactl
+
+if !OS_IS_WIN32
+bin_PROGRAMS += pasuspender
+endif
 
 if HAVE_AF_UNIX
 bin_PROGRAMS += pacmd
@@ -256,9 +259,7 @@ TESTS = \
 		envelope-test \
 		proplist-test \
 		lock-autospawn-test \
-		prioq-test \
-		sigbus-test \
-		usergroup-test
+		prioq-test
 
 TESTS_BINARIES = \
 		mainloop-test \
@@ -295,9 +296,16 @@ TESTS_BINARIES = \
 		rtstutter \
 		stripnul \
 		lock-autospawn-test \
-		prioq-test \
+		prioq-test
+
+if !OS_IS_WIN32
+TESTS += \
+		sigbus-test \
+		usergroup-test
+TESTS_BINARIES += \
 		sigbus-test \
 		usergroup-test
+endif
 
 if HAVE_SIGXCPU
 #TESTS += \
@@ -326,9 +334,11 @@ TESTS_BINARIES += \
 endif
 
 if !OS_IS_DARWIN
+if !OS_IS_WIN32
 TESTS_BINARIES += \
 		once-test
 endif
+endif
 
 if BUILD_TESTS_DEFAULT
 noinst_PROGRAMS = $(TESTS_BINARIES)
diff --git a/src/daemon/main.c b/src/daemon/main.c
index 5aeb9bc..243e7c0 100644
--- a/src/daemon/main.c
+++ b/src/daemon/main.c
@@ -1078,7 +1078,7 @@ finish:
     }
 
 #ifdef OS_IS_WIN32
-    if (win32_timer)
+    if (mainloop && win32_timer)
         pa_mainloop_get_api(mainloop)->time_free(win32_timer);
 #endif
 
diff --git a/src/pulsecore/authkey.c b/src/pulsecore/authkey.c
index d671e36..684bc01 100644
--- a/src/pulsecore/authkey.c
+++ b/src/pulsecore/authkey.c
@@ -151,7 +151,7 @@ static char *normalize_path(const char *fn) {
 #ifndef OS_IS_WIN32
     if (fn[0] != '/') {
 #else
-    if (strlen(fn) < 3 || !isalpha(fn[0]) || fn[1] != ':' || fn[2] != '\\') {
+    if (strlen(fn) < 3 || !IsCharAlpha(fn[0]) || fn[1] != ':' || fn[2] != '\\') {
 #endif
         char *homedir, *s;
 
diff --git a/src/pulsecore/core-util.c b/src/pulsecore/core-util.c
index f2a0946..04a2341 100644
--- a/src/pulsecore/core-util.c
+++ b/src/pulsecore/core-util.c
@@ -91,6 +91,10 @@
 #include <windows.h>
 #endif
 
+#ifndef ENOTSUP
+#define ENOTSUP   135
+#endif
+
 #ifdef HAVE_PWD_H
 #include <pwd.h>
 #endif
@@ -147,20 +151,18 @@ static pa_strlist *recorded_env = NULL;
 #define PULSE_ROOTENV "PULSE_ROOT"
 
 int pa_set_root(HANDLE handle) {
-    char library_path[MAX_PATH + sizeof(PULSE_ROOTENV) + 1], *sep;
-
-    strcpy(library_path, PULSE_ROOTENV "=");
+    char library_path[MAX_PATH], *sep;
 
     /* FIXME: Needs to set errno */
 
-    if (!GetModuleFileName(handle, library_path + sizeof(PULSE_ROOTENV), MAX_PATH))
+    if (!GetModuleFileName(handle, library_path, MAX_PATH))
         return 0;
 
     sep = strrchr(library_path, PA_PATH_SEP_CHAR);
     if (sep)
         *sep = '\0';
 
-    if (_putenv(library_path) < 0)
+    if (!SetEnvironmentVariable(PULSE_ROOTENV, library_path))
         return 0;
 
     return 1;
@@ -696,14 +698,21 @@ int pa_make_realtime(int rtprio) {
             pa_log_info("Successfully enabled SCHED_RR scheduling for thread, with priority %i, which is lower than the requested %i.", p, rtprio);
             return 0;
         }
+#elif defined(OS_IS_WIN32)
+    /* Windows only allows realtime scheduling to be set on a per process basis.
+     * Therefore, instead of making the thread realtime, just give it the highest non-realtime priority. */
+    if(SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_TIME_CRITICAL)) {
+        pa_log_info("Successfully enabled THREAD_PRIORITY_TIME_CRITICAL scheduling for thread.");
+        return 0;
+    }
 
-    pa_log_info("Failed to acquire real-time scheduling: %s", pa_cstrerror(errno));
-    return -1;
+    pa_log_warn("SetThreadPriority() failed: 0x%08X", GetLastError());
+    errno = EPERM;
 #else
-
     errno = ENOTSUP;
-    return -1;
 #endif
+    pa_log_info("Failed to acquire real-time scheduling: %s", pa_cstrerror(errno));
+    return -1;
 }
 
 static int set_nice(int nice_level) {
@@ -1499,6 +1508,9 @@ static int make_random_dir_and_link(mode_t m, const char *k) {
         errno = saved_errno;
         return -1;
     }
+#else
+    pa_xfree(p);
+    return -1;
 #endif
 
     pa_xfree(p);
@@ -1558,6 +1570,7 @@ char *pa_get_runtime_dir(void) {
                 goto fail;
             }
 
+#ifdef HAVE_SYMLINK
             /* Hmm, so the runtime directory didn't exist yet, so let's
              * create one in /tmp and symlink that to it */
 
@@ -1570,6 +1583,11 @@ char *pa_get_runtime_dir(void) {
 
                 goto fail;
             }
+#else
+            /* No symlink possible, so let's just create the runtime directly */
+            if (!mkdir(k))
+                goto fail;
+#endif
 
             return k;
         }
@@ -2539,7 +2557,11 @@ void pa_set_env(const char *key, const char *value) {
 
     /* This is not thread-safe */
 
+#ifdef OS_IS_WIN32
+    SetEnvironmentVariable(key, value);
+#else
     setenv(key, value, 1);
+#endif
 }
 
 void pa_set_env_and_record(const char *key, const char *value) {
@@ -2564,7 +2586,11 @@ void pa_unset_env_recorded(void) {
         if (!s)
             break;
 
+#ifdef OS_IS_WIN32
+        SetEnvironmentVariable(s, NULL);
+#else
         unsetenv(s);
+#endif
         pa_xfree(s);
     }
 }
@@ -2682,11 +2708,22 @@ char *pa_session_id(void) {
 }
 
 char *pa_uname_string(void) {
+#ifdef HAVE_UNAME
     struct utsname u;
 
     pa_assert_se(uname(&u) >= 0);
 
     return pa_sprintf_malloc("%s %s %s %s", u.sysname, u.machine, u.release, u.version);
+#endif
+#ifdef OS_IS_WIN32
+    OSVERSIONINFO i;
+
+    pa_zero(i);
+    i.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
+    pa_assert_se(GetVersionEx(&i));
+
+    return pa_sprintf_malloc("Windows %d.%d (%d) %s", i.dwMajorVersion, i.dwMinorVersion, i.dwBuildNumber, i.szCSDVersion);
+#endif
 }
 
 #ifdef HAVE_VALGRIND_MEMCHECK_H
@@ -2835,10 +2872,17 @@ char *pa_realpath(const char *path) {
         char *path_buf;
         path_buf = pa_xmalloc(PATH_MAX);
 
+#if defined(OS_IS_WIN32)
+        if (!(t = _fullpath(path_buf, path, _MAX_PATH))) {
+            pa_xfree(path_buf);
+            return NULL;
+        }
+#else
         if (!(t = realpath(path, path_buf))) {
             pa_xfree(path_buf);
             return NULL;
         }
+#endif
     }
 #else
 #error "It's not clear whether this system supports realpath(..., NULL) like GNU libc does. If it doesn't we need a private version of realpath() here."

commit 5699954d3360716ad693e0b88596e372afe74443
Author: Maarten Bosmans <mkbosmans at gmail.com>
Date:   Mon Jan 17 13:17:48 2011 +0100

    win32: flush stderr after log output

diff --git a/src/pulsecore/log.c b/src/pulsecore/log.c
index 7ba41ee..2c0e267 100644
--- a/src/pulsecore/log.c
+++ b/src/pulsecore/log.c
@@ -374,6 +374,9 @@ void pa_log_levelv_meta(
                     fprintf(stderr, "%s%c: %s%s%s%s%s%s\n", timestamp, level_to_char[level], location, prefix, t, grey, pa_strempty(bt), suffix);
                 else
                     fprintf(stderr, "%s%s%s%s%s%s%s\n", timestamp, location, prefix, t, grey, pa_strempty(bt), suffix);
+#ifdef OS_IS_WIN32
+                fflush(stderr);
+#endif
 
                 pa_xfree(local_t);
 

commit a39a83665f07a0819a31ee2d1ab60210a67c47a2
Author: Maarten Bosmans <mkbosmans at gmail.com>
Date:   Tue Jan 18 11:26:57 2011 +0100

    win32: Implement rtclock based on QueryPerformanceCounter
    
    Also remove some unnecessary <time.h> headers.

diff --git a/src/pulse/def.h b/src/pulse/def.h
index 4a8da13..ac4ae53 100644
--- a/src/pulse/def.h
+++ b/src/pulse/def.h
@@ -25,7 +25,6 @@
 
 #include <inttypes.h>
 #include <sys/time.h>
-#include <time.h>
 
 #include <pulse/cdecl.h>
 #include <pulse/sample.h>
diff --git a/src/pulse/mainloop-api.h b/src/pulse/mainloop-api.h
index aa0d5e7..0ce2219 100644
--- a/src/pulse/mainloop-api.h
+++ b/src/pulse/mainloop-api.h
@@ -24,7 +24,6 @@
 ***/
 
 #include <sys/time.h>
-#include <time.h>
 
 #include <pulse/cdecl.h>
 #include <pulse/sample.h>
diff --git a/src/pulse/rtclock.c b/src/pulse/rtclock.c
index 49ff6aa..baa0f3a 100644
--- a/src/pulse/rtclock.c
+++ b/src/pulse/rtclock.c
@@ -23,10 +23,10 @@
 #include <config.h>
 #endif
 
+#include <pulse/timeval.h>
 #include <pulsecore/core-rtclock.h>
 
 #include "rtclock.h"
-#include "timeval.h"
 
 pa_usec_t pa_rtclock_now(void) {
     struct timeval tv;
diff --git a/src/pulse/timeval.c b/src/pulse/timeval.c
index c4a0841..10ba322 100644
--- a/src/pulse/timeval.c
+++ b/src/pulse/timeval.c
@@ -37,29 +37,22 @@
 #include "timeval.h"
 
 struct timeval *pa_gettimeofday(struct timeval *tv) {
-#ifdef HAVE_GETTIMEOFDAY
     pa_assert(tv);
 
-    pa_assert_se(gettimeofday(tv, NULL) == 0);
-    return tv;
-#elif defined(OS_IS_WIN32)
+#if defined(OS_IS_WIN32)
     /*
      * Copied from implementation by Steven Edwards (LGPL).
      * Found on wine mailing list.
      */
-
 #if defined(_MSC_VER) || defined(__BORLANDC__)
 #define EPOCHFILETIME (116444736000000000i64)
 #else
 #define EPOCHFILETIME (116444736000000000LL)
 #endif
-
     FILETIME ft;
     LARGE_INTEGER li;
     int64_t t;
 
-    pa_assert(tv);
-
     GetSystemTimeAsFileTime(&ft);
     li.LowPart  = ft.dwLowDateTime;
     li.HighPart = ft.dwHighDateTime;
@@ -68,11 +61,13 @@ struct timeval *pa_gettimeofday(struct timeval *tv) {
     t /= 10;                /* In microseconds */
     tv->tv_sec  = (time_t) (t / PA_USEC_PER_SEC);
     tv->tv_usec = (suseconds_t) (t % PA_USEC_PER_SEC);
-
-    return tv;
+#elif defined(HAVE_GETTIMEOFDAY)
+    pa_assert_se(gettimeofday(tv, NULL) == 0);
 #else
 #error "Platform lacks gettimeofday() or equivalent function."
 #endif
+
+    return tv;
 }
 
 pa_usec_t pa_timeval_diff(const struct timeval *a, const struct timeval *b) {
diff --git a/src/pulsecore/authkey.c b/src/pulsecore/authkey.c
index 684bc01..92509d8 100644
--- a/src/pulsecore/authkey.c
+++ b/src/pulsecore/authkey.c
@@ -31,7 +31,6 @@
 #include <stdio.h>
 #include <inttypes.h>
 #include <stdlib.h>
-#include <time.h>
 #include <limits.h>
 #include <sys/stat.h>
 
diff --git a/src/pulsecore/core-rtclock.c b/src/pulsecore/core-rtclock.c
index a69b466..ac2c097 100644
--- a/src/pulsecore/core-rtclock.c
+++ b/src/pulsecore/core-rtclock.c
@@ -40,12 +40,20 @@
 #include <unistd.h>
 #endif
 
+#ifdef HAVE_WINDOWS_H
+#include <windows.h>
+#endif
+
 #include <pulse/timeval.h>
 #include <pulsecore/macro.h>
 #include <pulsecore/core-error.h>
 
 #include "core-rtclock.h"
 
+#ifdef OS_IS_WIN32
+static int64_t counter_freq = 0;
+#endif
+
 pa_usec_t pa_rtclock_age(const struct timeval *tv) {
     struct timeval now;
     pa_assert(tv);
@@ -88,6 +96,17 @@ struct timeval *pa_rtclock_get(struct timeval *tv) {
     tv->tv_usec = ts.tv_nsec / PA_NSEC_PER_USEC;
 
     return tv;
+#elif defined(OS_IS_WIN32)
+    if (counter_freq > 0) {
+        LARGE_INTEGER count;
+
+        pa_assert_se(QueryPerformanceCounter(&count));
+
+        tv->tv_sec = count.QuadPart / counter_freq;
+        tv->tv_usec = (count.QuadPart % counter_freq) * PA_USEC_PER_SEC / counter_freq;
+
+        return tv;
+    }
 #endif /* HAVE_CLOCK_GETTIME */
 
     return pa_gettimeofday(tv);
@@ -118,6 +137,11 @@ pa_bool_t pa_rtclock_hrtimer(void) {
     pa_assert_se(clock_getres(CLOCK_REALTIME, &ts) == 0);
     return ts.tv_sec == 0 && ts.tv_nsec <= (long) (PA_HRTIMER_THRESHOLD_USEC*PA_NSEC_PER_USEC);
 
+#elif defined(OS_IS_WIN32)
+
+    if (counter_freq > 0)
+        return counter_freq >= (int64_t) (PA_USEC_PER_SEC/PA_HRTIMER_THRESHOLD_USEC);
+
 #endif /* HAVE_CLOCK_GETTIME */
 
     return FALSE;
@@ -148,6 +172,12 @@ void pa_rtclock_hrtimer_enable(void) {
         }
     }
 
+#elif defined(OS_IS_WIN32)
+    LARGE_INTEGER freq;
+
+    pa_assert_se(QueryPerformanceFrequency(&freq));
+    counter_freq = freq.QuadPart;
+
 #endif
 }
 
diff --git a/src/pulsecore/core-util.c b/src/pulsecore/core-util.c
index 04a2341..8a377e3 100644
--- a/src/pulsecore/core-util.c
+++ b/src/pulsecore/core-util.c
@@ -34,11 +34,9 @@
 #include <fcntl.h>
 #include <unistd.h>
 #include <limits.h>
-#include <time.h>
 #include <ctype.h>
 #include <sys/types.h>
 #include <sys/stat.h>
-#include <sys/time.h>
 #include <dirent.h>
 
 #ifdef HAVE_LANGINFO_H
diff --git a/src/pulsecore/memblockq.c b/src/pulsecore/memblockq.c
index c784048..11faeda 100644
--- a/src/pulsecore/memblockq.c
+++ b/src/pulsecore/memblockq.c
@@ -23,8 +23,6 @@
 #include <config.h>
 #endif
 
-#include <sys/time.h>
-#include <time.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
diff --git a/src/pulsecore/tagstruct.h b/src/pulsecore/tagstruct.h
index 1a99e92..b6553ad 100644
--- a/src/pulsecore/tagstruct.h
+++ b/src/pulsecore/tagstruct.h
@@ -25,7 +25,6 @@
 #include <inttypes.h>
 #include <sys/types.h>
 #include <sys/time.h>
-#include <time.h>
 
 #include <pulse/sample.h>
 #include <pulse/channelmap.h>

commit 5205e6a85ac8699c464e2d676c4d8b1c2b7989e5
Author: Maarten Bosmans <mkbosmans at gmail.com>
Date:   Tue Jan 18 11:28:13 2011 +0100

    win32: Implement pa_random

diff --git a/src/pulsecore/random.c b/src/pulsecore/random.c
index 3d159bf..bdbc143 100644
--- a/src/pulsecore/random.c
+++ b/src/pulsecore/random.c
@@ -31,6 +31,11 @@
 #include <stdlib.h>
 #include <time.h>
 
+#ifdef HAVE_WINDOWS_H
+#include <windows.h>
+#include <wincrypt.h>
+#endif
+
 #include <pulsecore/core-util.h>
 #include <pulsecore/log.h>
 #include <pulsecore/macro.h>
@@ -43,10 +48,20 @@ static const char * const devices[] = { "/dev/urandom", "/dev/random", NULL };
 
 static int random_proper(void *ret_data, size_t length) {
 #ifdef OS_IS_WIN32
+    int ret = -1;
+
     pa_assert(ret_data);
     pa_assert(length > 0);
 
-    return -1;
+    HCRYPTPROV hCryptProv = NULL;
+
+    if (CryptAcquireContext(&hCryptProv, NULL, NULL, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT | CRYPT_SILENT)) {
+        if(CryptGenRandom(hCryptProv, length, ret_data))
+            ret = 0;
+        CryptReleaseContext(hCryptProv, 0);
+    }
+
+    return ret;
 
 #else /* OS_IS_WIN32 */
 

commit 110b14ec21eacaf6baa4fa111a76e26bad585dcd
Author: Maarten Bosmans <mkbosmans at gmail.com>
Date:   Wed Jan 12 15:02:18 2011 +0100

    module-waveout: Adapted to updated API
    
    Waveout sink works again, Wavein source still needs some work.

diff --git a/src/Makefile.am b/src/Makefile.am
index c17c225..ed4a06a 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -1183,10 +1183,10 @@ pulselibexec_PROGRAMS += \
 		gconf-helper
 endif
 
-#if OS_IS_WIN32
-#modlibexec_LTLIBRARIES += \
-#		module-waveout.la
-#endif
+if OS_IS_WIN32
+modlibexec_LTLIBRARIES += \
+		module-waveout.la
+endif
 
 if HAVE_HAL
 modlibexec_LTLIBRARIES += \
@@ -1624,11 +1624,10 @@ module_mmkbd_evdev_la_LIBADD = $(MODULE_LIBADD)
 module_mmkbd_evdev_la_CFLAGS = $(AM_CFLAGS)
 
 # Windows waveout
-
-#module_waveout_la_SOURCES = modules/module-waveout.c
-#module_waveout_la_LDFLAGS = $(MODULE_LDFLAGS)
-#module_waveout_la_LIBADD = $(MODULE_LIBADD) -lwinmm
-#module_waveout_la_CFLAGS = $(AM_CFLAGS)
+module_waveout_la_SOURCES = modules/module-waveout.c
+module_waveout_la_LDFLAGS = $(MODULE_LDFLAGS)
+module_waveout_la_LIBADD = $(MODULE_LIBADD) -lwinmm
+module_waveout_la_CFLAGS = $(AM_CFLAGS)
 
 # Hardware autodetection module
 module_detect_la_SOURCES = modules/module-detect.c
diff --git a/src/modules/module-waveout.c b/src/modules/module-waveout.c
index 6fedceb..0dbf7ef 100644
--- a/src/modules/module-waveout.c
+++ b/src/modules/module-waveout.c
@@ -31,6 +31,7 @@
 
 #include <pulse/xmalloc.h>
 #include <pulse/timeval.h>
+#include <pulse/rtclock.h>
 
 #include <pulsecore/sink.h>
 #include <pulsecore/source.h>
@@ -39,12 +40,14 @@
 #include <pulsecore/sample-util.h>
 #include <pulsecore/core-util.h>
 #include <pulsecore/log.h>
+#include <pulsecore/thread.h>
+#include <pulsecore/thread-mq.h>
 
 #include "module-waveout-symdef.h"
 
-PA_MODULE_AUTHOR("Pierre Ossman")
-PA_MODULE_DESCRIPTION("Windows waveOut Sink/Source")
-PA_MODULE_VERSION(PACKAGE_VERSION)
+PA_MODULE_AUTHOR("Pierre Ossman");
+PA_MODULE_DESCRIPTION("Windows waveOut Sink/Source");
+PA_MODULE_VERSION(PACKAGE_VERSION);
 PA_MODULE_USAGE(
     "sink_name=<name for the sink> "
     "source_name=<name for the source> "
@@ -56,7 +59,7 @@ PA_MODULE_USAGE(
     "rate=<sample rate> "
     "fragments=<number of fragments> "
     "fragment_size=<fragment size> "
-    "channel_map=<channel map>")
+    "channel_map=<channel map>");
 
 #define DEFAULT_SINK_NAME "wave_output"
 #define DEFAULT_SOURCE_NAME "wave_input"
@@ -67,10 +70,12 @@ struct userdata {
     pa_sink *sink;
     pa_source *source;
     pa_core *core;
-    pa_time_event *event;
-    pa_defer_event *defer;
     pa_usec_t poll_timeout;
 
+    pa_thread *thread;
+    pa_thread_mq thread_mq;
+    pa_rtpoll *rtpoll;
+
     uint32_t fragments, fragment_size;
 
     uint32_t free_ofrags, free_ifrags;
@@ -103,22 +108,19 @@ static const char* const valid_modargs[] = {
     NULL
 };
 
-static void update_usage(struct userdata *u) {
-   pa_module_set_used(u->module,
-                      (u->sink ? pa_sink_used_by(u->sink) : 0) +
-                      (u->source ? pa_source_used_by(u->source) : 0));
-}
-
-static void do_write(struct userdata *u)
-{
+static void do_write(struct userdata *u) {
     uint32_t free_frags;
     pa_memchunk memchunk;
     WAVEHDR *hdr;
     MMRESULT res;
+    void *p;
 
     if (!u->sink)
         return;
 
+    if (!PA_SINK_IS_LINKED(u->sink->state))
+        return;
+
     EnterCriticalSection(&u->crit);
     free_frags = u->free_ofrags;
     LeaveCriticalSection(&u->crit);
@@ -137,18 +139,17 @@ static void do_write(struct userdata *u)
 
             len = u->fragment_size - hdr->dwBufferLength;
 
-            if (pa_sink_render(u->sink, len, &memchunk) < 0)
-                break;
+            pa_sink_render(u->sink, len, &memchunk);
 
-            assert(memchunk.memblock);
-            assert(memchunk.memblock->data);
-            assert(memchunk.length);
+            pa_assert(memchunk.memblock);
+            pa_assert(memchunk.length);
 
             if (memchunk.length < len)
                 len = memchunk.length;
 
-            memcpy(hdr->lpData + hdr->dwBufferLength,
-                (char*)memchunk.memblock->data + memchunk.index, len);
+            p = pa_memblock_acquire(memchunk.memblock);
+            memcpy(hdr->lpData + hdr->dwBufferLength, (char*) p + memchunk.index, len);
+            pa_memblock_release(memchunk.memblock);
 
             hdr->dwBufferLength += len;
 
@@ -165,15 +166,12 @@ static void do_write(struct userdata *u)
         u->sink_underflow = 0;
 
         res = waveOutPrepareHeader(u->hwo, hdr, sizeof(WAVEHDR));
-        if (res != MMSYSERR_NOERROR) {
-            pa_log_error(__FILE__ ": ERROR: Unable to prepare waveOut block: %d",
-                res);
-        }
+        if (res != MMSYSERR_NOERROR)
+            pa_log_error("Unable to prepare waveOut block: %d", res);
+
         res = waveOutWrite(u->hwo, hdr, sizeof(WAVEHDR));
-        if (res != MMSYSERR_NOERROR) {
-            pa_log_error(__FILE__ ": ERROR: Unable to write waveOut block: %d",
-                res);
-        }
+        if (res != MMSYSERR_NOERROR)
+            pa_log_error("Unable to write waveOut block: %d", res);
 
         u->written_bytes += hdr->dwBufferLength;
 
@@ -187,21 +185,22 @@ static void do_write(struct userdata *u)
     }
 }
 
-static void do_read(struct userdata *u)
-{
+static void do_read(struct userdata *u) {
     uint32_t free_frags;
     pa_memchunk memchunk;
     WAVEHDR *hdr;
     MMRESULT res;
+    void *p;
 
     if (!u->source)
         return;
 
-    EnterCriticalSection(&u->crit);
+    if (!PA_SOURCE_IS_LINKED(u->source->state))
+        return;
 
+    EnterCriticalSection(&u->crit);
     free_frags = u->free_ifrags;
     u->free_ifrags = 0;
-
     LeaveCriticalSection(&u->crit);
 
     if (free_frags == u->fragments)
@@ -214,11 +213,13 @@ static void do_read(struct userdata *u)
 
         if (hdr->dwBytesRecorded) {
             memchunk.memblock = pa_memblock_new(u->core->mempool, hdr->dwBytesRecorded);
-            assert(memchunk.memblock);
+            pa_assert(memchunk.memblock);
 
-            memcpy((char*)memchunk.memblock->data, hdr->lpData, hdr->dwBytesRecorded);
+            p = pa_memblock_acquire(memchunk.memblock);
+            memcpy((char*) p, hdr->lpData, hdr->dwBytesRecorded);
+            pa_memblock_release(memchunk.memblock);
 
-            memchunk.length = memchunk.memblock->length = hdr->dwBytesRecorded;
+            memchunk.length = hdr->dwBytesRecorded;
             memchunk.index = 0;
 
             pa_source_post(u->source, &memchunk);
@@ -226,15 +227,12 @@ static void do_read(struct userdata *u)
         }
 
         res = waveInPrepareHeader(u->hwi, hdr, sizeof(WAVEHDR));
-        if (res != MMSYSERR_NOERROR) {
-            pa_log_error(__FILE__ ": ERROR: Unable to prepare waveIn block: %d",
-                res);
-        }
+        if (res != MMSYSERR_NOERROR)
+            pa_log_error("Unable to prepare waveIn block: %d", res);
+
         res = waveInAddBuffer(u->hwi, hdr, sizeof(WAVEHDR));
-        if (res != MMSYSERR_NOERROR) {
-            pa_log_error(__FILE__ ": ERROR: Unable to add waveIn block: %d",
-                res);
-        }
+        if (res != MMSYSERR_NOERROR)
+            pa_log_error("Unable to add waveIn block: %d", res);
 
         free_frags--;
         u->cur_ihdr++;
@@ -242,32 +240,53 @@ static void do_read(struct userdata *u)
     }
 }
 
-static void poll_cb(pa_mainloop_api*a, pa_time_event *e, const struct timeval *tv, void *userdata) {
+static void thread_func(void *userdata) {
     struct userdata *u = userdata;
-    struct timeval ntv;
 
-    assert(u);
+    pa_assert(u);
+    pa_assert(u->sink || u->source);
 
-    update_usage(u);
+    pa_log_debug("Thread starting up");
 
-    do_write(u);
-    do_read(u);
+    if (u->core->realtime_scheduling)
+        pa_make_realtime(u->core->realtime_priority);
 
-    pa_gettimeofday(&ntv);
-    pa_timeval_add(&ntv, u->poll_timeout);
+    pa_thread_mq_install(&u->thread_mq);
 
-    a->rtclock_time_restart(e, &ntv);
-}
+    for (;;) {
+        int ret;
 
-static void defer_cb(pa_mainloop_api*a, pa_defer_event *e, void *userdata) {
-    struct userdata *u = userdata;
+        if (PA_SINK_IS_OPENED(u->sink->thread_info.state) ||
+            PA_SOURCE_IS_OPENED(u->source->thread_info.state)) {
+
+            if (u->sink->thread_info.rewind_requested)
+                pa_sink_process_rewind(u->sink, 0);
 
-    assert(u);
+            if (PA_SINK_IS_OPENED(u->sink->thread_info.state))
+                do_write(u);
+            if (PA_SOURCE_IS_OPENED(u->source->thread_info.state))
+                do_read(u);
 
-    a->defer_enable(e, 0);
+            pa_rtpoll_set_timer_relative(u->rtpoll, u->poll_timeout);
+        } else
+            pa_rtpoll_set_timer_disabled(u->rtpoll);
 
-    do_write(u);
-    do_read(u);
+        /* Hmm, nothing to do. Let's sleep */
+        if ((ret = pa_rtpoll_run(u->rtpoll, TRUE)) < 0)
+            goto fail;
+
+        if (ret == 0)
+            goto finish;
+    }
+
+fail:
+    /* If this was no regular exit from the loop we have to continue
+     * processing messages until we received PA_MESSAGE_SHUTDOWN */
+    pa_asyncmsgq_post(u->thread_mq.outq, PA_MSGOBJECT(u->core), PA_CORE_MESSAGE_UNLOAD_MODULE, u->module, 0, NULL, NULL);
+    pa_asyncmsgq_wait_for(u->thread_mq.inq, PA_MESSAGE_SHUTDOWN);
+
+finish:
+    pa_log_debug("Thread shutting down");
 }
 
 static void CALLBACK chunk_done_cb(HWAVEOUT hwo, UINT msg, DWORD_PTR inst, DWORD param1, DWORD param2) {
@@ -277,10 +296,8 @@ static void CALLBACK chunk_done_cb(HWAVEOUT hwo, UINT msg, DWORD_PTR inst, DWORD
         return;
 
     EnterCriticalSection(&u->crit);
-
     u->free_ofrags++;
-    assert(u->free_ofrags <= u->fragments);
-
+    pa_assert(u->free_ofrags <= u->fragments);
     LeaveCriticalSection(&u->crit);
 }
 
@@ -291,107 +308,124 @@ static void CALLBACK chunk_ready_cb(HWAVEIN hwi, UINT msg, DWORD_PTR inst, DWORD
         return;
 
     EnterCriticalSection(&u->crit);
-
     u->free_ifrags++;
-    assert(u->free_ifrags <= u->fragments);
-
+    pa_assert(u->free_ifrags <= u->fragments);
     LeaveCriticalSection(&u->crit);
 }
 
-static pa_usec_t sink_get_latency_cb(pa_sink *s) {
-    struct userdata *u = s->userdata;
+static pa_usec_t sink_get_latency(struct userdata *u) {
     uint32_t free_frags;
     MMTIME mmt;
-    assert(s && u && u->sink);
+    pa_assert(u);
+    pa_assert(u->sink);
 
     memset(&mmt, 0, sizeof(mmt));
     mmt.wType = TIME_BYTES;
     if (waveOutGetPosition(u->hwo, &mmt, sizeof(mmt)) == MMSYSERR_NOERROR)
-        return pa_bytes_to_usec(u->written_bytes - mmt.u.cb, &s->sample_spec);
+        return pa_bytes_to_usec(u->written_bytes - mmt.u.cb, &u->sink->sample_spec);
     else {
         EnterCriticalSection(&u->crit);
-
         free_frags = u->free_ofrags;
-
         LeaveCriticalSection(&u->crit);
 
-        return pa_bytes_to_usec((u->fragments - free_frags) * u->fragment_size,
-                              &s->sample_spec);
+        return pa_bytes_to_usec((u->fragments - free_frags) * u->fragment_size, &u->sink->sample_spec);
     }
 }
 
-static pa_usec_t source_get_latency_cb(pa_source *s) {
+static pa_usec_t source_get_latency(struct userdata *u) {
     pa_usec_t r = 0;
-    struct userdata *u = s->userdata;
     uint32_t free_frags;
-    assert(s && u && u->sink);
+    pa_assert(u);
+    pa_assert(u->source);
 
     EnterCriticalSection(&u->crit);
-
     free_frags = u->free_ifrags;
-
     LeaveCriticalSection(&u->crit);
 
-    r += pa_bytes_to_usec((free_frags + 1) * u->fragment_size, &s->sample_spec);
+    r += pa_bytes_to_usec((free_frags + 1) * u->fragment_size, &u->source->sample_spec);
 
     return r;
 }
 
-static void notify_sink_cb(pa_sink *s) {
-    struct userdata *u = s->userdata;
-    assert(u);
+static int process_msg(pa_msgobject *o, int code, void *data, int64_t offset, pa_memchunk *chunk) {
+    struct userdata *u;
 
-    u->core->mainloop->defer_enable(u->defer, 1);
-}
+    if (pa_sink_isinstance(o)) {
+        u = PA_SINK(o)->userdata;
 
-static void notify_source_cb(pa_source *s) {
-    struct userdata *u = s->userdata;
-    assert(u);
+        switch (code) {
+
+            case PA_SINK_MESSAGE_GET_LATENCY: {
+                pa_usec_t r = 0;
+                if (u->hwo)
+                    r = sink_get_latency(u);
+                *((pa_usec_t*) data) = r;
+                return 0;
+            }
+
+        }
+
+        return pa_sink_process_msg(o, code, data, offset, chunk);
+    }
+
+    if (pa_source_isinstance(o)) {
+        u = PA_SOURCE(o)->userdata;
+
+        switch (code) {
 
-    u->core->mainloop->defer_enable(u->defer, 1);
+            case PA_SOURCE_MESSAGE_GET_LATENCY: {
+                pa_usec_t r = 0;
+                if (u->hwi)
+                    r = source_get_latency(u);
+                *((pa_usec_t*) data) = r;
+                return 0;
+            }
+
+        }
+
+        return pa_source_process_msg(o, code, data, offset, chunk);
+    }
+
+    return -1;
 }
 
-static int sink_get_hw_volume_cb(pa_sink *s) {
+static void sink_get_volume_cb(pa_sink *s) {
     struct userdata *u = s->userdata;
     DWORD vol;
     pa_volume_t left, right;
 
     if (waveOutGetVolume(u->hwo, &vol) != MMSYSERR_NOERROR)
-        return -1;
+        return;
 
     left = PA_CLAMP_VOLUME((vol & 0xFFFF) * PA_VOLUME_NORM / WAVEOUT_MAX_VOLUME);
     right = PA_CLAMP_VOLUME(((vol >> 16) & 0xFFFF) * PA_VOLUME_NORM / WAVEOUT_MAX_VOLUME);
 
     /* Windows supports > 2 channels, except for volume control */
-    if (s->hw_volume.channels > 2)
-        pa_cvolume_set(&s->hw_volume, s->hw_volume.channels, (left + right)/2);
-
-    s->hw_volume.values[0] = left;
-    if (s->hw_volume.channels > 1)
-        s->hw_volume.values[1] = right;
+    if (s->real_volume.channels > 2)
+        pa_cvolume_set(&s->real_volume, s->real_volume.channels, (left + right)/2);
 
-    return 0;
+    s->real_volume.values[0] = left;
+    if (s->real_volume.channels > 1)
+        s->real_volume.values[1] = right;
 }
 
-static int sink_set_hw_volume_cb(pa_sink *s) {
+static void sink_set_volume_cb(pa_sink *s) {
     struct userdata *u = s->userdata;
     DWORD vol;
 
-    vol = s->hw_volume.values[0] * WAVEOUT_MAX_VOLUME / PA_VOLUME_NORM;
-    if (s->hw_volume.channels > 1)
-        vol |= (s->hw_volume.values[0] * WAVEOUT_MAX_VOLUME / PA_VOLUME_NORM) << 16;
+    vol = s->real_volume.values[0] * WAVEOUT_MAX_VOLUME / PA_VOLUME_NORM;
+    if (s->real_volume.channels > 1)
+        vol |= (s->real_volume.values[1] * WAVEOUT_MAX_VOLUME / PA_VOLUME_NORM) << 16;
 
     if (waveOutSetVolume(u->hwo, vol) != MMSYSERR_NOERROR)
-        return -1;
-
-    return 0;
+        return;
 }
 
 static int ss_to_waveformat(pa_sample_spec *ss, LPWAVEFORMATEX wf) {
     wf->wFormatTag = WAVE_FORMAT_PCM;
 
     if (ss->channels > 2) {
-        pa_log_error("ERROR: More than two channels not supported.");
+        pa_log_error("More than two channels not supported.");
         return -1;
     }
 
@@ -404,7 +438,7 @@ static int ss_to_waveformat(pa_sample_spec *ss, LPWAVEFORMATEX wf) {
     case 44100:
         break;
     default:
-        pa_log_error("ERROR: Unsupported sample rate.");
+        pa_log_error("Unsupported sample rate.");
         return -1;
     }
 
@@ -415,7 +449,7 @@ static int ss_to_waveformat(pa_sample_spec *ss, LPWAVEFORMATEX wf) {
     else if (ss->format == PA_SAMPLE_S16NE)
         wf->wBitsPerSample = 16;
     else {
-        pa_log_error("ERROR: Unsupported sample format.");
+        pa_log_error("Unsupported sample format.");
         return -1;
     }
 
@@ -427,21 +461,31 @@ static int ss_to_waveformat(pa_sample_spec *ss, LPWAVEFORMATEX wf) {
     return 0;
 }
 
-int pa__init(pa_core *c, pa_module*m) {
+int pa__get_n_used(pa_module *m) {
+    struct userdata *u;
+    pa_assert(m);
+    pa_assert(m->userdata);
+    u = (struct userdata *)m->userdata;
+
+    return (u->sink ? pa_sink_used_by(u->sink) : 0) +
+           (u->source ? pa_source_used_by(u->source) : 0);
+}
+
+int pa__init(pa_module *m) {
     struct userdata *u = NULL;
     HWAVEOUT hwo = INVALID_HANDLE_VALUE;
     HWAVEIN hwi = INVALID_HANDLE_VALUE;
     WAVEFORMATEX wf;
     int nfrags, frag_size;
-    int record = 1, playback = 1;
+    pa_bool_t record = TRUE, playback = TRUE;
     unsigned int device;
     pa_sample_spec ss;
     pa_channel_map map;
     pa_modargs *ma = NULL;
     unsigned int i;
-    struct timeval tv;
 
-    assert(c && m);
+    pa_assert(m);
+    pa_assert(m->core);
 
     if (!(ma = pa_modargs_new(m->argument, valid_modargs))) {
         pa_log("failed to parse module arguments.");
@@ -471,7 +515,7 @@ int pa__init(pa_core *c, pa_module*m) {
         goto fail;
     }
 
-    ss = c->default_sample_spec;
+    ss = m->core->default_sample_spec;
     if (pa_modargs_get_sample_spec_and_channel_map(ma, &ss, &map, PA_CHANNEL_MAP_WAVEEX) < 0) {
         pa_log("failed to parse sample specification");
         goto fail;
@@ -505,34 +549,47 @@ int pa__init(pa_core *c, pa_module*m) {
     InitializeCriticalSection(&u->crit);
 
     if (hwi != INVALID_HANDLE_VALUE) {
-        u->source = pa_source_new(c, __FILE__, pa_modargs_get_value(ma, "source_name", DEFAULT_SOURCE_NAME), 0, &ss, &map);
-        assert(u->source);
+        pa_source_new_data data;
+        pa_source_new_data_init(&data);
+        data.driver = __FILE__;
+        data.module = m;
+        pa_source_new_data_set_sample_spec(&data, &ss);
+        pa_source_new_data_set_channel_map(&data, &map);
+        pa_source_new_data_set_name(&data, pa_modargs_get_value(ma, "source_name", DEFAULT_SOURCE_NAME));
+        u->source = pa_source_new(m->core, &data, PA_SOURCE_HARDWARE|PA_SOURCE_LATENCY);
+        pa_source_new_data_done(&data);
+
+        pa_assert(u->source);
         u->source->userdata = u;
-        u->source->notify = notify_source_cb;
-        u->source->get_latency = source_get_latency_cb;
-        pa_source_set_owner(u->source, m);
         pa_source_set_description(u->source, "Windows waveIn PCM");
-        u->source->is_hardware = 1;
+        u->source->parent.process_msg = process_msg;
     } else
         u->source = NULL;
 
     if (hwo != INVALID_HANDLE_VALUE) {
-        u->sink = pa_sink_new(c, __FILE__, pa_modargs_get_value(ma, "sink_name", DEFAULT_SINK_NAME), 0, &ss, &map);
-        assert(u->sink);
-        u->sink->notify = notify_sink_cb;
-        u->sink->get_latency = sink_get_latency_cb;
-        u->sink->get_hw_volume = sink_get_hw_volume_cb;
-        u->sink->set_hw_volume = sink_set_hw_volume_cb;
+        pa_sink_new_data data;
+        pa_sink_new_data_init(&data);
+        data.driver = __FILE__;
+        data.module = m;
+        pa_sink_new_data_set_sample_spec(&data, &ss);
+        pa_sink_new_data_set_channel_map(&data, &map);
+        pa_sink_new_data_set_name(&data, pa_modargs_get_value(ma, "sink_name", DEFAULT_SINK_NAME));
+        u->sink = pa_sink_new(m->core, &data, PA_SINK_HARDWARE|PA_SINK_LATENCY);
+        pa_sink_new_data_done(&data);
+
+        pa_assert(u->sink);
+        u->sink->get_volume = sink_get_volume_cb;
+        u->sink->set_volume = sink_set_volume_cb;
         u->sink->userdata = u;
-        pa_sink_set_owner(u->sink, m);
         pa_sink_set_description(u->sink, "Windows waveOut PCM");
-        u->sink->is_hardware = 1;
+        u->sink->parent.process_msg = process_msg;
     } else
         u->sink = NULL;
 
-    assert(u->source || u->sink);
+    pa_assert(u->source || u->sink);
+    pa_modargs_free(ma);
 
-    u->core = c;
+    u->core = m->core;
     u->hwi = hwi;
     u->hwo = hwo;
 
@@ -546,82 +603,84 @@ int pa__init(pa_core *c, pa_module*m) {
 
     u->poll_timeout = pa_bytes_to_usec(u->fragments * u->fragment_size / 10, &ss);
 
-    pa_gettimeofday(&tv);
-    pa_timeval_add(&tv, u->poll_timeout);
-
-    u->event = c->mainloop->rtclock_time_new(c->mainloop, &tv, poll_cb, u);
-    assert(u->event);
-
-    u->defer = c->mainloop->defer_new(c->mainloop, defer_cb, u);
-    assert(u->defer);
-    c->mainloop->defer_enable(u->defer, 0);
-
     u->cur_ihdr = 0;
     u->cur_ohdr = 0;
     u->ihdrs = pa_xmalloc0(sizeof(WAVEHDR) * u->fragments);
-    assert(u->ihdrs);
+    pa_assert(u->ihdrs);
     u->ohdrs = pa_xmalloc0(sizeof(WAVEHDR) * u->fragments);
-    assert(u->ohdrs);
+    pa_assert(u->ohdrs);
     for (i = 0;i < u->fragments;i++) {
         u->ihdrs[i].dwBufferLength = u->fragment_size;
         u->ohdrs[i].dwBufferLength = u->fragment_size;
         u->ihdrs[i].lpData = pa_xmalloc(u->fragment_size);
-        assert(u->ihdrs);
+        pa_assert(u->ihdrs);
         u->ohdrs[i].lpData = pa_xmalloc(u->fragment_size);
-        assert(u->ohdrs);
+        pa_assert(u->ohdrs);
     }
 
     u->module = m;
     m->userdata = u;
 
-    pa_modargs_free(ma);
-
     /* Read mixer settings */
     if (u->sink)
-        sink_get_hw_volume_cb(u->sink);
-
-    return 0;
+        sink_get_volume_cb(u->sink);
 
-fail:
-   if (hwi != INVALID_HANDLE_VALUE)
-        waveInClose(hwi);
+    u->rtpoll = pa_rtpoll_new();
+    pa_thread_mq_init(&u->thread_mq, m->core->mainloop, u->rtpoll);
+    if (!(u->thread = pa_thread_new("waveout-source", thread_func, u))) {
+        pa_log("Failed to create thread.");
+        goto fail;
+    }
 
-   if (hwo != INVALID_HANDLE_VALUE)
-        waveOutClose(hwo);
+    if (u->sink) {
+        pa_sink_set_asyncmsgq(u->sink, u->thread_mq.inq);
+        pa_sink_set_rtpoll(u->sink, u->rtpoll);
+        pa_sink_put(u->sink);
+    }
+    if (u->source) {
+        pa_source_set_asyncmsgq(u->source, u->thread_mq.inq);
+        pa_source_set_rtpoll(u->source, u->rtpoll);
+        pa_source_put(u->source);
+    }
 
-    if (u)
-        pa_xfree(u);
+    return 0;
 
+fail:
     if (ma)
         pa_modargs_free(ma);
 
+    pa__done(m);
+
     return -1;
 }
 
-void pa__done(pa_core *c, pa_module*m) {
+void pa__done(pa_module *m) {
     struct userdata *u;
     unsigned int i;
 
-    assert(c && m);
+    pa_assert(m);
+    pa_assert(m->core);
 
     if (!(u = m->userdata))
         return;
 
-    if (u->event)
-        c->mainloop->time_free(u->event);
+    if (u->sink)
+        pa_sink_unlink(u->sink);
+    if (u->source)
+        pa_source_unlink(u->source);
 
-    if (u->defer)
-        c->mainloop->defer_free(u->defer);
+    pa_asyncmsgq_send(u->thread_mq.inq, NULL, PA_MESSAGE_SHUTDOWN, NULL, 0, NULL);
+    if (u->thread)
+      pa_thread_free(u->thread);
+    pa_thread_mq_done(&u->thread_mq);
 
-    if (u->sink) {
-        pa_sink_disconnect(u->sink);
+    if (u->sink)
         pa_sink_unref(u->sink);
-    }
-
-    if (u->source) {
-        pa_source_disconnect(u->source);
+    if (u->source)
         pa_source_unref(u->source);
-    }
+
+    if (u->rtpoll)
+        pa_rtpoll_free(u->rtpoll);
 
     if (u->hwi != INVALID_HANDLE_VALUE) {
         waveInReset(u->hwi);

commit f2a9fd779e6bfc79d7e6f6f45447e9adbb873c34
Author: Maarten Bosmans <mkbosmans at gmail.com>
Date:   Thu Feb 17 11:28:54 2011 +0100

    Give module-waveout a configure switch
    
     - Also disable the scary DBus and udev warnings when building for win32
     - and only install some dbus/x11 specific files when appropriate

diff --git a/configure.ac b/configure.ac
index a2657c0..8b4f586 100644
--- a/configure.ac
+++ b/configure.ac
@@ -878,6 +878,39 @@ fi
 AC_SUBST(HAVE_SOLARIS)
 AM_CONDITIONAL([HAVE_SOLARIS], [test "x$HAVE_SOLARIS" = x1])
 
+#### WaveOut audio support (optional) ####
+
+AC_ARG_ENABLE([waveout],
+    AS_HELP_STRING([--disable-waveout],[Disable optional WaveOut audio support]),
+        [
+            case "${enableval}" in
+                yes) waveout=yes ;;
+                no) waveout=no ;;
+                *) AC_MSG_ERROR(bad value ${enableval} for --disable-waveout) ;;
+            esac
+        ],
+        [waveout=auto])
+
+if test "x${waveout}" != xno ; then
+    AC_CHECK_HEADERS([mmsystem.h],
+        [
+            HAVE_WAVEOUT=1
+            AC_DEFINE([HAVE_WAVEOUT], 1, [Have WaveOut audio?])
+        ],
+        [
+            HAVE_WAVEOUT=0
+            if test "x$waveout" = xyes ; then
+                AC_MSG_ERROR([*** WaveOut audio support not found])
+            fi
+        ],
+        [#include <windows.h>])
+else
+    HAVE_WAVEOUT=0
+fi
+
+AC_SUBST(HAVE_WAVEOUT)
+AM_CONDITIONAL([HAVE_WAVEOUT], [test "x$HAVE_WAVEOUT" = x1])
+
 #### GLib 2 support (optional) ####
 
 AC_ARG_ENABLE([glib2],
@@ -1529,6 +1562,11 @@ if test "x$HAVE_SOLARIS" = "x1" ; then
    ENABLE_SOLARIS=yes
 fi
 
+ENABLE_WAVEOUT=no
+if test "x$HAVE_WAVEOUT" = "x1" ; then
+   ENABLE_WAVEOUT=yes
+fi
+
 ENABLE_GTK20=no
 if test "x$HAVE_GTK20" = "x1" ; then
    ENABLE_GTK20=yes
@@ -1650,6 +1688,7 @@ echo "
     System Config Path:            ${PA_SYSTEM_CONFIG_PATH}
     Compiler:                      ${CC}
     CFLAGS:                        ${CFLAGS}
+    LIBS:                          ${LIBS}
 
     Have X11:                      ${ENABLE_X11}
     Enable OSS Output:             ${ENABLE_OSS_OUTPUT}
@@ -1657,6 +1696,7 @@ echo "
     Enable CoreAudio:              ${ENABLE_COREAUDIO}
     Enable Alsa:                   ${ENABLE_ALSA}
     Enable Solaris:                ${ENABLE_SOLARIS}
+    Enable WaveOut:                ${ENABLE_WAVEOUT}
     Enable GLib 2.0:               ${ENABLE_GLIB20}
     Enable Gtk+ 2.0:               ${ENABLE_GTK20}
     Enable GConf:                  ${ENABLE_GCONF}
@@ -1687,7 +1727,7 @@ echo "
     Preopened modules:             ${PREOPEN_MODS}
 "
 
-if test "${ENABLE_DBUS}" = "no" ; then
+if test "${ENABLE_DBUS}" = "no" && test "x$os_is_win32" != "x1" ; then
    echo "
 ===== WARNING WARNING WARNING WARNING WARNING WARNING WARNING =====
 You do not have DBUS support enabled. It is strongly recommended
@@ -1700,7 +1740,7 @@ controling the PulseAudio daemon itself.
 "
 fi
 
-if test "${ENABLE_UDEV}" = "no" ; then
+if test "${ENABLE_UDEV}" = "no" && test "x$os_is_win32" != "x1" ; then
    echo "
 ===== WARNING WARNING WARNING WARNING WARNING WARNING WARNING =====
 You do not have udev support enabled. It is strongly recommended
diff --git a/src/Makefile.am b/src/Makefile.am
index ed4a06a..d49d91c 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -112,8 +112,10 @@ pulseconf_DATA = \
 		daemon.conf \
 		client.conf
 
+if HAVE_DBUS
 dbuspolicy_DATA = \
 		daemon/pulseaudio-system.conf
+endif
 
 if HAVE_X11
 xdgautostart_in_files = \
@@ -175,6 +177,8 @@ endif
 #       Utility programs          #
 ###################################
 
+bin_SCRIPTS = esdcompat
+
 bin_PROGRAMS += \
 		pacat \
 		pactl
@@ -189,14 +193,13 @@ endif
 
 if HAVE_X11
 bin_PROGRAMS += pax11publish
+bin_SCRIPTS += start-pulseaudio-x11 start-pulseaudio-kde
 endif
 
 if HAVE_AVAHI
 bin_PROGRAMS += pabrowse
 endif
 
-bin_SCRIPTS = esdcompat start-pulseaudio-x11 start-pulseaudio-kde
-
 pacat_SOURCES = utils/pacat.c
 pacat_LDADD = $(AM_LDADD) libpulse.la libpulsecommon- at PA_MAJORMINOR@.la $(LIBSNDFILE_LIBS)
 pacat_CFLAGS = $(AM_CFLAGS) $(LIBSNDFILE_CFLAGS)
@@ -1183,7 +1186,7 @@ pulselibexec_PROGRAMS += \
 		gconf-helper
 endif
 
-if OS_IS_WIN32
+if HAVE_WAVEOUT
 modlibexec_LTLIBRARIES += \
 		module-waveout.la
 endif

commit aebf66bef6ebc8561b3cd4bfb4189ea739056f65
Author: Maarten Bosmans <mkbosmans at gmail.com>
Date:   Thu Feb 17 11:50:10 2011 +0100

    Use pa_* instead of generic functions to improve portability

diff --git a/src/pulsecore/inet_ntop.c b/src/pulsecore/inet_ntop.c
index 64c28ed..059b25c 100644
--- a/src/pulsecore/inet_ntop.c
+++ b/src/pulsecore/inet_ntop.c
@@ -29,6 +29,7 @@
 #ifndef HAVE_INET_NTOP
 
 #include <pulsecore/core-util.h>
+#include <pulsecore/macro.h>
 #include <pulsecore/socket.h>
 
 #include "inet_ntop.h"
@@ -39,7 +40,8 @@ const char *inet_ntop(int af, const void *src, char *dst, socklen_t cnt) {
     struct in6_addr *in6 = (struct in6_addr*)src;
 #endif
 
-    assert(src && dst);
+    pa_assert(src);
+    pa_assert(dst);
 
     switch (af) {
     case AF_INET:
diff --git a/src/pulsecore/inet_pton.c b/src/pulsecore/inet_pton.c
index 198d1a0..efb1526 100644
--- a/src/pulsecore/inet_pton.c
+++ b/src/pulsecore/inet_pton.c
@@ -28,6 +28,7 @@
 
 #ifndef HAVE_INET_PTON
 
+#include <pulsecore/macro.h>
 #include <pulsecore/socket.h>
 
 #include "inet_pton.h"
@@ -38,7 +39,8 @@ int inet_pton(int af, const char *src, void *dst) {
     struct in6_addr *in6 = (struct in6_addr*)dst;
 #endif
 
-    assert(src && dst);
+    pa_assert(src);
+    pa_assert(dst);
 
     switch (af) {
     case AF_INET:
diff --git a/src/tests/asyncq-test.c b/src/tests/asyncq-test.c
index 538bbb1..eae8cce 100644
--- a/src/tests/asyncq-test.c
+++ b/src/tests/asyncq-test.c
@@ -51,7 +51,7 @@ static void consumer(void *_q) {
     void *p;
     int i;
 
-    sleep(1);
+    pa_msleep(1000);
 
     for (i = 0;; i++) {
         p = pa_asyncq_pop(q, TRUE);
diff --git a/src/tests/rtstutter.c b/src/tests/rtstutter.c
index 21f33bf..21e3cde 100644
--- a/src/tests/rtstutter.c
+++ b/src/tests/rtstutter.c
@@ -26,7 +26,6 @@
 #include <stdlib.h>
 #include <unistd.h>
 #include <time.h>
-#include <sched.h>
 #include <inttypes.h>
 #include <string.h>
 
@@ -34,25 +33,24 @@
 #include <pthread.h>
 #endif
 
+#include <pulse/util.h>
 #include <pulse/timeval.h>
 #include <pulse/gccmacro.h>
 
 #include <pulsecore/log.h>
 #include <pulsecore/macro.h>
+#include <pulsecore/thread.h>
 #include <pulsecore/core-util.h>
 
 static int msec_lower, msec_upper;
 
-static void* work(void *p) PA_GCC_NORETURN;
+static void work(void *p) PA_GCC_NORETURN;
 
-static void* work(void *p) {
-    struct sched_param param;
+static void work(void *p) {
 
     pa_log_notice("CPU%i: Created thread.", PA_PTR_TO_UINT(p));
 
-    memset(&param, 0, sizeof(param));
-    param.sched_priority = 12;
-    pa_assert_se(pthread_setschedparam(pthread_self(), SCHED_FIFO, &param) == 0);
+    pa_make_realtime(12);
 
 #ifdef HAVE_PTHREAD_SETAFFINITY_NP
 {
@@ -69,7 +67,7 @@ static void* work(void *p) {
         uint64_t nsec;
 
         pa_log_notice("CPU%i: Sleeping for 1s", PA_PTR_TO_UINT(p));
-        sleep(1);
+        pa_msleep(1000);
 
 #ifdef CLOCK_REALTIME
         pa_assert_se(clock_gettime(CLOCK_REALTIME, &end) == 0);
@@ -101,7 +99,7 @@ static void* work(void *p) {
 int main(int argc, char*argv[]) {
     unsigned n;
 
-    pa_log_set_level(PA_LOG_DEBUG);
+    pa_log_set_level(PA_LOG_INFO);
 
     srand((unsigned) time(NULL));
 
@@ -122,8 +120,7 @@ int main(int argc, char*argv[]) {
     pa_log_notice("Creating random latencies in the range of %ims to  %ims.", msec_lower, msec_upper);
 
     for (n = 1; n < pa_ncpus(); n++) {
-        pthread_t t;
-        pa_assert_se(pthread_create(&t, NULL, work, PA_UINT_TO_PTR(n)) == 0);
+        pa_assert_se(pa_thread_new("rtstutter", work, PA_UINT_TO_PTR(n)));
     }
 
     work(PA_INT_TO_PTR(0));

commit 30c7c9518440670ca3b627298c4e32885204882f
Author: Maarten Bosmans <mkbosmans at gmail.com>
Date:   Tue Jan 18 11:28:53 2011 +0100

    tests/rtstutter: Use pa_rtclock

diff --git a/src/tests/rtstutter.c b/src/tests/rtstutter.c
index 21e3cde..9ef835c 100644
--- a/src/tests/rtstutter.c
+++ b/src/tests/rtstutter.c
@@ -41,6 +41,7 @@
 #include <pulsecore/macro.h>
 #include <pulsecore/thread.h>
 #include <pulsecore/core-util.h>
+#include <pulsecore/core-rtclock.h>
 
 static int msec_lower, msec_upper;
 
@@ -63,36 +64,24 @@ static void work(void *p) {
 #endif
 
     for (;;) {
-        struct timespec now, end;
-        uint64_t nsec;
+        struct timeval now, end;
+        uint64_t usec;
 
         pa_log_notice("CPU%i: Sleeping for 1s", PA_PTR_TO_UINT(p));
         pa_msleep(1000);
 
-#ifdef CLOCK_REALTIME
-        pa_assert_se(clock_gettime(CLOCK_REALTIME, &end) == 0);
-#endif
-
-        nsec =
-            (uint64_t) ((((double) rand())*(double)(msec_upper-msec_lower)*PA_NSEC_PER_MSEC)/RAND_MAX) +
-            (uint64_t) ((uint64_t) msec_lower*PA_NSEC_PER_MSEC);
+        usec =
+            (uint64_t) ((((double) rand())*(double)(msec_upper-msec_lower)*PA_USEC_PER_MSEC)/RAND_MAX) +
+            (uint64_t) ((uint64_t) msec_lower*PA_USEC_PER_MSEC);
 
-        pa_log_notice("CPU%i: Freezing for %ims", PA_PTR_TO_UINT(p), (int) (nsec/PA_NSEC_PER_MSEC));
+        pa_log_notice("CPU%i: Freezing for %ims", PA_PTR_TO_UINT(p), (int) (usec/PA_USEC_PER_MSEC));
 
-        end.tv_sec += (time_t) (nsec / PA_NSEC_PER_SEC);
-        end.tv_nsec += (long int) (nsec % PA_NSEC_PER_SEC);
-
-        while ((pa_usec_t) end.tv_nsec > PA_NSEC_PER_SEC) {
-            end.tv_sec++;
-            end.tv_nsec -= (long int) PA_NSEC_PER_SEC;
-        }
+        pa_rtclock_get(&end);
+        pa_timeval_add(&end, usec);
 
         do {
-#ifdef CLOCK_REALTIME
-            pa_assert_se(clock_gettime(CLOCK_REALTIME, &now) == 0);
-#endif
-        } while (now.tv_sec < end.tv_sec ||
-                 (now.tv_sec == end.tv_sec && now.tv_nsec < end.tv_nsec));
+            pa_rtclock_get(&now);
+        } while (pa_timeval_cmp(&now, &end) < 0);
     }
 }
 

commit 821562b9bc8d1a9033daaae0fd5373498a085054
Author: Maarten Bosmans <mkbosmans at gmail.com>
Date:   Wed Jan 5 19:50:44 2011 +0100

    Use pa_read, pa_write and pa_poll instead of system functions

diff --git a/src/daemon/cpulimit.c b/src/daemon/cpulimit.c
index f5042a7..c1c2a6f 100644
--- a/src/daemon/cpulimit.c
+++ b/src/daemon/cpulimit.c
@@ -140,7 +140,7 @@ static void signal_handler(int sig) {
             write_err("Soft CPU time limit exhausted, terminating.\n");
 
             /* Try a soft cleanup */
-            (void) write(the_pipe[1], &c, sizeof(c));
+            (void) pa_write(the_pipe[1], &c, sizeof(c), NULL);
             phase = PHASE_SOFT;
             reset_cpu_time(CPUTIME_INTERVAL_HARD);
 
diff --git a/src/pulse/thread-mainloop.c b/src/pulse/thread-mainloop.c
index d8c82c8..ef4ef56 100644
--- a/src/pulse/thread-mainloop.c
+++ b/src/pulse/thread-mainloop.c
@@ -67,7 +67,7 @@ static int poll_func(struct pollfd *ufds, unsigned long nfds, int timeout, void
      * avahi_simple_poll_quit() can succeed from another thread. */
 
     pa_mutex_unlock(mutex);
-    r = poll(ufds, nfds, timeout);
+    r = pa_poll(ufds, nfds, timeout);
     pa_mutex_lock(mutex);
 
     return r;
diff --git a/src/pulsecore/fdsem.c b/src/pulsecore/fdsem.c
index 5bf9947..6238045 100644
--- a/src/pulsecore/fdsem.c
+++ b/src/pulsecore/fdsem.c
@@ -154,7 +154,7 @@ static void flush(pa_fdsem *f) {
         if (f->efd >= 0) {
             uint64_t u;
 
-            if ((r = read(f->efd, &u, sizeof(u))) != sizeof(u)) {
+            if ((r = pa_read(f->efd, &u, sizeof(u), NULL)) != sizeof(u)) {
 
                 if (r >= 0 || errno != EINTR) {
                     pa_log_error("Invalid read from eventfd: %s", r < 0 ? pa_cstrerror(errno) : "EOF");
@@ -167,7 +167,7 @@ static void flush(pa_fdsem *f) {
         } else
 #endif
 
-        if ((r = read(f->fds[0], &x, sizeof(x))) <= 0) {
+        if ((r = pa_read(f->fds[0], &x, sizeof(x), NULL)) <= 0) {
 
             if (r >= 0 || errno != EINTR) {
                 pa_log_error("Invalid read from pipe: %s", r < 0 ? pa_cstrerror(errno) : "EOF");
@@ -197,9 +197,9 @@ void pa_fdsem_post(pa_fdsem *f) {
                 if (f->efd >= 0) {
                     uint64_t u = 1;
 
-                    if ((r = write(f->efd, &u, sizeof(u))) != sizeof(u)) {
+                    if ((r = pa_write(f->efd, &u, sizeof(u), NULL)) != sizeof(u)) {
                         if (r >= 0 || errno != EINTR) {
-                            pa_log_error("Invalid read from pipe: %s", r < 0 ? pa_cstrerror(errno) : "EOF");
+                            pa_log_error("Invalid write to eventfd: %s", r < 0 ? pa_cstrerror(errno) : "EOF");
                             pa_assert_not_reached();
                         }
 
@@ -208,9 +208,9 @@ void pa_fdsem_post(pa_fdsem *f) {
                 } else
 #endif
 
-                if ((r = write(f->fds[1], &x, 1)) != 1) {
+                if ((r = pa_write(f->fds[1], &x, 1, NULL)) != 1) {
                     if (r >= 0 || errno != EINTR) {
-                        pa_log_error("Invalid read from pipe: %s", r < 0 ? pa_cstrerror(errno) : "EOF");
+                        pa_log_error("Invalid write to pipe: %s", r < 0 ? pa_cstrerror(errno) : "EOF");
                         pa_assert_not_reached();
                     }
 
@@ -241,10 +241,10 @@ void pa_fdsem_wait(pa_fdsem *f) {
         if (f->efd >= 0) {
             uint64_t u;
 
-            if ((r = read(f->efd, &u, sizeof(u))) != sizeof(u)) {
+            if ((r = pa_read(f->efd, &u, sizeof(u), NULL)) != sizeof(u)) {
 
                 if (r >= 0 || errno != EINTR) {
-                    pa_log_error("Invalid read from pipe: %s", r < 0 ? pa_cstrerror(errno) : "EOF");
+                    pa_log_error("Invalid read from eventfd: %s", r < 0 ? pa_cstrerror(errno) : "EOF");
                     pa_assert_not_reached();
                 }
 
@@ -255,7 +255,7 @@ void pa_fdsem_wait(pa_fdsem *f) {
         } else
 #endif
 
-        if ((r = read(f->fds[0], &x, sizeof(x))) <= 0) {
+        if ((r = pa_read(f->fds[0], &x, sizeof(x), NULL)) <= 0) {
 
             if (r >= 0 || errno != EINTR) {
                 pa_log_error("Invalid read from pipe: %s", r < 0 ? pa_cstrerror(errno) : "EOF");
diff --git a/src/pulsecore/lock-autospawn.c b/src/pulsecore/lock-autospawn.c
index 1a082db..a9c942f 100644
--- a/src/pulsecore/lock-autospawn.c
+++ b/src/pulsecore/lock-autospawn.c
@@ -161,7 +161,7 @@ static void ping(void) {
     for (;;) {
         char x = 'x';
 
-        if ((s = write(pipe_fd[1], &x, 1)) == 1)
+        if ((s = pa_write(pipe_fd[1], &x, 1, NULL)) == 1)
             break;
 
         pa_assert(s < 0);
@@ -188,7 +188,7 @@ static void wait_for_ping(void) {
     if ((k = pa_poll(&pfd, 1, -1)) != 1) {
         pa_assert(k < 0);
         pa_assert(errno == EINTR);
-    } else if ((s = read(pipe_fd[0], &x, 1)) != 1) {
+    } else if ((s = pa_read(pipe_fd[0], &x, 1, NULL)) != 1) {
         pa_assert(s < 0);
         pa_assert(errno == EAGAIN);
     }
@@ -200,7 +200,7 @@ static void empty_pipe(void) {
 
     pa_assert(pipe_fd[0] >= 0);
 
-    if ((s = read(pipe_fd[0], &x, sizeof(x))) < 1) {
+    if ((s = pa_read(pipe_fd[0], &x, sizeof(x), NULL)) < 1) {
         pa_assert(s < 0);
         pa_assert(errno == EAGAIN);
     }

commit a3dbdb044656e2f3ab9c7ae54fe74b9669155f2d
Merge: f51889c 821562b
Author: Colin Guthrie <cguthrie at mandriva.org>
Date:   Fri Feb 25 09:24:07 2011 +0000

    Merge remote-tracking branch 'mkbosmans/mingw32-build'

diff --cc configure.ac
index c5e8d6b,8b4f586..21dae30
--- a/configure.ac
+++ b/configure.ac
@@@ -1683,12 -1727,12 +1727,12 @@@ echo 
      Preopened modules:             ${PREOPEN_MODS}
  "
  
- if test "${ENABLE_DBUS}" = "no" ; then
+ if test "${ENABLE_DBUS}" = "no" && test "x$os_is_win32" != "x1" ; then
     echo "
  ===== WARNING WARNING WARNING WARNING WARNING WARNING WARNING =====
 -You do not have DBUS support enabled. It is strongly recommended
 -that you enable DBUS support if you platform supports it.
 -Many parts of PulseAudio use udev, from Console Kit interaction
 +You do not have D-Bus support enabled. It is strongly recommended
 +that you enable D-Bus support if your platform supports it.
 +Many parts of PulseAudio use D-Bus, from ConsoleKit interaction
  to the Device Reservation Protocol to speak to JACK, Bluetooth
  support and even a native control protocol for communicating and
  controling the PulseAudio daemon itself.

commit 6bd32ee2d960b7fe1930851c4006775f4c20374e
Author: Kim Therkelsen <kim_t26 at hotmail.com>
Date:   Fri Oct 15 09:14:31 2010 +0200

    Support for multichannel DSP processing in module-ladspa-sink

diff --git a/src/modules/module-ladspa-sink.c b/src/modules/module-ladspa-sink.c
index cdccf1a..f6430f2 100644
--- a/src/modules/module-ladspa-sink.c
+++ b/src/modules/module-ladspa-sink.c
@@ -50,19 +50,24 @@ PA_MODULE_DESCRIPTION(_("Virtual LADSPA sink"));
 PA_MODULE_VERSION(PACKAGE_VERSION);
 PA_MODULE_LOAD_ONCE(FALSE);
 PA_MODULE_USAGE(
-        _("sink_name=<name for the sink> "
-          "sink_properties=<properties for the sink> "
-          "master=<name of sink to filter> "
-          "format=<sample format> "
-          "rate=<sample rate> "
-          "channels=<number of channels> "
-          "channel_map=<channel map> "
-          "plugin=<ladspa plugin name> "
-          "label=<ladspa plugin label> "
-          "control=<comma seperated list of input control values>"));
+    _("sink_name=<name for the sink> "
+      "sink_properties=<properties for the sink> "
+      "master=<name of sink to filter> "
+      "format=<sample format> "
+      "rate=<sample rate> "
+      "channels=<number of channels> "
+      "channel_map=<input channel map> "
+      "plugin=<ladspa plugin name> "
+      "label=<ladspa plugin label> "
+      "control=<comma seperated list of input control values> "
+      "input_ladspaport_map=<comma separated list of input LADSPA port names> "
+      "output_ladspaport_map=<comma separated list of output LADSPA port names> "));
 
 #define MEMBLOCKQ_MAXLENGTH (16*1024*1024)
 
+/* PLEASE NOTICE: The PortAudio ports and the LADSPA ports are two different concepts.
+They are not related and where possible the names of the LADSPA port variables contains "ladspa" to avoid confusion */
+
 struct userdata {
     pa_module *module;
 
@@ -70,15 +75,14 @@ struct userdata {
     pa_sink_input *sink_input;
 
     const LADSPA_Descriptor *descriptor;
-    unsigned channels;
     LADSPA_Handle handle[PA_CHANNELS_MAX];
-    LADSPA_Data *input, *output;
+    unsigned long max_ladspaport_count, input_count, output_count, channels;
+    LADSPA_Data **input, **output;
     size_t block_size;
-    unsigned long input_port, output_port;
     LADSPA_Data *control;
 
     /* This is a dummy buffer. Every port must be connected, but we don't care
-       about control out ports. We connect them all to this single buffer. */
+    about control out ports. We connect them all to this single buffer. */
     LADSPA_Data control_out;
 
     pa_memblockq *memblockq;
@@ -97,6 +101,8 @@ static const char* const valid_modargs[] = {
     "plugin",
     "label",
     "control",
+    "input_ladspaport_map",
+    "output_ladspaport_map",
     NULL
 };
 
@@ -106,26 +112,26 @@ static int sink_process_msg_cb(pa_msgobject *o, int code, void *data, int64_t of
 
     switch (code) {
 
-        case PA_SINK_MESSAGE_GET_LATENCY:
+    case PA_SINK_MESSAGE_GET_LATENCY:
 
-            /* The sink is _put() before the sink input is, so let's
-             * make sure we don't access it in that time. Also, the
-             * sink input is first shut down, the sink second. */
-            if (!PA_SINK_IS_LINKED(u->sink->thread_info.state) ||
+        /* The sink is _put() before the sink input is, so let's
+         * make sure we don't access it in that time. Also, the
+         * sink input is first shut down, the sink second. */
+        if (!PA_SINK_IS_LINKED(u->sink->thread_info.state) ||
                 !PA_SINK_INPUT_IS_LINKED(u->sink_input->thread_info.state)) {
-                *((pa_usec_t*) data) = 0;
-                return 0;
-            }
+            *((pa_usec_t*) data) = 0;
+            return 0;
+        }
 
-            *((pa_usec_t*) data) =
+        *((pa_usec_t*) data) =
 
-                /* Get the latency of the master sink */
-                pa_sink_get_latency_within_thread(u->sink_input->sink) +
+            /* Get the latency of the master sink */
+            pa_sink_get_latency_within_thread(u->sink_input->sink) +
 
-                /* Add the latency internal to our sink input on top */
-                pa_bytes_to_usec(pa_memblockq_get_length(u->sink_input->thread_info.render_memblockq), &u->sink_input->sink->sample_spec);
+            /* Add the latency internal to our sink input on top */
+            pa_bytes_to_usec(pa_memblockq_get_length(u->sink_input->thread_info.render_memblockq), &u->sink_input->sink->sample_spec);
 
-            return 0;
+        return 0;
     }
 
     return pa_sink_process_msg(o, code, data, offset, chunk);
@@ -139,7 +145,7 @@ static int sink_set_state_cb(pa_sink *s, pa_sink_state_t state) {
     pa_assert_se(u = s->userdata);
 
     if (!PA_SINK_IS_LINKED(state) ||
-        !PA_SINK_INPUT_IS_LINKED(pa_sink_input_get_state(u->sink_input)))
+            !PA_SINK_INPUT_IS_LINKED(pa_sink_input_get_state(u->sink_input)))
         return 0;
 
     pa_sink_input_cork(u->sink_input, state == PA_SINK_SUSPENDED);
@@ -154,7 +160,7 @@ static void sink_request_rewind_cb(pa_sink *s) {
     pa_assert_se(u = s->userdata);
 
     if (!PA_SINK_IS_LINKED(u->sink->thread_info.state) ||
-        !PA_SINK_INPUT_IS_LINKED(u->sink_input->thread_info.state))
+            !PA_SINK_INPUT_IS_LINKED(u->sink_input->thread_info.state))
         return;
 
     /* Just hand this one over to the master sink */
@@ -171,13 +177,13 @@ static void sink_update_requested_latency_cb(pa_sink *s) {
     pa_assert_se(u = s->userdata);
 
     if (!PA_SINK_IS_LINKED(u->sink->thread_info.state) ||
-        !PA_SINK_INPUT_IS_LINKED(u->sink_input->thread_info.state))
+            !PA_SINK_INPUT_IS_LINKED(u->sink_input->thread_info.state))
         return;
 
     /* Just hand this one over to the master sink */
     pa_sink_input_set_requested_latency_within_thread(
-            u->sink_input,
-            pa_sink_get_requested_latency_within_thread(s));
+        u->sink_input,
+        pa_sink_get_requested_latency_within_thread(s));
 }
 
 /* Called from main context */
@@ -188,7 +194,7 @@ static void sink_set_volume_cb(pa_sink *s) {
     pa_assert_se(u = s->userdata);
 
     if (!PA_SINK_IS_LINKED(pa_sink_get_state(s)) ||
-        !PA_SINK_INPUT_IS_LINKED(pa_sink_input_get_state(u->sink_input)))
+            !PA_SINK_INPUT_IS_LINKED(pa_sink_input_get_state(u->sink_input)))
         return;
 
     pa_sink_input_set_volume(u->sink_input, &s->real_volume, s->save_volume, TRUE);
@@ -202,7 +208,7 @@ static void sink_set_mute_cb(pa_sink *s) {
     pa_assert_se(u = s->userdata);
 
     if (!PA_SINK_IS_LINKED(pa_sink_get_state(s)) ||
-        !PA_SINK_INPUT_IS_LINKED(pa_sink_input_get_state(u->sink_input)))
+            !PA_SINK_INPUT_IS_LINKED(pa_sink_input_get_state(u->sink_input)))
         return;
 
     pa_sink_input_set_mute(u->sink_input, s->muted, s->save_muted);
@@ -213,7 +219,7 @@ static int sink_input_pop_cb(pa_sink_input *i, size_t nbytes, pa_memchunk *chunk
     struct userdata *u;
     float *src, *dst;
     size_t fs;
-    unsigned n, c;
+    unsigned n, h, c;
     pa_memchunk tchunk;
 
     pa_sink_input_assert_ref(i);
@@ -248,10 +254,12 @@ static int sink_input_pop_cb(pa_sink_input *i, size_t nbytes, pa_memchunk *chunk
     src = (float*) ((uint8_t*) pa_memblock_acquire(tchunk.memblock) + tchunk.index);
     dst = (float*) pa_memblock_acquire(chunk->memblock);
 
-    for (c = 0; c < u->channels; c++) {
-        pa_sample_clamp(PA_SAMPLE_FLOAT32NE, u->input, sizeof(float), src+c, u->channels*sizeof(float), n);
-        u->descriptor->run(u->handle[c], n);
-        pa_sample_clamp(PA_SAMPLE_FLOAT32NE, dst+c, u->channels*sizeof(float), u->output, sizeof(float), n);
+    for (h = 0; h < (u->channels / u->max_ladspaport_count); h++) {
+        for (c = 0; c < u->input_count; c++)
+            pa_sample_clamp(PA_SAMPLE_FLOAT32NE, u->input[c], sizeof(float), src+ h*u->max_ladspaport_count + c, u->channels*sizeof(float), n);
+        u->descriptor->run(u->handle[h], n);
+        for (c = 0; c < u->output_count; c++)
+            pa_sample_clamp(PA_SAMPLE_FLOAT32NE, dst + h*u->max_ladspaport_count + c, u->channels*sizeof(float), u->output[c], sizeof(float), n);
     }
 
     pa_memblock_release(tchunk.memblock);
@@ -286,10 +294,10 @@ static void sink_input_process_rewind_cb(pa_sink_input *i, size_t nbytes) {
 
             /* Reset the plugin */
             if (u->descriptor->deactivate)
-                for (c = 0; c < u->channels; c++)
+                for (c = 0; c < (u->channels / u->max_ladspaport_count); c++)
                     u->descriptor->deactivate(u->handle[c]);
             if (u->descriptor->activate)
-                for (c = 0; c < u->channels; c++)
+                for (c = 0; c < (u->channels / u->max_ladspaport_count); c++)
                     u->descriptor->activate(u->handle[c]);
         }
     }
@@ -399,7 +407,7 @@ static void sink_input_state_change_cb(pa_sink_input *i, pa_sink_input_state_t s
     /* If we are added for the first time, ask for a rewinding so that
      * we are heard right-away. */
     if (PA_SINK_INPUT_IS_LINKED(state) &&
-        i->thread_info.state == PA_SINK_INPUT_INIT) {
+            i->thread_info.state == PA_SINK_INPUT_INIT) {
         pa_log_debug("Requesting rewind due to state change.");
         pa_sink_input_request_rewind(i, 0, FALSE, TRUE, TRUE);
     }
@@ -471,14 +479,13 @@ int pa__init(pa_module*m) {
     pa_sink *master;
     pa_sink_input_new_data sink_input_data;
     pa_sink_new_data sink_data;
-    const char *plugin, *label;
+    const char *plugin, *label, *input_ladspaport_map, *output_ladspaport_map;
     LADSPA_Descriptor_Function descriptor_func;
+    unsigned long input_ladspaport[PA_CHANNELS_MAX], output_ladspaport[PA_CHANNELS_MAX];
     const char *e, *cdata;
     const LADSPA_Descriptor *d;
-    unsigned long input_port, output_port, p, j, n_control;
-    unsigned c;
+    unsigned long p, h, j, n_control, c;
     pa_bool_t *use_default = NULL;
-    pa_memchunk silence;
 
     pa_assert(m);
 
@@ -512,15 +519,22 @@ int pa__init(pa_module*m) {
         goto fail;
     }
 
+    if (!(input_ladspaport_map = pa_modargs_get_value(ma, "input_ladspaport_map", NULL)))
+        pa_log_debug("Using default input ladspa port mapping");
+
+    if (!(output_ladspaport_map = pa_modargs_get_value(ma, "output_ladspaport_map", NULL)))
+        pa_log_debug("Using default output ladspa port mapping");
+
     cdata = pa_modargs_get_value(ma, "control", NULL);
 
     u = pa_xnew0(struct userdata, 1);
     u->module = m;
     m->userdata = u;
-
-    pa_silence_memchunk_get(&m->core->silence_cache, m->core->mempool, &silence, &ss, 0);
-    u->memblockq = pa_memblockq_new(0, MEMBLOCKQ_MAXLENGTH, 0, pa_frame_size(&ss), 1, 1, 0, &silence);
-    pa_memblock_unref(silence.memblock);
+    u->memblockq = pa_memblockq_new(0, MEMBLOCKQ_MAXLENGTH, 0, pa_frame_size(&ss), 1, 1, 0, NULL);
+    u->max_ladspaport_count = 1; /*to avoid division by zero etc. in pa__done when failing before this value has been set*/
+    u->channels = 0;
+    u->input = NULL;
+    u->output = NULL;
 
     if (!(e = getenv("LADSPA_PATH")))
         e = LADSPA_PATH;
@@ -562,64 +576,127 @@ int pa__init(pa_module*m) {
     pa_log_debug("Maker: %s", d->Maker);
     pa_log_debug("Copyright: %s", d->Copyright);
 
-    input_port = output_port = (unsigned long) -1;
     n_control = 0;
+    u->channels = ss.channels;
 
+    /*
+    * Enumerate ladspa ports
+    * Default mapping is in order given by the plugin
+    */
     for (p = 0; p < d->PortCount; p++) {
+        if (LADSPA_IS_PORT_AUDIO(d->PortDescriptors[p])) {
+            if (LADSPA_IS_PORT_INPUT(d->PortDescriptors[p])) {
+                pa_log_debug("Port %lu is input: %s", p, d->PortNames[p]);
+                input_ladspaport[u->input_count] = p;
+                u->input_count++;
+            } else if (LADSPA_IS_PORT_OUTPUT(d->PortDescriptors[p])) {
+                pa_log_debug("Port %lu is output: %s", p, d->PortNames[p]);
+                output_ladspaport[u->output_count] = p;
+                u->output_count++;
+            }
+        } else if (LADSPA_IS_PORT_CONTROL(d->PortDescriptors[p]) && LADSPA_IS_PORT_INPUT(d->PortDescriptors[p])) {
+            pa_log_debug("Port %lu is control: %s", p, d->PortNames[p]);
+            n_control++;
+        } else
+            pa_log_debug("Ignored port %s", d->PortNames[p]);
+        /* XXX: Has anyone ever seen an in-place plugin with non-equal number of input and output ports? */
+        /* Could be if the plugin is for up-mixing stereo to 5.1 channels */
+        /* Or if the plugin is down-mixing 5.1 to two channel stereo or binaural encoded signal */
+        if (u->input_count > u->max_ladspaport_count)
+            u->max_ladspaport_count = u->input_count;
+        else
+            u->max_ladspaport_count = u->output_count;
+    }
+
+    if (u->channels % u->max_ladspaport_count) {
+        pa_log("Cannot handle non-integral number of plugins required for given number of channels");
+        goto fail;
+    }
 
-        if (LADSPA_IS_PORT_INPUT(d->PortDescriptors[p]) && LADSPA_IS_PORT_AUDIO(d->PortDescriptors[p])) {
+    pa_log_debug("Will run %lu plugin instances", u->channels / u->max_ladspaport_count);
 
-            if (strcmp(d->PortNames[p], "Input") == 0) {
-                pa_assert(input_port == (unsigned long) -1);
-                input_port = p;
-            } else {
-                pa_log("Found audio input port on plugin we cannot handle: %s", d->PortNames[p]);
+    /* Parse data for input ladspa port map */
+    if (input_ladspaport_map) {
+        const char *state = NULL;
+        char *pname;
+        c = 0;
+        while ((pname = pa_split(input_ladspaport_map, ",", &state))) {
+            if (c == u->input_count) {
+                pa_log("Too many ports in input ladspa port map");
                 goto fail;
             }
 
-        } else if (LADSPA_IS_PORT_OUTPUT(d->PortDescriptors[p]) && LADSPA_IS_PORT_AUDIO(d->PortDescriptors[p])) {
 
-            if (strcmp(d->PortNames[p], "Output") == 0) {
-                pa_assert(output_port == (unsigned long) -1);
-                output_port = p;
-            } else {
-                pa_log("Found audio output port on plugin we cannot handle: %s", d->PortNames[p]);
-                goto fail;
+            for (p = 0; p < d->PortCount; p++) {
+                if (strcmp(d->PortNames[p], pname) == 0) {
+                    if (LADSPA_IS_PORT_AUDIO(d->PortDescriptors[p]) && LADSPA_IS_PORT_INPUT(d->PortDescriptors[p])) {
+                        input_ladspaport[c] = p;
+                    } else {
+                        pa_log("Port %s is not an audio input ladspa port", pname);
+                        pa_xfree(pname);
+                        goto fail;
+                    }
+                }
             }
-
-        } else if (LADSPA_IS_PORT_INPUT(d->PortDescriptors[p]) && LADSPA_IS_PORT_CONTROL(d->PortDescriptors[p]))
-            n_control++;
-        else {
-            pa_assert(LADSPA_IS_PORT_OUTPUT(d->PortDescriptors[p]) && LADSPA_IS_PORT_CONTROL(d->PortDescriptors[p]));
-            pa_log_debug("Ignored control output port \"%s\".", d->PortNames[p]);
+            c++;
+            pa_xfree(pname);
         }
     }
 
-    if ((input_port == (unsigned long) -1) || (output_port == (unsigned long) -1)) {
-        pa_log("Failed to identify input and output ports. "
-               "Right now this module can only deal with plugins which provide an 'Input' and an 'Output' audio port. "
-               "Patches welcome!");
-        goto fail;
+    /* Parse data for output port map */
+    if (output_ladspaport_map) {
+        const char *state = NULL;
+        char *pname;
+        c = 0;
+        while ((pname = pa_split(output_ladspaport_map, ",", &state))) {
+            if (c == u->output_count) {
+                pa_log("Too many ports in output ladspa port map");
+                goto fail;
+            }
+            for (p = 0; p < d->PortCount; p++) {
+                if (strcmp(d->PortNames[p], pname) == 0) {
+                    if (LADSPA_IS_PORT_AUDIO(d->PortDescriptors[p]) && LADSPA_IS_PORT_OUTPUT(d->PortDescriptors[p])) {
+                        output_ladspaport[c] = p;
+                    } else {
+                        pa_log("Port %s is not an output ladspa port", pname);
+                        pa_xfree(pname);
+                        goto fail;
+                    }
+                }
+            }
+            c++;
+            pa_xfree(pname);
+        }
     }
 
+
     u->block_size = pa_frame_align(pa_mempool_block_size_max(m->core->mempool), &ss);
 
-    u->input = (LADSPA_Data*) pa_xnew(uint8_t, (unsigned) u->block_size);
-    if (LADSPA_IS_INPLACE_BROKEN(d->Properties))
-        u->output = (LADSPA_Data*) pa_xnew(uint8_t, (unsigned) u->block_size);
-    else
+    /* Create buffers */
+    if (LADSPA_IS_INPLACE_BROKEN(d->Properties)) {
+        u->input = (LADSPA_Data**) pa_xnew(LADSPA_Data*, (unsigned) u->input_count);
+        for (c = 0; c < u->input_count; c++)
+            u->input[c] = (LADSPA_Data*) pa_xnew(uint8_t, (unsigned) u->block_size);
+        u->output = (LADSPA_Data**) pa_xnew(LADSPA_Data*, (unsigned) u->output_count);
+        for (c = 0; c < u->output_count; c++)
+            u->output[c] = (LADSPA_Data*) pa_xnew(uint8_t, (unsigned) u->block_size);
+    } else {
+        u->input = (LADSPA_Data**) pa_xnew(LADSPA_Data*, (unsigned) u->max_ladspaport_count);
+        for (c = 0; c < u->max_ladspaport_count; c++)
+            u->input[c] = (LADSPA_Data*) pa_xnew(uint8_t, (unsigned) u->block_size);
         u->output = u->input;
-
-    u->channels = ss.channels;
-
-    for (c = 0; c < ss.channels; c++) {
-        if (!(u->handle[c] = d->instantiate(d, ss.rate))) {
-            pa_log("Failed to instantiate plugin %s with label %s for channel %i", plugin, d->Label, c);
+    }
+    /* Initialize plugin instances */
+    for (h = 0; h < (u->channels / u->max_ladspaport_count); h++) {
+        if (!(u->handle[h] = d->instantiate(d, ss.rate))) {
+            pa_log("Failed to instantiate plugin %s with label %s", plugin, d->Label);
             goto fail;
         }
 
-        d->connect_port(u->handle[c], input_port, u->input);
-        d->connect_port(u->handle[c], output_port, u->output);
+        for (c = 0; c < u->input_count; c++)
+            d->connect_port(u->handle[h], input_ladspaport[c], u->input[c]);
+        for (c = 0; c < u->output_count; c++)
+            d->connect_port(u->handle[h], output_ladspaport[c], u->output[c]);
     }
 
     if (!cdata && n_control > 0) {
@@ -630,7 +707,6 @@ int pa__init(pa_module*m) {
     if (n_control > 0) {
         const char *state = NULL;
         char *k;
-        unsigned long h;
 
         u->control = pa_xnew(LADSPA_Data, (unsigned) n_control);
         use_default = pa_xnew(pa_bool_t, (unsigned) n_control);
@@ -658,7 +734,7 @@ int pa__init(pa_module*m) {
         }
 
         /* The previous loop doesn't take the last control value into account
-           if it is left empty, so we do it here. */
+        if it is left empty, so we do it here. */
         if (*cdata == 0 || cdata[strlen(cdata) - 1] == ',') {
             if (p < n_control)
                 use_default[p] = TRUE;
@@ -684,7 +760,7 @@ int pa__init(pa_module*m) {
                 continue;
 
             if (LADSPA_IS_PORT_OUTPUT(d->PortDescriptors[p])) {
-                for (c = 0; c < ss.channels; c++)
+                for (c = 0; c < (u->channels / u->max_ladspaport_count); c++)
                     d->connect_port(u->handle[c], p, &u->control_out);
                 continue;
             }
@@ -709,53 +785,53 @@ int pa__init(pa_module*m) {
 
                 switch (hint & LADSPA_HINT_DEFAULT_MASK) {
 
-                    case LADSPA_HINT_DEFAULT_MINIMUM:
-                        u->control[h] = lower;
-                        break;
-
-                    case LADSPA_HINT_DEFAULT_MAXIMUM:
-                        u->control[h] = upper;
-                        break;
-
-                    case LADSPA_HINT_DEFAULT_LOW:
-                        if (LADSPA_IS_HINT_LOGARITHMIC(hint))
-                            u->control[h] = (LADSPA_Data) exp(log(lower) * 0.75 + log(upper) * 0.25);
-                        else
-                            u->control[h] = (LADSPA_Data) (lower * 0.75 + upper * 0.25);
-                        break;
-
-                    case LADSPA_HINT_DEFAULT_MIDDLE:
-                        if (LADSPA_IS_HINT_LOGARITHMIC(hint))
-                            u->control[h] = (LADSPA_Data) exp(log(lower) * 0.5 + log(upper) * 0.5);
-                        else
-                            u->control[h] = (LADSPA_Data) (lower * 0.5 + upper * 0.5);
-                        break;
-
-                    case LADSPA_HINT_DEFAULT_HIGH:
-                        if (LADSPA_IS_HINT_LOGARITHMIC(hint))
-                            u->control[h] = (LADSPA_Data) exp(log(lower) * 0.25 + log(upper) * 0.75);
-                        else
-                            u->control[h] = (LADSPA_Data) (lower * 0.25 + upper * 0.75);
-                        break;
-
-                    case LADSPA_HINT_DEFAULT_0:
-                        u->control[h] = 0;
-                        break;
-
-                    case LADSPA_HINT_DEFAULT_1:
-                        u->control[h] = 1;
-                        break;
-
-                    case LADSPA_HINT_DEFAULT_100:
-                        u->control[h] = 100;
-                        break;
-
-                    case LADSPA_HINT_DEFAULT_440:
-                        u->control[h] = 440;
-                        break;
-
-                    default:
-                        pa_assert_not_reached();
+                case LADSPA_HINT_DEFAULT_MINIMUM:
+                    u->control[h] = lower;
+                    break;
+
+                case LADSPA_HINT_DEFAULT_MAXIMUM:
+                    u->control[h] = upper;
+                    break;
+
+                case LADSPA_HINT_DEFAULT_LOW:
+                    if (LADSPA_IS_HINT_LOGARITHMIC(hint))
+                        u->control[h] = (LADSPA_Data) exp(log(lower) * 0.75 + log(upper) * 0.25);
+                    else
+                        u->control[h] = (LADSPA_Data) (lower * 0.75 + upper * 0.25);
+                    break;
+
+                case LADSPA_HINT_DEFAULT_MIDDLE:
+                    if (LADSPA_IS_HINT_LOGARITHMIC(hint))
+                        u->control[h] = (LADSPA_Data) exp(log(lower) * 0.5 + log(upper) * 0.5);
+                    else
+                        u->control[h] = (LADSPA_Data) (lower * 0.5 + upper * 0.5);
+                    break;
+
+                case LADSPA_HINT_DEFAULT_HIGH:
+                    if (LADSPA_IS_HINT_LOGARITHMIC(hint))
+                        u->control[h] = (LADSPA_Data) exp(log(lower) * 0.25 + log(upper) * 0.75);
+                    else
+                        u->control[h] = (LADSPA_Data) (lower * 0.25 + upper * 0.75);
+                    break;
+
+                case LADSPA_HINT_DEFAULT_0:
+                    u->control[h] = 0;
+                    break;
+
+                case LADSPA_HINT_DEFAULT_1:
+                    u->control[h] = 1;
+                    break;
+
+                case LADSPA_HINT_DEFAULT_100:
+                    u->control[h] = 100;
+                    break;
+
+                case LADSPA_HINT_DEFAULT_440:
+                    u->control[h] = 440;
+                    break;
+
+                default:
+                    pa_assert_not_reached();
                 }
             }
 
@@ -764,7 +840,7 @@ int pa__init(pa_module*m) {
 
             pa_log_debug("Binding %f to port %s", u->control[h], d->PortNames[p]);
 
-            for (c = 0; c < ss.channels; c++)
+            for (c = 0; c < (u->channels / u->max_ladspaport_count); c++)
                 d->connect_port(u->handle[c], p, &u->control[h]);
 
             h++;
@@ -774,7 +850,7 @@ int pa__init(pa_module*m) {
     }
 
     if (d->activate)
-        for (c = 0; c < u->channels; c++)
+        for (c = 0; c < (u->channels / u->max_ladspaport_count); c++)
             d->activate(u->handle[c]);
 
     /* Create sink */
@@ -866,7 +942,6 @@ int pa__init(pa_module*m) {
     pa_sink_input_put(u->sink_input);
 
     pa_modargs_free(ma);
-
     pa_xfree(use_default);
 
     return 0;
@@ -901,7 +976,7 @@ void pa__done(pa_module*m) {
         return;
 
     /* See comments in sink_input_kill_cb() above regarding
-     * destruction order! */
+    * destruction order! */
 
     if (u->sink_input)
         pa_sink_input_unlink(u->sink_input);
@@ -915,21 +990,36 @@ void pa__done(pa_module*m) {
     if (u->sink)
         pa_sink_unref(u->sink);
 
-    for (c = 0; c < u->channels; c++)
+    for (c = 0; c < (u->channels / u->max_ladspaport_count); c++) {
         if (u->handle[c]) {
             if (u->descriptor->deactivate)
                 u->descriptor->deactivate(u->handle[c]);
             u->descriptor->cleanup(u->handle[c]);
         }
+    }
 
-    if (u->output != u->input)
-        pa_xfree(u->output);
+    if (u->output == u->input) {
+        if (u->input != NULL) {
+            for (c = 0; c < u->max_ladspaport_count; c++)
+                pa_xfree(u->input[c]);
+            pa_xfree(u->input);
+        }
+    } else {
+        if (u->input != NULL) {
+            for (c = 0; c < u->input_count; c++)
+                pa_xfree(u->input[c]);
+            pa_xfree(u->input);
+        }
+        if (u->output != NULL) {
+            for (c = 0; c < u->output_count; c++)
+                pa_xfree(u->output[c]);
+            pa_xfree(u->output);
+        }
+    }
 
     if (u->memblockq)
         pa_memblockq_free(u->memblockq);
 
-    pa_xfree(u->input);
     pa_xfree(u->control);
-
     pa_xfree(u);
 }

commit 9379d4015c48ed15a9f5bde8dac085dbca08bea3
Author: Kim Therkelsen <kim_t26 at hotmail.com>
Date:   Fri Oct 15 09:25:12 2010 +0200

    core: Added new hooks: PA_CORE_HOOK_SOURCE_PORT_CHANGED and PA_CORE_HOOK_SINK_PORT_CHANGED
    
    This allows modules to know when certain ports are changed.
    This will allow e.g. a filter module (or LADSAP) to only load
    when a certain port is used on the device (e.g. to only filter
    headphones and not normal speakers).
    
    (Comment from Colin Guthrie: This may also have use in UCM)

diff --git a/src/pulsecore/core.h b/src/pulsecore/core.h
index a1215bb..daa89c1 100644
--- a/src/pulsecore/core.h
+++ b/src/pulsecore/core.h
@@ -74,6 +74,7 @@ typedef enum pa_core_hook {
     PA_CORE_HOOK_SINK_UNLINK_POST,
     PA_CORE_HOOK_SINK_STATE_CHANGED,
     PA_CORE_HOOK_SINK_PROPLIST_CHANGED,
+    PA_CORE_HOOK_SINK_PORT_CHANGED,
     PA_CORE_HOOK_SOURCE_NEW,
     PA_CORE_HOOK_SOURCE_FIXATE,
     PA_CORE_HOOK_SOURCE_PUT,
@@ -81,6 +82,7 @@ typedef enum pa_core_hook {
     PA_CORE_HOOK_SOURCE_UNLINK_POST,
     PA_CORE_HOOK_SOURCE_STATE_CHANGED,
     PA_CORE_HOOK_SOURCE_PROPLIST_CHANGED,
+    PA_CORE_HOOK_SOURCE_PORT_CHANGED,
     PA_CORE_HOOK_SINK_INPUT_NEW,
     PA_CORE_HOOK_SINK_INPUT_FIXATE,
     PA_CORE_HOOK_SINK_INPUT_PUT,
diff --git a/src/pulsecore/sink.c b/src/pulsecore/sink.c
index 0de544c..773123d 100644
--- a/src/pulsecore/sink.c
+++ b/src/pulsecore/sink.c
@@ -2700,6 +2700,8 @@ int pa_sink_set_port(pa_sink *s, const char *name, pa_bool_t save) {
     s->active_port = port;
     s->save_port = save;
 
+    pa_hook_fire(&s->core->hooks[PA_CORE_HOOK_SINK_PORT_CHANGED], s);
+
     return 0;
 }
 
diff --git a/src/pulsecore/source.c b/src/pulsecore/source.c
index 24d0ff6..a553662 100644
--- a/src/pulsecore/source.c
+++ b/src/pulsecore/source.c
@@ -1571,5 +1571,7 @@ int pa_source_set_port(pa_source *s, const char *name, pa_bool_t save) {
     s->active_port = port;
     s->save_port = save;
 
+    pa_hook_fire(&s->core->hooks[PA_CORE_HOOK_SOURCE_PORT_CHANGED], s);
+
     return 0;
 }

commit 3153b60a62fec0a3d826b3c0427044d1a11df3a1
Author: Colin Guthrie <cguthrie at mandriva.org>
Date:   Fri Feb 25 10:27:23 2011 +0000

    core: Add a new hook PA_CORE_HOOK_CARD_PROFILE_CHANGED
    
    This will allow modules to know when a card profile has changed
    and take appropriate action. This might prove useful when developing
    UCM so that the appropriate verb can be set.

diff --git a/src/pulsecore/card.c b/src/pulsecore/card.c
index 2f0a3af..feaa444 100644
--- a/src/pulsecore/card.c
+++ b/src/pulsecore/card.c
@@ -241,6 +241,8 @@ int pa_card_set_profile(pa_card *c, const char *name, pa_bool_t save) {
     c->active_profile = profile;
     c->save_profile = save;
 
+    pa_hook_fire(&c->core->hooks[PA_CORE_HOOK_CARD_PROFILE_CHANGED], c);
+
     return 0;
 }
 
diff --git a/src/pulsecore/core.h b/src/pulsecore/core.h
index daa89c1..358b98d 100644
--- a/src/pulsecore/core.h
+++ b/src/pulsecore/core.h
@@ -113,6 +113,7 @@ typedef enum pa_core_hook {
     PA_CORE_HOOK_CARD_NEW,
     PA_CORE_HOOK_CARD_PUT,
     PA_CORE_HOOK_CARD_UNLINK,
+    PA_CORE_HOOK_CARD_PROFILE_CHANGED,
     PA_CORE_HOOK_MAX
 } pa_core_hook_t;
 

commit 46359043c45df4a89cd73eb0c4ca655c6b90f6d2
Author: Tanu Kaskinen <tanu.kaskinen at digia.com>
Date:   Fri Feb 25 16:27:27 2011 +0200

    alsa-mixer: Fix path set building when using the element-output or element-input mapping options in profile set configuration.
    
    When creating synthesized paths, pa_alsa_path_set_new() created duplicate
    elements for each path, and one of the duplicate elements would be marked as
    required absent. That made path probing fail. While debugging this, I noticed
    also that pa_alsa_path_synthesize() didn't initialize p->last_element properly.

diff --git a/src/modules/alsa/alsa-mixer.c b/src/modules/alsa/alsa-mixer.c
index 946cbe2..7d811a8 100644
--- a/src/modules/alsa/alsa-mixer.c
+++ b/src/modules/alsa/alsa-mixer.c
@@ -1992,6 +1992,7 @@ pa_alsa_path* pa_alsa_path_synthesize(const char*element, pa_alsa_direction_t di
     e->volume_use = PA_ALSA_VOLUME_MERGE;
 
     PA_LLIST_PREPEND(pa_alsa_element, p->elements, e);
+    p->last_element = e;
     return p;
 }
 
@@ -2390,6 +2391,10 @@ pa_alsa_path_set *pa_alsa_path_set_new(pa_alsa_mapping *m, pa_alsa_direction_t d
         /* Mark all other passed elements for require-absent */
         for (je = en; *je; je++) {
             pa_alsa_element *e;
+
+            if (je == ie)
+                continue;
+
             e = pa_xnew0(pa_alsa_element, 1);
             e->path = p;
             e->alsa_name = pa_xstrdup(*je);

commit 624152dac3ba253940fd893ee9e0f0cdb50cfa0f
Author: Tanu Kaskinen <tanu.kaskinen at digia.com>
Date:   Fri Feb 25 16:28:10 2011 +0200

    alsa-card: Add a new modarg "profile_set" for giving the card a custom profile set configuration file.

diff --git a/src/modules/alsa/module-alsa-card.c b/src/modules/alsa/module-alsa-card.c
index ebd2f8a..3f8576d 100644
--- a/src/modules/alsa/module-alsa-card.c
+++ b/src/modules/alsa/module-alsa-card.c
@@ -65,7 +65,8 @@ PA_MODULE_USAGE(
         "tsched_buffer_watermark=<lower fill watermark> "
         "profile=<profile name> "
         "ignore_dB=<ignore dB information from the device?> "
-        "sync_volume=<syncronize sw and hw voluchanges in IO-thread?>");
+        "sync_volume=<syncronize sw and hw voluchanges in IO-thread?> "
+        "profile_set=<profile set configuration file> ");
 
 static const char* const valid_modargs[] = {
     "name",
@@ -88,6 +89,7 @@ static const char* const valid_modargs[] = {
     "profile",
     "ignore_dB",
     "sync_volume",
+    "profile_set",
     NULL
 };
 
@@ -328,6 +330,11 @@ int pa__init(pa_module *m) {
     fn = pa_udev_get_property(alsa_card_index, "PULSE_PROFILE_SET");
 #endif
 
+    if (pa_modargs_get_value(ma, "profile_set", NULL)) {
+        pa_xfree(fn);
+        fn = pa_xstrdup(pa_modargs_get_value(ma, "profile_set", NULL));
+    }
+
     u->profile_set = pa_alsa_profile_set_new(fn, &u->core->default_channel_map);
     pa_xfree(fn);
 

commit 0ce3017b7407ab1c4094f7ce271bb68319a7eba7
Author: David Henningsson <david.henningsson at canonical.com>
Date:   Mon Dec 20 11:13:37 2010 +0100

    alsa-mixer: Add a few well-known descriptions
    
    Add front mic, rear mic, and docking line-in. These are likely to be
    present on modern hda chips, for reference see
    linux-2.6/sound/pci/hda/hda_codec.c:hda_get_input_pin_label
    
    Signed-off-by: David Henningsson <david.henningsson at canonical.com>

diff --git a/src/modules/alsa/alsa-mixer.c b/src/modules/alsa/alsa-mixer.c
index 7d811a8..c1bbdce 100644
--- a/src/modules/alsa/alsa-mixer.c
+++ b/src/modules/alsa/alsa-mixer.c
@@ -1804,8 +1804,11 @@ static int option_verify(pa_alsa_option *o) {
         { "input",                     N_("Input") },
         { "input-docking",             N_("Docking Station Input") },
         { "input-docking-microphone",  N_("Docking Station Microphone") },
+        { "input-docking-linein",      N_("Docking Station Line-In") },
         { "input-linein",              N_("Line-In") },
         { "input-microphone",          N_("Microphone") },
+        { "input-microphone-front",    N_("Front Microphone") },
+        { "input-microphone-rear",     N_("Rear Microphone") },
         { "input-microphone-external", N_("External Microphone") },
         { "input-microphone-internal", N_("Internal Microphone") },
         { "input-radio",               N_("Radio") },
@@ -1879,6 +1882,10 @@ static int path_verify(pa_alsa_path *p) {
     static const struct description_map well_known_descriptions[] = {
         { "analog-input",               N_("Analog Input") },
         { "analog-input-microphone",    N_("Analog Microphone") },
+        { "analog-input-microphone-front",    N_("Front Microphone") },
+        { "analog-input-microphone-rear",     N_("Rear Microphone") },
+        { "analog-input-microphone-dock",     N_("Docking Station Microphone") },
+        { "analog-input-microphone-internal", N_("Internal Microphone") },
         { "analog-input-linein",        N_("Analog Line-In") },
         { "analog-input-radio",         N_("Analog Radio") },
         { "analog-input-video",         N_("Analog Video") },

commit b0f72311cf49e25ea05279e3a978bb4db54dd332
Author: David Henningsson <david.henningsson at canonical.com>
Date:   Mon Dec 20 12:29:27 2010 +0100

    alsa-mixer: add required-any and required-* for enum options
    
    Now you can add required-any to elements in a path and the path
    will be valid as long as at least one of the elements are present.
    Also you can have required, required-any and required-absent in
    element options, causing a path to be unsupported if an option is
    (not) present (simplified example: to skip line in path if
    "Capture source" doesn't have a "Line In" option).
    
    Signed-off-by: David Henningsson <david.henningsson at canonical.com>

diff --git a/src/modules/alsa/alsa-mixer.c b/src/modules/alsa/alsa-mixer.c
index c1bbdce..967140b 100644
--- a/src/modules/alsa/alsa-mixer.c
+++ b/src/modules/alsa/alsa-mixer.c
@@ -1121,6 +1121,41 @@ static int check_required(pa_alsa_element *e, snd_mixer_elem_t *me) {
     if (e->required_absent == PA_ALSA_REQUIRED_ANY && (has_switch || has_volume || has_enumeration))
         return -1;
 
+    if (e->required_any != PA_ALSA_REQUIRED_IGNORE) {
+        switch (e->required_any) {
+        case PA_ALSA_REQUIRED_VOLUME:
+            e->path->req_any_present |= (e->volume_use != PA_ALSA_VOLUME_IGNORE);
+            break;
+        case PA_ALSA_REQUIRED_SWITCH:
+            e->path->req_any_present |= (e->switch_use != PA_ALSA_SWITCH_IGNORE);
+            break;
+        case PA_ALSA_REQUIRED_ENUMERATION:
+            e->path->req_any_present |= (e->enumeration_use != PA_ALSA_ENUMERATION_IGNORE);
+            break;
+        case PA_ALSA_REQUIRED_ANY:
+            e->path->req_any_present |=
+                (e->volume_use != PA_ALSA_VOLUME_IGNORE) ||
+                (e->switch_use != PA_ALSA_SWITCH_IGNORE) ||
+                (e->enumeration_use != PA_ALSA_ENUMERATION_IGNORE);
+            break;
+        }
+    }
+
+    if (e->enumeration_use == PA_ALSA_ENUMERATION_SELECT) {
+        pa_alsa_option *o;
+        PA_LLIST_FOREACH(o, e->options) {
+            e->path->req_any_present |= (o->required_any != PA_ALSA_REQUIRED_IGNORE) &&
+                (o->alsa_idx >= 0);
+            if (o->required != PA_ALSA_REQUIRED_IGNORE && o->alsa_idx < 0)
+                return -1;
+            if (o->required_absent != PA_ALSA_REQUIRED_IGNORE && o->alsa_idx >= 0)
+                return -1;
+        }
+    }
+
+    if (check_required(e, me) < 0)
+        return -1;
+
     return 0;
 }
 
@@ -1293,9 +1328,6 @@ static int element_probe(pa_alsa_element *e, snd_mixer_t *m) {
 
     }
 
-    if (check_required(e, me) < 0)
-        return -1;
-
     if (e->switch_use == PA_ALSA_SWITCH_SELECT) {
         pa_alsa_option *o;
 
@@ -1581,20 +1613,23 @@ static int element_parse_required(
 
     pa_alsa_path *p = userdata;
     pa_alsa_element *e;
+    pa_alsa_option *o;
     pa_alsa_required_t req;
 
     pa_assert(p);
 
-    if (!(e = element_get(p, section, TRUE))) {
+    e = element_get(p, section, TRUE);
+    o = option_get(p, section);
+    if (!e && !o) {
         pa_log("[%s:%u] Required makes no sense in '%s'", filename, line, section);
         return -1;
     }
 
     if (pa_streq(rvalue, "ignore"))
         req = PA_ALSA_REQUIRED_IGNORE;
-    else if (pa_streq(rvalue, "switch"))
+    else if (pa_streq(rvalue, "switch") && e)
         req = PA_ALSA_REQUIRED_SWITCH;
-    else if (pa_streq(rvalue, "volume"))
+    else if (pa_streq(rvalue, "volume") && e)
         req = PA_ALSA_REQUIRED_VOLUME;
     else if (pa_streq(rvalue, "enumeration"))
         req = PA_ALSA_REQUIRED_ENUMERATION;
@@ -1605,10 +1640,28 @@ static int element_parse_required(
         return -1;
     }
 
-    if (pa_streq(lvalue, "required-absent"))
-        e->required_absent = req;
-    else
-        e->required = req;
+    if (pa_streq(lvalue, "required-absent")) {
+        if (e)
+            e->required_absent = req;
+        if (o)
+            o->required_absent = req;
+    }
+    else if (pa_streq(lvalue, "required-any")) {
+        if (e) {
+            e->required_any = req;
+            e->path->has_req_any = TRUE;
+        }
+        if (o) {
+            o->required_any = req;
+            o->element->path->has_req_any = TRUE;
+        }
+    }
+    else {
+        if (e)
+            e->required = req;
+        if (o)
+            o->required = req;
+    }
 
     return 0;
 }
@@ -1860,7 +1913,10 @@ static int element_verify(pa_alsa_element *e) {
 
     pa_assert(e);
 
+//    pa_log_debug("Element %s, path %s: r=%d, r-any=%d, r-abs=%d", e->alsa_name, e->path->name, e->required, e->required_any, e->required_absent);
     if ((e->required != PA_ALSA_REQUIRED_IGNORE && e->required == e->required_absent) ||
+        (e->required_any != PA_ALSA_REQUIRED_IGNORE && e->required_any == e->required_absent) ||
+        (e->required_absent == PA_ALSA_REQUIRED_ANY && e->required_any != PA_ALSA_REQUIRED_IGNORE) ||
         (e->required_absent == PA_ALSA_REQUIRED_ANY && e->required != PA_ALSA_REQUIRED_IGNORE)) {
         pa_log("Element %s cannot be required and absent at the same time.", e->alsa_name);
         return -1;
@@ -1941,6 +1997,7 @@ pa_alsa_path* pa_alsa_path_new(const char *fname, pa_alsa_direction_t direction)
         { "override-map.2",      element_parse_override_map,        NULL, NULL },
         /* ... later on we might add override-map.3 and so on here ... */
         { "required",            element_parse_required,            NULL, NULL },
+        { "required-any",        element_parse_required,            NULL, NULL },
         { "required-absent",     element_parse_required,            NULL, NULL },
         { "direction",           element_parse_direction,           NULL, NULL },
         { "direction-try-other", element_parse_direction_try_other, NULL, NULL },
@@ -2185,11 +2242,13 @@ int pa_alsa_path_probe(pa_alsa_path *p, snd_mixer_t *m, pa_bool_t ignore_dB) {
                                 min_dB[t] += e->min_dB;
                                 max_dB[t] += e->max_dB;
                             }
-                    } else
+                    } else {
                         /* Hmm, there's another element before us
                          * which cannot do dB volumes, so we we need
                          * to 'neutralize' this slider */
                         e->volume_use = PA_ALSA_VOLUME_ZERO;
+                        pa_log_info("Zeroing volume of '%s' on path '%s'", e->alsa_name, p->name);
+                    }
                 }
             } else if (p->has_volume)
                 /* We can't use this volume, so let's ignore it */
@@ -2202,6 +2261,12 @@ int pa_alsa_path_probe(pa_alsa_path *p, snd_mixer_t *m, pa_bool_t ignore_dB) {
             p->has_mute = TRUE;
     }
 
+    if (p->has_req_any && !p->req_any_present) {
+        p->supported = FALSE;
+        pa_log_debug("Skipping path '%s', none of required-any elements preset.", p->name);
+        return -1;
+    }
+
     path_drop_unsupported(p);
     path_make_options_unique(p);
     path_create_settings(p);
@@ -2247,13 +2312,14 @@ void pa_alsa_element_dump(pa_alsa_element *e) {
     pa_alsa_option *o;
     pa_assert(e);
 
-    pa_log_debug("Element %s, direction=%i, switch=%i, volume=%i, enumeration=%i, required=%i, required_absent=%i, mask=0x%llx, n_channels=%u, override_map=%s",
+    pa_log_debug("Element %s, direction=%i, switch=%i, volume=%i, enumeration=%i, required=%i, required_any=%i, required_absent=%i, mask=0x%llx, n_channels=%u, override_map=%s",
                  e->alsa_name,
                  e->direction,
                  e->switch_use,
                  e->volume_use,
                  e->enumeration_use,
                  e->required,
+                 e->required_any,
                  e->required_absent,
                  (long long unsigned) e->merged_mask,
                  e->n_channels,
diff --git a/src/modules/alsa/alsa-mixer.h b/src/modules/alsa/alsa-mixer.h
index 7fb408a..0fcfc0a 100644
--- a/src/modules/alsa/alsa-mixer.h
+++ b/src/modules/alsa/alsa-mixer.h
@@ -112,6 +112,10 @@ struct pa_alsa_option {
     char *name;
     char *description;
     unsigned priority;
+
+    pa_alsa_required_t required;
+    pa_alsa_required_t required_any;
+    pa_alsa_required_t required_absent;
 };
 
 /* And element wraps one specific ALSA element. A series of elements *
@@ -129,6 +133,7 @@ struct pa_alsa_element {
     pa_alsa_enumeration_use_t enumeration_use;
 
     pa_alsa_required_t required;
+    pa_alsa_required_t required_any;
     pa_alsa_required_t required_absent;
 
     pa_bool_t override_map:1;
@@ -164,6 +169,9 @@ struct pa_alsa_path {
     pa_bool_t has_mute:1;
     pa_bool_t has_volume:1;
     pa_bool_t has_dB:1;
+    /* These two are used during probing only */
+    pa_bool_t has_req_any:1;
+    pa_bool_t req_any_present:1;
 
     long min_volume, max_volume;
     double min_dB, max_dB;
diff --git a/src/modules/alsa/mixer/paths/analog-output.conf.common b/src/modules/alsa/mixer/paths/analog-output.conf.common
index 6131da5..ffd1b41 100644
--- a/src/modules/alsa/mixer/paths/analog-output.conf.common
+++ b/src/modules/alsa/mixer/paths/analog-output.conf.common
@@ -63,10 +63,15 @@
 ;                                        # by the option name, resp. on/off if the element is a switch.
 ; name = ...                             # Logical name to use in the path identifier
 ; priority = ...                         # Priority if this is made into a device port
+; required = ignore | enumeration | any            # In this element, this option must exist or the path will be invalid. ("any" is an alias for "enumeration".)
+; required-any = ignore | enumeration | any        # In this element, either this or another option must exist (or an element)
+; required-absent = ignore | enumeration | any     # In this element, this option must not exist or the path will be invalid
 ;
 ; [Element ...]                          # For each element that we shall control
 ; required = ignore | switch | volume | enumeration | any     # If set, require this element to be of this kind and available,
 ;                                                             # otherwise don't consider this path valid for the card
+; required-any = ignore | switch | volume | enumeration | any # If set, at least one of the elements with required-any in this
+;                                                             # path must be present, otherwise this path is invalid for the card
 ; required-absent = ignore | switch | volume                  # If set, require this element to not be of this kind and not
 ;                                                             # available, otherwise don't consider this path valid for the card
 ;

commit ade0a6f88464d8aecf83982d400ccfc402341920
Author: David Henningsson <david.henningsson at canonical.com>
Date:   Wed Jan 5 12:36:59 2011 +0100

    alsa-mixer: always round towards 0 dB
    
    Always round towards 0 dB. Also add a few debug comments to aid
    troubleshooting.
    
    Signed-off-by: David Henningsson <david.henningsson at canonical.com>

diff --git a/src/modules/alsa/alsa-mixer.c b/src/modules/alsa/alsa-mixer.c
index 967140b..e111388 100644
--- a/src/modules/alsa/alsa-mixer.c
+++ b/src/modules/alsa/alsa-mixer.c
@@ -804,6 +804,7 @@ static int element_set_volume(pa_alsa_element *e, snd_mixer_t *m, const pa_chann
 
         if (e->has_dB) {
             long value = to_alsa_dB(f);
+            int rounding = value > 0 ? -1 : +1;
 
             if (e->direction == PA_ALSA_DIRECTION_OUTPUT) {
                 /* If we call set_play_volume() without checking first
@@ -811,11 +812,11 @@ static int element_set_volume(pa_alsa_element *e, snd_mixer_t *m, const pa_chann
                  * strangely and doesn't fail the call */
                 if (snd_mixer_selem_has_playback_channel(me, c)) {
                     if (write_to_hw) {
-                        if ((r = snd_mixer_selem_set_playback_dB(me, c, value, +1)) >= 0)
+                        if ((r = snd_mixer_selem_set_playback_dB(me, c, value, rounding)) >= 0)
                             r = snd_mixer_selem_get_playback_dB(me, c, &value);
                     } else {
                         long alsa_val;
-                        if ((r = snd_mixer_selem_ask_playback_dB_vol(me, value, +1, &alsa_val)) >= 0)
+                        if ((r = snd_mixer_selem_ask_playback_dB_vol(me, value, rounding, &alsa_val)) >= 0)
                             r = snd_mixer_selem_ask_playback_vol_dB(me, alsa_val, &value);
                     }
                 } else
@@ -823,11 +824,11 @@ static int element_set_volume(pa_alsa_element *e, snd_mixer_t *m, const pa_chann
             } else {
                 if (snd_mixer_selem_has_capture_channel(me, c)) {
                     if (write_to_hw) {
-                        if ((r = snd_mixer_selem_set_capture_dB(me, c, value, +1)) >= 0)
+                        if ((r = snd_mixer_selem_set_capture_dB(me, c, value, rounding)) >= 0)
                             r = snd_mixer_selem_get_capture_dB(me, c, &value);
                     } else {
                         long alsa_val;
-                        if ((r = snd_mixer_selem_ask_capture_dB_vol(me, value, +1, &alsa_val)) >= 0)
+                        if ((r = snd_mixer_selem_ask_capture_dB_vol(me, value, rounding, &alsa_val)) >= 0)
                             r = snd_mixer_selem_ask_capture_vol_dB(me, alsa_val, &value);
                     }
                 } else
@@ -2214,6 +2215,7 @@ int pa_alsa_path_probe(pa_alsa_path *p, snd_mixer_t *m, pa_bool_t ignore_dB) {
             pa_log_debug("Probe of element '%s' failed.", e->alsa_name);
             return -1;
         }
+        pa_log_debug("Probe of element '%s' succeeded (volume=%d, switch=%d, enumeration=%d).", e->alsa_name, e->volume_use, e->switch_use, e->enumeration_use);
 
         if (ignore_dB)
             e->has_dB = FALSE;
@@ -2250,10 +2252,11 @@ int pa_alsa_path_probe(pa_alsa_path *p, snd_mixer_t *m, pa_bool_t ignore_dB) {
                         pa_log_info("Zeroing volume of '%s' on path '%s'", e->alsa_name, p->name);
                     }
                 }
-            } else if (p->has_volume)
+            } else if (p->has_volume) {
                 /* We can't use this volume, so let's ignore it */
                 e->volume_use = PA_ALSA_VOLUME_IGNORE;
-
+                pa_log_info("Ignoring volume of '%s' on path '%s' (missing dB info)", e->alsa_name, p->name);
+            }
             p->has_volume = TRUE;
         }
 

commit 3618268757792ac5f1fe931e3c0e8ae5d2ecea83
Author: David Henningsson <david.henningsson at canonical.com>
Date:   Wed Jan 5 13:27:53 2011 +0100

    alsa-mixer: Add new paths for Internal Mic, Front Mic, Rear Mic and Dock Mic
    
    Signed-off-by: David Henningsson <david.henningsson at canonical.com>

diff --git a/src/Makefile.am b/src/Makefile.am
index 77fc882..1da9818 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -1120,9 +1120,12 @@ dist_alsapaths_DATA = \
 		modules/alsa/mixer/paths/analog-input.conf \
 		modules/alsa/mixer/paths/analog-input.conf.common \
 		modules/alsa/mixer/paths/analog-input-fm.conf \
-		modules/alsa/mixer/paths/analog-input-internal-mic.conf \
 		modules/alsa/mixer/paths/analog-input-linein.conf \
 		modules/alsa/mixer/paths/analog-input-mic.conf \
+		modules/alsa/mixer/paths/analog-input-dock-mic.conf \
+		modules/alsa/mixer/paths/analog-input-front-mic.conf \
+		modules/alsa/mixer/paths/analog-input-internal-mic.conf \
+		modules/alsa/mixer/paths/analog-input-rear-mic.conf \
 		modules/alsa/mixer/paths/analog-input-mic.conf.common \
 		modules/alsa/mixer/paths/analog-input-mic-line.conf \
 		modules/alsa/mixer/paths/analog-input-tvtuner.conf \
diff --git a/src/modules/alsa/mixer/paths/analog-input-dock-mic.conf b/src/modules/alsa/mixer/paths/analog-input-dock-mic.conf
new file mode 100644
index 0000000..df8567e
--- /dev/null
+++ b/src/modules/alsa/mixer/paths/analog-input-dock-mic.conf
@@ -0,0 +1,79 @@
+# This file is part of PulseAudio.
+#
+# PulseAudio is free software; you can redistribute it and/or modify
+# it under the terms of the GNU Lesser General Public License as
+# published by the Free Software Foundation; either version 2.1 of the
+# License, or (at your option) any later version.
+#
+# PulseAudio is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public License
+# along with PulseAudio; if not, write to the Free Software Foundation,
+# Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+
+; For devices where a 'Dock Mic' or 'Dock Mic Boost' element exists
+;
+; See analog-output.conf.common for an explanation on the directives
+
+[General]
+priority = 80
+name = analog-input-microphone-dock
+
+[Element Dock Mic Boost]
+required-any = any
+switch = select
+volume = merge
+override-map.1 = all
+override-map.2 = all-left,all-right
+
+[Option Dock Mic Boost:on]
+name = input-boost-on
+
+[Option Dock Mic Boost:off]
+name = input-boost-off
+
+[Element Dock Mic]
+required-any = any
+switch = mute
+volume = merge
+override-map.1 = all
+override-map.2 = all-left,all-right
+
+[Element Capture]
+switch = mute
+volume = merge
+override-map.1 = all
+override-map.2 = all-left,all-right
+
+[Element Input Source]
+enumeration = select
+
+[Option Input Source:Dock Mic]
+name = analog-input-microphone-dock
+
+[Element Capture Source]
+enumeration = select
+
+[Option Capture Source:Dock Mic]
+name = analog-input-microphone-dock
+
+[Element Mic]
+switch = off
+volume = off
+
+[Element Internal Mic]
+switch = off
+volume = off
+
+[Element Front Mic]
+switch = off
+volume = off
+
+[Element Rear Mic]
+switch = off
+volume = off
+
+.include analog-input-mic.conf.common
diff --git a/src/modules/alsa/mixer/paths/analog-input-front-mic.conf b/src/modules/alsa/mixer/paths/analog-input-front-mic.conf
new file mode 100644
index 0000000..516b487
--- /dev/null
+++ b/src/modules/alsa/mixer/paths/analog-input-front-mic.conf
@@ -0,0 +1,79 @@
+# This file is part of PulseAudio.
+#
+# PulseAudio is free software; you can redistribute it and/or modify
+# it under the terms of the GNU Lesser General Public License as
+# published by the Free Software Foundation; either version 2.1 of the
+# License, or (at your option) any later version.
+#
+# PulseAudio is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public License
+# along with PulseAudio; if not, write to the Free Software Foundation,
+# Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+
+; For devices where a 'Front Mic' or 'Front Mic Boost' element exists
+;
+; See analog-output.conf.common for an explanation on the directives
+
+[General]
+priority = 90
+name = analog-input-microphone-front
+
+[Element Front Mic Boost]
+required-any = any
+switch = select
+volume = merge
+override-map.1 = all
+override-map.2 = all-left,all-right
+
+[Option Front Mic Boost:on]
+name = input-boost-on
+
+[Option Front Mic Boost:off]
+name = input-boost-off
+
+[Element Front Mic]
+required-any = any
+switch = mute
+volume = merge
+override-map.1 = all
+override-map.2 = all-left,all-right
+
+[Element Capture]
+switch = mute
+volume = merge
+override-map.1 = all
+override-map.2 = all-left,all-right
+
+[Element Input Source]
+enumeration = select
+
+[Option Input Source:Front Mic]
+name = analog-input-microphone-front
+
+[Element Capture Source]
+enumeration = select
+
+[Option Capture Source:Front Mic]
+name = analog-input-microphone-front
+
+[Element Mic]
+switch = off
+volume = off
+
+[Element Internal Mic]
+switch = off
+volume = off
+
+[Element Rear Mic]
+switch = off
+volume = off
+
+[Element Dock Mic]
+switch = off
+volume = off
+
+.include analog-input-mic.conf.common
diff --git a/src/modules/alsa/mixer/paths/analog-input-internal-mic.conf b/src/modules/alsa/mixer/paths/analog-input-internal-mic.conf
index 70cd512..3e45bcf 100644
--- a/src/modules/alsa/mixer/paths/analog-input-internal-mic.conf
+++ b/src/modules/alsa/mixer/paths/analog-input-internal-mic.conf
@@ -14,54 +14,94 @@
 # along with PulseAudio; if not, write to the Free Software Foundation,
 # Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
 
-; For devices where a 'Internal Mic' element exists
+; For devices where a 'Internal Mic' or 'Internal Mic Boost' element exists
+; 'Int Mic' and 'Int Mic Boost' are for compatibility with kernels < 2.6.38
 ;
 ; See analog-output.conf.common for an explanation on the directives
 
 [General]
-priority = 90
-name = analog-input-microphone
+priority = 89
+name = analog-input-microphone-internal
 
-[Element Capture]
-switch = mute
+[Element Internal Mic Boost]
+required-any = any
+switch = select
 volume = merge
 override-map.1 = all
 override-map.2 = all-left,all-right
 
-[Element Mic]
-switch = off
-volume = off
+[Option Internal Mic Boost:on]
+name = input-boost-on
+
+[Option Internal Mic Boost:off]
+name = input-boost-off
+
+[Element Int Mic Boost]
+required-any = any
+switch = select
+volume = merge
+override-map.1 = all
+override-map.2 = all-left,all-right
+
+[Option Int Mic Boost:on]
+name = input-boost-on
+
+[Option Int Mic Boost:off]
+name = input-boost-off
+
 
 [Element Internal Mic]
-required = any
+required-any = any
 switch = mute
 volume = merge
 override-map.1 = all
 override-map.2 = all-left,all-right
 
-[Element Line]
-switch = off
-volume = off
+[Element Int Mic]
+required-any = any
+switch = mute
+volume = merge
+override-map.1 = all
+override-map.2 = all-left,all-right
 
-[Element Aux]
-switch = off
-volume = off
+[Element Capture]
+switch = mute
+volume = merge
+override-map.1 = all
+override-map.2 = all-left,all-right
+
+[Element Input Source]
+enumeration = select
+
+[Option Input Source:Internal Mic]
+name = analog-input-microphone-internal
+
+[Option Input Source:Int Mic]
+name = analog-input-microphone-internal
 
-[Element Video]
+[Element Capture Source]
+enumeration = select
+
+[Option Capture Source:Internal Mic]
+name = analog-input-microphone-internal
+
+[Option Capture Source:Int Mic]
+name = analog-input-microphone-internal
+
+[Element Mic]
 switch = off
 volume = off
 
-[Element Mic/Line]
+[Element Dock Mic]
 switch = off
 volume = off
 
-[Element TV Tuner]
+[Element Front Mic]
 switch = off
 volume = off
 
-[Element FM]
+[Element Rear Mic]
 switch = off
 volume = off
 
-.include analog-input.conf.common
 .include analog-input-mic.conf.common
diff --git a/src/modules/alsa/mixer/paths/analog-input-mic.conf.common b/src/modules/alsa/mixer/paths/analog-input-mic.conf.common
index 9bddd48..1ffe59f 100644
--- a/src/modules/alsa/mixer/paths/analog-input-mic.conf.common
+++ b/src/modules/alsa/mixer/paths/analog-input-mic.conf.common
@@ -18,64 +18,26 @@
 ;
 ; See analog-output.conf.common for an explanation on the directives
 
-;;; 'Mic Select'
+[Element Line]
+switch = off
+volume = off
 
-[Element Mic Select]
-enumeration = select
+[Element Aux]
+switch = off
+volume = off
 
-[Option Mic Select:Mic1]
-name = input-microphone
-priority = 20
+[Element Video]
+switch = off
+volume = off
 
-[Option Mic Select:Mic2]
-name = input-microphone
-priority = 19
+[Element Mic/Line]
+switch = off
+volume = off
 
-;;; Various Boosts
+[Element TV Tuner]
+switch = off
+volume = off
 
-[Element Mic Boost (+20dB)]
-switch = select
-volume = merge
-
-[Option Mic Boost (+20dB):on]
-name = input-boost-on
-
-[Option Mic Boost (+20dB):off]
-name = input-boost-off
-
-[Element Mic Boost]
-switch = select
-volume = merge
-
-[Option Mic Boost:on]
-name = input-boost-on
-
-[Option Mic Boost:off]
-name = input-boost-off
-
-[Element Front Mic Boost]
-switch = select
-
-[Option Front Mic Boost:on]
-name = input-boost-on
-
-[Option Front Mic Boost:off]
-name = input-boost-off
-
-[Element Rear Mic Boost]
-switch = select
-
-[Option Rear Mic Boost:on]
-name = input-boost-on
-
-[Option Rear Mic Boost:off]
-name = input-boost-off
-
-[Element Int Mic Boost]
-switch = select
-
-[Option Int Mic Boost:on]
-name = input-boost-on
-
-[Option Int Mic Boost:off]
-name = input-boost-off
+[Element FM]
+switch = off
+volume = off
diff --git a/src/modules/alsa/mixer/paths/analog-input-rear-mic.conf b/src/modules/alsa/mixer/paths/analog-input-rear-mic.conf
new file mode 100644
index 0000000..45f7730
--- /dev/null
+++ b/src/modules/alsa/mixer/paths/analog-input-rear-mic.conf
@@ -0,0 +1,79 @@
+# This file is part of PulseAudio.
+#
+# PulseAudio is free software; you can redistribute it and/or modify
+# it under the terms of the GNU Lesser General Public License as
+# published by the Free Software Foundation; either version 2.1 of the
+# License, or (at your option) any later version.
+#
+# PulseAudio is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public License
+# along with PulseAudio; if not, write to the Free Software Foundation,
+# Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+
+; For devices where a 'Rear Mic' or 'Rear Mic Boost' element exists
+;
+; See analog-output.conf.common for an explanation on the directives
+
+[General]
+priority = 89
+name = analog-input-microphone-rear
+
+[Element Rear Mic Boost]
+required-any = any
+switch = select
+volume = merge
+override-map.1 = all
+override-map.2 = all-left,all-right
+
+[Option Rear Mic Boost:on]
+name = input-boost-on
+
+[Option Rear Mic Boost:off]
+name = input-boost-off
+
+[Element Rear Mic]
+required-any = any
+switch = mute
+volume = merge
+override-map.1 = all
+override-map.2 = all-left,all-right
+
+[Element Capture]
+switch = mute
+volume = merge
+override-map.1 = all
+override-map.2 = all-left,all-right
+
+[Element Input Source]
+enumeration = select
+
+[Option Input Source:Rear Mic]
+name = analog-input-microphone-rear
+
+[Element Capture Source]
+enumeration = select
+
+[Option Capture Source:Rear Mic]
+name = analog-input-microphone-rear
+
+[Element Mic]
+switch = off
+volume = off
+
+[Element Internal Mic]
+switch = off
+volume = off
+
+[Element Front Mic]
+switch = off
+volume = off
+
+[Element Dock Mic]
+switch = off
+volume = off
+
+.include analog-input-mic.conf.common
diff --git a/src/modules/alsa/mixer/profile-sets/default.conf b/src/modules/alsa/mixer/profile-sets/default.conf
index f470d60..cf207bd 100644
--- a/src/modules/alsa/mixer/profile-sets/default.conf
+++ b/src/modules/alsa/mixer/profile-sets/default.conf
@@ -63,14 +63,14 @@ auto-profiles = yes
 device-strings = hw:%f
 channel-map = mono
 paths-output = analog-output analog-output-speaker analog-output-desktop-speaker analog-output-headphones analog-output-headphones-2 analog-output-mono analog-output-lfe-on-mono
-paths-input = analog-input analog-input-mic analog-input-linein analog-input-aux analog-input-video analog-input-tvtuner analog-input-fm analog-input-mic-line
+paths-input = analog-input-front-mic analog-input-rear-mic analog-input-internal-mic analog-input-dock-mic analog-input analog-input-mic analog-input-linein analog-input-aux analog-input-video analog-input-tvtuner analog-input-fm analog-input-mic-line
 priority = 1
 
 [Mapping analog-stereo]
 device-strings = front:%f hw:%f
 channel-map = left,right
 paths-output = analog-output analog-output-speaker analog-output-desktop-speaker analog-output-headphones analog-output-headphones-2 analog-output-mono analog-output-lfe-on-mono
-paths-input = analog-input analog-input-mic analog-input-linein analog-input-aux analog-input-video analog-input-tvtuner analog-input-fm analog-input-mic-line
+paths-input = analog-input-front-mic analog-input-rear-mic analog-input-internal-mic analog-input-dock-mic analog-input analog-input-mic analog-input-linein analog-input-aux analog-input-video analog-input-tvtuner analog-input-fm analog-input-mic-line
 priority = 10
 
 [Mapping analog-surround-40]

commit 65317c824158daab926e41111e8f73d1520fbadf
Author: David Henningsson <david.henningsson at canonical.com>
Date:   Wed Jan 5 14:03:15 2011 +0100

    alsa-mixer: Fixup "Mic"/"Line"/"analog-input" paths to work with the new paths
    
    Signed-off-by: David Henningsson <david.henningsson at canonical.com>

diff --git a/src/modules/alsa/mixer/paths/analog-input-linein.conf b/src/modules/alsa/mixer/paths/analog-input-linein.conf
index 57568cc..9362227 100644
--- a/src/modules/alsa/mixer/paths/analog-input-linein.conf
+++ b/src/modules/alsa/mixer/paths/analog-input-linein.conf
@@ -36,12 +36,27 @@ switch = off
 volume = off
 
 [Element Line]
-required = any
+required-any = any
 switch = mute
 volume = merge
 override-map.1 = all
 override-map.2 = all-left,all-right
 
+[Element Input Source]
+enumeration = select
+
+[Option Input Source:Line]
+name = analog-input-linein
+required-any = any
+
+[Element Capture Source]
+enumeration = select
+
+[Option Capture Source:Line]
+name = analog-input-linein
+required-any = any
+
+
 [Element Aux]
 switch = off
 volume = off
@@ -62,4 +77,10 @@ volume = off
 switch = off
 volume = off
 
-.include analog-input.conf.common
+[Element Mic Jack Mode]
+enumeration = select
+
+[Option Mic Jack Mode:Line In]
+priority = 19
+required-any = any
+name = input-linein
diff --git a/src/modules/alsa/mixer/paths/analog-input-mic.conf b/src/modules/alsa/mixer/paths/analog-input-mic.conf
index 9b8b75a..8565ebe 100644
--- a/src/modules/alsa/mixer/paths/analog-input-mic.conf
+++ b/src/modules/alsa/mixer/paths/analog-input-mic.conf
@@ -14,54 +14,89 @@
 # along with PulseAudio; if not, write to the Free Software Foundation,
 # Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
 
-; For devices where a 'Mic' element exists
+; For devices where a 'Mic' or 'Mic Boost' element exists
 ;
 ; See analog-output.conf.common for an explanation on the directives
 
 [General]
-priority = 100
+priority = 89
 name = analog-input-microphone
 
-[Element Capture]
-switch = mute
+[Element Mic Boost]
+required-any = any
+switch = select
 volume = merge
 override-map.1 = all
 override-map.2 = all-left,all-right
 
+[Option Mic Boost:on]
+name = input-boost-on
+
+[Option Mic Boost:off]
+name = input-boost-off
+
 [Element Mic]
-required = any
+required-any = any
 switch = mute
 volume = merge
 override-map.1 = all
 override-map.2 = all-left,all-right
 
-[Element Internal Mic]
-switch = off
-volume = off
+[Element Capture]
+switch = mute
+volume = merge
+override-map.1 = all
+override-map.2 = all-left,all-right
 
-[Element Line]
-switch = off
-volume = off
+[Element Input Source]
+enumeration = select
 
-[Element Aux]
-switch = off
-volume = off
+[Option Input Source:Mic]
+name = analog-input-microphone
+
+[Element Capture Source]
+enumeration = select
+
+[Option Capture Source:Mic]
+name = analog-input-microphone
+
+;;; Some AC'97s have "Mic Select" and "Mic Boost (+20dB)"
+
+[Element Mic Select]
+enumeration = select
 
-[Element Video]
+[Option Mic Select:Mic1]
+name = input-microphone
+priority = 20
+
+[Option Mic Select:Mic2]
+name = input-microphone
+priority = 19
+
+[Element Mic Boost (+20dB)]
+switch = select
+volume = merge
+
+[Option Mic Boost (+20dB):on]
+name = input-boost-on
+
+[Option Mic Boost (+20dB):off]
+name = input-boost-off
+
+[Element Front Mic]
 switch = off
 volume = off
 
-[Element Mic/Line]
+[Element Internal Mic]
 switch = off
 volume = off
 
-[Element TV Tuner]
+[Element Rear Mic]
 switch = off
 volume = off
 
-[Element FM]
+[Element Dock Mic]
 switch = off
 volume = off
 
-.include analog-input.conf.common
 .include analog-input-mic.conf.common
diff --git a/src/modules/alsa/mixer/paths/analog-input-mic.conf.common b/src/modules/alsa/mixer/paths/analog-input-mic.conf.common
index 1ffe59f..4bebc29 100644
--- a/src/modules/alsa/mixer/paths/analog-input-mic.conf.common
+++ b/src/modules/alsa/mixer/paths/analog-input-mic.conf.common
@@ -41,3 +41,10 @@ volume = off
 [Element FM]
 switch = off
 volume = off
+
+[Element Mic Jack Mode]
+enumeration = select
+
+[Option Mic Jack Mode:Mic In]
+priority = 19
+name = input-microphone
diff --git a/src/modules/alsa/mixer/paths/analog-input.conf b/src/modules/alsa/mixer/paths/analog-input.conf
index 3050738..b86c356 100644
--- a/src/modules/alsa/mixer/paths/analog-input.conf
+++ b/src/modules/alsa/mixer/paths/analog-input.conf
@@ -32,9 +32,36 @@ override-map.2 = all-left,all-right
 [Element Mic]
 required-absent = any
 
+[Element Dock Mic]
+required-absent = any
+
+[Element Dock Mic Boost]
+required-absent = any
+
+[Element Front Mic]
+required-absent = any
+
+[Element Front Mic Boost]
+required-absent = any
+
+[Element Int Mic]
+required-absent = any
+
+[Element Int Mic Boost]
+required-absent = any
+
 [Element Internal Mic]
 required-absent = any
 
+[Element Internal Mic Boost]
+required-absent = any
+
+[Element Rear Mic]
+required-absent = any
+
+[Element Rear Mic Boost]
+required-absent = any
+
 [Element Line]
 required-absent = any
 
@@ -54,4 +81,3 @@ required-absent = any
 required-absent = any
 
 .include analog-input.conf.common
-.include analog-input-mic.conf.common

commit dbdb4607b02bf312255da980e3b01aa6733c0800
Author: David Henningsson <david.henningsson at canonical.com>
Date:   Wed Jan 19 15:40:56 2011 +0100

    alsa-mixer: Make sure capture source and input source use right path
    
    Make sure that mic and line (with common names) use the specific
    path instead of the analog-input one.
    
    Signed-off-by: David Henningsson <david.henningsson at canonical.com>

diff --git a/src/modules/alsa/mixer/paths/analog-input-dock-mic.conf b/src/modules/alsa/mixer/paths/analog-input-dock-mic.conf
index df8567e..74826a9 100644
--- a/src/modules/alsa/mixer/paths/analog-input-dock-mic.conf
+++ b/src/modules/alsa/mixer/paths/analog-input-dock-mic.conf
@@ -53,12 +53,14 @@ enumeration = select
 
 [Option Input Source:Dock Mic]
 name = analog-input-microphone-dock
+required-any = any
 
 [Element Capture Source]
 enumeration = select
 
 [Option Capture Source:Dock Mic]
 name = analog-input-microphone-dock
+required-any = any
 
 [Element Mic]
 switch = off
diff --git a/src/modules/alsa/mixer/paths/analog-input-front-mic.conf b/src/modules/alsa/mixer/paths/analog-input-front-mic.conf
index 516b487..6c58ece 100644
--- a/src/modules/alsa/mixer/paths/analog-input-front-mic.conf
+++ b/src/modules/alsa/mixer/paths/analog-input-front-mic.conf
@@ -53,12 +53,14 @@ enumeration = select
 
 [Option Input Source:Front Mic]
 name = analog-input-microphone-front
+required-any = any
 
 [Element Capture Source]
 enumeration = select
 
 [Option Capture Source:Front Mic]
 name = analog-input-microphone-front
+required-any = any
 
 [Element Mic]
 switch = off
diff --git a/src/modules/alsa/mixer/paths/analog-input-internal-mic.conf b/src/modules/alsa/mixer/paths/analog-input-internal-mic.conf
index 3e45bcf..70a1cd1 100644
--- a/src/modules/alsa/mixer/paths/analog-input-internal-mic.conf
+++ b/src/modules/alsa/mixer/paths/analog-input-internal-mic.conf
@@ -75,18 +75,22 @@ enumeration = select
 
 [Option Input Source:Internal Mic]
 name = analog-input-microphone-internal
+required-any = any
 
 [Option Input Source:Int Mic]
 name = analog-input-microphone-internal
+required-any = any
 
 [Element Capture Source]
 enumeration = select
 
 [Option Capture Source:Internal Mic]
 name = analog-input-microphone-internal
+required-any = any
 
 [Option Capture Source:Int Mic]
 name = analog-input-microphone-internal
+required-any = any
 
 [Element Mic]
 switch = off
diff --git a/src/modules/alsa/mixer/paths/analog-input-mic.conf b/src/modules/alsa/mixer/paths/analog-input-mic.conf
index 8565ebe..d88028b 100644
--- a/src/modules/alsa/mixer/paths/analog-input-mic.conf
+++ b/src/modules/alsa/mixer/paths/analog-input-mic.conf
@@ -53,12 +53,14 @@ enumeration = select
 
 [Option Input Source:Mic]
 name = analog-input-microphone
+required-any = any
 
 [Element Capture Source]
 enumeration = select
 
 [Option Capture Source:Mic]
 name = analog-input-microphone
+required-any = any
 
 ;;; Some AC'97s have "Mic Select" and "Mic Boost (+20dB)"
 
diff --git a/src/modules/alsa/mixer/paths/analog-input-rear-mic.conf b/src/modules/alsa/mixer/paths/analog-input-rear-mic.conf
index 45f7730..75ed61b 100644
--- a/src/modules/alsa/mixer/paths/analog-input-rear-mic.conf
+++ b/src/modules/alsa/mixer/paths/analog-input-rear-mic.conf
@@ -53,12 +53,14 @@ enumeration = select
 
 [Option Input Source:Rear Mic]
 name = analog-input-microphone-rear
+required-any = any
 
 [Element Capture Source]
 enumeration = select
 
 [Option Capture Source:Rear Mic]
 name = analog-input-microphone-rear
+required-any = any
 
 [Element Mic]
 switch = off
diff --git a/src/modules/alsa/mixer/paths/analog-input.conf.common b/src/modules/alsa/mixer/paths/analog-input.conf.common
index 0b2cfd9..9416577 100644
--- a/src/modules/alsa/mixer/paths/analog-input.conf.common
+++ b/src/modules/alsa/mixer/paths/analog-input.conf.common
@@ -66,42 +66,18 @@ enumeration = select
 name = input-microphone
 priority = 20
 
-[Option Input Source:Mic]
-name = input-microphone
-priority = 20
-
 [Option Input Source:Microphone]
 name = input-microphone
 priority = 20
 
-[Option Input Source:Front Mic]
-name = input-microphone
-priority = 19
-
 [Option Input Source:Front Microphone]
 name = input-microphone
 priority = 19
 
-[Option Input Source:Int Mic]
-name = input-microphone
-priority = 19
-
-[Option Input Source:Internal Mic]
-name = input-microphone
-priority = 19
-
-[Option Input Source:Rear Mic]
-name = input-microphone
-priority = 19
-
 [Option Input Source:Internal Mic 1]
 name = input-microphone
 priority = 19
 
-[Option Input Source:Line]
-name = input-linein
-priority = 18
-
 [Option Input Source:Line-In]
 name = input-linein
 priority = 18
@@ -135,21 +111,12 @@ name = input
 [Option Capture Source:Line/Mic]
 name = input
 
-[Option Capture Source:Mic]
-name = input-microphone
-
 [Option Capture Source:Microphone]
 name = input-microphone
 
-[Option Capture Source:Int Mic]
-name = input-microphone-internal
-
 [Option Capture Source:Int DMic]
 name = input-microphone-internal
 
-[Option Capture Source:Internal Mic]
-name = input-microphone-internal
-
 [Option Capture Source:iMic]
 name = input-microphone-internal
 
@@ -159,15 +126,9 @@ name = input-microphone-internal
 [Option Capture Source:Internal Microphone]
 name = input-microphone-internal
 
-[Option Capture Source:Front Mic]
-name = input-microphone
-
 [Option Capture Source:Front Microphone]
 name = input-microphone
 
-[Option Capture Source:Rear Mic]
-name = input-microphone
-
 [Option Capture Source:Mic1]
 name = input-microphone
 
@@ -198,9 +159,6 @@ name = input-linein
 [Option Capture Source:Analog]
 name = input
 
-[Option Capture Source:Line]
-name = input-linein
-
 [Option Capture Source:Line-In]
 name = input-linein
 
@@ -261,9 +219,6 @@ name = input
 [Option Capture Source:Docking-Station]
 name = input-docking
 
-[Option Capture Source:Dock Mic]
-name = input-docking-microphone
-
 ;;; 'Mic Jack Mode'
 
 [Element Mic Jack Mode]

commit c9c88fb8dcbd35774e7aaae09e057e1b8bcdc3d4
Author: Tanu Kaskinen <tanu.kaskinen at digia.com>
Date:   Thu Feb 24 16:16:38 2011 +0200

    Implement the "volume sharing" feature.
    
    When we have a filter sink that does some processing, currently the
    benefits of the flat volume feature are not really available. That's
    because if you have a music player that is connected to the filter sink,
    the hardware sink doesn't have any idea of the music player's stream
    volume.
    
    This problem is solved by this "volume sharing" feature. The volume
    sharing feature works so that the filter sinks that want to avoid the
    previously described problem declare that they don't want to have
    independent volume, but they follow the master sink volume instead.
    The PA_SINK_SHARE_VOLUME_WITH_MASTER sink flag is used for that
    declaration. Then the volume logic is changed so that the hardware
    sink calculates its real volume using also the streams connected to the
    filter sink in addition to the streams that are connected directly to
    the hardware sink. Basically we're trying to create an illusion that
    from volume point of view all streams are connected directly to the
    hardware sink.
    
    For that illusion to work, the volumes of the filter sinks and their
    virtual streams have to be managed carefully according to a set of
    rules:
    
    If a filter sink follows the hardware sink volume, then the filter sink's
     * reference_volume always equals the hw sink's reference_volume
     * real_volume always equals the hw sink's real_volume
     * soft_volume is always 0dB (ie. no soft volume)
    
    If a filter sink doesn't follow the hardware sink volume, then the filter
    sink's
     * reference_volume can be whatever (completely independent from the hw sink)
     * real_volume always equals reference_volume
     * soft_volume always equals real_volume (and reference_volume)
    
    If a filter sink follows the hardware sink volume, and the hardware sink
    supports flat volume, then the filter sink's virtual stream's
     * volume always equals the hw sink's real_volume
     * reference_ratio is calculated normally from the stream volume and the hw
       sink's reference_volume
     * real_ratio always equals 0dB (follows from the first point)
     * soft_volume always equals volume_factor (follows from the previous point)
    
    If a filter sink follows the hardware sink volume, and the hardware sink
    doesn't support flat volume, then the filter sink's virtual stream's
     * volume is always 0dB
     * reference_ratio is always 0dB
     * real_ratio is always 0dB
     * soft_volume always equals volume_factor
    
    If a filter sink doesn't follow the hardware sink volume, then the filter
    sink's virtual stream is handled as a regular stream.
    
    Since the volumes of the virtual streams are controlled by a set of rules,
    the user is not allowed to change the virtual streams' volumes. It would
    probably also make sense to forbid changing the filter sinks' volume, but
    that's not strictly necessary, and currently changing a filter sink's volume
    changes actually the hardware sink's volume, and from there it propagates to
    all filter sinks ("funny" effects are expected when adjusting a single
    channel in cases where all sinks don't have the same channel maps).
    
    This patch is based on the work of Marc-André Lureau, who did the
    initial implementation for Pulseaudio 0.9.15.

diff --git a/src/pulse/def.h b/src/pulse/def.h
index ac4ae53..a3b8622 100644
--- a/src/pulse/def.h
+++ b/src/pulse/def.h
@@ -748,6 +748,16 @@ typedef enum pa_sink_flags {
     /**< The HW volume changes are syncronized with SW volume.
      * \since 1.0 */
 
+/** \cond fulldocs */
+    /* PRIVATE: Server-side values -- do not try to use these at client-side.
+     * The server will filter out these flags anyway, so you should never see
+     * these flags in sinks. */
+
+    PA_SINK_SHARE_VOLUME_WITH_MASTER = 0x0400U,
+    /**< This sink shares the volume with the master sink (used by some filter
+     * sinks). */
+/** \endcond */
+
 } pa_sink_flags_t;
 
 /** \cond fulldocs */
@@ -761,6 +771,7 @@ typedef enum pa_sink_flags {
 #define PA_SINK_DYNAMIC_LATENCY PA_SINK_DYNAMIC_LATENCY
 #define PA_SINK_PASSTHROUGH PA_SINK_PASSTHROUGH
 #define PA_SINK_SYNC_VOLUME PA_SINK_SYNC_VOLUME
+#define PA_SINK_SHARE_VOLUME_WITH_MASTER PA_SINK_SHARE_VOLUME_WITH_MASTER
 
 /** \endcond */
 
diff --git a/src/pulsecore/protocol-native.c b/src/pulsecore/protocol-native.c
index 9257524..c812a3e 100644
--- a/src/pulsecore/protocol-native.c
+++ b/src/pulsecore/protocol-native.c
@@ -2902,7 +2902,7 @@ static void sink_fill_tagstruct(pa_native_connection *c, pa_tagstruct *t, pa_sin
         PA_TAG_STRING, sink->monitor_source ? sink->monitor_source->name : NULL,
         PA_TAG_USEC, pa_sink_get_latency(sink),
         PA_TAG_STRING, sink->driver,
-        PA_TAG_U32, sink->flags,
+        PA_TAG_U32, sink->flags & ~PA_SINK_SHARE_VOLUME_WITH_MASTER,
         PA_TAG_INVALID);
 
     if (c->version >= 13) {
diff --git a/src/pulsecore/sink-input.c b/src/pulsecore/sink-input.c
index 283d026..0c421da 100644
--- a/src/pulsecore/sink-input.c
+++ b/src/pulsecore/sink-input.c
@@ -115,7 +115,13 @@ void pa_sink_input_new_data_set_channel_map(pa_sink_input_new_data *data, const
 pa_bool_t pa_sink_input_new_data_is_volume_writable(pa_sink_input_new_data *data) {
     pa_assert(data);
 
-    return !(data->flags & PA_SINK_INPUT_PASSTHROUGH);
+    if (data->flags & PA_SINK_INPUT_PASSTHROUGH)
+        return FALSE;
+
+    if (data->origin_sink && (data->origin_sink->flags & PA_SINK_SHARE_VOLUME_WITH_MASTER))
+        return FALSE;
+
+    return TRUE;
 }
 
 void pa_sink_input_new_data_set_volume(pa_sink_input_new_data *data, const pa_cvolume *volume) {
@@ -337,7 +343,7 @@ int pa_sink_input_new(
     i->sample_spec = data->sample_spec;
     i->channel_map = data->channel_map;
 
-    if ((i->sink->flags & PA_SINK_FLAT_VOLUME) && !data->volume_is_absolute) {
+    if (!data->volume_is_absolute && pa_sink_flat_volume_enabled(i->sink)) {
         pa_cvolume remapped;
 
         /* When the 'absolute' bool is not set then we'll treat the volume
@@ -532,7 +538,7 @@ void pa_sink_input_unlink(pa_sink_input *i) {
 
     if (linked && i->sink) {
         /* We might need to update the sink's volume if we are in flat volume mode. */
-        if (i->sink->flags & PA_SINK_FLAT_VOLUME)
+        if (pa_sink_flat_volume_enabled(i->sink))
             pa_sink_set_volume(i->sink, NULL, FALSE, FALSE);
 
         if (i->sink->asyncmsgq)
@@ -619,10 +625,16 @@ void pa_sink_input_put(pa_sink_input *i) {
     i->state = state;
 
     /* We might need to update the sink's volume if we are in flat volume mode. */
-    if (i->sink->flags & PA_SINK_FLAT_VOLUME)
+    if (pa_sink_flat_volume_enabled(i->sink))
         pa_sink_set_volume(i->sink, NULL, FALSE, i->save_volume);
-    else
+    else {
+        if (i->origin_sink && (i->origin_sink->flags & PA_SINK_SHARE_VOLUME_WITH_MASTER)) {
+            pa_assert(pa_cvolume_is_norm(&i->volume));
+            pa_assert(pa_cvolume_is_norm(&i->reference_ratio));
+        }
+
         set_real_ratio(i, &i->volume);
+    }
 
     i->thread_info.soft_volume = i->soft_volume;
     i->thread_info.muted = i->muted;
@@ -1079,7 +1091,13 @@ pa_bool_t pa_sink_input_is_volume_writable(pa_sink_input *i) {
     pa_sink_input_assert_ref(i);
     pa_assert_ctl_context();
 
-    return !(i->flags & PA_SINK_INPUT_PASSTHROUGH);
+    if (i->flags & PA_SINK_INPUT_PASSTHROUGH)
+        return FALSE;
+
+    if (i->origin_sink && (i->origin_sink->flags & PA_SINK_SHARE_VOLUME_WITH_MASTER))
+        return FALSE;
+
+    return TRUE;
 }
 
 /* Called from main context */
@@ -1095,7 +1113,7 @@ pa_cvolume *pa_sink_input_get_volume(pa_sink_input *i, pa_cvolume *volume, pa_bo
     pa_assert(PA_SINK_INPUT_IS_LINKED(i->state));
     pa_assert(pa_sink_input_is_volume_readable(i));
 
-    if (absolute || !(i->sink->flags & PA_SINK_FLAT_VOLUME))
+    if (absolute || !pa_sink_flat_volume_enabled(i->sink))
         *volume = i->volume;
     else
         *volume = i->reference_ratio;
@@ -1266,7 +1284,7 @@ int pa_sink_input_start_move(pa_sink_input *i) {
     if (pa_sink_input_get_state(i) == PA_SINK_INPUT_CORKED)
         pa_assert_se(i->sink->n_corked-- >= 1);
 
-    if (i->sink->flags & PA_SINK_FLAT_VOLUME)
+    if (pa_sink_flat_volume_enabled(i->sink))
         /* We might need to update the sink's volume if we are in flat
          * volume mode. */
         pa_sink_set_volume(i->sink, NULL, FALSE, FALSE);
@@ -1282,6 +1300,156 @@ int pa_sink_input_start_move(pa_sink_input *i) {
     return 0;
 }
 
+/* Called from main context. If i has an origin sink that uses volume sharing,
+ * then also the origin sink and all streams connected to it need to update
+ * their volume - this function does all that by using recursion. */
+static void update_volume_due_to_moving(pa_sink_input *i, pa_sink *dest) {
+    pa_cvolume old_volume;
+
+    pa_assert(i);
+    pa_assert(dest);
+    pa_assert(i->sink); /* The destination sink should already be set. */
+
+    if (i->origin_sink && (i->origin_sink->flags & PA_SINK_SHARE_VOLUME_WITH_MASTER)) {
+        pa_sink *root_sink = i->sink;
+        pa_sink_input *origin_sink_input;
+        uint32_t idx;
+
+        while (root_sink->flags & PA_SINK_SHARE_VOLUME_WITH_MASTER)
+            root_sink = root_sink->input_to_master->sink;
+
+        if (pa_sink_flat_volume_enabled(i->sink)) {
+            /* Ok, so the origin sink uses volume sharing, and flat volume is
+             * enabled. The volume will have to be updated as follows:
+             *
+             *     i->volume := i->sink->real_volume
+             *         (handled later by pa_sink_set_volume)
+             *     i->reference_ratio := i->volume / i->sink->reference_volume
+             *         (handled later by pa_sink_set_volume)
+             *     i->real_ratio stays unchanged
+             *         (streams whose origin sink uses volume sharing should
+             *          always have real_ratio of 0 dB)
+             *     i->soft_volume stays unchanged
+             *         (streams whose origin sink uses volume sharing should
+             *          always have volume_factor as soft_volume, so no change
+             *          should be needed) */
+
+            pa_assert(pa_cvolume_is_norm(&i->real_ratio));
+            pa_assert(pa_cvolume_equal(&i->soft_volume, &i->volume_factor));
+
+            /* Notifications will be sent by pa_sink_set_volume(). */
+
+        } else {
+            /* Ok, so the origin sink uses volume sharing, and flat volume is
+             * disabled. The volume will have to be updated as follows:
+             *
+             *     i->volume := 0 dB
+             *     i->reference_ratio := 0 dB
+             *     i->real_ratio stays unchanged
+             *         (streams whose origin sink uses volume sharing should
+             *          always have real_ratio of 0 dB)
+             *     i->soft_volume stays unchanged
+             *         (streams whose origin sink uses volume sharing should
+             *          always have volume_factor as soft_volume, so no change
+             *          should be needed) */
+
+            old_volume = i->volume;
+            pa_cvolume_reset(&i->volume, i->volume.channels);
+            pa_cvolume_reset(&i->reference_ratio, i->reference_ratio.channels);
+            pa_assert(pa_cvolume_is_norm(&i->real_ratio));
+            pa_assert(pa_cvolume_equal(&i->soft_volume, &i->volume_factor));
+
+            /* Notify others about the changed sink input volume. */
+            if (!pa_cvolume_equal(&i->volume, &old_volume)) {
+                if (i->volume_changed)
+                    i->volume_changed(i);
+
+                pa_subscription_post(i->core, PA_SUBSCRIPTION_EVENT_SINK_INPUT|PA_SUBSCRIPTION_EVENT_CHANGE, i->index);
+            }
+        }
+
+        /* Additionally, the origin sink volume needs updating:
+         *
+         *     i->origin_sink->reference_volume := root_sink->reference_volume
+         *     i->origin_sink->real_volume := root_sink->real_volume
+         *     i->origin_sink->soft_volume stays unchanged
+         *         (sinks that use volume sharing should always have
+         *          soft_volume of 0 dB) */
+
+        old_volume = i->origin_sink->reference_volume;
+
+        i->origin_sink->reference_volume = root_sink->reference_volume;
+        pa_cvolume_remap(&i->origin_sink->reference_volume, &root_sink->channel_map, &i->origin_sink->channel_map);
+
+        i->origin_sink->real_volume = root_sink->real_volume;
+        pa_cvolume_remap(&i->origin_sink->real_volume, &root_sink->channel_map, &i->origin_sink->channel_map);
+
+        pa_assert(pa_cvolume_is_norm(&i->origin_sink->soft_volume));
+
+        /* Notify others about the changed sink volume. If you wonder whether
+         * i->origin_sink->set_volume() should be called somewhere, that's not
+         * the case, because sinks that use volume sharing shouldn't have any
+         * internal volume that set_volume() would update. If you wonder
+         * whether the thread_info variables should be synced, yes, they
+         * should, and it's done by the PA_SINK_MESSAGE_FINISH_MOVE message
+         * handler. */
+        if (!pa_cvolume_equal(&i->origin_sink->reference_volume, &old_volume))
+            pa_subscription_post(i->core, PA_SUBSCRIPTION_EVENT_SINK|PA_SUBSCRIPTION_EVENT_CHANGE, i->origin_sink->index);
+
+        /* Recursively update origin sink inputs. */
+        PA_IDXSET_FOREACH(origin_sink_input, i->origin_sink->inputs, idx)
+            update_volume_due_to_moving(origin_sink_input, dest);
+
+    } else {
+        old_volume = i->volume;
+
+        if (pa_sink_flat_volume_enabled(i->sink)) {
+            /* Ok, so this is a regular stream, and flat volume is enabled. The
+             * volume will have to be updated as follows:
+             *
+             *     i->volume := i->reference_ratio * i->sink->reference_volume
+             *     i->reference_ratio stays unchanged
+             *     i->real_ratio := i->volume / i->sink->real_volume
+             *         (handled later by pa_sink_set_volume)
+             *     i->soft_volume := i->real_ratio * i->volume_factor
+             *         (handled later by pa_sink_set_volume) */
+
+            i->volume = i->sink->reference_volume;
+            pa_cvolume_remap(&i->volume, &i->sink->channel_map, &i->channel_map);
+            pa_sw_cvolume_multiply(&i->volume, &i->volume, &i->reference_ratio);
+
+        } else {
+            /* Ok, so this is a regular stream, and flat volume is disabled.
+             * The volume will have to be updated as follows:
+             *
+             *     i->volume := i->reference_ratio
+             *     i->reference_ratio stays unchanged
+             *     i->real_ratio := i->reference_ratio
+             *     i->soft_volume := i->real_ratio * i->volume_factor */
+
+            i->volume = i->reference_ratio;
+            i->real_ratio = i->reference_ratio;
+            pa_sw_cvolume_multiply(&i->soft_volume, &i->real_ratio, &i->volume_factor);
+        }
+
+        /* Notify others about the changed sink input volume. */
+        if (!pa_cvolume_equal(&i->volume, &old_volume)) {
+            /* XXX: In case i->sink has flat volume enabled, then real_ratio
+             * and soft_volume are not updated yet. Let's hope that the
+             * callback implementation doesn't care about those variables... */
+            if (i->volume_changed)
+                i->volume_changed(i);
+
+            pa_subscription_post(i->core, PA_SUBSCRIPTION_EVENT_SINK_INPUT|PA_SUBSCRIPTION_EVENT_CHANGE, i->index);
+        }
+    }
+
+    /* If i->sink == dest, then recursion has finished, and we can finally call
+     * pa_sink_set_volume(), which will do the rest of the updates. */
+    if ((i->sink == dest) && pa_sink_flat_volume_enabled(i->sink))
+        pa_sink_set_volume(i->sink, NULL, FALSE, i->save_volume);
+}
+
 /* Called from main context */
 int pa_sink_input_finish_move(pa_sink_input *i, pa_sink *dest, pa_bool_t save) {
     pa_resampler *new_resampler;
@@ -1355,17 +1523,7 @@ int pa_sink_input_finish_move(pa_sink_input *i, pa_sink *dest, pa_bool_t save) {
     }
     pa_sink_update_status(dest);
 
-    if (i->sink->flags & PA_SINK_FLAT_VOLUME) {
-        pa_cvolume remapped;
-
-        /* Make relative volumes absolute */
-        remapped = dest->reference_volume;
-        pa_cvolume_remap(&remapped, &dest->channel_map, &i->channel_map);
-        pa_sw_cvolume_multiply(&i->volume, &i->reference_ratio, &remapped);
-
-        /* We might need to update the sink's volume if we are in flat volume mode. */
-        pa_sink_set_volume(i->sink, NULL, FALSE, i->save_volume);
-    }
+    update_volume_due_to_moving(i, dest);
 
     pa_assert_se(pa_asyncmsgq_send(i->sink->asyncmsgq, PA_MSGOBJECT(i->sink), PA_SINK_MESSAGE_FINISH_MOVE, i, 0, NULL) == 0);
 
@@ -1374,9 +1532,6 @@ int pa_sink_input_finish_move(pa_sink_input *i, pa_sink *dest, pa_bool_t save) {
     /* Notify everyone */
     pa_hook_fire(&i->core->hooks[PA_CORE_HOOK_SINK_INPUT_MOVE_FINISH], i);
 
-    if (i->volume_changed)
-        i->volume_changed(i);
-
     pa_subscription_post(i->core, PA_SUBSCRIPTION_EVENT_SINK_INPUT|PA_SUBSCRIPTION_EVENT_CHANGE, i->index);
 
     return 0;
@@ -1876,7 +2031,7 @@ void pa_sink_input_set_volume_with_ramping(pa_sink_input *i, const pa_cvolume *v
     pa_assert(volume->channels == 1 || pa_cvolume_compatible(volume, &i->sample_spec));
     pa_assert(pa_sink_input_is_volume_writable(i));
 
-    if ((i->sink->flags & PA_SINK_FLAT_VOLUME) && !absolute) {
+    if (!absolute && pa_sink_flat_volume_enabled(i->sink)) {
         v = i->sink->reference_volume;
         pa_cvolume_remap(&v, &i->sink->channel_map, &i->channel_map);
 
@@ -1911,7 +2066,7 @@ void pa_sink_input_set_volume_with_ramping(pa_sink_input *i, const pa_cvolume *v
     if (t > 0 && target_virtual_volume > 0)
         pa_atomic_store(&i->before_ramping_v, 1);
 
-    if (i->sink->flags & PA_SINK_FLAT_VOLUME) {
+    if (pa_sink_flat_volume_enabled(i->sink)) {
         /* We are in flat volume mode, so let's update all sink input
          * volumes and update the flat volume of the sink */
 
@@ -1920,6 +2075,7 @@ void pa_sink_input_set_volume_with_ramping(pa_sink_input *i, const pa_cvolume *v
     } else {
         /* OK, we are in normal volume mode. The volume only affects
          * ourselves */
+        i->reference_ratio = *volume;
         set_real_ratio(i, volume);
 
         /* Copy the new soft_volume to the thread_info struct */
diff --git a/src/pulsecore/sink.c b/src/pulsecore/sink.c
index 773123d..d713be1 100644
--- a/src/pulsecore/sink.c
+++ b/src/pulsecore/sink.c
@@ -226,8 +226,14 @@ pa_sink* pa_sink_new(
     pa_return_null_if_fail(pa_channel_map_valid(&data->channel_map));
     pa_return_null_if_fail(data->channel_map.channels == data->sample_spec.channels);
 
-    if (!data->volume_is_set)
+    /* FIXME: There should probably be a general function for checking whether
+     * the sink volume is allowed to be set, like there is for sink inputs. */
+    pa_assert(!data->volume_is_set || !(flags & PA_SINK_SHARE_VOLUME_WITH_MASTER));
+
+    if (!data->volume_is_set) {
         pa_cvolume_reset(&data->volume, data->sample_spec.channels);
+        data->save_volume = FALSE;
+    }
 
     pa_return_null_if_fail(pa_cvolume_valid(&data->volume));
     pa_return_null_if_fail(pa_cvolume_compatible(&data->volume, &data->sample_spec));
@@ -447,6 +453,7 @@ void pa_sink_put(pa_sink* s) {
     pa_assert_ctl_context();
 
     pa_assert(s->state == PA_SINK_INIT);
+    pa_assert(!(s->flags & PA_SINK_SHARE_VOLUME_WITH_MASTER) || s->input_to_master);
 
     /* The following fields must be initialized properly when calling _put() */
     pa_assert(s->asyncmsgq);
@@ -456,22 +463,43 @@ void pa_sink_put(pa_sink* s) {
      * special exception we allow volume related flags to be set
      * between _new() and _put(). */
 
-    if (!(s->flags & PA_SINK_HW_VOLUME_CTRL))
+    /* XXX: Currently decibel volume is disabled for all sinks that use volume
+     * sharing. When the master sink supports decibel volume, it would be good
+     * to have the flag also in the filter sink, but currently we don't do that
+     * so that the flags of the filter sink never change when it's moved from
+     * a master sink to another. One solution for this problem would be to
+     * remove user-visible volume altogether from filter sinks when volume
+     * sharing is used, but the current approach was easier to implement... */
+    if (!(s->flags & PA_SINK_HW_VOLUME_CTRL) && !(s->flags & PA_SINK_SHARE_VOLUME_WITH_MASTER))
         s->flags |= PA_SINK_DECIBEL_VOLUME;
 
     if ((s->flags & PA_SINK_DECIBEL_VOLUME) && s->core->flat_volumes)
         s->flags |= PA_SINK_FLAT_VOLUME;
 
-    /* We assume that if the sink implementor changed the default
-     * volume he did so in real_volume, because that is the usual
-     * place where he is supposed to place his changes.  */
-    s->reference_volume = s->real_volume;
+    if (s->flags & PA_SINK_SHARE_VOLUME_WITH_MASTER) {
+        pa_sink *root_sink = s->input_to_master->sink;
+
+        while (root_sink->flags & PA_SINK_SHARE_VOLUME_WITH_MASTER)
+            root_sink = root_sink->input_to_master->sink;
+
+        s->reference_volume = root_sink->reference_volume;
+        pa_cvolume_remap(&s->reference_volume, &root_sink->channel_map, &s->channel_map);
+
+        s->real_volume = root_sink->real_volume;
+        pa_cvolume_remap(&s->real_volume, &root_sink->channel_map, &s->channel_map);
+    } else
+        /* We assume that if the sink implementor changed the default
+         * volume he did so in real_volume, because that is the usual
+         * place where he is supposed to place his changes.  */
+        s->reference_volume = s->real_volume;
 
     s->thread_info.soft_volume = s->soft_volume;
     s->thread_info.soft_muted = s->muted;
     pa_sw_cvolume_multiply(&s->thread_info.current_hw_volume, &s->soft_volume, &s->real_volume);
 
-    pa_assert((s->flags & PA_SINK_HW_VOLUME_CTRL) || (s->base_volume == PA_VOLUME_NORM && s->flags & PA_SINK_DECIBEL_VOLUME));
+    pa_assert((s->flags & PA_SINK_HW_VOLUME_CTRL)
+              || (s->base_volume == PA_VOLUME_NORM
+                  && ((s->flags & PA_SINK_DECIBEL_VOLUME || (s->flags & PA_SINK_SHARE_VOLUME_WITH_MASTER)))));
     pa_assert(!(s->flags & PA_SINK_DECIBEL_VOLUME) || s->n_volume_steps == PA_VOLUME_NORM+1);
     pa_assert(!(s->flags & PA_SINK_DYNAMIC_LATENCY) == (s->thread_info.fixed_latency != 0));
     pa_assert(!(s->flags & PA_SINK_LATENCY) == !(s->monitor_source->flags & PA_SOURCE_LATENCY));
@@ -1196,47 +1224,61 @@ pa_usec_t pa_sink_get_latency_within_thread(pa_sink *s) {
     return usec;
 }
 
-static pa_cvolume* cvolume_remap_minimal_impact(
-        pa_cvolume *v,
-        const pa_cvolume *template,
-        const pa_channel_map *from,
-        const pa_channel_map *to) {
+/* Called from the main thread (and also from the IO thread while the main
+ * thread is waiting).
+ *
+ * When a sink uses volume sharing, it never has the PA_SINK_FLAT_VOLUME flag
+ * set. Instead, flat volume mode is detected by checking whether the root sink
+ * has the flag set. */
+pa_bool_t pa_sink_flat_volume_enabled(pa_sink *s) {
+    pa_sink_assert_ref(s);
 
-    pa_cvolume t;
+    while (s->flags & PA_SINK_SHARE_VOLUME_WITH_MASTER)
+        s = s->input_to_master->sink;
 
-    pa_assert(v);
-    pa_assert(template);
-    pa_assert(from);
-    pa_assert(to);
+    return (s->flags & PA_SINK_FLAT_VOLUME);
+}
 
-    pa_return_val_if_fail(pa_cvolume_compatible_with_channel_map(v, from), NULL);
-    pa_return_val_if_fail(pa_cvolume_compatible_with_channel_map(template, to), NULL);
+/* Called from main context. */
+static void compute_reference_ratio(pa_sink_input *i) {
+    unsigned c = 0;
+    pa_cvolume remapped;
 
-    /* Much like pa_cvolume_remap(), but tries to minimize impact when
-     * mapping from sink input to sink volumes:
-     *
-     * If template is a possible remapping from v it is used instead
-     * of remapping anew.
+    pa_assert(i);
+    pa_assert(pa_sink_flat_volume_enabled(i->sink));
+
+    /*
+     * Calculates the reference ratio from the sink's reference
+     * volume. This basically calculates:
      *
-     * If the channel maps don't match we set an all-channel volume on
-     * the sink to ensure that changing a volume on one stream has no
-     * effect that cannot be compensated for in another stream that
-     * does not have the same channel map as the sink. */
+     * i->reference_ratio = i->volume / i->sink->reference_volume
+     */
 
-    if (pa_channel_map_equal(from, to))
-        return v;
+    remapped = i->sink->reference_volume;
+    pa_cvolume_remap(&remapped, &i->sink->channel_map, &i->channel_map);
 
-    t = *template;
-    if (pa_cvolume_equal(pa_cvolume_remap(&t, to, from), v)) {
-        *v = *template;
-        return v;
-    }
+    i->reference_ratio.channels = i->sample_spec.channels;
 
-    pa_cvolume_set(v, to->channels, pa_cvolume_max(v));
-    return v;
+    for (c = 0; c < i->sample_spec.channels; c++) {
+
+        /* We don't update when the sink volume is 0 anyway */
+        if (remapped.values[c] <= PA_VOLUME_MUTED)
+            continue;
+
+        /* Don't update the reference ratio unless necessary */
+        if (pa_sw_volume_multiply(
+                    i->reference_ratio.values[c],
+                    remapped.values[c]) == i->volume.values[c])
+            continue;
+
+        i->reference_ratio.values[c] = pa_sw_volume_divide(
+                i->volume.values[c],
+                remapped.values[c]);
+    }
 }
 
-/* Called from main context */
+/* Called from main context. Only called for the root sink in volume sharing
+ * cases, except for internal recursive calls. */
 static void compute_reference_ratios(pa_sink *s) {
     uint32_t idx;
     pa_sink_input *i;
@@ -1244,44 +1286,18 @@ static void compute_reference_ratios(pa_sink *s) {
     pa_sink_assert_ref(s);
     pa_assert_ctl_context();
     pa_assert(PA_SINK_IS_LINKED(s->state));
-    pa_assert(s->flags & PA_SINK_FLAT_VOLUME);
+    pa_assert(pa_sink_flat_volume_enabled(s));
 
     PA_IDXSET_FOREACH(i, s->inputs, idx) {
-        unsigned c;
-        pa_cvolume remapped;
-
-        /*
-         * Calculates the reference volume from the sink's reference
-         * volume. This basically calculates:
-         *
-         * i->reference_ratio = i->volume / s->reference_volume
-         */
-
-        remapped = s->reference_volume;
-        pa_cvolume_remap(&remapped, &s->channel_map, &i->channel_map);
-
-        i->reference_ratio.channels = i->sample_spec.channels;
-
-        for (c = 0; c < i->sample_spec.channels; c++) {
+        compute_reference_ratio(i);
 
-            /* We don't update when the sink volume is 0 anyway */
-            if (remapped.values[c] <= PA_VOLUME_MUTED)
-                continue;
-
-            /* Don't update the reference ratio unless necessary */
-            if (pa_sw_volume_multiply(
-                        i->reference_ratio.values[c],
-                        remapped.values[c]) == i->volume.values[c])
-                continue;
-
-            i->reference_ratio.values[c] = pa_sw_volume_divide(
-                    i->volume.values[c],
-                    remapped.values[c]);
-        }
+        if (i->origin_sink && (i->origin_sink->flags & PA_SINK_SHARE_VOLUME_WITH_MASTER))
+            compute_reference_ratios(i->origin_sink);
     }
 }
 
-/* Called from main context */
+/* Called from main context. Only called for the root sink in volume sharing
+ * cases, except for internal recursive calls. */
 static void compute_real_ratios(pa_sink *s) {
     pa_sink_input *i;
     uint32_t idx;
@@ -1289,12 +1305,24 @@ static void compute_real_ratios(pa_sink *s) {
     pa_sink_assert_ref(s);
     pa_assert_ctl_context();
     pa_assert(PA_SINK_IS_LINKED(s->state));
-    pa_assert(s->flags & PA_SINK_FLAT_VOLUME);
+    pa_assert(pa_sink_flat_volume_enabled(s));
 
     PA_IDXSET_FOREACH(i, s->inputs, idx) {
         unsigned c;
         pa_cvolume remapped;
 
+        if (i->origin_sink && (i->origin_sink->flags & PA_SINK_SHARE_VOLUME_WITH_MASTER)) {
+            /* The origin sink uses volume sharing, so this input's real ratio
+             * is handled as a special case - the real ratio must be 0 dB, and
+             * as a result i->soft_volume must equal i->volume_factor. */
+            pa_cvolume_reset(&i->real_ratio, i->real_ratio.channels);
+            i->soft_volume = i->volume_factor;
+
+            compute_real_ratios(i->origin_sink);
+
+            continue;
+        }
+
         /*
          * This basically calculates:
          *
@@ -1335,23 +1363,144 @@ static void compute_real_ratios(pa_sink *s) {
     }
 }
 
-/* Called from main thread */
-static void compute_real_volume(pa_sink *s) {
+static pa_cvolume *cvolume_remap_minimal_impact(
+        pa_cvolume *v,
+        const pa_cvolume *template,
+        const pa_channel_map *from,
+        const pa_channel_map *to) {
+
+    pa_cvolume t;
+
+    pa_assert(v);
+    pa_assert(template);
+    pa_assert(from);
+    pa_assert(to);
+    pa_assert(pa_cvolume_compatible_with_channel_map(v, from));
+    pa_assert(pa_cvolume_compatible_with_channel_map(template, to));
+
+    /* Much like pa_cvolume_remap(), but tries to minimize impact when
+     * mapping from sink input to sink volumes:
+     *
+     * If template is a possible remapping from v it is used instead
+     * of remapping anew.
+     *
+     * If the channel maps don't match we set an all-channel volume on
+     * the sink to ensure that changing a volume on one stream has no
+     * effect that cannot be compensated for in another stream that
+     * does not have the same channel map as the sink. */
+
+    if (pa_channel_map_equal(from, to))
+        return v;
+
+    t = *template;
+    if (pa_cvolume_equal(pa_cvolume_remap(&t, to, from), v)) {
+        *v = *template;
+        return v;
+    }
+
+    pa_cvolume_set(v, to->channels, pa_cvolume_max(v));
+    return v;
+}
+
+/* Called from main thread. Only called for the root sink in volume sharing
+ * cases, except for internal recursive calls. */
+static void get_maximum_input_volume(pa_sink *s, pa_cvolume *max_volume, const pa_channel_map *channel_map) {
     pa_sink_input *i;
     uint32_t idx;
 
     pa_sink_assert_ref(s);
+    pa_assert(max_volume);
+    pa_assert(channel_map);
+    pa_assert(pa_sink_flat_volume_enabled(s));
+
+    PA_IDXSET_FOREACH(i, s->inputs, idx) {
+        pa_cvolume remapped;
+
+        if (i->origin_sink && (i->origin_sink->flags & PA_SINK_SHARE_VOLUME_WITH_MASTER)) {
+            get_maximum_input_volume(i->origin_sink, max_volume, channel_map);
+
+            /* Ignore this input. The origin sink uses volume sharing, so this
+             * input's volume will be set to be equal to the root sink's real
+             * volume. Obviously this input's current volume must not then
+             * affect what the root sink's real volume will be. */
+            continue;
+        }
+
+        remapped = i->volume;
+        cvolume_remap_minimal_impact(&remapped, max_volume, &i->channel_map, channel_map);
+        pa_cvolume_merge(max_volume, max_volume, &remapped);
+    }
+}
+
+/* Called from main thread. Only called for the root sink in volume sharing
+ * cases, except for internal recursive calls. */
+static pa_bool_t has_inputs(pa_sink *s) {
+    pa_sink_input *i;
+    uint32_t idx;
+
+    pa_sink_assert_ref(s);
+
+    PA_IDXSET_FOREACH(i, s->inputs, idx) {
+        if (!i->origin_sink || !(i->origin_sink->flags & PA_SINK_SHARE_VOLUME_WITH_MASTER) || has_inputs(i->origin_sink))
+            return TRUE;
+    }
+
+    return FALSE;
+}
+
+/* Called from main thread. Only called for the root sink in volume sharing
+ * cases, except for internal recursive calls. */
+static void update_real_volume(pa_sink *s, const pa_cvolume *new_volume, pa_channel_map *channel_map) {
+    pa_sink_input *i;
+    uint32_t idx;
+
+    pa_sink_assert_ref(s);
+    pa_assert(new_volume);
+    pa_assert(channel_map);
+
+    s->real_volume = *new_volume;
+    pa_cvolume_remap(&s->real_volume, channel_map, &s->channel_map);
+
+    PA_IDXSET_FOREACH(i, s->inputs, idx) {
+        if (i->origin_sink && (i->origin_sink->flags & PA_SINK_SHARE_VOLUME_WITH_MASTER)) {
+            if (pa_sink_flat_volume_enabled(s)) {
+                pa_cvolume old_volume = i->volume;
+
+                /* Follow the root sink's real volume. */
+                i->volume = *new_volume;
+                pa_cvolume_remap(&i->volume, channel_map, &i->channel_map);
+                compute_reference_ratio(i);
+
+                /* The volume changed, let's tell people so */
+                if (!pa_cvolume_equal(&old_volume, &i->volume)) {
+                    if (i->volume_changed)
+                        i->volume_changed(i);
+
+                    pa_subscription_post(i->core, PA_SUBSCRIPTION_EVENT_SINK_INPUT|PA_SUBSCRIPTION_EVENT_CHANGE, i->index);
+                }
+            }
+
+            update_real_volume(i->origin_sink, new_volume, channel_map);
+        }
+    }
+}
+
+/* Called from main thread. Only called for the root sink in shared volume
+ * cases. */
+static void compute_real_volume(pa_sink *s) {
+    pa_sink_assert_ref(s);
     pa_assert_ctl_context();
     pa_assert(PA_SINK_IS_LINKED(s->state));
-    pa_assert(s->flags & PA_SINK_FLAT_VOLUME);
+    pa_assert(pa_sink_flat_volume_enabled(s));
+    pa_assert(!(s->flags & PA_SINK_SHARE_VOLUME_WITH_MASTER));
 
     /* This determines the maximum volume of all streams and sets
      * s->real_volume accordingly. */
 
-    if (pa_idxset_isempty(s->inputs)) {
-        /* In the special case that we have no sink input we leave the
+    if (!has_inputs(s)) {
+        /* In the special case that we have no sink inputs we leave the
          * volume unmodified. */
-        s->real_volume = s->reference_volume;
+        update_real_volume(s, &s->reference_volume, &s->channel_map);
         return;
     }
 
@@ -1359,20 +1508,16 @@ static void compute_real_volume(pa_sink *s) {
 
     /* First let's determine the new maximum volume of all inputs
      * connected to this sink */
-    PA_IDXSET_FOREACH(i, s->inputs, idx) {
-        pa_cvolume remapped;
-
-        remapped = i->volume;
-        cvolume_remap_minimal_impact(&remapped, &s->real_volume, &i->channel_map, &s->channel_map);
-        pa_cvolume_merge(&s->real_volume, &s->real_volume, &remapped);
-    }
+    get_maximum_input_volume(s, &s->real_volume, &s->channel_map);
+    update_real_volume(s, &s->real_volume, &s->channel_map);
 
     /* Then, let's update the real ratios/soft volumes of all inputs
      * connected to this sink */
     compute_real_ratios(s);
 }
 
-/* Called from main thread */
+/* Called from main thread. Only called for the root sink in shared volume
+ * cases, except for internal recursive calls. */
 static void propagate_reference_volume(pa_sink *s) {
     pa_sink_input *i;
     uint32_t idx;
@@ -1380,14 +1525,23 @@ static void propagate_reference_volume(pa_sink *s) {
     pa_sink_assert_ref(s);
     pa_assert_ctl_context();
     pa_assert(PA_SINK_IS_LINKED(s->state));
-    pa_assert(s->flags & PA_SINK_FLAT_VOLUME);
+    pa_assert(pa_sink_flat_volume_enabled(s));
 
     /* This is called whenever the sink volume changes that is not
      * caused by a sink input volume change. We need to fix up the
      * sink input volumes accordingly */
 
     PA_IDXSET_FOREACH(i, s->inputs, idx) {
-        pa_cvolume old_volume, remapped;
+        pa_cvolume old_volume;
+
+        if (i->origin_sink && (i->origin_sink->flags & PA_SINK_SHARE_VOLUME_WITH_MASTER)) {
+            propagate_reference_volume(i->origin_sink);
+
+            /* Since the origin sink uses volume sharing, this input's volume
+             * needs to be updated to match the root sink's real volume, but
+             * that will be done later in update_shared_real_volume(). */
+            continue;
+        }
 
         old_volume = i->volume;
 
@@ -1395,9 +1549,9 @@ static void propagate_reference_volume(pa_sink *s) {
          *
          * i->volume := s->reference_volume * i->reference_ratio  */
 
-        remapped = s->reference_volume;
-        pa_cvolume_remap(&remapped, &s->channel_map, &i->channel_map);
-        pa_sw_cvolume_multiply(&i->volume, &remapped, &i->reference_ratio);
+        i->volume = s->reference_volume;
+        pa_cvolume_remap(&i->volume, &s->channel_map, &i->channel_map);
+        pa_sw_cvolume_multiply(&i->volume, &i->volume, &i->reference_ratio);
 
         /* The volume changed, let's tell people so */
         if (!pa_cvolume_equal(&old_volume, &i->volume)) {
@@ -1410,6 +1564,54 @@ static void propagate_reference_volume(pa_sink *s) {
     }
 }
 
+/* Called from main thread. Only called for the root sink in volume sharing
+ * cases, except for internal recursive calls. The return value indicates
+ * whether any reference volume actually changed. */
+static pa_bool_t update_reference_volume(pa_sink *s, const pa_cvolume *v, const pa_channel_map *channel_map, pa_bool_t save) {
+    pa_cvolume volume;
+    pa_bool_t reference_volume_changed;
+    pa_sink_input *i;
+    uint32_t idx;
+
+    pa_sink_assert_ref(s);
+    pa_assert(PA_SINK_IS_LINKED(s->state));
+    pa_assert(v);
+    pa_assert(channel_map);
+    pa_assert(pa_cvolume_valid(v));
+
+    volume = *v;
+    pa_cvolume_remap(&volume, channel_map, &s->channel_map);
+
+    reference_volume_changed = !pa_cvolume_equal(&volume, &s->reference_volume);
+    s->reference_volume = volume;
+
+    s->save_volume = (!reference_volume_changed && s->save_volume) || save;
+
+    if (reference_volume_changed)
+        pa_subscription_post(s->core, PA_SUBSCRIPTION_EVENT_SINK|PA_SUBSCRIPTION_EVENT_CHANGE, s->index);
+    else if (!(s->flags & PA_SINK_SHARE_VOLUME_WITH_MASTER))
+        /* If the root sink's volume doesn't change, then there can't be any
+         * changes in the other sinks in the sink tree either.
+         *
+         * It's probably theoretically possible that even if the root sink's
+         * volume changes slightly, some filter sink doesn't change its volume
+         * due to rounding errors. If that happens, we still want to propagate
+         * the changed root sink volume to the sinks connected to the
+         * intermediate sink that didn't change its volume. This theoretical
+         * possiblity is the reason why we have that !(s->flags &
+         * PA_SINK_SHARE_VOLUME_WITH_MASTER) condition. Probably nobody would
+         * notice even if we returned here FALSE always if
+         * reference_volume_changed is FALSE. */
+        return FALSE;
+
+    PA_IDXSET_FOREACH(i, s->inputs, idx) {
+        if (i->origin_sink && (i->origin_sink->flags & PA_SINK_SHARE_VOLUME_WITH_MASTER))
+            update_reference_volume(i->origin_sink, v, channel_map, FALSE);
+    }
+
+    return TRUE;
+}
+
 /* Called from main thread */
 void pa_sink_set_volume(
         pa_sink *s,
@@ -1417,14 +1619,14 @@ void pa_sink_set_volume(
         pa_bool_t send_msg,
         pa_bool_t save) {
 
-    pa_cvolume old_reference_volume;
-    pa_bool_t reference_changed;
+    pa_cvolume new_reference_volume;
+    pa_sink *root_sink = s;
 
     pa_sink_assert_ref(s);
     pa_assert_ctl_context();
     pa_assert(PA_SINK_IS_LINKED(s->state));
     pa_assert(!volume || pa_cvolume_valid(volume));
-    pa_assert(volume || (s->flags & PA_SINK_FLAT_VOLUME));
+    pa_assert(volume || pa_sink_flat_volume_enabled(s));
     pa_assert(!volume || volume->channels == 1 || pa_cvolume_compatible(volume, &s->sample_spec));
 
     /* make sure we don't change the volume when a PASSTHROUGH input is connected */
@@ -1445,76 +1647,82 @@ void pa_sink_set_volume(
         }
     }
 
+    /* In case of volume sharing, the volume is set for the root sink first,
+     * from which it's then propagated to the sharing sinks. */
+    while (root_sink->flags & PA_SINK_SHARE_VOLUME_WITH_MASTER)
+        root_sink = root_sink->input_to_master->sink;
+
     /* As a special exception we accept mono volumes on all sinks --
      * even on those with more complex channel maps */
 
+    if (volume) {
+        if (pa_cvolume_compatible(volume, &s->sample_spec))
+            new_reference_volume = *volume;
+        else {
+            new_reference_volume = s->reference_volume;
+            pa_cvolume_scale(&new_reference_volume, pa_cvolume_max(volume));
+        }
+
+        pa_cvolume_remap(&new_reference_volume, &s->channel_map, &root_sink->channel_map);
+    }
+
     /* If volume is NULL we synchronize the sink's real and reference
      * volumes with the stream volumes. If it is not NULL we update
      * the reference_volume with it. */
 
-    old_reference_volume = s->reference_volume;
-
     if (volume) {
-
-        if (pa_cvolume_compatible(volume, &s->sample_spec))
-            s->reference_volume = *volume;
-        else
-            pa_cvolume_scale(&s->reference_volume, pa_cvolume_max(volume));
-
-        if (s->flags & PA_SINK_FLAT_VOLUME) {
-            /* OK, propagate this volume change back to the inputs */
-            propagate_reference_volume(s);
-
-            /* And now recalculate the real volume */
-            compute_real_volume(s);
-        } else
-            s->real_volume = s->reference_volume;
+        if (update_reference_volume(root_sink, &new_reference_volume, &root_sink->channel_map, save)) {
+            if (pa_sink_flat_volume_enabled(root_sink)) {
+                /* OK, propagate this volume change back to the inputs */
+                propagate_reference_volume(root_sink);
+
+                /* And now recalculate the real volume */
+                compute_real_volume(root_sink);
+            } else
+                update_real_volume(root_sink, &root_sink->reference_volume, &root_sink->channel_map);
+        }
 
     } else {
-        pa_assert(s->flags & PA_SINK_FLAT_VOLUME);
+        pa_assert(pa_sink_flat_volume_enabled(root_sink));
 
         /* Ok, let's determine the new real volume */
-        compute_real_volume(s);
+        compute_real_volume(root_sink);
 
         /* Let's 'push' the reference volume if necessary */
-        pa_cvolume_merge(&s->reference_volume, &s->reference_volume, &s->real_volume);
+        pa_cvolume_merge(&new_reference_volume, &s->reference_volume, &root_sink->real_volume);
+        update_reference_volume(root_sink, &new_reference_volume, &root_sink->channel_map, save);
 
-        /* We need to fix the reference ratios of all streams now that
-         * we changed the reference volume */
-        compute_reference_ratios(s);
+        /* Now that the reference volume is updated, we can update the streams'
+         * reference ratios. */
+        compute_reference_ratios(root_sink);
     }
 
-    reference_changed = !pa_cvolume_equal(&old_reference_volume, &s->reference_volume);
-    s->save_volume = (!reference_changed && s->save_volume) || save;
-
-    if (s->set_volume) {
+    if (root_sink->set_volume) {
         /* If we have a function set_volume(), then we do not apply a
          * soft volume by default. However, set_volume() is free to
-         * apply one to s->soft_volume */
+         * apply one to root_sink->soft_volume */
 
-        pa_cvolume_reset(&s->soft_volume, s->sample_spec.channels);
-        if (!(s->flags & PA_SINK_SYNC_VOLUME))
-            s->set_volume(s);
+        pa_cvolume_reset(&root_sink->soft_volume, root_sink->sample_spec.channels);
+        if (!(root_sink->flags & PA_SINK_SYNC_VOLUME))
+            root_sink->set_volume(root_sink);
         else
             send_msg = TRUE;
 
     } else
         /* If we have no function set_volume(), then the soft volume
-         * becomes the virtual volume */
-        s->soft_volume = s->real_volume;
+         * becomes the real volume */
+        root_sink->soft_volume = root_sink->real_volume;
 
-    /* This tells the sink that soft and/or virtual volume changed */
+    /* This tells the sink that soft volume and/or real volume changed */
     if (send_msg)
-        pa_assert_se(pa_asyncmsgq_send(s->asyncmsgq, PA_MSGOBJECT(s), PA_SINK_MESSAGE_SET_VOLUME_SYNCED, NULL, 0, NULL) == 0);
-
-    if (reference_changed)
-        pa_subscription_post(s->core, PA_SUBSCRIPTION_EVENT_SINK|PA_SUBSCRIPTION_EVENT_CHANGE, s->index);
+        pa_assert_se(pa_asyncmsgq_send(root_sink->asyncmsgq, PA_MSGOBJECT(root_sink), PA_SINK_MESSAGE_SET_SHARED_VOLUME, NULL, 0, NULL) == 0);
 }
 
 /* Called from the io thread if sync volume is used, otherwise from the main thread.
  * Only to be called by sink implementor */
 void pa_sink_set_soft_volume(pa_sink *s, const pa_cvolume *volume) {
     pa_sink_assert_ref(s);
+    pa_assert(!(s->flags & PA_SINK_SHARE_VOLUME_WITH_MASTER));
     if (s->flags & PA_SINK_SYNC_VOLUME)
         pa_sink_assert_io_context(s);
     else
@@ -1531,12 +1739,14 @@ void pa_sink_set_soft_volume(pa_sink *s, const pa_cvolume *volume) {
         s->thread_info.soft_volume = s->soft_volume;
 }
 
+/* Called from the main thread. Only called for the root sink in volume sharing
+ * cases, except for internal recursive calls. */
 static void propagate_real_volume(pa_sink *s, const pa_cvolume *old_real_volume) {
     pa_sink_input *i;
     uint32_t idx;
-    pa_cvolume old_reference_volume;
 
     pa_sink_assert_ref(s);
+    pa_assert(old_real_volume);
     pa_assert_ctl_context();
     pa_assert(PA_SINK_IS_LINKED(s->state));
 
@@ -1545,20 +1755,18 @@ static void propagate_real_volume(pa_sink *s, const pa_cvolume *old_real_volume)
      * reference volume and then rebuild the stream volumes based on
      * i->real_ratio which should stay fixed. */
 
-    if (old_real_volume && pa_cvolume_equal(old_real_volume, &s->real_volume))
-        return;
-
-    old_reference_volume = s->reference_volume;
+    if (!(s->flags & PA_SINK_SHARE_VOLUME_WITH_MASTER)) {
+        if (pa_cvolume_equal(old_real_volume, &s->real_volume))
+            return;
 
-    /* 1. Make the real volume the reference volume */
-    s->reference_volume = s->real_volume;
+        /* 1. Make the real volume the reference volume */
+        update_reference_volume(s, &s->real_volume, &s->channel_map, TRUE);
+    }
 
-    if (s->flags & PA_SINK_FLAT_VOLUME) {
+    if (pa_sink_flat_volume_enabled(s)) {
 
         PA_IDXSET_FOREACH(i, s->inputs, idx) {
-            pa_cvolume old_volume, remapped;
-
-            old_volume = i->volume;
+            pa_cvolume old_volume = i->volume;
 
             /* 2. Since the sink's reference and real volumes are equal
              * now our ratios should be too. */
@@ -1572,9 +1780,9 @@ static void propagate_real_volume(pa_sink *s, const pa_cvolume *old_real_volume)
              * i->volume = s->reference_volume * i->reference_ratio
              *
              * This is identical to propagate_reference_volume() */
-            remapped = s->reference_volume;
-            pa_cvolume_remap(&remapped, &s->channel_map, &i->channel_map);
-            pa_sw_cvolume_multiply(&i->volume, &remapped, &i->reference_ratio);
+            i->volume = s->reference_volume;
+            pa_cvolume_remap(&i->volume, &s->channel_map, &i->channel_map);
+            pa_sw_cvolume_multiply(&i->volume, &i->volume, &i->reference_ratio);
 
             /* Notify if something changed */
             if (!pa_cvolume_equal(&old_volume, &i->volume)) {
@@ -1584,16 +1792,17 @@ static void propagate_real_volume(pa_sink *s, const pa_cvolume *old_real_volume)
 
                 pa_subscription_post(i->core, PA_SUBSCRIPTION_EVENT_SINK_INPUT|PA_SUBSCRIPTION_EVENT_CHANGE, i->index);
             }
+
+            if (i->origin_sink && (i->origin_sink->flags & PA_SINK_SHARE_VOLUME_WITH_MASTER))
+                propagate_real_volume(i->origin_sink, old_real_volume);
         }
     }
 
     /* Something got changed in the hardware. It probably makes sense
      * to save changed hw settings given that hw volume changes not
      * triggered by PA are almost certainly done by the user. */
-    s->save_volume = TRUE;
-
-    if (!pa_cvolume_equal(&old_reference_volume, &s->reference_volume))
-        pa_subscription_post(s->core, PA_SUBSCRIPTION_EVENT_SINK|PA_SUBSCRIPTION_EVENT_CHANGE, s->index);
+    if (!(s->flags & PA_SINK_SHARE_VOLUME_WITH_MASTER))
+        s->save_volume = TRUE;
 }
 
 /* Called from io thread */
@@ -1613,6 +1822,8 @@ const pa_cvolume *pa_sink_get_volume(pa_sink *s, pa_bool_t force_refresh) {
     if (s->refresh_volume || force_refresh) {
         struct pa_cvolume old_real_volume;
 
+        pa_assert(!(s->flags & PA_SINK_SHARE_VOLUME_WITH_MASTER));
+
         old_real_volume = s->real_volume;
 
         if (!(s->flags & PA_SINK_SYNC_VOLUME) && s->get_volume)
@@ -1620,25 +1831,27 @@ const pa_cvolume *pa_sink_get_volume(pa_sink *s, pa_bool_t force_refresh) {
 
         pa_assert_se(pa_asyncmsgq_send(s->asyncmsgq, PA_MSGOBJECT(s), PA_SINK_MESSAGE_GET_VOLUME, NULL, 0, NULL) == 0);
 
+        update_real_volume(s, &s->real_volume, &s->channel_map);
         propagate_real_volume(s, &old_real_volume);
     }
 
     return &s->reference_volume;
 }
 
-/* Called from main thread */
+/* Called from main thread. In volume sharing cases, only the root sink may
+ * call this. */
 void pa_sink_volume_changed(pa_sink *s, const pa_cvolume *new_real_volume) {
     pa_cvolume old_real_volume;
 
     pa_sink_assert_ref(s);
     pa_assert_ctl_context();
     pa_assert(PA_SINK_IS_LINKED(s->state));
+    pa_assert(!(s->flags & PA_SINK_SHARE_VOLUME_WITH_MASTER));
 
     /* The sink implementor may call this if the volume changed to make sure everyone is notified */
 
     old_real_volume = s->real_volume;
-    s->real_volume = *new_real_volume;
-
+    update_real_volume(s, new_real_volume, &s->channel_map);
     propagate_real_volume(s, &old_real_volume);
 }
 
@@ -1853,10 +2066,27 @@ static void sync_input_volumes_within_thread(pa_sink *s) {
 
         if (!pa_atomic_load(&i->before_ramping_v))
             i->thread_info.soft_volume = i->soft_volume;
+
         pa_sink_input_request_rewind(i, 0, TRUE, FALSE, FALSE);
     }
 }
 
+/* Called from the IO thread. Only called for the root sink in volume sharing
+ * cases, except for internal recursive calls. */
+static void set_shared_volume_within_thread(pa_sink *s) {
+    pa_sink_input *i = NULL;
+    void *state = NULL;
+
+    pa_sink_assert_ref(s);
+
+    PA_MSGOBJECT(s)->process_msg(PA_MSGOBJECT(s), PA_SINK_MESSAGE_SET_VOLUME_SYNCED, NULL, 0, NULL);
+
+    PA_HASHMAP_FOREACH(i, s->thread_info.inputs, state) {
+        if (i->origin_sink && (i->origin_sink->flags & PA_SINK_SHARE_VOLUME_WITH_MASTER))
+            set_shared_volume_within_thread(i->origin_sink);
+    }
+}
+
 /* Called from IO thread, except when it is not */
 int pa_sink_process_msg(pa_msgobject *o, int code, void *userdata, int64_t offset, pa_memchunk *chunk) {
     pa_sink *s = PA_SINK(o);
@@ -1913,7 +2143,7 @@ int pa_sink_process_msg(pa_msgobject *o, int code, void *userdata, int64_t offse
 
             /* In flat volume mode we need to update the volume as
              * well */
-            return o->process_msg(o, PA_SINK_MESSAGE_SET_VOLUME_SYNCED, NULL, 0, NULL);
+            return o->process_msg(o, PA_SINK_MESSAGE_SET_SHARED_VOLUME, NULL, 0, NULL);
         }
 
         case PA_SINK_MESSAGE_REMOVE_INPUT: {
@@ -1956,7 +2186,7 @@ int pa_sink_process_msg(pa_msgobject *o, int code, void *userdata, int64_t offse
 
             /* In flat volume mode we need to update the volume as
              * well */
-            return o->process_msg(o, PA_SINK_MESSAGE_SET_VOLUME_SYNCED, NULL, 0, NULL);
+            return o->process_msg(o, PA_SINK_MESSAGE_SET_SHARED_VOLUME, NULL, 0, NULL);
         }
 
         case PA_SINK_MESSAGE_START_MOVE: {
@@ -2001,7 +2231,7 @@ int pa_sink_process_msg(pa_msgobject *o, int code, void *userdata, int64_t offse
 
             /* In flat volume mode we need to update the volume as
              * well */
-            return o->process_msg(o, PA_SINK_MESSAGE_SET_VOLUME_SYNCED, NULL, 0, NULL);
+            return o->process_msg(o, PA_SINK_MESSAGE_SET_SHARED_VOLUME, NULL, 0, NULL);
         }
 
         case PA_SINK_MESSAGE_FINISH_MOVE: {
@@ -2042,9 +2272,17 @@ int pa_sink_process_msg(pa_msgobject *o, int code, void *userdata, int64_t offse
                 pa_sink_request_rewind(s, nbytes);
             }
 
-            /* In flat volume mode we need to update the volume as
-             * well */
-            return o->process_msg(o, PA_SINK_MESSAGE_SET_VOLUME_SYNCED, NULL, 0, NULL);
+            return o->process_msg(o, PA_SINK_MESSAGE_SET_SHARED_VOLUME, NULL, 0, NULL);
+        }
+
+        case PA_SINK_MESSAGE_SET_SHARED_VOLUME: {
+            pa_sink *root_sink = s;
+
+            while (root_sink->flags & PA_SINK_SHARE_VOLUME_WITH_MASTER)
+                root_sink = root_sink->input_to_master->sink;
+
+            set_shared_volume_within_thread(root_sink);
+            return 0;
         }
 
         case PA_SINK_MESSAGE_SET_VOLUME_SYNCED:
@@ -2062,9 +2300,6 @@ int pa_sink_process_msg(pa_msgobject *o, int code, void *userdata, int64_t offse
                 pa_sink_request_rewind(s, (size_t) -1);
             }
 
-            if (!(s->flags & PA_SINK_FLAT_VOLUME))
-                return 0;
-
             /* Fall through ... */
 
         case PA_SINK_MESSAGE_SYNC_VOLUMES:
diff --git a/src/pulsecore/sink.h b/src/pulsecore/sink.h
index 8a51587..ef69881 100644
--- a/src/pulsecore/sink.h
+++ b/src/pulsecore/sink.h
@@ -264,6 +264,7 @@ typedef enum pa_sink_message {
     PA_SINK_MESSAGE_ADD_INPUT,
     PA_SINK_MESSAGE_REMOVE_INPUT,
     PA_SINK_MESSAGE_GET_VOLUME,
+    PA_SINK_MESSAGE_SET_SHARED_VOLUME,
     PA_SINK_MESSAGE_SET_VOLUME_SYNCED,
     PA_SINK_MESSAGE_SET_VOLUME,
     PA_SINK_MESSAGE_SYNC_VOLUMES,
@@ -374,6 +375,9 @@ int pa_sink_update_status(pa_sink*s);
 int pa_sink_suspend(pa_sink *s, pa_bool_t suspend, pa_suspend_cause_t cause);
 int pa_sink_suspend_all(pa_core *c, pa_bool_t suspend, pa_suspend_cause_t cause);
 
+/* Use this instead of checking s->flags & PA_SINK_FLAT_VOLUME directly. */
+pa_bool_t pa_sink_flat_volume_enabled(pa_sink *s);
+
 void pa_sink_set_volume(pa_sink *sink, const pa_cvolume *volume, pa_bool_t sendmsg, pa_bool_t save);
 const pa_cvolume *pa_sink_get_volume(pa_sink *sink, pa_bool_t force_refresh);
 

commit 8702d15d0303fdb53e9aaf66656610741728d2e3
Author: Tanu Kaskinen <tanu.kaskinen at digia.com>
Date:   Thu Feb 24 16:16:39 2011 +0200

    virtual-sink: Add a modarg for enabling volume sharing.

diff --git a/src/modules/module-virtual-sink.c b/src/modules/module-virtual-sink.c
index 40bab5a..ceb2697 100644
--- a/src/modules/module-virtual-sink.c
+++ b/src/modules/module-virtual-sink.c
@@ -57,6 +57,7 @@ PA_MODULE_USAGE(
           "rate=<sample rate> "
           "channels=<number of channels> "
           "channel_map=<channel map> "
+          "use_volume_sharing=<yes or no> "
         ));
 
 #define MEMBLOCKQ_MAXLENGTH (16*1024*1024)
@@ -81,6 +82,7 @@ static const char* const valid_modargs[] = {
     "rate",
     "channels",
     "channel_map",
+    "use_volume_sharing",
     NULL
 };
 
@@ -478,6 +480,7 @@ int pa__init(pa_module*m) {
     pa_sink_input_new_data sink_input_data;
     pa_sink_new_data sink_data;
     pa_bool_t *use_default = NULL;
+    pa_bool_t use_volume_sharing = FALSE;
 
     pa_assert(m);
 
@@ -501,6 +504,11 @@ int pa__init(pa_module*m) {
         goto fail;
     }
 
+    if (pa_modargs_get_value_boolean(ma, "use_volume_sharing", &use_volume_sharing) < 0) {
+        pa_log("use_volume_sharing= expects a boolean argument");
+        goto fail;
+    }
+
     u = pa_xnew0(struct userdata, 1);
     u->module = m;
     m->userdata = u;
@@ -531,9 +539,8 @@ int pa__init(pa_module*m) {
         pa_proplist_setf(sink_data.proplist, PA_PROP_DEVICE_DESCRIPTION, "Virtual Sink %s on %s", sink_data.name, z ? z : master->name);
     }
 
-    u->sink = pa_sink_new(m->core, &sink_data,
-                          PA_SINK_HW_MUTE_CTRL|PA_SINK_HW_VOLUME_CTRL|PA_SINK_DECIBEL_VOLUME|
-                          (master->flags & (PA_SINK_LATENCY|PA_SINK_DYNAMIC_LATENCY)));
+    u->sink = pa_sink_new(m->core, &sink_data, (master->flags & (PA_SINK_LATENCY|PA_SINK_DYNAMIC_LATENCY))
+                                               | (use_volume_sharing ? PA_SINK_SHARE_VOLUME_WITH_MASTER : 0));
     pa_sink_new_data_done(&sink_data);
 
     if (!u->sink) {
@@ -545,7 +552,7 @@ int pa__init(pa_module*m) {
     u->sink->set_state = sink_set_state_cb;
     u->sink->update_requested_latency = sink_update_requested_latency_cb;
     u->sink->request_rewind = sink_request_rewind_cb;
-    u->sink->set_volume = sink_set_volume_cb;
+    u->sink->set_volume = use_volume_sharing ? NULL : sink_set_volume_cb;
     u->sink->set_mute = sink_set_mute_cb;
     u->sink->userdata = u;
 
@@ -580,7 +587,7 @@ int pa__init(pa_module*m) {
     u->sink_input->state_change = sink_input_state_change_cb;
     u->sink_input->may_move_to = sink_input_may_move_to_cb;
     u->sink_input->moving = sink_input_moving_cb;
-    u->sink_input->volume_changed = sink_input_volume_changed_cb;
+    u->sink_input->volume_changed = use_volume_sharing ? NULL : sink_input_volume_changed_cb;
     u->sink_input->mute_changed = sink_input_mute_changed_cb;
     u->sink_input->userdata = u;
 

commit d2d36beb801cc78b53ea1942634c158882604432
Author: Tanu Kaskinen <tanu.kaskinen at digia.com>
Date:   Thu Feb 24 16:16:40 2011 +0200

    virtual-sink: Add a modarg for forcing flat volume.

diff --git a/src/modules/module-virtual-sink.c b/src/modules/module-virtual-sink.c
index ceb2697..e55e890 100644
--- a/src/modules/module-virtual-sink.c
+++ b/src/modules/module-virtual-sink.c
@@ -58,6 +58,7 @@ PA_MODULE_USAGE(
           "channels=<number of channels> "
           "channel_map=<channel map> "
           "use_volume_sharing=<yes or no> "
+          "force_flat_volume=<yes or no> "
         ));
 
 #define MEMBLOCKQ_MAXLENGTH (16*1024*1024)
@@ -83,6 +84,7 @@ static const char* const valid_modargs[] = {
     "channels",
     "channel_map",
     "use_volume_sharing",
+    "force_flat_volume",
     NULL
 };
 
@@ -481,6 +483,7 @@ int pa__init(pa_module*m) {
     pa_sink_new_data sink_data;
     pa_bool_t *use_default = NULL;
     pa_bool_t use_volume_sharing = FALSE;
+    pa_bool_t force_flat_volume = FALSE;
 
     pa_assert(m);
 
@@ -509,6 +512,16 @@ int pa__init(pa_module*m) {
         goto fail;
     }
 
+    if (pa_modargs_get_value_boolean(ma, "force_flat_volume", &force_flat_volume) < 0) {
+        pa_log("force_flat_volume= expects a boolean argument");
+        goto fail;
+    }
+
+    if (use_volume_sharing && force_flat_volume) {
+        pa_log("Flat volume can't be forced when using volume sharing.");
+        goto fail;
+    }
+
     u = pa_xnew0(struct userdata, 1);
     u->module = m;
     m->userdata = u;
@@ -540,7 +553,8 @@ int pa__init(pa_module*m) {
     }
 
     u->sink = pa_sink_new(m->core, &sink_data, (master->flags & (PA_SINK_LATENCY|PA_SINK_DYNAMIC_LATENCY))
-                                               | (use_volume_sharing ? PA_SINK_SHARE_VOLUME_WITH_MASTER : 0));
+                                               | (use_volume_sharing ? PA_SINK_SHARE_VOLUME_WITH_MASTER : 0)
+                                               | (force_flat_volume ? PA_SINK_FLAT_VOLUME : 0));
     pa_sink_new_data_done(&sink_data);
 
     if (!u->sink) {

commit 1fda23c02cec2032306c1edf92f38ce3474c9bed
Author: Tanu Kaskinen <tanu.kaskinen at digia.com>
Date:   Thu Feb 24 16:16:41 2011 +0200

    virtual-sink/source: Use a more descriptive stream name.

diff --git a/src/modules/module-virtual-sink.c b/src/modules/module-virtual-sink.c
index e55e890..a45f4f5 100644
--- a/src/modules/module-virtual-sink.c
+++ b/src/modules/module-virtual-sink.c
@@ -578,7 +578,7 @@ int pa__init(pa_module*m) {
     sink_input_data.module = m;
     sink_input_data.sink = master;
     sink_input_data.origin_sink = u->sink;
-    pa_proplist_sets(sink_input_data.proplist, PA_PROP_MEDIA_NAME, "Virtual Sink Stream");
+    pa_proplist_setf(sink_input_data.proplist, PA_PROP_MEDIA_NAME, "Virtual Sink Stream from %s", pa_proplist_gets(u->sink->proplist, PA_PROP_DEVICE_DESCRIPTION));
     pa_proplist_sets(sink_input_data.proplist, PA_PROP_MEDIA_ROLE, "filter");
     pa_sink_input_new_data_set_sample_spec(&sink_input_data, &ss);
     pa_sink_input_new_data_set_channel_map(&sink_input_data, &map);
diff --git a/src/modules/module-virtual-source.c b/src/modules/module-virtual-source.c
index a2b073f..2b27b05 100644
--- a/src/modules/module-virtual-source.c
+++ b/src/modules/module-virtual-source.c
@@ -633,7 +633,7 @@ int pa__init(pa_module*m) {
     /* FIXME
        source_output_data.flags = PA_SOURCE_OUTPUT_DONT_INHIBIT_AUTO_SUSPEND; */
 
-    pa_proplist_sets(source_output_data.proplist, PA_PROP_MEDIA_NAME, "Virtual Source Stream");
+    pa_proplist_setf(source_output_data.proplist, PA_PROP_MEDIA_NAME, "Virtual Source Stream of %s", pa_proplist_gets(u->source->proplist, PA_PROP_DEVICE_DESCRIPTION));
     pa_proplist_sets(source_output_data.proplist, PA_PROP_MEDIA_ROLE, "filter");
     pa_source_output_new_data_set_sample_spec(&source_output_data, &ss);
     pa_source_output_new_data_set_channel_map(&source_output_data, &map);

commit b3644c1bcd5f5d73fd2dc7b898e66b11ca3ad588
Author: Tanu Kaskinen <tanu.kaskinen at digia.com>
Date:   Thu Feb 24 16:16:42 2011 +0200

    virtual-sink/source: Remove an unused variable.

diff --git a/src/modules/module-virtual-sink.c b/src/modules/module-virtual-sink.c
index a45f4f5..bad159c 100644
--- a/src/modules/module-virtual-sink.c
+++ b/src/modules/module-virtual-sink.c
@@ -481,7 +481,6 @@ int pa__init(pa_module*m) {
     pa_sink *master=NULL;
     pa_sink_input_new_data sink_input_data;
     pa_sink_new_data sink_data;
-    pa_bool_t *use_default = NULL;
     pa_bool_t use_volume_sharing = FALSE;
     pa_bool_t force_flat_volume = FALSE;
 
@@ -619,16 +618,12 @@ int pa__init(pa_module*m) {
 
     pa_modargs_free(ma);
 
-    pa_xfree(use_default);
-
     return 0;
 
  fail:
     if (ma)
         pa_modargs_free(ma);
 
-    pa_xfree(use_default);
-
     pa__done(m);
 
     return -1;
diff --git a/src/modules/module-virtual-source.c b/src/modules/module-virtual-source.c
index 2b27b05..d7e1c21 100644
--- a/src/modules/module-virtual-source.c
+++ b/src/modules/module-virtual-source.c
@@ -535,7 +535,6 @@ int pa__init(pa_module*m) {
     pa_source *master=NULL;
     pa_source_output_new_data source_output_data;
     pa_source_new_data source_data;
-    pa_bool_t *use_default = NULL;
 
     /* optional for uplink_sink */
     pa_sink_new_data sink_data;
@@ -714,16 +713,12 @@ int pa__init(pa_module*m) {
 
     pa_modargs_free(ma);
 
-    pa_xfree(use_default);
-
     return 0;
 
  fail:
     if (ma)
         pa_modargs_free(ma);
 
-    pa_xfree(use_default);
-
     pa__done(m);
 
     return -1;

commit 6bd34156b130c07b130de10111a12ef6dab18b52
Author: Tanu Kaskinen <tanu.kaskinen at digia.com>
Date:   Thu Feb 24 16:16:43 2011 +0200

    virtual-sink: Fix a crash when moving the sink to a new master right after setup.
    
    If the virtual sink is moved to a new master right after it has been created,
    then the virtual sink input's memblockq can be rewound to a negative read
    index. The data written prior to the move starts from index zero, so after the
    rewind there's a bit of silence. If the memblockq doesn't have a silence
    memchunk set, then pa_memblockq_peek() will return zero in such case, and the
    returned memchunk's memblock pointer will be NULL.
    
    That scenario wasn't taken into account in the implementation of
    sink_input_pop_cb. Setting a silence memchunk for the memblockq solves this
    problem, because pa_memblock_peek() will now return a valid memblock if the
    read index happens to point to a hole in the memblockq.
    
    I believe this isn't the best possible solution, though. It doesn't really make
    sense to rewind the sink input's memblockq beyond index 0 in the first place,
    because now when the stream starts to play to the new master sink, there's some
    unnecessary silence before the actual data starts. This is a small problem,
    though, and I don't grok the rewinding system well enough to know how to fix
    this issue properly.
    
    I went through all files that call pa_memblockq_peek() to see if there are more
    similar bugs. play-memblockq.c was the only one that looked to me like it might
    be broken in the same way. I didn't try reproducing the bug with
    play-memblockq.c, though, so I just added a FIXME comment there.

diff --git a/src/modules/module-virtual-sink.c b/src/modules/module-virtual-sink.c
index bad159c..58ea932 100644
--- a/src/modules/module-virtual-sink.c
+++ b/src/modules/module-virtual-sink.c
@@ -483,6 +483,7 @@ int pa__init(pa_module*m) {
     pa_sink_new_data sink_data;
     pa_bool_t use_volume_sharing = FALSE;
     pa_bool_t force_flat_volume = FALSE;
+    pa_memchunk silence;
 
     pa_assert(m);
 
@@ -606,12 +607,11 @@ int pa__init(pa_module*m) {
 
     u->sink->input_to_master = u->sink_input;
 
-    /* (9) IF YOU REQUIRE A FIXED BLOCK SIZE MAKE SURE TO PASS A
-     * SILENCE MEMBLOCK AS LAST PARAMETER
-     * HERE. pa_sink_input_get_silence() IS USEFUL HERE. */
-    u->memblockq = pa_memblockq_new(0, MEMBLOCKQ_MAXLENGTH, 0, pa_frame_size(&ss), 1, 1, 0, NULL);
+    pa_sink_input_get_silence(u->sink_input, &silence);
+    u->memblockq = pa_memblockq_new(0, MEMBLOCKQ_MAXLENGTH, 0, pa_frame_size(&ss), 1, 1, 0, &silence);
+    pa_memblock_unref(silence.memblock);
 
-    /* (10) INITIALIZE ANYTHING ELSE YOU NEED HERE */
+    /* (9) INITIALIZE ANYTHING ELSE YOU NEED HERE */
 
     pa_sink_put(u->sink);
     pa_sink_input_put(u->sink_input);
diff --git a/src/modules/rtp/rtp.h b/src/modules/rtp/rtp.h
index b197e82..e975e75 100644
--- a/src/modules/rtp/rtp.h
+++ b/src/modules/rtp/rtp.h
@@ -40,6 +40,9 @@ typedef struct pa_rtp_context {
 } pa_rtp_context;
 
 pa_rtp_context* pa_rtp_context_init_send(pa_rtp_context *c, int fd, uint32_t ssrc, uint8_t payload, size_t frame_size);
+
+/* If the memblockq doesn't have a silence memchunk set, then the caller must
+ * guarantee that the current read index doesn't point to a hole. */
 int pa_rtp_send(pa_rtp_context *c, size_t size, pa_memblockq *q);
 
 pa_rtp_context* pa_rtp_context_init_recv(pa_rtp_context *c, int fd, size_t frame_size);
diff --git a/src/pulsecore/play-memblockq.c b/src/pulsecore/play-memblockq.c
index 0d6da3e..f075a5b 100644
--- a/src/pulsecore/play-memblockq.c
+++ b/src/pulsecore/play-memblockq.c
@@ -135,6 +135,12 @@ static int sink_input_pop_cb(pa_sink_input *i, size_t nbytes, pa_memchunk *chunk
         return -1;
     }
 
+    /* FIXME: u->memblockq doesn't have a silence memchunk set, so
+     * pa_memblockq_peek() will return 0 without returning any memblock if the
+     * read index points to a hole. If the memblockq is rewound beyond index 0,
+     * then there will be a hole. */
+    pa_assert(chunk->memblock);
+
     chunk->length = PA_MIN(chunk->length, nbytes);
     pa_memblockq_drop(u->memblockq, chunk->length);
 

commit 0d8bbaf40d07806069ca350a8ffe78075c4453e4
Author: Tanu Kaskinen <tanuk at iki.fi>
Date:   Sun Feb 27 13:20:42 2011 +0200

    sink: Don't send unnecessary PA_SINK_MESSAGE_SET_SHARED_VOLUME messages.
    
    If send_msg is false, the message will be sent by the caller.

diff --git a/src/pulsecore/sink.c b/src/pulsecore/sink.c
index d713be1..4da36f3 100644
--- a/src/pulsecore/sink.c
+++ b/src/pulsecore/sink.c
@@ -1705,8 +1705,6 @@ void pa_sink_set_volume(
         pa_cvolume_reset(&root_sink->soft_volume, root_sink->sample_spec.channels);
         if (!(root_sink->flags & PA_SINK_SYNC_VOLUME))
             root_sink->set_volume(root_sink);
-        else
-            send_msg = TRUE;
 
     } else
         /* If we have no function set_volume(), then the soft volume

commit 59f2b4436a89f4a334c762a0e1942889881f842d
Author: Tanu Kaskinen <tanuk at iki.fi>
Date:   Sun Feb 27 13:21:41 2011 +0200

    sink: Add casts to some printf arguments to get rid of compiler warnings.

diff --git a/src/pulsecore/sink.c b/src/pulsecore/sink.c
index 4da36f3..9eb3791 100644
--- a/src/pulsecore/sink.c
+++ b/src/pulsecore/sink.c
@@ -3178,11 +3178,11 @@ void pa_sink_volume_change_push(pa_sink *s) {
         PA_LLIST_INSERT_AFTER(pa_sink_volume_change, s->thread_info.volume_changes, c, nc);
     }
 
-    pa_log_debug("Volume going %s to %d at %llu", direction, pa_cvolume_avg(&nc->hw_volume), nc->at);
+    pa_log_debug("Volume going %s to %d at %llu", direction, pa_cvolume_avg(&nc->hw_volume), (long long unsigned) nc->at);
 
     /* We can ignore volume events that came earlier but should happen later than this. */
     PA_LLIST_FOREACH(c, nc->next) {
-        pa_log_debug("Volume change to %d at %llu was dropped", pa_cvolume_avg(&c->hw_volume), c->at);
+        pa_log_debug("Volume change to %d at %llu was dropped", pa_cvolume_avg(&c->hw_volume), (long long unsigned) c->at);
         pa_sink_volume_change_free(c);
     }
     nc->next = NULL;
@@ -3213,7 +3213,8 @@ pa_bool_t pa_sink_volume_change_apply(pa_sink *s, pa_usec_t *usec_to_next) {
     while (s->thread_info.volume_changes && now >= s->thread_info.volume_changes->at) {
         pa_sink_volume_change *c = s->thread_info.volume_changes;
         PA_LLIST_REMOVE(pa_sink_volume_change, s->thread_info.volume_changes, c);
-        pa_log_debug("Volume change to %d at %llu was written %llu usec late", pa_cvolume_avg(&c->hw_volume), c->at, now - c->at);
+        pa_log_debug("Volume change to %d at %llu was written %llu usec late",
+                     pa_cvolume_avg(&c->hw_volume), (long long unsigned) c->at, (long long unsigned) (now - c->at));
         ret = TRUE;
         s->thread_info.current_hw_volume = c->hw_volume;
         pa_sink_volume_change_free(c);
@@ -3226,7 +3227,7 @@ pa_bool_t pa_sink_volume_change_apply(pa_sink *s, pa_usec_t *usec_to_next) {
         if (usec_to_next)
             *usec_to_next = s->thread_info.volume_changes->at - now;
         if (pa_log_ratelimit(PA_LOG_DEBUG))
-            pa_log_debug("Next volume change in %lld usec", s->thread_info.volume_changes->at - now);
+            pa_log_debug("Next volume change in %lld usec", (long long) (s->thread_info.volume_changes->at - now));
     }
     else {
         if (usec_to_next)
@@ -3244,7 +3245,7 @@ static void pa_sink_volume_change_rewind(pa_sink *s, size_t nbytes) {
     pa_usec_t rewound = pa_bytes_to_usec(nbytes, &s->sample_spec);
     pa_usec_t limit = pa_sink_get_latency_within_thread(s);
 
-    pa_log_debug("latency = %lld", limit);
+    pa_log_debug("latency = %lld", (long long) limit);
     limit += pa_rtclock_now() + s->thread_info.volume_change_extra_delay;
 
     PA_LLIST_FOREACH(c, s->thread_info.volume_changes) {

commit bed4b73cfe99b2be5da2f2b0937e9c24699418d3
Author: Tanu Kaskinen <tanuk at iki.fi>
Date:   Sun Feb 27 12:50:16 2011 +0200

    Add src/*-symdef.h to .gitignore.
    
    Also remove src/module/.gitignore as this is no longer needed
    as pointed out by Arun Raghavan

diff --git a/src/.gitignore b/src/.gitignore
index c93974b..1380e26 100644
--- a/src/.gitignore
+++ b/src/.gitignore
@@ -66,3 +66,4 @@ voltest
 start-pulseaudio-x11
 start-pulseaudio-kde
 vector-test
+*-symdef.h
diff --git a/src/modules/.gitignore b/src/modules/.gitignore
deleted file mode 100644
index 2d2d942..0000000
--- a/src/modules/.gitignore
+++ /dev/null
@@ -1 +0,0 @@
-module-*-symdef.h

-- 
hooks/post-receive
PulseAudio Sound Server



More information about the pulseaudio-commits mailing list