[pulseaudio-commits] [SCM] PulseAudio Sound Server branch, master, updated. ac032549cd7eba9459f1fcd8983f1d513913f14f

Lennart Poettering gitmailer-noreply at 0pointer.de
Mon Jun 23 17:17:16 PDT 2008


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  398514f577d2f0cb801320b3466a4c4e25b6586e (commit)

- Log -----------------------------------------------------------------
ac03254... Merge branch 'master' of git://git.debian.org/git/pkg-pulseaudio/pulseaudio-upstream
1562671... Merge dead branch 'glitch-free'
126e4cf... Merge dead branch 'lennart'
0be9bc2... Merge dead branch 'lockfree'
63c1eb1... Merge dead branch 'ossman'
a87ba42... Merge dead branch 'liboil-test'
1a3984c... Merge dead branch 'prepare-0.9.10'
3aadad1... update protocol spec
43dfc2a... follow recent alsa sink changes in the alsa source
734f071... decrease default tsched buffer to 2s to reduce overall memory consumption
813d40c... fix up requested latency when we move a record stream
e3c5a77... fix moving of record streams
99a4516... don't access stream before it is valid
74f8a67... fix suspend for alsa sink
f021538... export a couple of more functions from libpulse
e0dc1e4... Print message when stream started playback, use terminal sequence to clear line when printing that message
86ea73a... reduce malloc() usage when logging, to minimize the hit of logging in RT threads. Not complete yet, i18n still uses malloc
b57c520... add pa_vsnprintf()
1a2e5a8... add adaptive resampler to the RTP receiver, other modernizations
cfc4842... export a few more properties for RTP streams
f96a8ad... increase default mempool size, make mempool_slot an abstract struct because the only fields it defined where actually unused
70c5967... increase shm size limit, modernizations
2bc77ff... reduce number of allocated memblocks when receiving RTP data by reusing blocks
d10ee7d... more pa_bool_t'ization
c801d08... use pa_bool_t
076ffa3... add 'stream' as media role
1b7157a... add PA_REFCNT_INIT_ZERO
6895280... add pa_ulog2()
103ceaa... add pa_memblockq_get_nblocks()
df73688... modernizations
37813d9... modernizations
787b869... initialize volume properly, set more properties, modernizations
2eca8c9... don't spam us with wakeup msgs in non-tsched mode
9c48ed1... update pipe source for glitch-free, too
8baa1a4... fix pipe sink for glitch-free
dd29f67... fix braindead mistake
94c269e... some fixes to make the esound protocol work on glitch-free again
8df6529... some fixes to make the simple protocol work on glitch-free again
c5faeb1... store peer name in native-protocol.peer property
aae8beb... if zero is passed to pa_memblock_new() allocate largest memory block possible from mempool
f124445... fix module-sine for glitch-free
df92b23... - Fix moving of sink inputs between sinks - Don't write more than a single buffer size in the ALSA driver at a time, to give the clients time to fill up the memblockq again - Add API for querying the requested latency of a sink input/source output - Drop get_letancy() from vtable of sinks/sources
580d563... modify test to generate data events out-of-order
0ea0e06... make sure the smoother code can deal with incoming data that is out-of-order; start smoothing only when we have at least a configurable number of entries in our history
e97a347... bah, english sucks
1f196e7... fix some comments
7b5c6a3... fix recording
21fa1cf... double default asyncq size
876d5b4... fix a race condition when tearing down the ladspa/remap sink
6f4d44b... apparently alsa expects us to free the memory for card names
d21f458... fix a memory leak
9354da4... make memchunk/memblockq streams work with glitch-free
dafcf20... beefup proplist handling for sound events
8afbdc3... update to new rewinding logic
9d7fde5... rework the rewinding logic once again, fixing
6c28f1d... decrease verbosity a bit
44241ac... define callback function types; allow pa_signal_done() to be called even without prior pa_signal_init()
91fbb69... explain why changing rlimits at this time is safe
dee3555... rename 'routing' to 'filter'
4fa6cb4... add a few more asserts, don't allow pa_limit_caps() to fail
71d14d4... fix remapping sink for glitch-free
a1c10b5... update LADSPA module for glitch-free moed
59835d9... explain why a rewind was requested
82caf5a... when rewinding after the end of an underrun, make sure to rewind as much as we can, so that we deal properly with changed latencies of the sink
3167e0f... follow _unlink() changes from sink-input
d2da344... send PA_SINK_MESSAGE_REMOVE_INPUT only when an asyncmsgq is available, reset resampler only when we really need to
d2be471... make sure to call sink->update_requested_latency() always when we change latency, same for source
59a7467... don't require a module name when resolving a dl symbol
ff09fa3... Fix typo: "now"->"not".
43a30a2... Fix setrlimit() return value comparsion.
bb4f83b... only send PA_SINK_MESSAGE_SET_STATE if there's still an asyncmsqg around to do so
bfb2691... a few modernizations
06b9140... reorderer a few things
792ef5c... fix a compiler warning
775bc6c... some modernizations
7d6269e... add multiarch paths to default LADSPA search path
49b1b15... don't enable prebuffering if we just call is_readable()
52e3628... Yes, yet another evil all-in-one commit of intervowen changes. I suck. * Drop "state" directory, fold that into "runtime directory" * No longer automatically rewind when a new stream connects * Rework sound file stream, to cause a rewind on initialisation, shorten _pop() code a bit * Fix reference counting of pa_socket_server in the protocol implementations * Rework daemon initialization code to be compatible with non-SUID-root setups where RLIMIT_RTPRIO is non-zero * Print warning if RT/HP is enabled in the config, but due to missing caps, rlimits, policy we cannot enable it. * Fix potential memory leak in pa_open_config_file() * Add pa_find_config_file() which works much like pa_open_config_file() but doesn't actually open the config file in question. Just searches for it. * Add portable pa_is_path_absolute() * Add pa_close_all() and use it on daemon startup to close leaking file descriptors (inspired from what I did for libdaemon) * Add pa_unblock_sigs() and use it on daemon startup to unblock all signals (inspired from libdaemon, too) * Add pa_reset_sigs() and use it on daemon startup to reset all signal handlers (inspired from libdaemon as well) * Implement pa_set_env() * Define RLIMIT_RTTIME and friends if not defined by glibc * Add pa_strempty() * rename state testing macros to include _IS_, to make clearer that they are no states, but testing macros * Implement pa_source_output_set_requested_latency_within_thread() to be able to forward latency info to sources from within the IO thread * Similar for sink inputs * generelize since_underrun counter in sink inputs to "playing_for" and "underrun_for". Use only this for ignore potential rewind requests over underruns * Add new native protocol message PLAYBACK_STREAM_MESSAGE_STARTED for notification about the end of an underrun * Port native protocol to use underrun_for/playing_for which is maintained by the sink input anyway * Pass underrun_for/playing_for in timing info to client * Drop pa_sink_skip() since it breaks underrun detection code * Move PID file and unix sockets to the runtime dir (i.e. ~/.pulse). This fixes a potention DoS attack from other users stealing dirs in /tmp from us so that we cannot take them anymore) * Allow setting of more resource limits from the config file. Set RTTIME by default * Streamline daemon startup code * Rework algorithm to find default configuration files * If run in system mode use "system.pa" instead of "default.pa" as default script file * Change ladspa sink to use pa_clamp_samples() for clamping samples * Teach module-null-sink how to deal with rewinding * Try to support ALSA devices with no implicit channel map. Synthesize one by padding with PA_CHANNEL_POSITION_AUX channels. This is not tested since I lack hardware with these problems. * Make use of time smoother in the client libraries. * Add new pa_stream_is_corked() and pa_stream_set_started_callback() functions to public API * Since our native socket moved, add some code for finding sockets created by old versions of PA. This should ease upgrades
f94fae3... move unlinking code to operation_unlink()
f3cc178... some minor updates
11559a6... parse boolean parameters as boolean instead of int wherever applicable. add new function pa_cli_command_execute_file_stream()
414f1d9... install gccmacro.h properly, drop  unused core-def.h file
d7cc1f5... change pa_rtpoll_set_timer_absolute() to take a pa_usec_t instead of struct timeval
5816871... save and restore errno in log functions
b93ea18... minor reformat
4f99c43... check for $PULSE_INTERNAL before enabling padsp
18ad6f8... don't allow overwriting of callback pointers when we're already dead
b70edf7... port pa_sample_clamp() to liboil
9dd8f6c... add new function pa_sample_clamp()
264385a... strip CRLF line breaks from read CLI commands. This should fix the cli interface for people accessing it via telnet.
f49df7a... * Increase history set to 64 to simplify reduction of indexes * Decrease memory consumption a bit by using bitfields for some bools * Rework reduction code * Drop an unnessacary counter * Before adding a new entry to the history, try to figure out if we already have an existing entry with the same x value and replace that. This fixes a division by zero * Fix up input x for all functions, according to the time offset
563f4b6... make check for $DISPLAY=="" more readable, pa_bool_tization
06a05bc... a bit of pa_bool_t'ization
b12b8ee... save errno before calling free()
caf742a... define minimal and maximal wakeup/sleep times; check for underrun condition only once during buffer fillup
5353cf4... fix size of requested_latency
067a68a... fix build for auxiliary modules
c8fc223... add stripnul to build
76031df... Big pile of interdependant changes: * Fix a deadlock when an asyncq overflows and an RT thread needed to wait until space became available again while the main thread was waiting for a operation to complete and thus didn't free any new items. Now, if the asyncq overflows, queue those items temporarily, and return immediately. Then, when the queue becomes writable again, flush it. * Modify pa_thread_mq_init() to also set up pa_rtpoll events properly for the MQ * Some more pa_bool_t'ization * Unify more common code between alsa-sink and alsa-source * The upper limit for the tsched watermark is max_use minus one frame * make module-alsa-source work * make the alsa modules use pa_alsa_build_pollfd() now * fix detection of dB scale for alsa-source
a197644... add new tool 'stripnul' which can be used to drop leading zeros from a file which is useful to do byte-by-byte comparison of what goes in and comes out of PA
f2dffb7... pa_bool_t'ization
0b183fb... respect the resampler's maximum block size to avoid that we get kicked out of the memory pool due to resampling. actually drop data from the delay queue after we used it
998ed8e... add missing header definitions for last commit
3f57d3a... add new function pa_alsa_build_pollfd() to alsa-util to unify a bit more common code from the sink and the source
ed0af46... unify code that fixes up buffering metrics
af03dd4... drop a misplaced newline
3c8e83f... do not fix automatic buffer attrs anymore, the new protocol version doesn't need this anymore and it creates more problems than it solves. Also drop the initial timing info query. Correct programs shouldn't depend on it anyway
5e6aacd... * don't increase tsched_watermark on underrun without limits * fix the watermark when we change the latency * fix latency measurement * move rewinding code into its own function * make use of new function pa_alsa_recover_from_poll() were applicable
6b4b95b... show configure latency metrics
1adbe82... some beautification updates, show msec instead of usec everywhere
cdb077b... if no timer was armed, we don't need to disarm it
4a1971a... if no latency was configure for a sink/source, fill in the max latency automatically
69f6bdf... add new function pa_alsa_recover_from_poll() to merge common core from module-alsa-sink and module-alsa-source
9a486ef... implement --process-time
0d01c43... make sure the client buffer has space for 2*minreq+tlength. Explain why
e16a198... - Change meaning of special values of latency request: 0 -> "minimal latency, please"; (pa_usec_t)-1 -> "don't care" - Remove "source" word from monitor source description - Increase default tsched watermark to 20ms again - For the first iteration after snd_pcm_start() halve the sleep time as workaround for USB devices with quick starts
88227c4... properly initialize memblock->is_silence for imported memory blocks; make is_silence and read_only a bit field
5e7e827... improve dB volume calculation
ba6c0e1... fix C++ compat
8181db1... initialize properties for ALSA sinks/sources more elaborately, re #277
c2c833c... use the sink description instead of the name to choose the description for the monitor source
64e048c... drop a redundant pa_init_proplist(), properly set MEDIA_NAME property on stream, not on context
5971345... rename sink_input->rewind to process_rewind() and set_max_rewind to update_max_rewind()
62e7bc1... Big pile of dependant changes: * Change pa_memblockq to carry silence memchunk instead of memblock and adapt all users * Add new call pa_sink_input_get_silence() to get the suitable silence block for a sink input * Implement monitoring sources properly by adding a delay queue to even out rewinds * Remove pa_{sink|source}_ping() becaused unnecessary these days and not used * Fix naming of various rewind related functions. Downstream is now _request_rewind(), upstream is _process_rewind() * Fix volume adjustments for a single stream in pa_sink_render() * Properly handle prebuf-style buffer underruns in pa_sink_input * Don't allow rewinding to more than the last underrun * Rework default buffering metrics selection for native protocol * New functions pa_memblockq_prebuf_active(), pa_memblockq_silence() * add option "mixer_reset=" to module-alsa-sink * Other cleanups
7556ef5... maintain a global silence memblock cache
a0671aa... fix for new location of gccmacro.h
d1d7a07... we have not periodic timers anymore
33a35b6... update to recent changes of proplist api
33cb589... split user supplied data in multiple memory blocks if necessary to fit in one mempool tile. If the caller supplied a free_cb and we use shm it's better to copy the data immediately to the shm region instead of keeping it around as user memblock
ed36f31... increase the default pool size to 16MB because we now need to keep a lot more memory around due to glitch-free.
03df088... add lower boundary for artifical latencies
af25697... follow pa_pstream_use_shm->pa_pstream_enable_shm rename
687aa29... add new pa_pstream_get_shm() API, rename pa_pstream_use_shm() to pa_pstream_enable_shm(); pa_bool_t-ization
bee409a... remove debug messages
1ddb95a... add new silence memblock caching subsystem
4b1d684... add new API function pa_memchunk_memcpy()
144b237... print a message on xrun
22ceb15... add new rtstutter tool which can be used generate artifical scheduling latencies in the OS to trigger buffer underrun events in your software. it's an awesome debug tool for glitch-free; also move test programs from automake's check_ back to noinst_ to make sure it is built everytime Lennart presses F9 in his emacs
c9d0159... define PA_xxxSEC_PER_yyySEC for usec, too
1f0a52d... the pointer to rewind() may actually be NULL
68e4a93... properly ask the sink to rewind on new sink inputs and when they disappear
6946d2a... make sure to clear all queued RT signals before arm a new timer
04178d4... add _cb suffix to _max_rewind function like with all other functions, too
14fd32e... add missing 'break's in switch
55f273e... s/pulsecore\/gccmacro.h/pulse\/gccmacro.h/
07f5c1d... register sink/source name as first step when creating a new sink/source so that we can hand the valid name string to the hook functions; se tup props for monitor sources correctly; fix implicit flag setting logic
aad9d39... dump all info we know about sinks/sources/... in pactl
dbe3633... properly initialize ->memblockq
cdb273d... add new pa_get_state_dir() function, move pa_strnull() here
dcf7173... fix help string for volume commands
fe3c42d... fix packet formatting for a few commands
2c6176f... mark shm marker struct as packed, to guarantee identical sizes between archs
29cbd88... add new PA_GCC_PACKED macro
096e7f0... make shm magic marker compat with multiarch systems where 64bit and 32bit processes might share SHM areas
c9db6d2... don't fail if a signalled writability of STDOUT is no longer true when we try it because some other thread already wrote something
413656b... update list-xxx commands a bit
28ab2a0... don't print 'signal' each time a rtpoll poll() call is canceled
50d585e... fix linker warning macro code, move pa_strnull() to core-util.h, move PA_LIKELY definitions here from gccmacro.h
d0ebb71... don't use fqdn if we don't have to
78368db... redirect alsa errors to normal PA log system; export buffer settings in device props
1c5f665... make use of new alsa SND_PCM_NO_AUTO_xxx flags; redirect alsa errors to normal PA log system
0f28de6... mark autoload functions as deprecated
d7e260b... remove misplaced PA_GCC_PURE
e832b0c... add C++ safety to header file
7dad635... fix bit depth guarantee for pa_usec_t
919bd98... add new API function pa_timeval_add()
566322a... remove gcc macros from cdecl.h because we have them in gccmacro.h now
007f82d... fix bad memory access when initializing client proplist
d491adf... add gccmacro.h to doxygen docs
e084e4b... add new module module-device-restore
c61c3b6... increase version of required ALSA to 1.0.16. check for gdbm
6cddf61... add new API pa_rtclock_from_wallclock()
e1c1a78... fix proplist serialization
bb9792a... move gccmacro from pulsecore/ to pulse/
5d7128a... add new describe-module CLI command
39afb14... add new pa_proplist_setf() API function
d69aeeb... implement server side of new sink/source reconfiguration commands
fc9d827... remove doxygen \since tag for API changes older than 0.9; properly implement new latency query APIs
cc1e265... init min/max latency properly; fix avail_min updating
f3109be... show configured latency and its ranges
da37a7e... export both min and max latency that is configured for a sink; add API for querying the requested latency of a sink/source from the main thread
ad18107... add new latency argument
0f9e977... bump protocol version
3138928... include proplist.h in doxygen docs
b3b8a63... call snd_pcm_hwsync() expclicitly before we access any of the status fields, since this seems to be necessary. try to find the right mixer device via the card index
c84a64c... fix bug where we silently dropped data that didn't fit into one mempool tile
98b0152... add utility functions to dump alsa PCM state
b9c10f2... propery calculate min_avail in frames instead of bytes. don't use device_id= parameter in alsa modules if parameter wasn't specified
064aa12... drop support for periodic timers, cleanup code a bit
122861f... mark libpulse-browse as obsolete
cdfcf66... - deprecate autoload stuff - allow setting of the requested latency of a sink input/source output before _put() is called - allow sinks/sources to have a "minimal" latency which applies to all requested latencies by sink inputs/source outputs - add new client library flags PA_STREAM_ADJUST_LATENCY, PA_STREAM_START_MUTED - allow client library to fill in 0 to buffer_attr fields - update module-alsa-source following module-alsa-sink - other cleanups and fixes
ecf6439... catch up with trunk HEAD (i.e. 2118:2213)
3e314b7... fix buildsystem to provide pa_log() in all binaries
cf37df4... rework pa_assert_se() to make sure it never gets optmized away, even if NDEBUG is defined
68b131d... make pa_drop_caps() abort on failure
dbf9037... avoid name clash with libc's remove() function
829197d... fix compiler warning
ed5528f... require autoconf 2.60 since we use AC_PROG_MKDIR_P
1c82694... bump soname
a3b8311... merge r2187 from trunk
0a108ec... don't fail on init if the default device does not exist and .nofail is active
fad6b41... don't segfault when module-tunnel is used without a sink_name/source_name parameter. Closes #197
13b9951... if we are run as root, always use 'root' as username, regardless of any env vars
8e60b01... actually set lennart to the user name, not the group name. Set lennart too.
2599213... Fix ioctl() definition for solaris compat. Patch from yippi. Closes #253
b0dc80d... work around yet another solaris braindamage
4ddc327... initialize gconf module before we publish our X11 credentials -- because gconf might cause network support enabled in the first place
e21a69e... merge r2146 from trunk
2b593d2... merge r2134 from trunk
e5e9ed6... merge r2133 from trunk
ac82029... merge r2132 from trunk
95422a8... merge r2131 from trunk
edd1a50... merge r2130 from trunk
02840a3... merge r2129 from trunk
a1ec3d7... merge r2128 from trunk
46cd225... merge r2127 from trunk
daaf70b... merge r2117 from trunk
28b7ddc... merge r2116 from trunk
cca3f49... merge r2113,r2214,r2115 from trunk
184dda8... merge r2112 from trunk
1eb7239... merge r2111 from trunk
5045d26... merge r2110 from trunk
39de4dd... merge r2109 from trunk
bc58240... merge r2108 from trunk
ec39786... merge r2107 from trunk
e704fd3... merge r2106 from trunk
b79c6b6... merge r2105 from trunk
b0a2049... merge r2104 from trunk
a451de1... merge r2098 from trunk
2735309... merge r2097 from trunk
640033a... merge r2096 from trunk
9dfbfce... merge r2095 from trunk
cc59e76... merge r2092,r2093,r2094,r2152 from trunk
db208e3... merge r2091 from trunk
9f0045a... merge r2090 from trunk
f10b531... merge r2084 from trunk
66d9e87... merge r2145 from trunk
d055127... merge r2083 from trunk
cefa0eb... merge r2081 from trunk
0e23606... merge r2079 from trunk
a86a48c... merge r2077 from trunk
5e13249... merge r2076 from trunk
aceb800... merge r2075 from trunk
e721ecd... merge r2073 from trunk
8d5ee50... merge r2074 from trunk
c59a90c... merge r2078 from trunk
05a7f5d... bump revision
e6bb276... create branch for 0.9.10
106ddb9... remaining bits and pieces
b5c5064... commit glitch-free work
d6bd152... commit glitch-free work
ebecf3d... commit glitch-free work
12c01e9... commit glitch-free work
347cfc3... commit glitch-free work
8d9bdac... really create glitch-free branch
dd81a90... create glitch-free branch
90a7f3b... bump revision
4d4dafb... fix CVE-2008-0008.patch
9423e67... prepare 0.9.9
d41744a... Tagging release 0.9.8
575541d... Merge r1502 from trunk: Move pthreads detection as it gets confused by things in LIBS.
f096ca4... Merge r1504 from trunk: Solaris hides inet_ntop in nsl
c6071b0... Merge r1505 from trunk: Make sure we link to the core to get all symbols.
9eb840c... Merge r1503 from trunk: Make -no-undefined actually work (and fix up error found by it).
d8976a2... Merge r1473 from trunk (mixer ioctls on /dev/dsp)
b718d18... fix error handling
daa2863... don't use errno on EOF
94cf167... port module-esound-sink to new core
66dc0b4... don't use SIGRTMAX, for compatibility with valgrind which apparently uses this signal
98d363c... minor cleanup
87faa54... minor fix to make gcc shut up
56804de... minor fixups, to make the test more deterministic
581e7f1... add ability to "pause" the input time temporarily. don't accidently overwrite variables we still need.
55e4a3e... modernize pa_iochannel a bit, add pa_iochannel_get_send_fd()
c4d9a2b... add missing pa_smoother destructor
b4bb747... add pa_rtclock_usec() API
ca744a4... add pa_timeval_load() API
ce5250e... hide smoother test
7ccf40e... Add "support" for plugins that have control output ports, i.e. don't crash on them anymore (the plugins correctly assume that every port is connected to a buffer, so we connect them to a dummy buffer that isn't used anywhere).
81ed6e6... A couple of comment typo fixes.
0d84e4c... fix alsa mmap initialization bogosity, discovered by Jyri Sarha
dc987e9... add better time interpolator: use linear regression to determine gradient from measurements, predict a short distance ahead, and smoothen estimation function with 3rd degree spline interpolation.
9464b9b... add definition of PA_USEC_PER_MSEC
65b570c... properly copy error string
498a156... also port over JACK source to new core
02adb5f... enable jack sink in Makefile
468c13e... Port JACK sink module over from old core
4029504... minor fixup
925eadd... add interleaving/deinterleaving APIs
1900817... Properly handle if ALSA sends us an POLLERR event, this should allow us to survive a system suspend cycle better
2385efe... fix url
b0bce20... add missing poll.h inclusion
215cac8... add missing poll.h inclusion
a687c31... add missing poll.h inclusion
3736246... s/timespec/timeval
2198c2e... fix build
efc81a8... add new API function pa_timeval_store()
d74fa66... Fix build; change return value of pa_rtclock_hrtimer() to pa_bool
87cc073... fix poll.h check, bad boy ossman broke
cb40087... Don't call pa_rtsig_configure() when we lack the necessary defines.
60a935b... module_ladspa used libltdl so make sure it links against it.
586ef22... Platform dependent semaphore implementation for Windows.
cef6563... Assorted minor Windows compatibility fixes for recent code updates.
ce74146... Add stubs when RT signals aren't available.
8dcc1fa... Adapt rtpoll and friends to Windows by replacing timespec with timeval and add a fallback when clock_gettime() isn't available.
ef8812e... Replace all references to sys/poll.h with poll.h as that's what POSIX defines.
7c1768d... update native protocol to make use of pa_memblockq_pop_missing
2e780e8... Move request size handling into pa_memblockq, function pa_memblockq_pop_missing()
d6a2203... Fix race condition between IO thread creation and pa_sink_put(). Move activation of rtpoll fds when we change the state INIT->IDLE.
9d34a1e... fix trivial typo
abd692e... fix silence initializer for alaw and ulaw
dbcd086... Fixed PA_GCC_CONST definition.
bdf9746... Update module-solaris to new structure.
67b899a... treat timer_enabled like a real, grown-up boolean variable
33f2f49... rework module-combine once again. We now run the data generation always in a seperate thread. This should help use to avoid all the awful race conditions we had in previously
229afb5... Move the poll() call outside the #ifdef checking for ppoll, since we want the poll in all cases. Prior to this change the check for negative return values of poll/ppoll was never actually executed when ppoll() was available
f8c1786... use the full range of RTSIGS for our stuff
3cdff5f... Allocate rtsigs from back to front, to avoid clashes with other libraries makeing use of rtsigs
df33b4c... only do IO if we are RUNNING or IDLE, but not when we are in INIT
6d8aea7... Incorrectly used str2sig() instead of sig2str().
584ca61... don't free silence memblocks that don't exist
107f12a... speed up semaphore allocation with an flist
008c709... Use Linux eventfd() if kernel supports it
e99bc33... fix build with compilers that lack __thread
a9e667b... make sure when can shutdown PA cleanly without segfault
5fe1589... work around newest open() magic in fedora glibc
1687226... fix make dist
86ec421... fix suspending in module-combine.c
609ad12... * decouple suspending of monitor sources and their sinks * implement resume-on-uncork
0e3e9e2... only post data into the monitor source when it is not suspended
f0f9df9... * add new state changed hook for streams * update sink->n_corked properly when moving streams
ac86fa1... fix IDLE vs. RUNNING state handling of sinks/sources when changing cork status for streams
3c75d35... rework zeroconf service publishing, to use synchronous hooks instead of asynchronous subscription events. Don't push autoload entries anymore.
e37fa01... add hooks for name/description changes of sinks/source and streams
ef020c6... fix stream corking: ignore pa_sink_input() when we are in corked state
55651ec... don't count streams using the monitor source in pa_sink_used_by(), because this would disallow suspending a sink ehn an rtp stream is connected
ba322a4... drop the PA_SOURCE_CAN_SUSPEND and PA_SINK_CAN_SUSPEND flags, since they were a bad idea in the first place. All sinks/sources are now *required* to handle suspending in one way or another. Luckily all current sink/source implementations handle it fine anyway.
77ed60c... instead of using the mixer ioctl()s on the dsp fd, open a seperate fd for the mixer. This allows us the keep the mixer fd open while closing the dsp device while suspending.
fc00eaf... use O_NOFOLLOW when creating lock files, too
2860685... use O_NOFOLLOW when creating PID file, to avoid symlink vulnerability
de079ac... Added an assertion for the case when the sink programmer hasn't installed the thread_mq properly.
7bcbf16... Comment typo fix.
ecad937... Fix the assignment of control values by using the right variable for indexing.
1c44be2... Correct the parameter positions with the pa_cvolume_set() call.
e04a857... minor optimization
6cfb096... include the name of the master sink in the name for piggy-backed virtual sinks
c6b43bf... prefix by order macros with PA_
6683400... rework a couple of sample type converters, to actually work
78a9ad3... - rework volume adjustment code to not require fp - don't hit an assert when we cannot do a volume adjustment, instead, print a warning and go on
d7a0876... fix selection of working format
9db4267... make use of byte swap builtins of gcc if they are available
f26de80... add test program for the resampler
c34a263... allow _unlink() functions to be called as many times as people want, even before _put() was called
1fc168b... clamp sample data to -1 .. 1, before passing it to the plugin; if a control port data specification is left empty, initialize with the default value of the plugin
29d25ec... add CLAMP macro
e205bb2... don't segfault when the master changes
3b2835d... properly detach/attach when moving sink inputs
f3f44da... rework module-combine again
c40c168... maintain the attach status in a boolean variable 'attach' accessible from the IO thread for sink_inputs/source_outputs
75647bc... render new data always in the master sink's thread, fixing missing locking
a8a9ee4... make sure we initialize thread private data before we move our ghost sink to the rt thread, not after
42b71ff... fix trivial typo
d716e3c... fix check for lrintf, make resample2.c again identical to upstream ffmpeg
75f799a... make O_CLOEXEC, O_NONBLOCK and socket low latency fd ops more uniform: always return void, name them similarly, only pass a single fd
0fcad97... copy free_cb into a temporary variable first, to avoid compiler warning
ac66b6a... fall back to plughw:, if hw: doesn't work, in the alsa source, too
781cf49... properly release memblock always abd as soon as possible
1fd9afd... make use of pa_bool_t on a few places where applicable; really start work_cb
b3093d8... lower SO_PRIORITY priority to 6, since this is the best we get without being root
ef8df41... make rtp send socket low delay
f44ddd1... add new pa_socket_udp_low_delay() API
6b2fd23... add two missing header file inclusions
eb23601... bug fixes for module-rtp-recv
8fdf054... make sure we don't call pa_source_post() for a monitor source after it was unlinked
ca71764... If PTHREAD_PRIO_INHERIT mutexes are not available fall back to normal mutexes
a558e93... port module-rtp-send.c to lock-free core
08d4b23... actually close the alsa device before we try to reopen it as plughw
4ed41f3... strtof() is a rather recent addition to C. Fall back to strtod() if it isn't available.
aff22cf... NSIG seems to be more common than _NSIG.
03d9863... Emulate lrintf with simple truncation if it isn't available.
31dfb31... Make sure the header file is only included on linux (as this is a linux-only feature).
df1d347... NSIG is not defined by neither C99 nor POSIX so we can't rely on it.
4cde507... add LADSPA sink than can be piggy-backed ontop of another sink
7b4f981... print a message when we fall back on plughw
8ff7d56... add a locale-independant pa_atof() implementation
4cdf2ce... hide sig2str-test
1ae473b... fall back to plughw: if hw: doesn't work
26a1ae7... Rename pa_strsignal() to pa_sig2str(), since we return the symbolical signal name, not a human readable string. This follows the Solaris API of sig2str() a bit. Also, add all remaining signals to the list of signal names.
d3b8985... drop a couple of WARNING prefixes in log messages, since we have pa_log_warn anyway for marking warnings especially
19eb7eb... once.c is no longer POSIX specific. Since it is now considerably more advanced than it used to be, use it on windows, too
7f9fea7... on Linu disable lazy binding altogether
a1526f1... add missing initialization
061e806... Add a special ltdl .so loader that avoids lazy frelocations during runtime
2741685... use priority inheritance on mutexes where applicable
61b90a0... add proper boolean type pa_bool_t
116ddaa... use gcc const and pure function attributes wherever applicable
35483ee... add a new module module-remap-sink which can be used to remap the channel maps of an already existant sink. one use case is to create a virtual sink that redirects stereo data to the rear speakers of a surround card.
1d1eda6... add a "length" argument to the seek functions, as an optimization to request a certain block size if any data needs to be generated. this is merely a hint.
5df7a85... split memblocks into multiples of the mempool tile size
ac1ee4e... add new API pa_mempool_block_size_max() to query the maximum tile size
fce8507... * add a new resampler "copy" which is does not change sample rates but copies data unmodified from input to output. * add a new API pa_resampler_max_block_size() which can be used to determine the maximum input buffer size for the resampler so that the bounce buffers don't grow larger then the mempool tile size
d079b48... properly define MAX/MIN macros
87795b0... add missing header file changes for frame alignment apis
e17fbf0... be a little bit more elaborate on the reason why we drop to software volume control if hw is not featureful enough for us
0469c84... add frame alignment APIs; don't require memory to be writable when silencing it (required of the mmap modes drivers where the hw data needs to be silenced, although it is not writable to others)
298d239... trivial typo
8389264... count corked streams per sink/source and make pa_sink_used_by() return only the number of streams that are not corked. Introduce pa_sink_linked_by() returning the number of streams connected at all. This will allow suspending of sinks/sources when all streams connected to a sink are corked.
5ae4eed... Move attaching/detaching from a pa_rtpoll into pa_sink proper, remove it from module-combine
3396b65... simplify rt loops a bit by moving more code into pa_rtpoll. It is now possible to attach "work" functions to a pa_rtpoll_item, which will be called in each loop iteration. This allows us to hide the message processing in the RT loops and to drop the seperate sink_input->process hooks. Basically, only the driver-specific code remains in the RT loops.
f0b9dce... explicitly destory TLS data before destroying TLS
bf274cb... add two new macros PA_ONCE_BEGIN and PA_ONCE_END which allow usage of pa_once without declaring a function to be called
04ed0f9... call dbus_shutdown() before exiting, to make valgrind output more useful
8775309... fix two typos in reference count handling
9be0d70... make newer gcc shut up
ef83a19... extend rtpoll API to allow registration of arbitray functions to be executed in the event loop. Add priority system for specifying the order of these functions.
cf3e9da... add missing config.h inclusion
03f311a... reindent, and s/assert/pa_assert/g
4137865... change pa_modargs_get_channel_map() to take an extra argument for specifying the name of the modargs attribute to parse
d9c4c95... add new pa_pipe_close() API to close two fds at the same time
7f92542... consolidate close() calls to pa_close(), and make sure on every occasion that we handle failures of close() sensibly
54506ab... on systems where we know that POSIX shm is mapped to /dev/shm, add the ability to cleanup stale SHM segments. (Right now only Linux)
d5bedbc... remaining s/assert/pa_assert/ and refcnt.h modernizations
2988c3d... Rework core-error.c on top of PA_STATIC_TLS_DECLARE, the windows specific parts need to be moved to thread-win32.c
abb18d9... explcitly initialize tls memory to NULL
9c523e0... more modernizations, s/assert/pa_assert/g
27f13b3... finish modernizations in pulse/, s/assert/pa_assert/g
038e560... More s/assert/pa_assert/ modernizations
391d09c... add 'wait' parameter to pa_rtpoll_run(), if zero pa_rtpoll_runn will only update the struct pollfd but not wait for an event
597a1c4... port client libs to refcnt.h
55d9fcb... add globally defined PA_PATH_SEP macro, replacing private per-file macros
6ac66e4... add missing config.h includes
e2e2ce7... Instead of including config.h from header files, check whether PACKAGE is defined and if not, fail (thus using PACKAGE as a check for inclusion of config.h)
848a4d7... more s/assert/pa_assert/ modernizations
9b0ab39... unify static TLS support, make use of gcc __thread attribute if available
3d122d0... s/assert/pa_assert/ modernizations
de21b54... add new API pa_threaded_mainloop_in_thread(), update test case for it
a6f8b81... simple modernizations: s/assert/pa_assert
6629886... make sure we send each memblock only once when recording, not twice
d5caa02... minor cleanup
a77158e... make the memchunk writeable before silencing it
841fcb4... beef up comment
98f9bd6... make sure that the device volume is properly read before we call pa_sink_put() and thus make the pa_sink available
69ece66... add pulseaudio logo with text
44e514c... update todo file a little
6c1682c... hide a couple of files
27c3bd4... document that the native amd64 atomic ops implementation is incomplete
06db921... don't call pa_source_process_msg() for PA_SOURCE_MESSAGE_GET_LATENCY, since it makes querying the latency always fail
d9b3c0e... posix_madvise and posix_fadvise aren't present on all systems.
9630e8d... Remove mkdir_p again...
028632f... TIOCINQ isn't present on all systems.
e176601... Monotonic clock is optional so treat is as such.
717b164... POSIX realtime clock functions are in time.h so make sure to include it.
dfdf1d7... Changed PA_SAMPLE_S16_NE to PA_SAMPLE_S16NE in the example code in the Simple API Doxygen documentation.
b41dbfd... fix an assert when runnig module-oss in record only-mode. optimize allocation of memblocks on playback
d60940d... install libpulsecore again, since libtool otherwise links it statically into every single module
e4eefb8... fix copynpaste error
45ba711... downgrade realtime group membership warning to 'info' at be a little bit more elaborate
3b2cf1a... update default config: - check for existance of modules before loading them - disable all event sounds except hotplug by default
b1fd53b... explicitly test for the availability of dbus_watch_get_unix_fd() before using it. The previous version-based check didn't work anyway since the constants checked for weren't set.
a0d19c0... update libltdl copy
a4757a1... add native amd64 atomic int implementation
984ef82... detect whether gcc atomic builtins are available
4c31ff9... fix a couple of compiler warnings
2dbe137... if available, use native gcc atomicity builtins
31c04a9... create config.rpath to fix build on fedora
ac5f978... add a few missing files for make dist
738f7d7... drop initial libtool_lock() call since this is a debian-specific borkage
d1927c7... initialize libltdl for multi-thread support
65ac0ea... When in PA_STREAM_AUTO_TIMING_UPDATE mode, delay completion of initialization until we have the first timing data
c029038... actually add source code of module-default-device-restore
11bf380... add a new module module-default-device-restore which automatically saves and restores the selected default device. Enable it by default.
1d3e70c... header file cleanup
104feb0... only list supported resampling methods when --dump-resample-methods is executed
c9a0df3... add new API function pa_resample_method_supported() which tests whether a resampling method is supported. Fix building with libsamplerate enabled
5bc1221... actually define HAVE_LIBSAMPLERATE with AC_DEFINE
b2c4779... make libpulse-core a noinst lib, because it does not have yet a stable API and won't get one anytime. Also, don't install its header files
b6bfaa9... add missing configure.ac part of the libsamplerate patch from r1753, re #125
2e8244b... Allow compilation without libsamplerate; based on patch from Marc-Andre Lureau; re #125
cc8c499... fix dbus version check for dbus_watch_get_unix_fd()
011dfa5... make argument to pa_memchunk_will_need() const
68981e5... fix build for dbus < 1.1.1, re #126, patch from Marc-Andre Lureau
ca059ab... Don't set RLIMIT_MEMBLOCK to 0 on startup. Retain 4 pages
3e188b1... make use of pa_memchunk_will_need() before handing sample cache audio to the RT threads
7dbabc4... add new pa_memchunk_will_need() API, similar to pa_memblock_will_need()
f36ca79... add new API pa_memblock_will_need() and make use of PA_PAGE_SIZE macro
2f7b6fe... add new pa_will_need() API for paging in memory
8cf822a... make use of new PA_PAGE_SIZE macro
b54e71a... make use of new memory page alignment macros, reindent
fe1f55b... add a couple of macros for memory page alignment
1df817c... add pa_channel_position_to_pretty_string() to header
718b1d2... add pa_channel_position_to_pretty_string() for usage in pavucontrol/pavumeter
02811bf... make sure that we make include paths absolute before calling chdir()
a132226... minor reformatting
6eb2f88... add two new functions pa_make_path_absolute()/pa_getcwd()
c627871... replace a pa_assert() by an pa_assert_se()
f59dd18... - fix suspend handling - set sink description properly - honour resample_method setting
241ad04... port module-combine to new core
4d623f0... Lots of assorted minor cleanups and fixes: * s/disconnect/unlink/ at many places where it makes sense * make "start_corked" a normal pa_sink_input/pa_source_output flag instead of a seperate boolean variable * add generic process() function to pa_sink_input/pa_source_output vtable that can be used by streams to do some arbitrary processing in each rt loop iteration even the sink/source is suspended * add detach()/attach() functions to pa_sink_input/pa_source_output vtable that are called when ever the rtpoll object of the event thread changes * add suspend() functions to pa_sink_input/pa_source_output vtable which are called whenever the sink/source they are attached to suspends/resumes * add PA_SINK_INIT/PA_SOURCE_INIT/PA_SINK_INPUT_INIT/PA_SINK_OUTPUT_INIT states to state machines which is active between _new() and _put() * seperate _put() from _new() for pa_sink/pa_source * add PA_SOURCE_OUTPUT_DONT_MOVE/PA_SINK_INPUT_DONT_MOVE flags * make the pa_rtpoll object a property of pa_sink/pa_source to allow streams attached to them make use of it * fix skipping over move_silence * update module-pipe-source to make use of pa_rtpoll * add pa_sink_skip() as optimization in cases where the actualy data returned by pa_sink_render() doesn't matter
b552541... reorder initialization of pa_core variables
ca72adf... modernize and make use of a static flist for allocating idxset entries
821eb8e... move queue processing code into pa_thread_mq
687f1f1... add new function pa_memblock_ref_is_one()
c2e4328... fix pa_memchunk_make_writable(), make memchunk functions return the memchunk they modify
bfe69ce... add an assert()
6817987... add pa_timespec_reset()
747b01b... make passing a code pointer to pa_asyncmsgq_get() optional
ee97c42... add new PA_SINK_CAN_SUSPEND/PA_SOURCE_CAN_SUSPEND flag
d88514c... drop check for gid < 500, since this isn't really a security improvement, re: #111
0362350... Add option --dump-resample-methods to list available resampler implementations
782d5a5... make floating point speex resampler the default
89fcd51... enable -ffast-math for gcc
f82067f... lower suspend timeout to 1s
f4e2d23... include ffmpeg resampler in build
9439e81... make ffmpeg resampler actually work
f0dbbe9... add makefiles to speex/ and ffmpeg/ to easy compilation from emacs
640ae04... Copy resampler from ffmpeg into our sources
f754a24... make speex resampler the default
ed4dc16... big resampler rework: support integer-only resampling, support speex resampler
4eb9bb0... fix a bad memory access when destructing pa_memimports
c1cdcfd... a couple of modernizations; parse RE sample types properly
c72d4c6... add a small speex wrapper so that we can include both the fp and the fixed-point resampler in the same binary
fdead57... build speex resampler tiwce, once for fixed point, one for floating point
5ff891c... add a copy of the speex resampler to our sources
b3b382d... fix minor typo
9d38159... port remaining sinks to pa_rtpoll
1bfa180... minor cleanups
0ff2afd... support absolute, relative and periodic timers in pa_rtpoll
53b872c... port alsa driver to make use of new pa_rtpoll object
79d3ddd... reverse hrtimer check, add missing #include
b937009... add convenience functions to hook up pa_fdsem and pa_asyncmsgq to an pa_rtpoll; add pa_rtpoll_item_get_userdata(), on EINTR/EAGAIN, reset revents; automatically destory left over items
7490977... add missing include
0449966... make pa_make_power_of_two() and pa_is_power_of_two() inline functions
190648a... add missing #include
0da65cf... add message about hrtimers, and initialize pa_core::high_priority
0af0fb8... hide rtpoll-test from svn
7fca890... check pa_core::high_priority before becoming rt thread
b302946... add new option to pa_core stating whether we are running as high prio process
3546198... add check for ppoll()
8568f70... add rtpoll, rtclock, rtsig to Makefile
dc9d803... add test program for pa_rtpoll
78c362c... add new realtime event loop abstraction which precise time keeping by using hrtimers on Linux, if they are available
8972d06... add facility for managing realtime signals
ef2bc41... add monotonic clock abstraction pa_rtclock
6bfeef1... rename a few things in a macro to make name collisions less likely
531cc3c... make use of new public function pa_is_power_of_two()
b7b119a... add pa_is_power_of_two() and pa_make_power_of_two() functions
a0ad42a... add macro for creating static TLS objects
b0b06b0... add more PA_PTR_TO_XXX macros
fa7fc31... modernizations
2d292be... use realtime scheduling for ALSA and OSS driver threads
876e682... never stay root after startup, even if we don't have capabilites
5e93816... seperately get high nice level and acquire realtime sched
d5cbf4f... Keep CAP_SYS_NICE not only in PERMITTED but also in EFFECTIVE capset
843dcce... only suspend device when server is local
39d1e65... truncate service names if necessary, include user name in service string
03b0b1d... add pa_truncate_utf8() function for truncating a string and guaranteeing it stays valid UTF8 afterwards
81cdb37... add fedora-snapshot target
c0d6684... fix an awful race condition when handling data requests
1ff4786... don't fail if no pa is srunning
a96c5f8... add new tool pasuspender which temporarily suspends all sinks and resumes them later again
33c6f9d... set CLOEXEC on more fds
5679de5... add new commands suspend-source, suspend-sink
d2d0978... add protocol support for muting sink inputs and suspending sinks/sources
0640615... bump protocol revision and soname of libpulse
b20d204... use pa_source_suspend_all/pa_sink_suspend_all for suspending all sinks/sources
a74e804... fix muting for sink inputs
3d92990... actually mute sinks when asked for i, add new function pa_sink_suspend_all
6f714d9... actually mute sinks when asked for i, add new function pa_sink_suspend_all
44f91cf... load module-x11-xsmp from a /etc/xdg/autostart file, to make sure it is loaded when we have XSMP
80f5abf... add load-module and unload-module commands to pactl
8a663d4... a couple of build fixes
1d5e9f0... deactivate module-x11-xsmp by default, due to a deadlock when pa is being started from gnome-session
e381dd9... 64 bit fixes and minor gcc shut ups
5e96d5d... yet another new glibc build fix
3cbcb98... build fix for newer glibc
e6714e1... make make distcheck pass
db7fdf6... make make dist work
55f3d34... ship full libltdl tree in SVN to make sure we can build this crack on fedora
b16d8e2... bump soname and stuff for fedora pre-release
1cecd46... Resurrect ability to move streams between sinks
79a586d... add comments describing the context these functions are called from
3d81dde... modernize pa_play_memblockq() and add a new function pa_memblockq_sink_input_new() which allows creation of memblockq streams without activating them immediately
14d93fc... minor cleanup
45e4954... fix latency reporting for oss and alsa modules
06f2799... minor modernizations
57734ec... hook into move operations for resuming/suspending devices appropriately
44b82a1... Add 'via DMA' to sink/source description if device is accessed with mmap()
e71a347... restore the ability move record streams between sources
50e014e... use single array for storing pa_core hook lists, add sink state changed hook, drop NO_HOOKS flags for sink inputs/source outputs, listen for resume events in module-suspend-on-idle.c
a3cd800... port oss driver to make use of the default fragment sizes as defined in pa_core: store in the sink/source description whether mmap is used; if mmap() fails, fall back to UNIX read/write mode instead of bailing out immediately
b71dde0... make sure that the device access event sound is only generated once
447c4a5... deal with messages properly which are recieved after destruction of a stream
107b23d... fix module-hal when no api= argument is specified
c1c59b4... add proper refcounting to pa_asyncmsgq objects, to allow destruction from the dispatched callbacks
f7b707b... allow destruction of pa_fdsem object that are still in 'poll' state
e1100b5... modify alsa drivers to make use of new global fragment setting variables
793f750... fix default device naming and fix api selection code
a7a5f43... modernization
e2a10de... allow setting the default sample and fragment settings from the config file
b44ce9e... add default fragment settings variables to pa_core
59c9ed5... move pstream item allocation to pa_flist
d2fed9d... make revoke/release thread safe in the native protocol
ff4814c... add callbacks for the revoke/release stuff, so that we can make this thing thread-safe
4e145b6... if no thread-mq is attached to the current thread, return an error, don't hit an assert
3eae903... make use of pa_thread_mq everywhere
b3f1a13... minor update
f7171e8... Wrap two pa_asyncmsq in a new pa_thread_mq object for bidirectional, lock-free communication between a main loop and a thread
aff77c1... update thread test to use pa_once instead of pa_once_t
27f75a5... Rename pa_once_t to pa_once
d4cb042... move pa_queue to an implementation based on pa_flist
ac49cc2... do not acces playback pa_messagq from main thread
72840ab... minor cleanliness fixes
357c0e4... fix closing of fds in gconf module
ffa1708... * drop redundant pa_core argument from module initialization functions * make pa__done() implementations optional * a couple of modernizations * wrap lt_dlsym() at a single place * allow passing of an "api" argument to the HAL module, to choose whether OSS devices or ALSA devices should be picked up * optimize fd closing a little on linux in the forked gconf helper * save a little memory in the xsmp module
e621071... fix minor memory leakage
10b135a... avoid duplicate loading of modules
1e5ca51... handle ACLAdded messages for previously unknown devices identically to a really new device
3b078b2... Avoid a race condition when one PA instance gets HAL's ACLAdded message before the previous owner instance has given up access to the device, and thus the device is blocked
d9e44c5... Add X11 XSMP module for hooking into the X11 session manager, for being notified about X11 disconnects before they actually happen, so that we are not killed by the bloody xlibs
5831677... modernize
3dfdb21... don't assume that sink/source is already unregistered from namereg when disconnect hook is called
1c7b842... play ACL event sound only when gained access, not when losing it
b751f3a... s/login.wav/startup3.wav
02bf2f2... update default configuration
0f15574... protect memimpors with a recursive mutex to avoid deadlock when shutting down
e76efa9... forgot to actually add the new suspend-on-idle module source code
bb46da3... add new module-suspend-on-idle module which suspends sinks/sources which are idle for more than 5s (or any other configurable time). Power saving, here we come\!
9c89f37... if we get access to a device we don't know yet, add it to our tree instead of ignoring it
30ccf9a... add a couple of additional hooks for modules to use
ed01e1a... don't hit an assert when we cannot resume a device
eaddc01... by default, store esd socket in /tmp/.esd-`id -u`/socket, instead of /tmp/.esd/socket, to allow multiple simultaneous esd instances. this is only compatible with a patched esd, which however ubuntu and fedora ship now. other distros need to patch their esd as well, or may pass socket=/tmp/.esd/socket to module-protocol-esound-unix
33cd5e2... listen for HAL ACL events; play an event sound on hw coldplug, hotplug and ACL access
0c29a2f... add new function pa_scache_play_item_by_name
23ba125... fix bug in handling of defer events
a69f470... modernize module-hal-detect.c and check for ALSA pcm_class != modem
26a0246... modernize dbus-util.c
e4e9a06... be more verbose when device does not support sampling parameters
fedca91... Remove warning when client is too slow to handle our data
df9522c... properly reinitialize pollfd array after resume
54b9f55... properly reinitialize pollfd array after resume
981d5fa... don't print error on socket read/write failure
366d1d3... reinitialize sw params after resume
0a6f9af... add global suspend command to cli
1f9ce59... port esound protocol to new lock-free core
243f2fc... minor fixes and cleanups
74b3b6d... fix playback status querying
455ff8d... fix a memory leak
62790cc... fix playback over native protocol
c306b83... initialize 'length' properly
6775386... make sure to handle disconnecting our own connection properly
41d67c4... minor optimization for cacheing in of samples by using posix_fadvise
872951c... use posix_fadvise to avoid page faults when reading audio files from disk
9d1eb1b... play memchunks completely
bd0782e... initialize method pointers properly
241a9e1... follow rename of pstream_close() to pstream_unlink()
55e0866... typesafe casts
23d01bb... Modernize pstream.[ch], reintroduce defer event to make things actually work
36dd781... modernize play-memchunk and port it to the new core
34e4165... minor cleanups
81760ad... merge compat changes from trunk
95fab18... Don't stop hardware on buffer underruns. Instead continue playing to guarantee that our time function stays as linear as possible.
a6c44c0... Remove unnecessary snd_pcm_hwsync()
9a4e84a... On recommendation of Takashi Iwai prefer Master volume control over PCM and don't control Mic control
d3eca28... rename pa_source_output_new_data::corked to start_corked to match pa_sink_input_new_data::start_corked
0defdfb... A lot of updates, all necessary to get the native protocol ported:
a82505e... port module-alsa-source to new lock-free core
13a4327... minor cleanups
6afbbba... fix suspending logic
81aa8ea... drop data from inputs only when in running state
1615450... It is now allowed to call pa_sink_get_volume() from thread context
8aee345... Fix suspending/resuming
5fbb8e1... add PA_SINK_OPENED/PA_SOURCE_OPENED macros for easier checking for _IDLE or _RUNNING states
10cb048... restore proper mixer volume control
9dac60c... reload OSS volume after unsuspend
dd40020... bring back alsa fd list managemet, since we need it for proper mixer change notification
787f935... port module-alsa-sink to new lock-free core. also add mmmap'ing support while doing so.
c7df4ba... minor modernizations
8e4660a... Disable memory mapping if we open the device in O_WRONLY. Unfortunately we cannot do mmap() in Linux without opening the device for reading as well.
c936e53... Fix channel remapping in resample; other modernizations
4cc0d0a... remove some log messages
86abfbf... remove debug messages; don't queue request messages like nothing when send file is finished
bbb347f... properly free memblocks when skipping over them
042cb09... make valgrind shut up regarding non-freed ident strings. other modernizations
bc17b8e... reverse order flist destruction and mempool allocation warning
222a6d2... Increase ref counter of sink input as long as it is included in the sink idxset
d80fd10... properly deref sink_input/source_output objects when removing them from a sink/source
58af737... Add fdsem to makefile
8cdde28... reverse order of printf and push to make output more readable
bc36932... port asyncq to make use of new fdsem object
6ad165c... add abstracted file descriptor based semaphore object that is lock-free in the best cases
8836396... Store strings directly in strlst elements, other modernizations
98d36ef... fix some alignment issues and modernize file a little bit
929526d... Convert most snprintf() calls to pa_snprintf()
8e83838... Modernize things a little bith more
2a43bbf... Modernize things a little
2380ad9... add our own implementation for pa_snprintf() because NUL termination is apparently not guaranteed on windows and a couple of other libcs
9e9dc0b... Simplify implementation of pa_assert_se()
068f5d5... drop chunk argument from various drop() functions, since it doesn't make any sense if we want to guarantee always monotonously increasing read pointers; a couple of other fixes
9cc20b4... update static free list usage in asyncmsgq
e339d4b... update static free list usage in hashmap
f42e443... destruct freelists properly, by using gcc destructors. we do this only to make valgrind shut up, not because it would have any real value during runtime
279b1b3... wrap destructor gcc attribute in macro
a094923... change order of munmap and freeing of memblocks
c76d035... Fix a couple of typos in the resampler code
2a19c46... Fix typo in pa_memblock_release() call; s/assert/pa_assert/
65d54d6... s/assert/pa_assert/g; make use of static flist for memblock allocation where applicable; properly initialize length value in pa_memexport_put()
0e84f04... Minor clarification
f2c98d7... Make use of static flist for hashmap entry alllocation
69bfa35... Actually make the static flist static
3b912ac... Port module-sine to the new lock-free core
8442926... Reenable a couple of more modules
59faa5d... Remove a superfluous pa_memblock_release(); properly handle buf4 allocation
63c231e... Fix concurrency bug when turning memblock into a local memblock
481b425... Fix off-by-one in mixing code
ca5874d... Replace a couple of assert()s by pa_assert()s
ac1387d... Remove module-oss-mmap, since it is now merged into module-oss
a42c19e... Merge module-oss-mmap into module-oss and make suspending working properly
295e1c8... Make pa_sink_render_* and pa_source_post work only when in RUNNING state, to fix handling of monitor sources when their sink is suspended
0a095f6... Properly initialize all revents on EINTR
1a84664... Make sure pollfd[POLLFD_ASYNCQ].revents is properly initialized on signal
683fc4c... fix segfault when recording with module-oss.c
eec2fbe... Port module-oss to the new lock-free core
6312938... remove pa_memblockq_is_writable() (because it is stupid and not used anywhere anyway, and replace all assert()s with pa_assert()s
a482b9f... make sure we don't free the same connection twice
6776678... Limit silence buffer size for pa_sink_render()
de02c74... Track the 'missing' variable safely between the threads
d873731... rework the logic of pa_asyncq
77ebe70... Make sure the returned pa_msgobject object has a valid refcnt before returning it
099f3f2... Include assert.h, since we use assert() for our pa_assert() macro
a9fcd59... Fix length calculation in pa_silence_memblock_new() and make use of pa_assert() everywhere instead of assert()
fdd3ac9... Make use of dbus_watch_get_unix_fd() instead of dbus_watch_get_fd() because of deprecation of the latter
bb3ad9d... Update OSS driver for new lock-free core
013a55a... remove underrun condition in pa_sinks. Instead return silence in pa_sink_render() when necessary. This is required to guarantee that the time functions in connected sink inputs stays linear
780f736... don't handle underrun special
f061636... drop silence generation from sink drivers
fff9081... fix a typo and some minor optimizations
1c9bd20... minor cleanups and optimizations
e24c8de... Fix minor typo
deb523e... Port module-pipe-source to the new threaded design
94f6ab5... Fix another ugly typo, which made source outputs unusable
e279778... use pa_memblockq_push_align() instead of pa_memblockq_push() to deal with unaligned data coming from clients
1d7096b... Show memchunk length in debug output
1c62ce6... Fix a nasty typo in pa_asyncq_pop
572c77f... Remove anotify.[ch], since it is now entirely replaced by pa_asyncmsgq
5e72ac3... rework sink input/source output state machine
260dd1e... Make debug message more useful
1b99fd2... Move a few things between the threads
111dcd5... trivial cleanups
be4a882... A lot of more work to get the lock-free stuff in place
6911568... make untabify
590ae20... Add new untabify makefile target
a4fed0f... make eolspace
00da37f... Merge HUGE set of changes temporarily into a branch, to allow me to move them from one machine to another (lock-free and stuff)
6aeec56... add a new private branch
d664492... Create branch for lock free memblock implementation.
34e81ff... Handle Windows paths when normalizing authkey path.
29118f5... Make sure the caps header check can also be disabled.
1015ea4... Store previous reported time in order to assure a monotonic clock.
d429222... Accidental use of a swapped int.
11c6cac... buf is needed on Windows aswell.
abdf9b1... Add needed error code.
0a9abdd... Unfortunately Windows has two different values for EBADF depending on if it's a file or a socket. We'll have to deal with these as they show up.
ba06340... Add some required headers.
357ab88... Make sure socklen_t is defined.
5e5808a... Static libs bork the creation of dlls and AC_CHECK_LIB isn't very bright, so we have to do a test first to see if getopt_long() is included in the system libs.
ff4cc62... Move library checks to a separate section and make sure it's before function checks. It could miss functions because they are hidden in extra libs otherwise.
f5a2cf1... getopt_long resides in libiberty on many platforms.
76bc56c... Put inet_ntop() emulation in a seperate file.
d3cb144... Update comment for pa_lock_fd() to reflect that locks are mandatory on Windows.
160d886... Merge with trunk.
8258146... Generalise lstat fallback.
5fcbf04... Condense winsock includes and defines into one header.
9818d67... Make the tagstruct handling safe on machines with alignment restrictions.
8a32357... Make sure the data gets endianness conversion.
067c00f... Reversing incorrect commit.
72795fc... Use autoconf detected define for getgroups() type.
d5ce3ec... Ignore windows exe:s.
1b472f7... Solaris support.
6781628... The Windows sound interface module.
19d9fcb... Port to Windows. This is mostly glue layers for the poor POSIX support on Windows. A few notes
2f74bb9... Protect pthread.h with an ifdef.
bdc02f7... Protect sys/resource.h with an ifdef.
67833c2... Protect sched.h with ifdef.
57dccd2... Replace paths with defines.
2c4d42e... ctime_r() is not available everywhere.
e72bbdb... c was used before it was assigned.
010476f... Protect getuid() with an ifdef.
5ac2cb9... No regexp funtions are used in this file.
ecaf8d8... PATH_MAX is defined in limits.h.
983fdb3... Stub uses socket defines so include the header.
7aba34b... config.h should always be included so that necessary fixes can take effect.
2cf165d... ifdef-protect setpgid and setsid.
08bbfd2... Make it possible to disable caps support since it breaks fully static builds.
be2ba90... Add option to select which modules get linked in during static builds.
9550c8e... No need for conditional generation of symdef files.
971e370... Add possibility for linking semi-static executables (libtools definition of static).
e2495c7... We need explicit actions here.
268aebb... Protect sys/wait.h with an ifdef.
8f3c364... Make sure all socket headers are protected by ifdefs.
e28ce8c... Use pa_get_path_filename() instead of duplicating code.
29a5b85... Emulate poll() through select() where needed.
d3bc7b2... Fix test for mkfifo(). HAVE_MKFIFO is only generated as a config.h define by default.
5cd8703... Remove ftruncate test since we're not doing anything with the result.
a24102c... Fix indentation.
e9be6fa... Handle platforms that do not support the UNIX user/group database.
59aa6ca... There was a race condition here that caused latency calculation to fail miserably under some conditions.
ec87cb1... Fall back to signal() when sigaction isn't supported.
3ed983c... SIGQUIT is an optional signal.
b8859b4... Compiler warning about uninitialized variable.
3728854... Make sure the array is never too small.
b69d881... Fix printf string.
7192238... Old kernel headers didn't define the input_id structure. Therefore we cannot rely on it.
c5bee95... Fix correct type.
4deeaef... Don't include sys/socket.h in the header when we do not need to.
14474ae... Esound latency should not include buffer length. This added an extra second to esound already horrible latency calculations.
f0e8c65... Two variables with the same name causing corrupt strings.
4384d31... Fix warning.
ff49e63... inet_ntop can't be found on all platforms. Do a stupid emulation when not found.
456e256... Fix some compiler warnings about unused variables.
cd3691d... PIPE_BUF has nothing to do with the esound buffers.
13496bb... Handle when the platform doesn't have UNIX sockets.
3a3b4af... AF_UNIX and PF_UNIX is more portable than the _LOCAL equivalent.
dbad54a... Remove any warnings about incorrect type to setsockopt() (char* vs void*).
7dcf4e4... The standard declares some signals as optional. Make sure we handle this gracefully.
eacffc3... To access the new pa_gettimeofday() we need to include util.h.
8c5a75d... Syslog is not present on all platforms.
3996c5f... SIXCPU isn't present on all platforms. Replace cpulimit with dummy functions on those systems.
2ce05b2... Glob is not present on all systems.
70223ba... Fallbacks for systems that do not have getaddrinfo(). Does not handle IPv6 though.
3f2ac7e... We have a generic function for extracting the filename, let's use it.
f6b0f87... Remove unnecessary dependency on timeval definition.
687e2d7... Abstract the gettimeofday call into a utility function to ease porting.
70710e1... Check for OSS by looking for its header. Win32 isn't the only platform where OSS isn't supported.
11a4c67... Remove unused automake conditional.
e8c71ed... Since README is generated conditionally we must make sure there are no dependencies on it when it's not built.
1f11ee3... Big cleanup of the build structure.
22f6694... Creating branch for patches from Pierre Ossman
e1f008f... commit liboil porting changes
0c9873e... create a copy for liboil porting
-----------------------------------------------------------------------

Summary of changes:

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

commit e1f008f2a395422b0f1e0c931ea1550df853e6e4
Author: Lennart Poettering <lennart at poettering.net>
Date:   Thu Sep 15 23:42:56 2005 +0000

    commit liboil porting changes
    
    
    git-svn-id: file:///home/lennart/svn/public/pulseaudio/branches/liboil-test@344 fefdeb5f-60dc-0310-8127-8f9354f1896f

diff --git a/polyp/Makefile.am b/polyp/Makefile.am
index 009707c..18e1a2a 100644
--- a/polyp/Makefile.am
+++ b/polyp/Makefile.am
@@ -542,7 +542,7 @@ mainloop_test_SOURCES = mainloop-test.c
 mainloop_test_CFLAGS = $(AM_CFLAGS)
 mainloop_test_LDADD = $(AM_LDADD) libpolyp-mainloop- at PA_MAJORMINOR@.la libpolyp- at PA_MAJORMINOR@.la
 
-voltest_SOURCES = voltest.c sample.c
+voltest_SOURCES = voltest.c volume.c
 voltest_CFLAGS = $(AM_CFLAGS)
 voltest_LDADD = $(AM_LDADD)
 
diff --git a/polyp/channelmap.c b/polyp/channelmap.c
new file mode 100644
index 0000000..9787652
--- /dev/null
+++ b/polyp/channelmap.c
@@ -0,0 +1,140 @@
+/* $Id$ */
+
+/***
+  This file is part of polypaudio.
+ 
+  polypaudio 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 of the License,
+  or (at your option) any later version.
+ 
+  polypaudio 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 polypaudio; if not, write to the Free Software
+  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+  USA.
+***/
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <assert.h>
+
+#include "channelmap.h"
+
+
+struct pa_channel_map* pa_channel_map_init(struct pa_channel_map *m) {
+    unsigned c;
+    assert(m);
+
+    for (c = 0; c < PA_CHANNELS_MAX; c++)
+        m->map[c] = PA_CHANNEL_POSITION_INVALID;
+
+    return m;
+}
+
+struct pa_channel_map* pa_channel_map_init_mono(struct pa_channel_map *m) {
+    assert(m);
+
+    pa_channel_map_init(m);
+    m->map[0] = PA_CHANNEL_POSITION_MONO;
+    return m;
+}
+
+struct pa_channel_map* pa_channel_map_init_stereo(struct pa_channel_map *m) {
+    assert(m);
+
+    pa_channel_map_init(m);
+    m->map[0] = PA_CHANNEL_POSITION_LEFT;
+    m->map[1] = PA_CHANNEL_POSITION_RIGHT;
+    return m;
+}
+
+struct pa_channel_map* pa_channel_map_init_auto(struct pa_channel_map *m, int channels) {
+    assert(m);
+    assert(channels > 0);
+
+    pa_channel_map_init(m);
+    
+    switch (channels) {
+        case 1:
+            m->map[0] = PA_CHANNEL_POSITION_MONO;
+            return m;
+
+        case 8:
+            m->mpa[6] = PA_CHANNEL_POSITION_SIDE_LEFT;
+            m->mpa[7] = PA_CHANNEL_POSITION_SIDE_RIGHT;
+            /* Fall through */
+            
+        case 6:
+            m->mpa[5] = PA_CHANNEL_POSITION_LFE;
+            /* Fall through */
+            
+        case 5:
+            m->map[4] = PA_CHANNEL_POSITION_FRONT_CENTER;
+            /* Fall through */
+            
+        case 4:
+            m->map[2] = PA_CHANNEL_POSITION_REAR_LEFT;
+            m->map[3] = PA_CHANNEL_POSITION_REAR_RIGHT;
+            /* Fall through */
+            
+        case 2:
+            m->map[0] = PA_CHANNEL_MAP_FRONT_LEFT;
+            m->map[1] = PA_CHANNEL_MAP_FRONT_RIGHT;
+            return m;
+            
+        default:
+            return NULL;
+    }
+}
+
+
+const char* pa_channel_position_to_string(pa_channel_position_t pos) {
+    const char *const table[] = {
+        [PA_CHANNEL_POSITION_MONO] = "mono",
+
+        [PA_CHANNEL_POSITION_FRONT_CENTER] = "front-center",
+        [PA_CHANNEL_POSITION_FRONT_LEFT] = "front-left",
+        [PA_CHANNEL_POSITION_FRONT_RIGHT] = "front-right",
+        
+        [PA_CHANNEL_POSITION_REAR_CENTER] = "rear-center",
+        [PA_CHANNEL_POSITION_REAR_LEFT] = "rear-left",
+        [PA_CHANNEL_POSITION_REAR_RIGHT] = "rear-right",
+
+        [PA_CHANNEL_POSITION_LFE] = "lfe",
+
+        [PA_CHANNEL_POSITION_FRONT_LEFT_OF_CENTER] = "front-left-of-center",
+        [PA_CHANNEL_POSITION_FRONT_RIGHT_OF_CENTER] = "front-right-of-center",
+        
+        [PA_CHANNEL_POSITION_SIDE_LEFT] = "side-left",
+        [PA_CHANNEL_POSITION_SIDE_RIGHT] = "side-right"
+    };
+
+    if (pos < 0 || pos >= PA_CHANNEL_POSITION_MAX)
+        return NULL;
+
+    return table[pos];
+}
+
+int pa_channel_map_equal(struct pa_channel_map *a, struct pa_channel_map *b, int channels) {
+    char c;
+    
+    assert(a);
+    assert(b);
+    assert(channels > 0);
+
+    if (channels > PA_CHANNELS_MAX)
+        channels = PA_CHANNELS_MAX;
+
+    for (c = 0; c < channels; c++)
+        if (a->map[c] != b->map[c])
+            return 1;
+
+    return 0;
+}
diff --git a/polyp/channelmap.h b/polyp/channelmap.h
new file mode 100644
index 0000000..946247a
--- /dev/null
+++ b/polyp/channelmap.h
@@ -0,0 +1,75 @@
+#ifndef foochannelmaphfoo
+#define foochannelmaphfoo
+
+/* $Id$ */
+
+/***
+  This file is part of polypaudio.
+ 
+  polypaudio 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 of the License,
+  or (at your option) any later version.
+ 
+  polypaudio 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 polypaudio; if not, write to the Free Software
+  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+  USA.
+***/
+
+#include <polyp/sample.h>
+#include <polyp/cdecl.h>
+
+/** \file
+ * Constants and routines for channel mapping handling */
+
+PA_C_DECL_BEGIN
+
+typedef enum {
+    PA_CHANNEL_POSITION_INVALID = -1,
+    PA_CHANNEL_POSITION_MONO = 0,
+
+    PA_CHANNEL_POSITION_LEFT,
+    PA_CHANNEL_POSITION_RIGHT,
+
+    PA_CHANNEL_POSITION_FRONT_CENTER,
+    PA_CHANNEL_POSITION_FRONT_LEFT = PA_CHANNEL_POSITION_LEFT,
+    PA_CHANNEL_POSITION_FRONT_RIGHT = PA_CHANNEL_POSITION_RIGHT,
+
+    PA_CHANNEL_POSITION_REAR_CENTER,
+    PA_CHANNEL_POSITION_REAR_LEFT,
+    PA_CHANNEL_POSITION_REAR_RIGHT,
+    
+    PA_CHANNEL_POSITION_LFE,
+    PA_CHANNEL_POSITION_SUBWOOFER = PA_CHANNEL_LFE,
+    
+    PA_CHANNEL_POSITION_FRONT_LEFT_OF_CENTER,
+    PA_CHANNEL_POSITION_FRONT_RIGHT_OF_CENTER,
+    
+    PA_CHANNEL_POSITION_SIDE_LEFT,
+    PA_CHANNEL_POSITION_SIDE_RIGHT,
+    
+    PA_CHANNEL_POSITION_MAX
+} pa_channel_position_t;
+
+struct {
+    pa_channel_position_t map[PA_CHANNELS_MAX];
+} pa_channel_map;
+
+struct pa_channel_map* pa_channel_map_init(struct pa_channel_map *m);
+struct pa_channel_map* pa_channel_map_init_mono(struct pa_channel_map *m);
+struct pa_channel_map* pa_channel_map_init_stereo(struct pa_channel_map *m);
+struct pa_channel_map* pa_channel_map_init_auto(struct pa_channel_map *m, int channels);
+
+const char* pa_channel_position_to_string(pa_channel_position_t pos);
+
+int pa_channel_map_equal(struct pa_channel_map *a, struct pa_channel_map *b, int channels)
+
+PA_C_DECL_END
+
+#endif
diff --git a/polyp/client.c b/polyp/client.c
index 8c7f480..dca7b52 100644
--- a/polyp/client.c
+++ b/polyp/client.c
@@ -33,16 +33,16 @@
 #include "subscribe.h"
 #include "log.h"
 
-struct pa_client *pa_client_new(struct pa_core *core, pa_typeid_t typeid, const char *name) {
+struct pa_client *pa_client_new(struct pa_core *core, const char *name, const char *driver) {
     struct pa_client *c;
     int r;
     assert(core);
 
     c = pa_xmalloc(sizeof(struct pa_client));
     c->name = pa_xstrdup(name);
+    c->driver = pa_xstrdup(driver);
     c->owner = NULL;
     c->core = core;
-    c->typeid = typeid;
 
     c->kill = NULL;
     c->userdata = NULL;
@@ -68,8 +68,8 @@ void pa_client_free(struct pa_client *c) {
     pa_log_info(__FILE__": freed %u \"%s\"\n", c->index, c->name);
     pa_subscription_post(c->core, PA_SUBSCRIPTION_EVENT_CLIENT|PA_SUBSCRIPTION_EVENT_REMOVE, c->index);
     pa_xfree(c->name);
+    pa_xfree(c->driver);
     pa_xfree(c);
-
 }
 
 void pa_client_kill(struct pa_client *c) {
diff --git a/polyp/client.h b/polyp/client.h
index 2a3a09e..082dc29 100644
--- a/polyp/client.h
+++ b/polyp/client.h
@@ -32,17 +32,16 @@
 
 struct pa_client {
     uint32_t index;
-    pa_typeid_t typeid;
 
     struct pa_module *owner;
-    char *name;
+    char *name, *driver;
     struct pa_core *core;
 
     void (*kill)(struct pa_client *c);
     void *userdata;
 };
 
-struct pa_client *pa_client_new(struct pa_core *c, pa_typeid_t typeid, const char *name);
+struct pa_client *pa_client_new(struct pa_core *c, const char *name, const char *driver);
 
 /* This function should be called only by the code that created the client */
 void pa_client_free(struct pa_client *c);
diff --git a/polyp/resampler.c b/polyp/resampler.c
index 28e4920..d3165c9 100644
--- a/polyp/resampler.c
+++ b/polyp/resampler.c
@@ -35,11 +35,12 @@
 
 struct pa_resampler {
     struct pa_sample_spec i_ss, o_ss;
+    struct pa_channel_map i_cm, o_cm;
     size_t i_fz, o_fz;
     struct pa_memblock_stat *memblock_stat;
     void *impl_data;
     int channels;
-    enum pa_resample_method resample_method;
+    pa_resample_method_t resample_method;
 
     void (*impl_free)(struct pa_resampler *r);
     void (*impl_set_input_rate)(struct pa_resampler *r, uint32_t rate);
@@ -62,7 +63,14 @@ struct impl_trivial {
 static int libsamplerate_init(struct pa_resampler*r);
 static int trivial_init(struct pa_resampler*r);
 
-struct pa_resampler* pa_resampler_new(const struct pa_sample_spec *a, const struct pa_sample_spec *b, struct pa_memblock_stat *s, enum pa_resample_method resample_method) {
+struct pa_resampler* pa_resampler_new(
+    const struct pa_sample_spec *a,
+    const struct pa_channel_map *am,
+    const struct pa_sample_spec *b,
+    const struct pa_channel_map *bm,
+    struct pa_memblock_stat *s,
+    pa_resample_method_t resample_method) {
+    
     struct pa_resampler *r = NULL;
     assert(a && b && pa_sample_spec_valid(a) && pa_sample_spec_valid(b) && resample_method != PA_RESAMPLER_INVALID);
 
@@ -82,6 +90,17 @@ struct pa_resampler* pa_resampler_new(const struct pa_sample_spec *a, const stru
     r->i_ss = *a;
     r->o_ss = *b;
 
+    if (am)
+        r->i_cm = *am;
+    else
+        pa_channel_map_init_auto(&r->i_cm, r->i_ss.channels);
+
+    if (bm)
+        r->o_cm = *bm;
+    else
+        pa_channel_map_init_auto(&r->o_cm, r->o_ss.channels);
+    
+
     r->i_fz = pa_frame_size(a);
     r->o_fz = pa_frame_size(b);
 
@@ -90,7 +109,7 @@ struct pa_resampler* pa_resampler_new(const struct pa_sample_spec *a, const stru
         r->channels = b->channels;
     
     /* Choose implementation */
-    if (a->channels != b->channels || a->format != b->format || resample_method != PA_RESAMPLER_TRIVIAL) {
+    if (a->channels != b->channels || a->format != b->format || resample_method != PA_RESAMPLER_TRIVIAL || !pa_channel_map_equal(&r->i_cm, &r->o_cm)) {
         /* Use the libsamplerate based resampler for the complicated cases */
         if (resample_method == PA_RESAMPLER_TRIVIAL)
             r->resample_method = PA_RESAMPLER_SRC_ZERO_ORDER_HOLD;
@@ -141,31 +160,11 @@ size_t pa_resampler_request(struct pa_resampler *r, size_t out_length) {
     return (((out_length / r->o_fz)*r->i_ss.rate)/r->o_ss.rate) * r->i_fz;
 }
 
-enum pa_resample_method pa_resampler_get_method(struct pa_resampler *r) {
+pa_resample_method_t pa_resampler_get_method(struct pa_resampler *r) {
     assert(r);
     return r->resample_method;
 }
 
-/* Parse a libsamplrate compatible resampling implementation */
-enum pa_resample_method pa_parse_resample_method(const char *string) {
-    assert(string);
-
-    if (!strcmp(string, "src-sinc-best-quality"))
-        return PA_RESAMPLER_SRC_SINC_BEST_QUALITY;
-    else if (!strcmp(string, "src-sinc-medium-quality"))
-        return PA_RESAMPLER_SRC_SINC_MEDIUM_QUALITY;
-    else if (!strcmp(string, "src-sinc-fastest"))
-        return PA_RESAMPLER_SRC_SINC_FASTEST;
-    else if (!strcmp(string, "src-zero-order-hold"))
-        return PA_RESAMPLER_SRC_ZERO_ORDER_HOLD;
-    else if (!strcmp(string, "src-linear"))
-        return PA_RESAMPLER_SRC_LINEAR;
-    else if (!strcmp(string, "trivial"))
-        return PA_RESAMPLER_TRIVIAL;
-    else
-        return PA_RESAMPLER_INVALID;
-}
-
 /*** libsamplerate based implementation ***/
 
 static void libsamplerate_free(struct pa_resampler *r) {
@@ -181,6 +180,70 @@ static void libsamplerate_free(struct pa_resampler *r) {
     pa_xfree(i);
 }
 
+static void calc_map_table(struct pa_resampler *r) {
+    struct impl_libsamplerate *u;
+    unsigned oc;
+    assert(r);
+    assert(r->impl_data);
+
+    u = r->impl_data;
+
+    if ((u->map_required = (!pa_channel_map_equal(&r->i_cm, r->o_cm) || r->i_ss.channels != r->o_ss.channels))) {
+
+        memset(u->map_table, -1, sizeof(u->map_table));
+
+        for (oc = 0; oc < r->o_iss.channels; oc++) {
+            unsigned i = 0, ic;
+
+            for (ic = 0; ic < r->i_ss.channels; ic++) {
+                pa_channel_position_t a, b;
+                
+                a = r->i_cm.map[ic];
+                b = r->o_cm.map[oc];
+                
+                if (a == b ||
+                    (a == PA_CHANNEL_POSITION_MONO && b == PA_CHANNEL_POSITION_LEFT) ||
+                    (a == PA_CHANNEL_POSITION_MONO && b == PA_CHANNEL_POSITION_RIGHT) ||
+                    (a == PA_CHANNEL_POSITION_LEFT && b == PA_CHANNEL_POSITION_MONO) ||
+                    (a == PA_CHANNEL_POSITION_RIGHT && b == PA_CHANNEL_POSITION_MONO))
+                    
+                    u->map_table[oc][i++] = ic;
+            }
+        }
+    }
+}
+
+
+static float *remap_to_float(struct pa_resampler *r, const struct pa_memchunk *in) {
+    unsigned nsamples;
+    struct impl_libsamplerate *u;
+    assert(r);
+    assert(r->impl_data);
+
+    u = r->impl_data;
+
+    nsamples = in->length / u->i_fz;
+
+    if () {
+
+        if (u->i_buf_samples < nsamples)
+            u->i_buf = pa_xrealloc(i->i_buf, sizeof(float) * (i->i_buf_samples = nsamples));
+
+        i->to_float32ne_func(ff_ins, (uint8_t*) in->memblock->data+in->index, i_nchannels, i->i_buf);
+
+    }
+
+    
+}
+
+
+static void libsamplerate_run(struct pa_resampler *r, const struct pa_memchunk *in, struct pa_memchunk *out) {
+
+    
+    
+}
+
+
 static void libsamplerate_run(struct pa_resampler *r, const struct pa_memchunk *in, struct pa_memchunk *out) {
     unsigned i_nchannels, o_nchannels, ins, ons, eff_ins, eff_ons;
     float *cbuf;
@@ -191,7 +254,8 @@ static void libsamplerate_run(struct pa_resampler *r, const struct pa_memchunk *
     /* How many input samples? */
     ins = in->length/r->i_fz;
 
-/*     pa_log("%u / %u = %u\n", in->length, r->i_fz, ins); */
+
+    /*     pa_log("%u / %u = %u\n", in->length, r->i_fz, ins); */
 
     /* How much space for output samples? */
     if (i->src_state)
@@ -395,7 +459,7 @@ static int trivial_init(struct pa_resampler*r) {
     return 0;
 }
 
-const char *pa_resample_method_to_string(enum pa_resample_method m) {
+const char *pa_resample_method_to_string(pa_resample_method_t m) {
     static const char * const resample_methods[] = {
         "src-sinc-best-quality",
         "src-sinc-medium-quality",
@@ -410,3 +474,23 @@ const char *pa_resample_method_to_string(enum pa_resample_method m) {
 
     return resample_methods[m];
 }
+
+pa_resample_method_t pa_parse_resample_method(const char *string) {
+    assert(string);
+
+    if (!strcmp(string, "src-sinc-best-quality"))
+        return PA_RESAMPLER_SRC_SINC_BEST_QUALITY;
+    else if (!strcmp(string, "src-sinc-medium-quality"))
+        return PA_RESAMPLER_SRC_SINC_MEDIUM_QUALITY;
+    else if (!strcmp(string, "src-sinc-fastest"))
+        return PA_RESAMPLER_SRC_SINC_FASTEST;
+    else if (!strcmp(string, "src-zero-order-hold"))
+        return PA_RESAMPLER_SRC_ZERO_ORDER_HOLD;
+    else if (!strcmp(string, "src-linear"))
+        return PA_RESAMPLER_SRC_LINEAR;
+    else if (!strcmp(string, "trivial"))
+        return PA_RESAMPLER_TRIVIAL;
+    else
+        return PA_RESAMPLER_INVALID;
+}
+
diff --git a/polyp/resampler.h b/polyp/resampler.h
index 0109e79..ec6a808 100644
--- a/polyp/resampler.h
+++ b/polyp/resampler.h
@@ -30,7 +30,7 @@
 
 struct pa_resampler;
 
-enum pa_resample_method {
+typedef enum {
     PA_RESAMPLER_INVALID                 = -1,
     PA_RESAMPLER_SRC_SINC_BEST_QUALITY   = SRC_SINC_BEST_QUALITY,
     PA_RESAMPLER_SRC_SINC_MEDIUM_QUALITY = SRC_SINC_MEDIUM_QUALITY,
@@ -39,9 +39,16 @@ enum pa_resample_method {
     PA_RESAMPLER_SRC_LINEAR              = SRC_LINEAR,
     PA_RESAMPLER_TRIVIAL,
     PA_RESAMPLER_MAX
-};
+} pa_resample_method_t;
+
+struct pa_resampler* pa_resampler_new(
+    const struct pa_sample_spec *a,
+    const struct pa_channel_map *am,
+    const struct pa_sample_spec *b,
+    const struct pa_channel_map *bm,
+    struct pa_memblock_stat *s,
+    pa_resample_method_t resample_method);
 
-struct pa_resampler* pa_resampler_new(const struct pa_sample_spec *a, const struct pa_sample_spec *b, struct pa_memblock_stat *s, int resample_method);
 void pa_resampler_free(struct pa_resampler *r);
 
 /* Returns the size of an input memory block which is required to return the specified amount of output data */
@@ -54,12 +61,12 @@ void pa_resampler_run(struct pa_resampler *r, const struct pa_memchunk *in, stru
 void pa_resampler_set_input_rate(struct pa_resampler *r, uint32_t rate);
 
 /* Return the resampling method of the resampler object */
-enum pa_resample_method pa_resampler_get_method(struct pa_resampler *r);
+pa_resample_method_t pa_resampler_get_method(struct pa_resampler *r);
 
 /* Try to parse the resampler method */
-enum pa_resample_method pa_parse_resample_method(const char *string);
+pa_resample_method_t pa_parse_resample_method(const char *string);
 
 /* return a human readable string for the specified resampling method. Inverse of pa_parse_resample_method() */
-const char *pa_resample_method_to_string(enum pa_resample_method m);
+const char *pa_resample_method_to_string(pa_resample_method_t m);
 
 #endif
diff --git a/polyp/sample-util.c b/polyp/sample-util.c
index d521afe..44cacfc 100644
--- a/polyp/sample-util.c
+++ b/polyp/sample-util.c
@@ -65,30 +65,37 @@ void pa_silence_memory(void *p, size_t length, const struct pa_sample_spec *spec
     memset(p, c, length);
 }
 
-size_t pa_mix(struct pa_mix_info channels[], unsigned nchannels, void *data, size_t length, const struct pa_sample_spec *spec, pa_volume_t volume) {
-    assert(channels && data && length && spec);
+size_t pa_mix(struct pa_mix_info streams[],
+              unsigned nstreams,
+              void *data,
+              size_t length,
+              const struct pa_sample_spec *spec,
+              const struct pa_cvolume *volume) {
+    
+    assert(streams && data && length && spec);
     
     if (spec->format == PA_SAMPLE_S16NE) {
         size_t d;
+        unsigned channel = 0;
         
         for (d = 0;; d += sizeof(int16_t)) {
-            unsigned c;
+            unsigned i;
             int32_t sum = 0;
             
             if (d >= length)
                 return d;
             
-            for (c = 0; c < nchannels; c++) {
+            for (i = 0; i < nstreams; i++) {
                 int32_t v;
-                pa_volume_t cvolume = channels[c].volume;
+                pa_volume_t cvolume = streams[i].volume.values[channel];
                 
-                if (d >= channels[c].chunk.length)
+                if (d >= streams[i].chunk.length)
                     return d;
                 
                 if (cvolume == PA_VOLUME_MUTED)
                     v = 0;
                 else {
-                    v = *((int16_t*) ((uint8_t*) channels[c].chunk.memblock->data + channels[c].chunk.index + d));
+                    v = *((int16_t*) ((uint8_t*) streams[i].chunk.memblock->data + streams[i].chunk.index + d));
                     
                     if (cvolume != PA_VOLUME_NORM) {
                         v *= cvolume;
@@ -111,28 +118,32 @@ size_t pa_mix(struct pa_mix_info channels[], unsigned nchannels, void *data, siz
             
             *((int16_t*) data) = sum;
             data = (uint8_t*) data + sizeof(int16_t);
+
+            if (++channel >= spec->channels)
+                channel = 0;
         }
     } else if (spec->format == PA_SAMPLE_U8) {
         size_t d;
+        unsigned channel = 0;
         
         for (d = 0;; d ++) {
             int32_t sum = 0;
-            unsigned c;
+            unsigned i;
             
             if (d >= length)
                 return d;
             
-            for (c = 0; c < nchannels; c++) {
+            for (i = 0; i < nstreams; i++) {
                 int32_t v;
-                pa_volume_t cvolume = channels[c].volume;
+                pa_volume_t cvolume = streams[i].volume.values[channel];
                 
-                if (d >= channels[c].chunk.length)
+                if (d >= streams[i].chunk.length)
                     return d;
                 
                 if (cvolume == PA_VOLUME_MUTED)
                     v = 0;
                 else {
-                    v = (int32_t) *((uint8_t*) channels[c].chunk.memblock->data + channels[c].chunk.index + d) - 0x80;
+                    v = (int32_t) *((uint8_t*) streams[i].chunk.memblock->data + streams[i].chunk.index + d) - 0x80;
                     
                     if (cvolume != PA_VOLUME_NORM) {
                         v *= cvolume;
@@ -155,29 +166,33 @@ size_t pa_mix(struct pa_mix_info channels[], unsigned nchannels, void *data, siz
             
             *((uint8_t*) data) = (uint8_t) (sum + 0x80);
             data = (uint8_t*) data + 1;
+
+            if (++channel >= spec->channels)
+                channel = 0;
         }
         
     } else if (spec->format == PA_SAMPLE_FLOAT32NE) {
         size_t d;
+        unsigned channel = 0;
         
         for (d = 0;; d += sizeof(float)) {
             float_t sum = 0;
-            unsigned c;
+            unsigned i;
             
             if (d >= length)
                 return d;
             
-            for (c = 0; c < nchannels; c++) {
+            for (i = 0; i < nstreams; i++) {
                 float v;
-                pa_volume_t cvolume = channels[c].volume;
+                pa_volume_t cvolume = streams[i].volume.values[channel];
                 
-                if (d >= channels[c].chunk.length)
+                if (d >= streams[i].chunk.length)
                     return d;
                 
                 if (cvolume == PA_VOLUME_MUTED)
                     v = 0;
                 else {
-                    v = *((float*) ((uint8_t*) channels[c].chunk.memblock->data + channels[c].chunk.index + d));
+                    v = *((float*) ((uint8_t*) streams[i].chunk.memblock->data + streams[i].chunk.index + d));
                     
                     if (cvolume != PA_VOLUME_NORM)
                         v = v*cvolume/PA_VOLUME_NORM;
@@ -196,6 +211,9 @@ size_t pa_mix(struct pa_mix_info channels[], unsigned nchannels, void *data, siz
             
             *((float*) data) = sum;
             data = (uint8_t*) data + sizeof(float);
+
+            if (++channel >= spec->channels)
+                channel = 0;
         }
     } else {
         abort();
@@ -203,13 +221,14 @@ size_t pa_mix(struct pa_mix_info channels[], unsigned nchannels, void *data, siz
 }
 
 
-void pa_volume_memchunk(struct pa_memchunk*c, const struct pa_sample_spec *spec, pa_volume_t volume) {
+void pa_volume_memchunk(struct pa_memchunk*c, const struct pa_sample_spec *spec, const struct pa_cvolume *volume) {
     assert(c && spec && (c->length % pa_frame_size(spec) == 0));
+    assert(volume);
 
-    if (volume == PA_VOLUME_NORM)
+    if (pa_cvolume_channels_equal_to(volume, spec->channels, PA_VOLUME_NORM))
         return;
 
-    if (volume == PA_VOLUME_MUTED) {
+    if (pa_cvolume_channels_equal_to(volume, spec->channels, PA_VOLUME_MUTED)) {
         pa_silence_memchunk(c, spec);
         return;
     }
@@ -217,26 +236,31 @@ void pa_volume_memchunk(struct pa_memchunk*c, const struct pa_sample_spec *spec,
     if (spec->format == PA_SAMPLE_S16NE) {
         int16_t *d;
         size_t n;
+        unsigned c = 0;
         
         for (d = (int16_t*) ((uint8_t*) c->memblock->data+c->index), n = c->length/sizeof(int16_t); n > 0; d++, n--) {
             int32_t t = (int32_t)(*d);
             
-            t *= volume;
+            t *= volume->values[c];
             t /= PA_VOLUME_NORM;
             
             if (t < -0x8000) t = -0x8000;
             if (t > 0x7FFF) t = 0x7FFF;
             
             *d = (int16_t) t;
+
+            if (++c >= spec->channels)
+                c = 0;
         }
     } else if (spec->format == PA_SAMPLE_U8) {
         uint8_t *d;
         size_t n;
+        unsigned c = 0;
 
         for (d = (uint8_t*) c->memblock->data + c->index, n = c->length; n > 0; d++, n--) {
             int32_t t = (int32_t) *d - 0x80;
 
-            t *= volume;
+            t *= volume->values[c];
             t /= PA_VOLUME_NORM;
 
             if (t < -0x80) t = -0x80;
@@ -244,21 +268,27 @@ void pa_volume_memchunk(struct pa_memchunk*c, const struct pa_sample_spec *spec,
 
             *d = (uint8_t) (t + 0x80);
             
+            if (++c >= spec->channels)
+                c = 0;
         }
     } else if (spec->format == PA_SAMPLE_FLOAT32NE) {
         float *d;
         size_t n;
+        unsigned c = 0;
 
         for (d = (float*) ((uint8_t*) c->memblock->data+c->index), n = c->length/sizeof(float); n > 0; d++, n--) {
             float t = *d;
 
-            t *= volume;
+            t *= volume->values[c];
             t /= PA_VOLUME_NORM;
 
             if (t < -1) t = -1;
             if (t > 1) t = 1;
 
             *d = t;
+
+            if (++c >= spec->channels)
+                c = 0;
         }
         
     } else {
diff --git a/polyp/sample-util.h b/polyp/sample-util.h
index aafdda6..f0c71b8 100644
--- a/polyp/sample-util.h
+++ b/polyp/sample-util.h
@@ -33,12 +33,19 @@ void pa_silence_memory(void *p, size_t length, const struct pa_sample_spec *spec
 
 struct pa_mix_info {
     struct pa_memchunk chunk;
-    pa_volume_t volume;
+    struct pa_cvolume cvolume;
     void *userdata;
 };
 
-size_t pa_mix(struct pa_mix_info channels[], unsigned nchannels, void *data, size_t length, const struct pa_sample_spec *spec, pa_volume_t volume);
+size_t pa_mix(const struct pa_mix_info channels[],
+              unsigned nchannels,
+              void *data,
+              size_t length,
+              const struct pa_sample_spec *spec,
+              const struct pa_cvolume *volume);
 
-void pa_volume_memchunk(struct pa_memchunk*c, const struct pa_sample_spec *spec, pa_volume_t volume);
+void pa_volume_memchunk(struct pa_memchunk*c,
+                        const struct pa_sample_spec *spec,
+                        const struct pa_cvolume *volume);
 
 #endif
diff --git a/polyp/sample.c b/polyp/sample.c
index f9d0c45..d38cc1b 100644
--- a/polyp/sample.c
+++ b/polyp/sample.c
@@ -69,10 +69,11 @@ pa_usec_t pa_bytes_to_usec(uint64_t length, const struct pa_sample_spec *spec) {
 int pa_sample_spec_valid(const struct pa_sample_spec *spec) {
     assert(spec);
 
-    if (spec->rate <= 0 || spec->channels <= 0)
-        return 0;
-
-    if (spec->format >= PA_SAMPLE_MAX || spec->format < 0)
+    if (spec->rate <= 0 ||
+        spec->channels <= 0 ||
+        spec->channels >= PA_CHANNELS_MAX ||
+        spec->format >= PA_SAMPLE_MAX ||
+        spec->format < 0)
         return 0;
 
     return 1;
@@ -86,13 +87,13 @@ int pa_sample_spec_equal(const struct pa_sample_spec*a, const struct pa_sample_s
 
 const char *pa_sample_format_to_string(enum pa_sample_format f) {
     static const char* const table[]= {
-        [PA_SAMPLE_U8] = "U8",
-        [PA_SAMPLE_ALAW] = "ALAW",
-        [PA_SAMPLE_ULAW] = "ULAW",
-        [PA_SAMPLE_S16LE] = "S16LE",
-        [PA_SAMPLE_S16BE] = "S16BE",
-        [PA_SAMPLE_FLOAT32LE] = "FLOAT32LE",
-        [PA_SAMPLE_FLOAT32BE] = "FLOAT32BE",
+        [PA_SAMPLE_U8] = "u8",
+        [PA_SAMPLE_ALAW] = "aLaw",
+        [PA_SAMPLE_ULAW] = "uLaw",
+        [PA_SAMPLE_S16LE] = "s16le",
+        [PA_SAMPLE_S16BE] = "s16be",
+        [PA_SAMPLE_FLOAT32LE] = "float32le",
+        [PA_SAMPLE_FLOAT32BE] = "float32be",
     };
 
     if (f >= PA_SAMPLE_MAX)
@@ -112,43 +113,6 @@ char *pa_sample_spec_snprint(char *s, size_t l, const struct pa_sample_spec *spe
     return s;
 }
 
-pa_volume_t pa_volume_multiply(pa_volume_t a, pa_volume_t b) {
-    uint64_t p = a;
-    p *= b;
-    p /= PA_VOLUME_NORM;
-
-    return (pa_volume_t) p;
-}
-
-pa_volume_t pa_volume_from_dB(double f) {
-    if (f <= PA_DECIBEL_MININFTY)
-        return PA_VOLUME_MUTED;
-
-    return (pa_volume_t) (pow(10, f/20)*PA_VOLUME_NORM);
-}
-
-double pa_volume_to_dB(pa_volume_t v) {
-    if (v == PA_VOLUME_MUTED)
-        return PA_DECIBEL_MININFTY;
-
-    return 20*log10((double) v/PA_VOLUME_NORM);
-}
-
-#define USER_DECIBEL_RANGE 30
-
-double pa_volume_to_user(pa_volume_t v) {
-    double dB = pa_volume_to_dB(v);
-
-    return dB < -USER_DECIBEL_RANGE ? 0 : dB/USER_DECIBEL_RANGE+1;
-}
-
-pa_volume_t pa_volume_from_user(double v) {
-
-    if (v <= 0)
-        return PA_VOLUME_MUTED;
-    
-    return pa_volume_from_dB((v-1)*USER_DECIBEL_RANGE);
-}
 
 void pa_bytes_snprint(char *s, size_t l, unsigned v) {
     if (v >= ((unsigned) 1024)*1024*1024)
diff --git a/polyp/sample.h b/polyp/sample.h
index 0494c7d..c4ccd3d 100644
--- a/polyp/sample.h
+++ b/polyp/sample.h
@@ -33,8 +33,11 @@
 
 PA_C_DECL_BEGIN
 
+/* Maximum allowed channels */
+#define PA_CHANNELS_MAX 16
+
 /** Sample format */
-enum pa_sample_format {
+typedef enum {
     PA_SAMPLE_U8,              /**< Unsigned 8 Bit PCM */
     PA_SAMPLE_ALAW,            /**< 8 Bit a-Law */
     PA_SAMPLE_ULAW,            /**< 8 Bit mu-Law */
@@ -44,7 +47,7 @@ enum pa_sample_format {
     PA_SAMPLE_FLOAT32BE,       /**< 32 Bit IEEE floating point, big endian, range -1..1 */
     PA_SAMPLE_MAX,             /**< Upper limit of valid sample types */
     PA_SAMPLE_INVALID = -1     /**< An invalid value */
-};
+} pa_sample_format_t;
 
 #ifdef WORDS_BIGENDIAN
 /** Signed 16 Bit PCM, native endian */
@@ -63,7 +66,7 @@ enum pa_sample_format {
 
 /** A sample format and attribute specification */
 struct pa_sample_spec {
-    enum pa_sample_format format;  /**< The sample format */
+    pa_sample_format_t format;     /**< The sample format */
     uint32_t rate;                 /**< The sample rate. (e.g. 44100) */
     uint8_t channels;              /**< Audio channels. (1 for mono, 2 for stereo, ...) */
 };
@@ -87,7 +90,10 @@ int pa_sample_spec_valid(const struct pa_sample_spec *spec);
 int pa_sample_spec_equal(const struct pa_sample_spec*a, const struct pa_sample_spec*b);
 
 /* Return a descriptive string for the specified sample format. \since 0.8 */
-const char *pa_sample_format_to_string(enum pa_sample_format f);
+const char *pa_sample_format_to_string(pa_sample_format_t f);
+
+/** Parse a sample format text. Inverse of pa_sample_format_to_string() */
+pa_sample_format_t pa_parse_sample_format(const char *format);
 
 /** Maximum required string length for pa_sample_spec_snprint() */
 #define PA_SAMPLE_SPEC_SNPRINT_MAX 32
@@ -95,43 +101,9 @@ const char *pa_sample_format_to_string(enum pa_sample_format f);
 /** Pretty print a sample type specification to a string */
 char* pa_sample_spec_snprint(char *s, size_t l, const struct pa_sample_spec *spec);
 
-/** Volume specification: 0: silence; < 256: diminished volume; 256: normal volume; > 256 amplified volume */
-typedef uint32_t pa_volume_t;
-
-/** Normal volume (100%) */
-#define PA_VOLUME_NORM (0x100)
-
-/** Muted volume (0%) */
-#define PA_VOLUME_MUTED (0)
-
-/** Multiply two volumes specifications, return the result. This uses PA_VOLUME_NORM as neutral element of multiplication. */
-pa_volume_t pa_volume_multiply(pa_volume_t a, pa_volume_t b);
-
-/** Convert volume from decibel to linear level. \since 0.4 */
-pa_volume_t pa_volume_from_dB(double f);
-
-/** Convert volume from linear level to decibel.  \since 0.4 */
-double pa_volume_to_dB(pa_volume_t v);
-
-/** Convert volume to scaled value understandable by the user (between 0 and 1). \since 0.6 */
-double pa_volume_to_user(pa_volume_t v);
-
-/** Convert user volume to polypaudio volume. \since 0.6 */
-pa_volume_t pa_volume_from_user(double v);
-
-#ifdef INFINITY
-#define PA_DECIBEL_MININFTY (-INFINITY)
-#else
-/** This value is used as minus infinity when using pa_volume_{to,from}_dB(). \since 0.4 */
-#define PA_DECIBEL_MININFTY (-200)
-#endif
-
 /** Pretty print a byte size value. (i.e. "2.5 MB") */
 void pa_bytes_snprint(char *s, size_t l, unsigned v);
 
-/** Parse a sample format text. Inverse of pa_sample_format_to_string() */
-enum pa_sample_format pa_parse_sample_format(const char *format);
-
 PA_C_DECL_END
 
 #endif
diff --git a/polyp/sink-input.c b/polyp/sink-input.c
index 3e7fdf7..40ee705 100644
--- a/polyp/sink-input.c
+++ b/polyp/sink-input.c
@@ -36,12 +36,23 @@
 
 #define CONVERT_BUFFER_LENGTH 4096
 
-struct pa_sink_input* pa_sink_input_new(struct pa_sink *s, pa_typeid_t typeid, const char *name, const struct pa_sample_spec *spec, int variable_rate, int resample_method) {
+struct pa_sink_input* pa_sink_input_new(
+    struct pa_sink *s,
+    const char *name,
+    const char *driver,
+    const struct pa_sample_spec *spec,
+    const struct pa_channel_map *map,
+    int variable_rate,
+    int resample_method) {
+    
     struct pa_sink_input *i;
     struct pa_resampler *resampler = NULL;
     int r;
     char st[256];
-    assert(s && spec && s->state == PA_SINK_RUNNING);
+
+    assert(s);
+    assert(spec);
+    assert(s->state == PA_SINK_RUNNING);
 
     if (pa_idxset_ncontents(s->inputs) >= PA_MAX_INPUTS_PER_SINK) {
         pa_log(__FILE__": Failed to create sink input: too many inputs per sink.\n");
@@ -52,18 +63,23 @@ struct pa_sink_input* pa_sink_input_new(struct pa_sink *s, pa_typeid_t typeid, c
         resample_method = s->core->resample_method;
     
     if (variable_rate || !pa_sample_spec_equal(spec, &s->sample_spec))
-        if (!(resampler = pa_resampler_new(spec, &s->sample_spec, s->core->memblock_stat, resample_method)))
+        if (!(resampler = pa_resampler_new(spec, map, &s->sample_spec, &s->channel_map, s->core->memblock_stat, resample_method)))
             return NULL;
     
     i = pa_xmalloc(sizeof(struct pa_sink_input));
     i->ref = 1;
     i->state = PA_SINK_INPUT_RUNNING;
     i->name = pa_xstrdup(name);
-    i->typeid = typeid;
+    i->driver = pa_xstrdup(driver);
     i->client = NULL;
     i->owner = NULL;
     i->sink = s;
+
     i->sample_spec = *spec;
+    if (map)
+        i->channel_map = *map;
+    else
+        pa_channel_map_init_auto(&i->channel_map, spec->channels);
 
     i->peek = NULL;
     i->drop = NULL;
@@ -72,7 +88,7 @@ struct pa_sink_input* pa_sink_input_new(struct pa_sink *s, pa_typeid_t typeid, c
     i->userdata = NULL;
     i->underrun = NULL;
 
-    i->volume = PA_VOLUME_NORM;
+    pa_cvolume_reset(&i->volume);
     i->playing = 0;
 
     i->resampled_chunk.memblock = NULL;
@@ -124,6 +140,7 @@ static void sink_input_free(struct pa_sink_input* i) {
         pa_resampler_free(i->resampler);
 
     pa_xfree(i->name);
+    pa_xfree(i->driver);
     pa_xfree(i);
 }
 
@@ -234,15 +251,22 @@ void pa_sink_input_drop(struct pa_sink_input *i, const struct pa_memchunk *chunk
     }
 }
 
-void pa_sink_input_set_volume(struct pa_sink_input *i, pa_volume_t volume) {
+void pa_sink_input_set_volume(struct pa_sink_input *i, const struct pa_cvolume *volume) {
     assert(i && i->sink && i->sink->core && i->ref >= 1);
 
-    if (i->volume != volume) {
-        i->volume = volume;
+    if (!pa_cvolume_equal(&i->volume, volume)) {
+        i->volume = *volume;
         pa_subscription_post(i->sink->core, PA_SUBSCRIPTION_EVENT_SINK_INPUT|PA_SUBSCRIPTION_EVENT_CHANGE, i->index);
     }
 }
 
+const struct pa_cvolume * pa_sink_input_get_volume(struct pa_sink_input *i) {
+    assert(i);
+    assert(i->ref >= 1);
+
+    return &i->volume;
+}
+
 void pa_sink_input_cork(struct pa_sink_input *i, int b) {
     int n;
     assert(i && i->ref >= 1);
diff --git a/polyp/sink-input.h b/polyp/sink-input.h
index 83abe53..90723c0 100644
--- a/polyp/sink-input.h
+++ b/polyp/sink-input.h
@@ -31,25 +31,25 @@
 #include "module.h"
 #include "client.h"
 
-enum pa_sink_input_state {
+typedef enum {
     PA_SINK_INPUT_RUNNING,
     PA_SINK_INPUT_CORKED,
     PA_SINK_INPUT_DISCONNECTED
-};
+} pa_sink_input_state_t;
 
 struct pa_sink_input {
     int ref;
-    enum pa_sink_input_state state;
-    
     uint32_t index;
-    pa_typeid_t typeid;
-
-    char *name;
+    pa_sink_input_state_t state;
+    
+    char *name, *driver;
     struct pa_module *owner;
     struct pa_client *client;
     struct pa_sink *sink;
+    
     struct pa_sample_spec sample_spec;
-    uint32_t volume;
+    struct pa_channel_map channel_map;
+    struct pa_cvolume volume;
     
     int (*peek) (struct pa_sink_input *i, struct pa_memchunk *chunk);
     void (*drop) (struct pa_sink_input *i, const struct pa_memchunk *chunk, size_t length);
@@ -65,7 +65,15 @@ struct pa_sink_input {
     struct pa_resampler *resampler;
 };
 
-struct pa_sink_input* pa_sink_input_new(struct pa_sink *s, pa_typeid_t typeid, const char *name, const struct pa_sample_spec *spec, int variable_rate, int resample_method);
+struct pa_sink_input* pa_sink_input_new(
+    struct pa_sink *s,
+    const char *name,
+    const char *driver,
+    const struct pa_sample_spec *spec,
+    const struct pa_channel_map *map,
+    int variable_rate,
+    int resample_method);
+
 void pa_sink_input_unref(struct pa_sink_input* i);
 struct pa_sink_input* pa_sink_input_ref(struct pa_sink_input* i);
 
@@ -80,7 +88,8 @@ pa_usec_t pa_sink_input_get_latency(struct pa_sink_input *i);
 int pa_sink_input_peek(struct pa_sink_input *i, struct pa_memchunk *chunk);
 void pa_sink_input_drop(struct pa_sink_input *i, const struct pa_memchunk *chunk, size_t length);
 
-void pa_sink_input_set_volume(struct pa_sink_input *i, pa_volume_t volume);
+void pa_sink_input_set_volume(struct pa_sink_input *i, const struct pa_cvolume *volume);
+const struct pa_cvolume *volume pa_sink_input_get_volume(struct pa_sink_input *i);
 
 void pa_sink_input_cork(struct pa_sink_input *i, int b);
 
diff --git a/polyp/sink.c b/polyp/sink.c
index 481e5cf..3b07472 100644
--- a/polyp/sink.c
+++ b/polyp/sink.c
@@ -39,12 +39,23 @@
 
 #define MAX_MIX_CHANNELS 32
 
-struct pa_sink* pa_sink_new(struct pa_core *core, pa_typeid_t typeid, const char *name, int fail, const struct pa_sample_spec *spec) {
+struct pa_sink* pa_sink_new(
+    struct pa_core *core,
+    const char *name,
+    const char *driver,
+    int fail,
+    const struct pa_sample_spec *spec,
+    const struct pa_channel_map *map) {
+    
     struct pa_sink *s;
     char *n = NULL;
     char st[256];
     int r;
-    assert(core && name && *name && spec);
+
+    assert(core);
+    assert(name);
+    assert(*name);
+    assert(spec);
 
     s = pa_xmalloc(sizeof(struct pa_sink));
 
@@ -53,31 +64,41 @@ struct pa_sink* pa_sink_new(struct pa_core *core, pa_typeid_t typeid, const char
         return NULL;
     }
 
-    s->name = pa_xstrdup(name);
-    s->description = NULL;
-    s->typeid = typeid;
-
     s->ref = 1;
+    s->core = core;
+
     s->state = PA_SINK_RUNNING;
-    
+    s->name = pa_xstrdup(name);
+    s->description = NULL;
+    s->driver = pa_xstrdup(driver);
     s->owner = NULL;
-    s->core = core;
+
     s->sample_spec = *spec;
+    if (map)
+        s->channel_map = *map;
+    else
+        pa_channel_map_init_auto(&s->channel_map, spec->channels);
+    
     s->inputs = pa_idxset_new(NULL, NULL);
 
     n = pa_sprintf_malloc("%s_monitor", name);
-    s->monitor_source = pa_source_new(core, typeid, n, 0, spec);
+    s->monitor_source = pa_source_new(core, n, driver, 0, spec, map);
     assert(s->monitor_source);
     pa_xfree(n);
     s->monitor_source->monitor_of = s;
     s->monitor_source->description = pa_sprintf_malloc("Monitor source of sink '%s'", s->name);
-    
-    s->volume = PA_VOLUME_NORM;
+
+    pa_cvolume_reset(&s->sw_volume);
+    pa_cvolume_reset(&s->hw_volume);
 
     s->notify = NULL;
     s->get_latency = NULL;
+    s->set_volume = NULL;
+    s->get_volume = NULL;
     s->userdata = NULL;
 
+    s->flags = 0;
+
     r = pa_idxset_put(core->sinks, s, &s->index);
     assert(s->index != PA_IDXSET_INVALID && r >= 0);
     
@@ -127,6 +148,7 @@ static void sink_free(struct pa_sink *s) {
 
     pa_xfree(s->name);
     pa_xfree(s->description);
+    pa_xfree(s->driver);
     pa_xfree(s);
 }
 
@@ -360,11 +382,38 @@ void pa_sink_set_owner(struct pa_sink *s, struct pa_module *m) {
         pa_source_set_owner(s->monitor_source, m);
 }
 
-void pa_sink_set_volume(struct pa_sink *s, pa_volume_t volume) {
-    assert(s && s->ref >= 1);
-    
-    if (s->volume != volume) {
-        s->volume = volume;
-        pa_subscription_post(s->core, PA_SUBSCRIPTION_EVENT_SINK|PA_SUBSCRIPTION_EVENT_CHANGE, s->index);
-    }
+void pa_sink_set_volume(struct pa_sink *s, pa_mixer_t m, const struct pa_cvolume *volume) {
+    struct pa_cvolume *v;
+    assert(s);
+    assert(s->ref >= 1);
+    assert(volume);
+
+    if ((m == PA_MIXER_HARDWARE || m == PA_MIXER_AUTO) && s->set_volume)
+        v = &s->hw_volume;
+    else
+        v = &s->sw_volume;
+
+    if (pa_cvolume_equal(v, volume))
+        return;
+
+    *v = volume;
+    pa_subscription_post(s->core, PA_SUBSCRIPTION_EVENT_SINK|PA_SUBSCRIPTION_EVENT_CHANGE, s->index);
+
+    if (v == &s->hw_volume)
+        s->set_volume(s);
+}
+
+const struct pa_cvolume *pa_sink_get_volume(struct pa_sink *sink, pa_mixer_t m) {
+    struct pa_cvolume *v;
+    assert(s);
+    assert(s->ref >= 1);
+
+    if ((m == PA_MIXER_HARDWARE || m == PA_MIXER_AUTO) && s->set_volume) {
+
+        if (s->get_volume)
+            s->get_volume(s);
+        
+        return &s->hw_volume;
+    } else
+        return &s->sw_volume;
 }
diff --git a/polyp/sink.h b/polyp/sink.h
index 844af96..a6d7efa 100644
--- a/polyp/sink.h
+++ b/polyp/sink.h
@@ -30,38 +30,51 @@ struct pa_sink;
 #include "sample.h"
 #include "idxset.h"
 #include "source.h"
-#include "typeid.h"
+#include "channelmap.h"
 
 #define PA_MAX_INPUTS_PER_SINK 6
 
-enum pa_sink_state {
+typedef enum {
     PA_SINK_RUNNING,
     PA_SINK_DISCONNECTED
-};
+} pa_sink_state_t;
+
+typedef enum {
+    PA_MIXER_AUTO,
+    PA_MIXER_SOFTWARE,
+    PA_MIXER_HARDWARE
+} pa_mixer_t;
 
 struct pa_sink {
     int ref;
-    enum pa_sink_state state;
-    
     uint32_t index;
-    pa_typeid_t typeid;
-
-    char *name, *description;
-    struct pa_module *owner;
     struct pa_core *core;
+    pa_sink_state_t state;
+
+    char *name, *description, *driver;
     struct pa_sample_spec sample_spec;
+    struct pa_channel_map channel_map;
     struct pa_idxset *inputs;
-
+    struct pa_module *owner;
     struct pa_source *monitor_source;
-
-    pa_volume_t volume;
+    struct pa_cvolume hw_volume, sw_volume;
 
     void (*notify)(struct pa_sink*sink);
     pa_usec_t (*get_latency)(struct pa_sink *s);
+    void (*set_volume)(struct pa_sink *s);
+    void (*get_volume)(struct pa_sink *s);
+    
     void *userdata;
 };
 
-struct pa_sink* pa_sink_new(struct pa_core *core, pa_typeid_t typeid, const char *name, int fail, const struct pa_sample_spec *spec);
+struct pa_sink* pa_sink_new(
+    struct pa_core *core,
+    const char *name,
+    const char *driver,
+    int fail,
+    const struct pa_sample_spec *spec,
+    const struct pa_channel_map *map);
+
 void pa_sink_disconnect(struct pa_sink* s);
 void pa_sink_unref(struct pa_sink*s);
 struct pa_sink* pa_sink_ref(struct pa_sink *s);
@@ -77,6 +90,7 @@ void pa_sink_notify(struct pa_sink*s);
 
 void pa_sink_set_owner(struct pa_sink *sink, struct pa_module *m);
 
-void pa_sink_set_volume(struct pa_sink *sink, pa_volume_t volume);
+void pa_sink_set_volume(struct pa_sink *sink, pa_mixer_t m, const struct pa_cvolume *volume);
+const struct pa_cvolume *pa_sink_get_volume(struct pa_sink *sink, pa_mixer_t m);
 
 #endif
diff --git a/polyp/source-output.c b/polyp/source-output.c
index f954c23..fa9f252 100644
--- a/polyp/source-output.c
+++ b/polyp/source-output.c
@@ -33,7 +33,14 @@
 #include "subscribe.h"
 #include "log.h"
 
-struct pa_source_output* pa_source_output_new(struct pa_source *s, pa_typeid_t typeid, const char *name, const struct pa_sample_spec *spec, int resample_method) {
+struct pa_source_output* pa_source_output_new(
+    struct pa_source *s,
+    const char *name,
+    const char *driver,
+    const struct pa_sample_spec *spec,
+    const struct pa_channel_map *map,
+    int resample_method) {
+    
     struct pa_source_output *o;
     struct pa_resampler *resampler = NULL;
     int r;
@@ -49,19 +56,24 @@ struct pa_source_output* pa_source_output_new(struct pa_source *s, pa_typeid_t t
         resample_method = s->core->resample_method;
 
     if (!pa_sample_spec_equal(&s->sample_spec, spec))
-        if (!(resampler = pa_resampler_new(&s->sample_spec, spec, s->core->memblock_stat, resample_method)))
+        if (!(resampler = pa_resampler_new(&s->sample_spec, &s->channel_map, spec, map, s->core->memblock_stat, resample_method)))
             return NULL;
     
     o = pa_xmalloc(sizeof(struct pa_source_output));
     o->ref = 1;
     o->state = PA_SOURCE_OUTPUT_RUNNING;
     o->name = pa_xstrdup(name);
-    o->typeid = typeid;
+    o->driver = pa_xstrdup(driver);
     
     o->client = NULL;
     o->owner = NULL;
     o->source = s;
+    
     o->sample_spec = *spec;
+    if (map)
+        c->channel_map = *map;
+    else
+        pa_channel_map_init_auto(&c->channel_map, spec->channels);
 
     o->push = NULL;
     o->kill = NULL;
@@ -96,7 +108,6 @@ void pa_source_output_disconnect(struct pa_source_output*o) {
     o->push = NULL;
     o->kill = NULL;
     
-    
     o->state = PA_SOURCE_OUTPUT_DISCONNECTED;
 }
 
@@ -112,6 +123,7 @@ static void source_output_free(struct pa_source_output* o) {
         pa_resampler_free(o->resampler);
 
     pa_xfree(o->name);
+    pa_xfree(o->driver);
     pa_xfree(o);
 }
 
diff --git a/polyp/source-output.h b/polyp/source-output.h
index f3187aa..f561e05 100644
--- a/polyp/source-output.h
+++ b/polyp/source-output.h
@@ -31,24 +31,24 @@
 #include "module.h"
 #include "client.h"
 
-enum pa_source_output_state {
+typedef enum {
     PA_SOURCE_OUTPUT_RUNNING,
     PA_SOURCE_OUTPUT_CORKED,
     PA_SOURCE_OUTPUT_DISCONNECTED
-};
+} pa_source_output_state_t;
 
 struct pa_source_output {
     int ref;
-    enum pa_source_output_state state;
-    
     uint32_t index;
-    pa_typeid_t typeid;
-
-    char *name;
+    pa_source_output_state_t state;
+    
+    char *name, *driver;
     struct pa_module *owner;
     struct pa_client *client;
     struct pa_source *source;
+
     struct pa_sample_spec sample_spec;
+    struct pa_channel_map channel_map;
     
     void (*push)(struct pa_source_output *o, const struct pa_memchunk *chunk);
     void (*kill)(struct pa_source_output* o);
@@ -59,7 +59,14 @@ struct pa_source_output {
     void *userdata;
 };
 
-struct pa_source_output* pa_source_output_new(struct pa_source *s, pa_typeid_t typeid, const char *name, const struct pa_sample_spec *spec, int resample_method);
+struct pa_source_output* pa_source_output_new(
+    struct pa_source *s,
+    const char *name,
+    const char *driver,
+    const struct pa_sample_spec *spec,
+    const struct pa_channel_map *map;
+    int resample_method);
+
 void pa_source_output_unref(struct pa_source_output* o);
 struct pa_source_output* pa_source_output_ref(struct pa_source_output *o);
 
diff --git a/polyp/source.c b/polyp/source.c
index fc73272..a80c6af 100644
--- a/polyp/source.c
+++ b/polyp/source.c
@@ -35,11 +35,22 @@
 #include "subscribe.h"
 #include "log.h"
 
-struct pa_source* pa_source_new(struct pa_core *core, pa_typeid_t typeid, const char *name, int fail, const struct pa_sample_spec *spec) {
+struct pa_source* pa_source_new(
+    struct pa_core *core,
+    const char *name,
+    const char *driver,
+    int fail,
+    const struct pa_sample_spec *spec,
+    const struct pa_channel_map *map) {
+    
     struct pa_source *s;
     char st[256];
     int r;
-    assert(core && spec && name && *name);
+    
+    assert(core);
+    assert(name);
+    assert(*name);
+    assert(spec);
 
     s = pa_xmalloc(sizeof(struct pa_source));
 
@@ -53,11 +64,16 @@ struct pa_source* pa_source_new(struct pa_core *core, pa_typeid_t typeid, const
     
     s->name = pa_xstrdup(name);
     s->description = NULL;
-    s->typeid = typeid; 
+    s->driver = pa_xstrdup(driver);
 
     s->owner = NULL;
     s->core = core;
     s->sample_spec = *spec;
+    if (map)
+        s->channel_map = *map;
+    else
+        pa_channel_map_init_auto(&s->channel_map, spec->channels);
+
     s->outputs = pa_idxset_new(NULL, NULL);
     s->monitor_of = NULL;
 
@@ -108,6 +124,7 @@ static void source_free(struct pa_source *s) {
 
     pa_xfree(s->name);
     pa_xfree(s->description);
+    pa_xfree(s->driver);
     pa_xfree(s);
 }
 
diff --git a/polyp/source.h b/polyp/source.h
index 0fac2b3..21ebda5 100644
--- a/polyp/source.h
+++ b/polyp/source.h
@@ -31,35 +31,42 @@ struct pa_source;
 #include "memblock.h"
 #include "memchunk.h"
 #include "sink.h"
-#include "typeid.h"
+#include "channelmap.h"
 
 #define PA_MAX_OUTPUTS_PER_SOURCE 16
 
-enum pa_source_state {
+typedef enum {
     PA_SOURCE_RUNNING,
     PA_SOURCE_DISCONNECTED
-};
+} pa_source_state_t;
 
 struct pa_source {
     int ref;
-    enum pa_source_state state;
-    
     uint32_t index;
-    pa_typeid_t typeid;
-    
-    char *name, *description;
-    struct pa_module *owner;
     struct pa_core *core;
+    pa_source_state_t state;
+    
+    char *name, *description, *driver;
     struct pa_sample_spec sample_spec;
+    struct pa_channel_map channel_map;
     struct pa_idxset *outputs;
     struct pa_sink *monitor_of;
+    struct pa_module *owner;
 
     void (*notify)(struct pa_source*source);
     pa_usec_t (*get_latency)(struct pa_source *s);
+    
     void *userdata;
 };
 
-struct pa_source* pa_source_new(struct pa_core *core, pa_typeid_t typeid, const char *name, int fail, const struct pa_sample_spec *spec);
+struct pa_source* pa_source_new(
+    struct pa_core *core,
+    const char *name,
+    const char *driver,
+    int fail,
+    const struct pa_sample_spec *spec,
+    const struct pa_channel_map *map);
+
 void pa_source_disconnect(struct pa_source *s);
 void pa_source_unref(struct pa_source *s);
 struct pa_source* pa_source_ref(struct pa_source *c);
diff --git a/polyp/tagstruct.h b/polyp/tagstruct.h
index 135825e..f867cfb 100644
--- a/polyp/tagstruct.h
+++ b/polyp/tagstruct.h
@@ -44,6 +44,8 @@ void pa_tagstruct_put_arbitrary(struct pa_tagstruct*t, const void *p, size_t len
 void pa_tagstruct_put_boolean(struct pa_tagstruct*t, int b);
 void pa_tagstruct_put_timeval(struct pa_tagstruct*t, const struct timeval *tv);
 void pa_tagstruct_put_usec(struct pa_tagstruct*t, pa_usec_t u);
+void pa_tagstruct_put_channel_map(struct pa_tagstruct *t, const struct pa_channel_map *map);
+void pa_tagstruct_put_cvolume(struct pa_tagstruct *t, const struct pa_cvolume *cvolume);
 
 int pa_tagstruct_gets(struct pa_tagstruct*t, const char **s);
 int pa_tagstruct_getu8(struct pa_tagstruct*t, uint8_t *c);
@@ -54,6 +56,8 @@ int pa_tagstruct_get_arbitrary(struct pa_tagstruct *t, const void **p, size_t le
 int pa_tagstruct_get_boolean(struct pa_tagstruct *t, int *b);
 int pa_tagstruct_get_timeval(struct pa_tagstruct*t, struct timeval *tv);
 int pa_tagstruct_get_usec(struct pa_tagstruct*t, pa_usec_t *u);
+int pa_tagstruct_get_channel_map(struct pa_tagstruct *t, struct pa_channel_map *map);
+int pa_tagstruct_get_cvolume(struct pa_tagstruct *t, struct pa_cvolume *v);
 
 int pa_tagstruct_eof(struct pa_tagstruct*t);
 const uint8_t* pa_tagstruct_data(struct pa_tagstruct*t, size_t *l);
diff --git a/polyp/voltest.c b/polyp/voltest.c
index d8d5c56..0c4e232 100644
--- a/polyp/voltest.c
+++ b/polyp/voltest.c
@@ -2,13 +2,18 @@
 
 #include <stdio.h>
 
-#include <polyp/sample.h>
+#include <polyp/volume.h>
 
 int main() {
-    int p;
-    for (p = 0; p <= 200; p++) {
-        pa_volume_t v = pa_volume_from_user((double) p/100);
-        double dB = pa_volume_to_dB(v);
-        printf("%3i%% = %u = %0.2f dB = %u = %3i%%\n", p, v, dB, pa_volume_from_dB(dB), (int) (pa_volume_to_user(v)*100));
+    pa_volume_t v;
+
+    for (v = PA_VOLUME_MUTED; v <= PA_VOLUME_NORM*2; v += 256) {
+
+        double dB = pa_sw_volume_to_dB(v);
+        double f = pa_sw_volume_to_linear(v);
+        
+        printf("Volume: %3i; percent: %i%%; decibel %0.2f; linear = %0.2f; volume(decibel): %3i; volume(linear): %3i\n",
+               v, (v*100)/PA_VOLUME_NORM, dB, f, pa_sw_volume_from_dB(dB), pa_sw_volume_from_linear(f));
+
     }
 }
diff --git a/polyp/volume.c b/polyp/volume.c
new file mode 100644
index 0000000..bb9d30d
--- /dev/null
+++ b/polyp/volume.c
@@ -0,0 +1,161 @@
+/* $Id$ */
+
+/***
+  This file is part of polypaudio.
+ 
+  polypaudio 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 of the License,
+  or (at your option) any later version.
+ 
+  polypaudio 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 polypaudio; if not, write to the Free Software
+  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+  USA.
+***/
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <assert.h>
+
+#include "volume.h"
+
+int pa_cvolume_equal(const struct pa_cvolume *a, const struct pa_cvolume *b) {
+    int i;
+    assert(a);
+    assert(b);
+
+    if (a->channels != b->channels)
+        return 0;
+    
+    for (i = 0; i < a->channels; i++)
+        if (a->values[i] != b->values[i])
+            return 0;
+
+    return 1;
+}
+
+void pa_cvolume_set(struct pa_cvolume *a, pa_volume_t v) {
+    int i;
+    assert(a);
+
+    a->channels = PA_CHANNELS_MAX;
+
+    for (i = 0; i < a->channels; i++)
+        a->values[i] = v;
+}
+
+void pa_cvolume_reset(struct pa_cvolume *a) {
+    assert(a);
+    pa_cvolume_set(a, PA_VOLUME_NORM);
+}
+
+void pa_cvolume_mute(struct pa_cvolume *a) {
+    assert(a);
+    pa_cvolume_set(a, PA_VOLUME_MUTED);
+}
+
+pa_volume_t pa_cvolume_avg(const struct pa_cvolume *a) {
+    uint64_t sum = 0;
+    int i;
+    assert(a);
+
+    for (i = 0; i < a->channels; i++)
+        sum += a->values[i];
+
+    sum /= a->channels;
+
+    return (pa_volume_t) sum;
+}
+
+pa_volume_t pa_sw_volume_multiply(pa_volume_t a, pa_volume_t b) {
+    uint64_t p = a;
+    p *= b;
+    p /= PA_VOLUME_NORM;
+
+    return pa_sw_volume_from_linear(pa_sw_volume_to_linear(a)* pa_sw_volume_to_linear(b));
+}
+
+#define USER_DECIBEL_RANGE 30
+
+pa_volume_t pa_sw_volume_from_dB(double dB) {
+    if (dB <= -USER_DECIBEL_RANGE)
+        return PA_VOLUME_MUTED;
+
+    return (pa_volume_t) ((dB/USER_DECIBEL_RANGE+1)*PA_VOLUME_NORM);
+}
+
+double pa_sw_volume_to_dB(pa_volume_t v) {
+    if (v == PA_VOLUME_MUTED)
+        return PA_DECIBEL_MININFTY;
+
+    return ((double) v/PA_VOLUME_NORM-1)*USER_DECIBEL_RANGE;
+}
+
+pa_volume_t pa_sw_volume_from_linear(double v) {
+
+    if (v <= 0)
+        return PA_VOLUME_MUTED;
+
+    if (v == 1)
+        return PA_VOLUME_NORM;
+
+    return pa_sw_volume_from_dB(20*log10(v));
+}
+
+double pa_sw_volume_to_linear(pa_volume_t v) {
+
+    if (v == PA_VOLUME_MUTED)
+        return 0;
+
+    return pow(10, pa_sw_volume_to_dB(v)/20);
+    
+}
+
+char *pa_cvolume_snprintf(char *s, size_t l, const struct pa_cvolume *c, unsigned channels) {
+    unsigned c;
+    int first = 1;
+    
+    assert(s);
+    assert(l > 0);
+    assert(c);
+
+    if (channels > PA_CHANNELS_MAX || channels <= 0)
+        channels = PA_CHANNELS_MAX;
+
+    *s = 0;
+
+    for (c = 0; c < channels && l > 1; c++) {
+        l -= snprintf(s, l, "%s%u: %3u%%",
+                      first ? "" : " ",
+                      c,
+                      (c->channels[c]*100)/PA_VOLUME_NORM);
+
+        s = strchr(s, 0);
+    }
+
+    return s;
+}
+
+
+/** Return non-zero if the volume of all channels is equal to the specified value */
+int pa_cvolume_channels_equal_to(const struct pa_cvolume *a, uint8_t channels, pa_volume_t v) {
+    unsigned c;
+    assert(a);
+
+    if (channels > PA_CHANNELS_MAX)
+        channels = PA_CHANNELS_MAX;
+
+    for (c = 0; c < channels; c++)
+        if (a->map[c] != v)
+            return 0;
+
+    return 1;
+}
diff --git a/polyp/volume.h b/polyp/volume.h
new file mode 100644
index 0000000..c013ddd
--- /dev/null
+++ b/polyp/volume.h
@@ -0,0 +1,98 @@
+#ifndef foovolumehfoo
+#define foovolumehfoo
+
+/* $Id$ */
+
+/***
+  This file is part of polypaudio.
+ 
+  polypaudio 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 of the License,
+  or (at your option) any later version.
+ 
+  polypaudio 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 polypaudio; if not, write to the Free Software
+  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+  USA.
+***/
+
+#include <inttypes.h>
+#include <polyp/cdecl.h>
+#include <polyp/sample.h>
+
+/** \file
+ * Constants and routines for volume handling */
+
+PA_C_DECL_BEGIN
+
+/** Volume specification:
+ *  PA_VOLUME_MUTED: silence;
+ * < PA_VOLUME_NORM: decreased volume;
+ *   PA_VOLUME_NORM: normal volume;
+ * > PA_VOLUME_NORM: increased volume */
+typedef uint32_t pa_volume_t;
+
+/** Normal volume (100%) */
+#define PA_VOLUME_NORM (0x10000)
+
+/** Muted volume (0%) */
+#define PA_VOLUME_MUTED (0)
+
+/** A structure encapsulating a per-channel volume */
+struct pa_cvolume {
+    uint8_t channels;
+    pa_volume_t values[PA_CHANNELS_MAX];
+};
+
+/** Return non-zero when *a == *b */
+int pa_cvolume_equal(const struct pa_cvolume *a, const struct pa_cvolume *b);
+
+/** Set the volume of all channels to PA_VOLUME_NORM */
+void pa_cvolume_reset(struct pa_cvolume *a);
+
+/** Set the volume of all channels to PA_VOLUME_MUTED */
+void pa_cvolume_mute(struct pa_cvolume *a);
+
+/** Set the volume of all channels to the specified parameter */
+void pa_cvolume_set(struct pa_cvolume *a, pa_volume_t v);
+
+/** Pretty print a volume structure */
+char *pa_cvolume_snprintf(char *s, size_t l, const struct pa_cvolume *c, unsigned channels);
+
+/** Return the average volume of all channels */
+pa_volume_t pa_cvolume_avg(const struct pa_cvolume *a);
+
+/** Return non-zero if the volume of all channels is equal to the specified value */
+int pa_cvolume_channels_equal_to(const struct pa_cvolume *a, uint8_t channels, pa_volume_t v);
+
+/** Multiply two volumes specifications, return the result. This uses PA_VOLUME_NORM as neutral element of multiplication. */
+pa_volume_t pa_sw_volume_multiply(pa_volume_t a, pa_volume_t b);
+
+/** Convert a decibel value to a volume. \since 0.4 */
+pa_volume_t pa_sw_volume_from_dB(double f);
+
+/** Convert a volume to a decibel value.  \since 0.4 */
+double pa_sw_volume_to_dB(pa_volume_t v);
+
+/** Convert a linear factor to a volume. \since 0.8 */
+pa_volume_t pa_sw_volume_from_linear(double v);
+
+/** Convert a volume to a linear factor. \since 0.8 */
+double pa_sw_volume_to_linear(pa_volume_t v);
+
+#ifdef INFINITY
+#define PA_DECIBEL_MININFTY (-INFINITY)
+#else
+/** This value is used as minus infinity when using pa_volume_{to,from}_dB(). \since 0.4 */
+#define PA_DECIBEL_MININFTY (-200)
+#endif
+
+PA_C_DECL_END
+
+#endif

commit 1f11ee3c8b392a68685875478637ce875de85da2
Author: Pierre Ossman <ossman at cendio.se>
Date:   Thu Jan 5 13:07:00 2006 +0000

    Big cleanup of the build structure.
    
     * configure.ac is divided into distinct sections for programs, headers,
       optional components, etc.
    
     * polyp/Makefile.am is organised into several sections instead of a big mess.
    
     * Conditionals are only for adding things to the primaries, not around their
       build rules.
    
     * polypcore has been brought up to date in preparation for the Windows port.
       It is not possible to use the current tricks there.
    
    
    git-svn-id: file:///home/lennart/svn/public/pulseaudio/branches/ossman@362 fefdeb5f-60dc-0310-8127-8f9354f1896f

diff --git a/Makefile.am b/Makefile.am
index 7935321..a6a012a 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -18,7 +18,7 @@
 # USA.
 
 EXTRA_DIST = bootstrap.sh README LICENSE doxygen/Makefile.am doxygen/Makefile.in doxygen/doxygen.conf.in libtool.m4 ltdl.m4
-SUBDIRS=polyp doc libltdl
+SUBDIRS=libltdl polyp doc
 
 MAINTAINERCLEANFILES=README
 noinst_DATA = README
@@ -49,8 +49,8 @@ homepage: all dist doxygen
 	cp -a doxygen/html/* $$HOME/homepage/private/projects/polypaudio/doxygen
 	cp $$HOME/homepage/private/projects/polypaudio/README.html $$HOME/homepage/private/projects/polypaudio/index.html
 
-distcleancheck:
-	@:
+#distcleancheck:
+#	@:
 
 doxygen:
 	$(MAKE) -C doxygen doxygen
diff --git a/acinclude.m4 b/acinclude.m4
index bedf51c..02f271b 100644
--- a/acinclude.m4
+++ b/acinclude.m4
@@ -197,3 +197,44 @@ else
 fi
 AC_LANG_RESTORE
 ])dnl ACX_PTHREAD
+
+AC_DEFUN([AC_CHECK_DEFINE],[
+AS_VAR_PUSHDEF([ac_var],[ac_cv_defined_$1])dnl
+AC_CACHE_CHECK([for $1 defined], ac_var,
+AC_TRY_COMPILE([#include <$2>],[
+  #ifdef $1
+  int ok;
+  #else
+  choke me
+  #endif
+],AS_VAR_SET(ac_var, yes),AS_VAR_SET(ac_var, no)))
+AS_IF([test AS_VAR_GET(ac_var) != "no"], [$3], [$4])dnl
+AS_VAR_POPDEF([ac_var])dnl
+])
+
+AC_DEFUN([ACX_LIBWRAP], [
+LIBWRAP_LIBS=
+saved_LIBS="$LIBS"
+LIBS="$LIBS -lwrap"
+AC_MSG_CHECKING([for tcpwrap library and headers])
+AC_LINK_IFELSE(
+AC_LANG_PROGRAM(
+[#include <tcpd.h>
+#include <syslog.h>
+int allow_severity = LOG_INFO;
+int deny_severity = LOG_WARNING;],
+[struct request_info *req; 
+return hosts_access (req);]),
+[AC_DEFINE(HAVE_LIBWRAP, [], [Have tcpwrap?])
+LIBWRAP_LIBS="-lwrap"
+AC_MSG_RESULT(yes)],
+[AC_MSG_RESULT(no)])
+LIBS="$saved_LIBS"
+])
+
+AC_DEFUN([ACX_LIRC], [
+LIRC_CFLAGS=
+LIRC_LIBS=
+AC_CHECK_HEADER(lirc/lirc_client.h,[AC_CHECK_LIB(lirc_client,lirc_init,[HAVE_LIRC=1
+LIRC_LIBS=-llirc_client],HAVE_LIRC=0)],HAVE_LIRC=0)
+])
diff --git a/configure.ac b/configure.ac
index 1254134..362077f 100644
--- a/configure.ac
+++ b/configure.ac
@@ -35,18 +35,60 @@ if type -p stow > /dev/null && test -d /usr/local/stow ; then
    ac_default_prefix="/usr/local/stow/${PACKAGE_NAME}-${PACKAGE_VERSION}"
 fi
 
-# Checks for programs.
+#### Checks for programs. ####
+
+# CC
+
 AC_PROG_CC
+AC_PROG_GCC_TRADITIONAL
+
+# If using GCC specify some additional parameters
+if test "x$GCC" = "xyes" ; then
+   CFLAGS="$CFLAGS -pipe -W -Wall -pedantic"
+
+   AC_LANG_CONFTEST([int main() {}])
+   $CC -c conftest.c -std=gnu9x -Wno-unused-parameter $CFLAGS > /dev/null 2> /dev/null && CFLAGS="$CFLAGS -std=gnu9x -Wno-unused-parameter"
+   rm -f conftest.o
+fi
+
+# M4
 
-# libtool stuff
+AC_PATH_PROG([M4], [m4 gm4], [no])
+if test "x$M4" = xno ; then
+   AC_MSG_ERROR([m4 missing])
+fi
+
+# LYNX documentation generation
+AC_ARG_ENABLE(lynx,
+        AC_HELP_STRING(--disable-lynx,Turn off lynx usage for documentation generation),
+[case "${enableval}" in
+  yes) lynx=yes ;;
+  no)  lynx=no ;;
+  *) AC_MSG_ERROR(bad value ${enableval} for --disable-lynx) ;;
+esac],[lynx=yes])
+
+if test x$lynx = xyes ; then
+   AC_CHECK_PROG(have_lynx, lynx, yes, no)
+
+   if test x$have_lynx = xno ; then
+     AC_MSG_WARN([*** lynx not found, plain text README will not be built ***])
+   fi
+fi
+
+AM_CONDITIONAL([USE_LYNX], [test "x$have_lynx" = xyes])
+
+#### libtool stuff ####
+
+AC_LTDL_ENABLE_INSTALL
 AC_LIBLTDL_INSTALLABLE
 AC_SUBST(LTDLINCL)
 AC_SUBST(LIBLTDL)
 AC_LIBTOOL_DLOPEN
+AC_LIBTOOL_WIN32_DLL
 AC_PROG_LIBTOOL
 AC_CONFIG_SUBDIRS(libltdl)
 
-if test "x$ac_cv_lib_ltdl_lt_dlinit" = "xno" ; then
+if test "x$enable_ltdl_install" = "xno" && test "x$ac_cv_lib_ltdl_lt_dlinit" = "xno" ; then
     AC_MSG_ERROR([[
 
         *** Cannot find the libltdl development files.
@@ -54,93 +96,167 @@ if test "x$ac_cv_lib_ltdl_lt_dlinit" = "xno" ; then
         ]])
 fi
 
-# Checks for header files.
+#### Determine build environment ####
+
+os_is_win32=0
+
+case "$host_os" in
+	mingw*)
+        AC_DEFINE([OS_IS_WIN32], 1, [Build target is Windows.])
+        os_is_win32=1
+		;;
+	esac
+
+AM_CONDITIONAL(OS_IS_WIN32, test "x$os_is_win32" = "x1")
+
+###################################
+#   Basic environment checks      #
+###################################
+
+#### Checks for header files. ####
+
+# ISO
 AC_HEADER_STDC
-AC_CHECK_HEADERS([arpa/inet.h fcntl.h inttypes.h limits.h malloc.h netdb.h netinet/in.h stddef.h stdint.h stdlib.h string.h sys/ioctl.h sys/socket.h sys/time.h unistd.h syslog.h])
 
-ACX_PTHREAD
-AC_PATH_XTRA
+# POSIX
+AC_CHECK_HEADERS([glob.h grp.h netdb.h netinet/in.h netinet/tcp.h pwd.h \
+    sched.h sys/capability.h sys/resource.h sys/select.h sys/socket.h \
+    syslog.h])
+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])
 
-HAVE_X11=0
-test "x$no_x" != "xyes" && HAVE_X11=1
-AC_SUBST(HAVE_X11)
-AM_CONDITIONAL(HAVE_X11, test "x$no_x" != "xyes")
-if test "x$no_x" != "xyes" ; then
-   AC_DEFINE([HAVE_X11], 1, [Have X11])
-fi
+AM_CONDITIONAL(HAVE_REGEX, test "x$HAVE_REGEX" = "x1")
+AM_CONDITIONAL(HAVE_AF_UNIX, test "x$HAVE_AF_UNIX" = "x1")
+
+# XPG4-UNIX
+AC_CHECK_HEADERS([sys/poll.h])
+
+# Linux
+AC_CHECK_HEADERS([linux/input.h], [HAVE_EVDEV=1], [HAVE_EVDEV=0])
+
+AM_CONDITIONAL([HAVE_EVDEV], [test "x$HAVE_EVDEV" = "x1"])
+
+# Windows
+AC_CHECK_HEADERS([winsock2.h ws2tcpip.h])
+
+# Other
+AC_CHECK_HEADERS([sys/ioctl.h])
+
+#### Typdefs, structures, etc. ####
 
-# Checks for typedefs, structures, and compiler characteristics.
 AC_C_CONST
+AC_C_BIGENDIAN
 AC_TYPE_PID_T
 AC_TYPE_SIZE_T
+AC_CHECK_TYPES(ssize_t, , [AC_DEFINE([ssize_t], [signed long],
+    [Define ssize_t if it is not done by the standard libs.])])
 AC_TYPE_OFF_T
-AC_HEADER_TIME
-
-# Checks for library functions.
-AC_FUNC_FORK
-AC_PROG_GCC_TRADITIONAL
-AC_FUNC_LSTAT
-AC_FUNC_LSTAT_FOLLOWS_SLASHED_SYMLINK
-AC_FUNC_MALLOC
-AC_FUNC_MEMCMP
-AC_FUNC_MMAP
-AC_FUNC_REALLOC
-AC_FUNC_SETPGRP
-AC_FUNC_VPRINTF
-AC_FUNC_CLOSEDIR_VOID
-AC_FUNC_SELECT_ARGTYPES
 AC_TYPE_SIGNAL
 AC_TYPE_UID_T
-AC_CHECK_FUNCS([gethostname gettimeofday memchr memmove memset mkdir mkfifo munmap rmdir socket strcspn strerror strrchr strspn strstr strtol strtoul strcasecmp putenv strchr strpbrk strdup getgrgid_r getpwuid_r regcomp ftruncate select])
-AC_CHECK_LIB(m, pow)
-AC_CHECK_FUNCS(pow)
-AC_FUNC_STAT
-AC_HEADER_SYS_WAIT
-AC_HEADER_DIRENT
 
-AC_C_BIGENDIAN
+AC_CHECK_DEFINE([SIGXCPU], [signal.h])
+AM_CONDITIONAL(HAVE_SIGXCPU, test "x$HAVE_SIGXCPU" = "x1")
+
+#### Check for functions ####
+
+# ISO
+AC_CHECK_LIB([m], [pow])
+
+# POSIX
+AC_FUNC_FORK
 AC_FUNC_GETGROUPS
+AC_FUNC_SELECT_ARGTYPES
+AC_CHECK_FUNCS([ftruncate getgrgid_r getpwuid_r gettimeofday getuid \
+    inet_ntop mkfifo nanosleep sigaction sleep])
 
-AC_CHECK_LIB(cap, cap_init, [CAP_LIBS='-lcap'], [CAP_LIBS=''])
-AC_SUBST(CAP_LIBS)
+AM_CONDITIONAL(HAVE_MKFIFO, test "x$HAVE_MKFIFO" = "x1")
 
-AC_CHECK_HEADERS(sys/capability.h)
+# X/OPEN
+AC_CHECK_FUNCS([readlink])
+
+# SUSv2
+AC_CHECK_FUNCS([ctime_r usleep])
+
+# Non-standard
 
 AC_CHECK_FUNCS(setresuid)
 AC_CHECK_FUNCS(setreuid)
 
+#### POSIX threads ####
+
+ACX_PTHREAD
+
+###################################
+#      External libraries         #
+###################################
+
+#### X11 (optional) ####
+
+HAVE_X11=0
+
+# The macro tests the host, not the build target
+if test "x$os_is_win32" != "x1" ; then
+    AC_PATH_XTRA
+    test "x$no_x" != "xyes" && HAVE_X11=1
+fi
+
+AC_SUBST(HAVE_X11)
+AM_CONDITIONAL(HAVE_X11, test "x$HAVE_X11" = "x1")
+if test "x$HAVE_X11" = "x1" ; then
+    AC_DEFINE([HAVE_X11], 1, [Have X11])
+fi
+
+#### Capabilities (optional) ####
+
+AC_CHECK_LIB(cap, cap_init, [CAP_LIBS='-lcap'], [CAP_LIBS=''])
+AC_SUBST(CAP_LIBS)
+
+#### Sample rate conversion ####
+
 PKG_CHECK_MODULES(LIBSAMPLERATE, [ samplerate >= 0.1.0 ])
 AC_SUBST(LIBSAMPLERATE_CFLAGS)
 AC_SUBST(LIBSAMPLERATE_LIBS)
 
+#### Sound file ####
+
 PKG_CHECK_MODULES(LIBSNDFILE, [ sndfile >= 1.0.10 ])
 AC_SUBST(LIBSNDFILE_CFLAGS)
 AC_SUBST(LIBSNDFILE_LIBS)
 
+#### ALSA support (optional) ####
+
 PKG_CHECK_MODULES(ASOUNDLIB, [ alsa >= 1.0.0 ], [HAVE_ALSA=1], [HAVE_ALSA=0])
 AC_SUBST(ASOUNDLIB_CFLAGS)
 AC_SUBST(ASOUNDLIB_LIBS) 
 AC_SUBST(HAVE_ALSA)
 AM_CONDITIONAL([HAVE_ALSA], [test "x$HAVE_ALSA" = x1])
 
+#### GLib 2 support (optional) ####
+
 PKG_CHECK_MODULES(GLIB20, [ glib-2.0 >= 2.4.0 ], HAVE_GLIB20=1, HAVE_GLIB20=0)
 AC_SUBST(GLIB20_CFLAGS)
 AC_SUBST(GLIB20_LIBS)
 AC_SUBST(HAVE_GLIB20)
 AM_CONDITIONAL([HAVE_GLIB20], [test "x$HAVE_GLIB20" = x1])
 
+#### GLib 1 support (optional) ####
+
 PKG_CHECK_MODULES(GLIB12, [ glib >= 1.2.0 ], HAVE_GLIB12=1, HAVE_GLIB12=0)
 AC_SUBST(GLIB12_CFLAGS)
 AC_SUBST(GLIB12_LIBS)
 AC_SUBST(HAVE_GLIB12)
 AM_CONDITIONAL([HAVE_GLIB12], [test "x$HAVE_GLIB12" = x1])
 
+#### Howl support (optional) ####
+
 PKG_CHECK_MODULES(HOWL, [ howl >= 0.9.8 ], HAVE_HOWL=1, HAVE_HOWL=0)
 AC_SUBST(HOWL_CFLAGS)
 AC_SUBST(HOWL_LIBS)
 AC_SUBST(HAVE_HOWL)
 AM_CONDITIONAL([HAVE_HOWL], [test "x$HAVE_HOWL" = x1])
 
+#### Async DNS support (optional) ####
+
 PKG_CHECK_MODULES(LIBASYNCNS, [ libasyncns >= 0.1 ], HAVE_LIBASYNCNS=1, HAVE_LIBASYNCNS=0)
 AC_SUBST(LIBASYNCNS_CFLAGS)
 AC_SUBST(LIBASYNCNS_LIBS)
@@ -151,70 +267,42 @@ if test "x$HAVE_LIBASYNCNS" != "x0" ; then
    AC_DEFINE([HAVE_LIBASYNCNS], 1, [Have libasyncns?])
 fi
 
-AC_PATH_PROG([M4], [m4 gm4], [no])
-if test "x$M4" = xno ; then
-   AC_MSG_ERROR([m4 missing])
-fi
+#### TCP wrappers (optional) ####
 
-AC_MSG_CHECKING([for tcpwrap library and headers])
-LIBWRAP_LIBS=
-saved_LIBS="$LIBS"
-LIBS="$LIBS -lwrap"
-AC_LINK_IFELSE(
-AC_LANG_PROGRAM(
-[#include <tcpd.h>
-#include <syslog.h>
-int allow_severity = LOG_INFO;
-int deny_severity = LOG_WARNING;],
-[struct request_info *req; 
-return hosts_access (req);]),
-[AC_DEFINE(HAVE_LIBWRAP, [], [Have tcpwrap?])
-LIBWRAP_LIBS="-lwrap"
-AC_MSG_RESULT(yes)],
-[AC_MSG_RESULT(no)])
+ACX_LIBWRAP
 AC_SUBST(LIBWRAP_LIBS)
-LIBS="$saved_LIBS"
 
-LIRC_CFLAGS=
-LIRC_LIBS=
-AC_CHECK_HEADER(lirc/lirc_client.h,[AC_CHECK_LIB(lirc_client,lirc_init,[HAVE_LIRC=1
-LIRC_LIBS=-llirc_client],HAVE_LIRC=0)],HAVE_LIRC=0)
+#### LIRC support (optional) ####
+
+ACX_LIRC
 AC_SUBST(LIRC_CFLAGS)
 AC_SUBST(LIRC_LIBS)
 AM_CONDITIONAL([HAVE_LIRC], [test "x$HAVE_LIRC" = x1])
 
-AC_CHECK_HEADER(linux/input.h,HAVE_EVDEV=1,HAVE_EVDEV=0)
-AM_CONDITIONAL([HAVE_EVDEV], [test "x$HAVE_EVDEV" = x1])
-
-# If using GCC specify some additional parameters
-if test "x$GCC" = "xyes" ; then
-   CFLAGS="$CFLAGS -pipe -W -Wall -pedantic"
-
-   AC_LANG_CONFTEST([int main() {}])
-   $CC -c conftest.c -std=c99 -Wno-unused-parameter $CFLAGS > /dev/null 2> /dev/null && CFLAGS="$CFLAGS -std=c99 -Wno-unused-parameter"
-   rm -f conftest.o
-fi
-
-# LYNX documentation generation
-AC_ARG_ENABLE(lynx,
-        AC_HELP_STRING(--disable-lynx,Turn off lynx usage for documentation generation),
-[case "${enableval}" in
-  yes) lynx=yes ;;
-  no)  lynx=no ;;
-  *) AC_MSG_ERROR(bad value ${enableval} for --disable-lynx) ;;
-esac],[lynx=yes])
-
-if test x$lynx = xyes ; then
-   AC_CHECK_PROG(have_lynx, lynx, yes, no)
-
-   if test x$have_lynx = xno ; then
-     AC_MSG_WARN([*** lynx not found, plain text README will not be built ***])
-   fi
-fi
-
-AM_CONDITIONAL([USE_LYNX], [test "x$lynx" = xyes])
+###################################
+#            Output               #
+###################################
 
 AM_CONDITIONAL(BUILD_LIBPOLYPCORE, false)
 
-AC_CONFIG_FILES([Makefile polyp/Makefile polyplib.pc polyplib-simple.pc polyplib-mainloop.pc polyplib-browse.pc polyplib-error.pc polyplib-glib-mainloop.pc polyplib-glib12-mainloop.pc doc/Makefile doc/README.html doc/cli.html doc/daemon.html doc/modules.html doxygen/Makefile doxygen/doxygen.conf polyp/polyplib-version.h doc/FAQ.html])
+AC_CONFIG_FILES([
+Makefile
+polyp/Makefile
+polyplib.pc
+polyplib-simple.pc
+polyplib-mainloop.pc
+polyplib-browse.pc
+polyplib-error.pc
+polyplib-glib-mainloop.pc
+polyplib-glib12-mainloop.pc
+doc/Makefile
+doc/README.html
+doc/cli.html
+doc/daemon.html
+doc/modules.html
+doxygen/Makefile
+doxygen/doxygen.conf
+polyp/polyplib-version.h
+doc/FAQ.html
+])
 AC_OUTPUT
diff --git a/polyp/Makefile.am b/polyp/Makefile.am
index 389cb0d..847be9a 100644
--- a/polyp/Makefile.am
+++ b/polyp/Makefile.am
@@ -17,72 +17,440 @@
 # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
 # USA.
 
+
+###################################
+#       Extra directories         #
+###################################
+
 polypincludedir=$(includedir)/polyp
 polypconfdir=$(sysconfdir)/polypaudio
 
 modlibdir=$(libdir)/polypaudio- at PA_MAJORMINOR@
 
-AM_CFLAGS=-D_GNU_SOURCE  -I$(top_srcdir) $(PTHREAD_CFLAGS) $(LIBSAMPLERATE_CFLAGS) $(LIBSNDFILE_CFLAGS)
-AM_CFLAGS+=-DDLSEARCHPATH=\"$(modlibdir)\"
-AM_CFLAGS+=-DDEFAULT_CONFIG_DIR=\"$(polypconfdir)\"
-AM_CFLAGS+=-DPOLYPAUDIO_BINARY=\"$(bindir)/polypaudio\"
+###################################
+#     Compiler/linker flags       #
+###################################
+
+AM_CFLAGS  = -D_GNU_SOURCE  -I$(top_srcdir)
+AM_CFLAGS += $(PTHREAD_CFLAGS) $(LTDLINCL)
+AM_CFLAGS += $(LIBSAMPLERATE_CFLAGS) $(LIBSNDFILE_CFLAGS)
+AM_CFLAGS += -DDLSEARCHPATH=\"$(modlibdir)\"
+AM_CFLAGS += -DDEFAULT_CONFIG_DIR=\"$(polypconfdir)\"
+AM_CFLAGS += -DPOLYPAUDIO_BINARY=\"$(bindir)/polypaudio$(EXEEXT)\"
 
 # This cool debug trap works on i386/gcc only
-AM_CFLAGS+='-DDEBUG_TRAP=__asm__("int $$3")'
+AM_CFLAGS += '-DDEBUG_TRAP=__asm__("int $$3")'
+
+AM_LIBADD = $(PTHREAD_LIBS)
+AM_LDADD = $(PTHREAD_LIBS)
+
+# Only required on some platforms but defined for all to avoid errors
+AM_LDFLAGS = -no-undefined
+
+if OS_IS_WIN32
+AM_LDFLAGS+=-Wl,--export-all-symbols
+WINSOCK_LIBS=-lwsock32 -lws2_32 -lwininet
+endif
+
+###################################
+#          Extra files            #
+###################################
 
-AM_LIBADD=$(PTHREAD_LIBS) -lm
-AM_LDADD=$(PTHREAD_LIBS) -lm
+EXTRA_DIST = \
+		client.conf.in \
+		daemon.conf.in \
+		default.pa.in \
+		depmod.py \
+		esdcompat.sh.in \
+		module-defs.h.m4
 
-EXTRA_DIST = default.pa.in daemon.conf.in client.conf.in depmod.py esdcompat.sh.in module-defs.h.m4
-bin_PROGRAMS = \
-		polypaudio \
+polypconf_DATA = default.pa daemon.conf client.conf
+
+BUILT_SOURCES = polyplib-version.h
+
+###################################
+#          Main daemon            #
+###################################
+
+bin_PROGRAMS = polypaudio
+
+polypaudio_SOURCES = \
+		caps.h caps.c \
+		cmdline.c cmdline.h \
+		cpulimit.c cpulimit.h \
+		conf-parser.h conf-parser.c \
+		daemon-conf.c daemon-conf.h \
+		dumpmodules.c dumpmodules.h \
+		gcc-printf.h \
+		main.c \
+		pid.c pid.h
+
+polypaudio_CFLAGS = $(AM_CFLAGS)
+polypaudio_CPPFLAGS = $(AM_CPPFLAGS)
+polypaudio_LDADD = $(AM_LDADD) libpolypcore.la $(LIBLTDL) \
+		$(LIBSAMPLERATE_LIBS) $(LIBSNDFILE_LIBS) $(CAP_LIBS)
+polypaudio_LDFLAGS= $(AM_LDFLAGS) -dlopen force 
+#q-static $(foreach f,$(modlib_LTLIBRARIES),-dlpreopen $(f))
+
+###################################
+#       Utility programs          #
+###################################
+
+bin_PROGRAMS += \
 		pacat \
 		pactl \
-		paplay \
-		pacmd
+		paplay
+
+if HAVE_AF_UNIX
+bin_PROGRAMS += pacmd
+endif
+
+if HAVE_X11
+bin_PROGRAMS += pax11publish
+endif
+
+if HAVE_HOWL
+bin_PROGRAMS += 	pabrowse
+endif
 
 bin_SCRIPTS = esdcompat.sh
 
+pacat_SOURCES = pacat.c
+pacat_LDADD = $(AM_LDADD) libpolyp- at PA_MAJORMINOR@.la libpolyp-error- at PA_MAJORMINOR@.la libpolyp-mainloop- at PA_MAJORMINOR@.la
+pacat_CFLAGS = $(AM_CFLAGS) 
+
+paplay_SOURCES = paplay.c
+paplay_LDADD = $(AM_LDADD) libpolyp- at PA_MAJORMINOR@.la libpolyp-error- at PA_MAJORMINOR@.la libpolyp-mainloop- at PA_MAJORMINOR@.la $(LIBSNDFILE_LIBS)
+paplay_CFLAGS = $(AM_CFLAGS) $(LIBSNDFILE_CFLAGS)
+
+pactl_SOURCES = pactl.c
+pactl_LDADD = $(AM_LDADD) libpolyp- at PA_MAJORMINOR@.la libpolyp-error- at PA_MAJORMINOR@.la libpolyp-mainloop- at PA_MAJORMINOR@.la $(LIBSNDFILE_LIBS)
+pactl_CFLAGS = $(AM_CFLAGS) $(LIBSNDFILE_CFLAGS)
+
+pacmd_SOURCES = pacmd.c util.c util.h xmalloc.c xmalloc.h log.c log.h pid.c pid.h
+pacmd_CFLAGS = $(AM_CFLAGS)
+pacmd_LDADD = $(AM_LDADD)
+
+pax11publish_SOURCES = pax11publish.c util.c util.h xmalloc.c xmalloc.h log.c log.h authkey.c authkey.h client-conf.c client-conf.h conf-parser.c conf-parser.h x11prop.c x11prop.h random.c random.h
+pax11publish_CFLAGS = $(AM_CFLAGS) $(X_CFLAGS)
+pax11publish_LDADD = $(AM_LDADD) $(X_PRE_LIBS) -lX11 $(X_LIBS) $(X_EXTRA_LIBS)
+
+pabrowse_SOURCES = pabrowse.c
+pabrowse_LDADD = $(AM_LDADD) libpolyp- at PA_MAJORMINOR@.la libpolyp-error- at PA_MAJORMINOR@.la libpolyp-mainloop- at PA_MAJORMINOR@.la libpolyp-browse- at PA_MAJORMINOR@.la
+pabrowse_CFLAGS = $(AM_CFLAGS)
+
+###################################
+#         Test programs           #
+###################################
+
 noinst_PROGRAMS = \
 		mainloop-test \
+		mcalign-test \
 		pacat-simple \
 		parec-simple \
-		cpulimit-test \
-		cpulimit-test2 \
-		voltest \
 		strlist-test \
-		mcalign-test
+		voltest
+
+if HAVE_SIGXCPU
+noinst_PROGRAMS += \
+		cpulimit-test \
+		cpulimit-test2
+endif
+
+if HAVE_GLIB20
+noinst_PROGRAMS += \
+		mainloop-test-glib
+endif
+
+if HAVE_GLIB12
+noinst_PROGRAMS += \
+		mainloop-test-glib12
+endif
+
+mainloop_test_SOURCES = mainloop-test.c
+mainloop_test_CFLAGS = $(AM_CFLAGS)
+mainloop_test_LDADD = $(AM_LDADD) libpolyp-mainloop- at PA_MAJORMINOR@.la libpolyp- at PA_MAJORMINOR@.la
+
+mcalign_test_SOURCES = mcalign-test.c util.c util.h xmalloc.c xmalloc.h log.c log.h mcalign.c mcalign.h memchunk.c memchunk.h memblock.c memblock.h
+mcalign_test_CFLAGS = $(AM_CFLAGS)
+mcalign_test_LDADD = $(AM_LDADD) $(WINSOCK_LIBS)
+
+pacat_simple_SOURCES = pacat-simple.c
+pacat_simple_LDADD = $(AM_LDADD) libpolyp- at PA_MAJORMINOR@.la libpolyp-simple- at PA_MAJORMINOR@.la libpolyp-error- at PA_MAJORMINOR@.la libpolyp-mainloop- at PA_MAJORMINOR@.la
+pacat_simple_CFLAGS = $(AM_CFLAGS)
+
+parec_simple_SOURCES = parec-simple.c
+parec_simple_LDADD = $(AM_LDADD) libpolyp- at PA_MAJORMINOR@.la libpolyp-simple- at PA_MAJORMINOR@.la libpolyp-error- at PA_MAJORMINOR@.la libpolyp-mainloop- at PA_MAJORMINOR@.la
+parec_simple_CFLAGS = $(AM_CFLAGS)
 
-polypconf_DATA=default.pa daemon.conf client.conf
+strlist_test_SOURCES = strlist-test.c strlist.c strlist.h strbuf.c strbuf.h util.c util.h xmalloc.c xmalloc.h log.c log.h
+strlist_test_CFLAGS = $(AM_CFLAGS)
+strlist_test_LDADD = $(AM_LDADD) $(WINSOCK_LIBS)
+
+voltest_SOURCES = voltest.c sample.c
+voltest_CFLAGS = $(AM_CFLAGS)
+voltest_LDADD = $(AM_LDADD)
+
+cpulimit_test_SOURCES = cpulimit-test.c cpulimit.c util.c log.c cpulimit.h util.h log.h
+cpulimit_test_CFLAGS = $(AM_CFLAGS)
+cpulimit_test_LDADD = $(AM_LDADD) libpolyp-mainloop- at PA_MAJORMINOR@.la
+
+cpulimit_test2_SOURCES = cpulimit-test.c cpulimit.c util.c log.c cpulimit.h util.h log.h
+cpulimit_test2_CFLAGS = $(AM_CFLAGS) -DTEST2
+cpulimit_test2_LDADD = $(AM_LDADD) libpolyp-mainloop- at PA_MAJORMINOR@.la
 
-BUILT_SOURCES=polyplib-version.h
+mainloop_test_glib_SOURCES = $(mainloop_test_SOURCES)
+mainloop_test_glib_CFLAGS = $(mainloop_test_CFLAGS) $(GLIB20_CFLAGS) -DGLIB_MAIN_LOOP
+mainloop_test_glib_LDADD = $(mainloop_test_LDADD) $(GLIB20_LIBS) libpolyp-mainloop-glib- at PA_MAJORMINOR@.la
+
+mainloop_test_glib12_SOURCES = $(mainloop_test_SOURCES)
+mainloop_test_glib12_CFLAGS = $(mainloop_test_CFLAGS) $(GLIB12_CFLAGS) -DGLIB_MAIN_LOOP
+mainloop_test_glib12_LDADD = $(mainloop_test_LDADD) $(GLIB12_LIBS) libpolyp-mainloop-glib12- at PA_MAJORMINOR@.la
 
-polypinclude_HEADERS= \
+###################################
+#         Client library          #
+###################################
+
+polypinclude_HEADERS = \
+		cdecl.h \
+		glib-mainloop.h \
+		mainloop.h \
+		mainloop-api.h \
+		mainloop-signal.h \
 		polyplib.h \
+		polyplib-context.h \
 		polyplib-def.h \
-		polyplib-simple.h \
 		polyplib-error.h \
-		polyplib-stream.h \
-		polyplib-context.h \
 		polyplib-introspect.h \
-		polyplib-subscribe.h \
 		polyplib-operation.h \
 		polyplib-scache.h \
+		polyplib-simple.h \
+		polyplib-stream.h \
+		polyplib-subscribe.h \
 		polyplib-version.h \
-		cdecl.h \
-		mainloop-api.h \
-		mainloop.h \
-		mainloop-signal.h \
 		sample.h \
-		glib-mainloop.h \
 		typeid.h
 
+if HAVE_HOWL
+polypinclude_HEADERS += \
+		polyplib-browser.h
+endif
+
+lib_LTLIBRARIES = \
+		libpolyp- at PA_MAJORMINOR@.la \
+		libpolyp-error- at PA_MAJORMINOR@.la \
+		libpolyp-mainloop- at PA_MAJORMINOR@.la \
+		libpolyp-simple- at PA_MAJORMINOR@.la
+
+if HAVE_HOWL
+lib_LTLIBRARIES += \
+		libpolyp-browse- at PA_MAJORMINOR@.la
+endif
+
+if HAVE_GLIB20
+lib_LTLIBRARIES += \
+		libpolyp-mainloop-glib- at PA_MAJORMINOR@.la
+endif
+
+if HAVE_GLIB12
+lib_LTLIBRARIES += \
+		libpolyp-mainloop-glib12- at PA_MAJORMINOR@.la
+endif
+
+libpolyp_ at PA_MAJORMINOR@_la_SOURCES = \
+		authkey.c authkey.h \
+		cdecl.h \
+		client-conf.c client-conf.h \
+		conf-parser.c conf-parser.h \
+		dynarray.c dynarray.h \
+		gcc-printf.h \
+		idxset.c idxset.h \
+		iochannel.c iochannel.h \
+		llist.h \
+		log.c log.h \
+		mainloop-api.c mainloop-api.h \
+		mcalign.c mcalign.h \
+		memblock.c memblock.h \
+		memchunk.c memchunk.h \
+		native-common.h \
+		packet.c packet.h \
+		parseaddr.c parseaddr.h \
+		pdispatch.c pdispatch.h \
+		polyplib.h \
+		polyplib-context.c polyplib-context.h \
+		polyplib-def.h \
+		polyplib-internal.h \
+		polyplib-introspect.c polyplib-introspect.h \
+		polyplib-operation.c polyplib-operation.h \
+		polyplib-scache.c polyplib-scache.h \
+		polyplib-stream.c polyplib-stream.h \
+		polyplib-subscribe.c polyplib-subscribe.h \
+		pstream.c pstream.h \
+		pstream-util.c pstream-util.h \
+		queue.c queue.h \
+		random.c random.h \
+		sample.c sample.h \
+		socket-client.c socket-client.h \
+		socket-util.c socket-util.h \
+		strbuf.c strbuf.h \
+		strlist.c strlist.h \
+		tagstruct.c tagstruct.h \
+		typeid.c typeid.h \
+		util.c util.h \
+		xmalloc.c xmalloc.h
+
+if HAVE_X11
+libpolyp_ at PA_MAJORMINOR@_la_SOURCES += \
+		client-conf-x11.c client-conf-x11.h \
+		x11prop.c x11prop.h
+endif
+
+libpolyp_ at PA_MAJORMINOR@_la_CFLAGS = $(AM_CFLAGS)
+libpolyp_ at PA_MAJORMINOR@_la_LDFLAGS = -version-info 0:0:0
+libpolyp_ at PA_MAJORMINOR@_la_LIBADD = $(AM_LIBADD) $(WINSOCK_LIBS)
+
+if HAVE_X11
+libpolyp_ at PA_MAJORMINOR@_la_CFLAGS += $(X_CFLAGS)
+libpolyp_ at PA_MAJORMINOR@_la_LDFLAGS += $(X_PRE_LIBS) -lX11 $(X_LIBS) $(X_EXTRA_LIBS)
+endif
+
+if HAVE_LIBASYNCNS
+libpolyp_ at PA_MAJORMINOR@_la_CFLAGS += $(LIBASYNCNS_CFLAGS)
+libpolyp_ at PA_MAJORMINOR@_la_LIBADD += $(LIBASYNCNS_LIBS)
+endif
+
+libpolyp_error_ at PA_MAJORMINOR@_la_SOURCES = polyplib-error.c polyplib-error.h
+libpolyp_error_ at PA_MAJORMINOR@_la_CFLAGS = $(AM_CFLAGS)
+libpolyp_error_ at PA_MAJORMINOR@_la_LIBADD = $(AM_LIBADD) libpolyp- at PA_MAJORMINOR@.la
+libpolyp_error_ at PA_MAJORMINOR@_la_LDFLAGS = -version-info 0:0:0
+
+libpolyp_mainloop_ at PA_MAJORMINOR@_la_SOURCES = \
+		mainloop.c mainloop.h \
+		mainloop-api.h mainloop-api.c \
+		mainloop-signal.c mainloop-signal.h
+libpolyp_mainloop_ at PA_MAJORMINOR@_la_CFLAGS = $(AM_CFLAGS)
+libpolyp_mainloop_ at PA_MAJORMINOR@_la_LIBADD = $(AM_LIBADD) libpolyp- at PA_MAJORMINOR@.la $(WINSOCK_LIBS)
+libpolyp_mainloop_ at PA_MAJORMINOR@_la_LDFLAGS = -version-info 0:0:0
+
+libpolyp_simple_ at PA_MAJORMINOR@_la_SOURCES = polyplib-simple.c polyplib-simple.h 
+libpolyp_simple_ at PA_MAJORMINOR@_la_CFLAGS = $(AM_CFLAGS)
+libpolyp_simple_ at PA_MAJORMINOR@_la_LIBADD = $(AM_LIBADD) libpolyp- at PA_MAJORMINOR@.la libpolyp-mainloop- at PA_MAJORMINOR@.la
+libpolyp_simple_ at PA_MAJORMINOR@_la_LDFLAGS = -version-info 0:0:0
+
+libpolyp_browse_ at PA_MAJORMINOR@_la_SOURCES = polyplib-browser.c polyplib-browser.h 
+libpolyp_browse_ at PA_MAJORMINOR@_la_CFLAGS = $(AM_CFLAGS) $(HOWL_CFLAGS)
+libpolyp_browse_ at PA_MAJORMINOR@_la_LIBADD = $(AM_LIBADD) libpolyp- at PA_MAJORMINOR@.la $(HOWL_LIBS)
+libpolyp_browse_ at PA_MAJORMINOR@_la_LDFLAGS = -version-info 0:0:0 
+
+libpolyp_mainloop_glib_ at PA_MAJORMINOR@_la_SOURCES = glib-mainloop.h glib-mainloop.c
+libpolyp_mainloop_glib_ at PA_MAJORMINOR@_la_CFLAGS = $(AM_CFLAGS) $(GLIB20_CFLAGS)
+libpolyp_mainloop_glib_ at PA_MAJORMINOR@_la_LIBADD = $(AM_LIBADD) libpolyp-mainloop- at PA_MAJORMINOR@.la $(GLIB20_LIBS)
+libpolyp_mainloop_glib_ at PA_MAJORMINOR@_la_LDFLAGS = -version-info 0:0:0
+
+libpolyp_mainloop_glib12_ at PA_MAJORMINOR@_la_SOURCES = glib-mainloop.h glib12-mainloop.c
+libpolyp_mainloop_glib12_ at PA_MAJORMINOR@_la_CFLAGS = $(AM_CFLAGS) $(GLIB12_CFLAGS)
+libpolyp_mainloop_glib12_ at PA_MAJORMINOR@_la_LIBADD = $(AM_LIBADD) libpolyp-mainloop- at PA_MAJORMINOR@.la $(GLIB12_LIBS)
+libpolyp_mainloop_glib12_ at PA_MAJORMINOR@_la_LDFLAGS = -version-info 0:0:0
+
+###################################
+#      Daemon core library        #
+###################################
+
+polypinclude_HEADERS += \
+		cli-command.h \
+		client.h \
+		core.h \
+		dynarray.h \
+		endianmacros.h \
+		hashmap.h \
+		idxset.h \
+		iochannel.h \
+		memblock.h \
+		memblockq.h \
+		memchunk.h \
+		modargs.h \
+		module.h \
+		namereg.h \
+		queue.h \
+		resampler.h \
+		sample-util.h \
+		sink.h \
+		sink-input.h \
+		sioman.h \
+		socket-server.h \
+		socket-client.h \
+		socket-util.h \
+		source.h \
+		source-output.h \
+		strbuf.h \
+		tokenizer.h \
+		tagstruct.h \
+		util.h
+
+lib_LTLIBRARIES += libpolypcore.la
+
+libpolypcore_la_SOURCES = \
+		autoload.c autoload.h \
+		cli-command.c cli-command.h \
+		cli-text.c cli-text.h \
+		client.c client.h \
+		core.c core.h \
+		dynarray.c dynarray.h \
+		endianmacros.h \
+		g711.c g711.h \
+		hashmap.c hashmap.h \
+		idxset.c idxset.h \
+		log.c log.h \
+		mainloop.c mainloop.h \
+		mainloop-api.c mainloop-api.h \
+		mainloop-signal.c mainloop-signal.h \
+		mcalign.c mcalign.h \
+		memblock.c memblock.h \
+		memblockq.c memblockq.h \
+		memchunk.c memchunk.h \
+		modargs.c modargs.h \
+		modinfo.c modinfo.h \
+		module.c module.h \
+		namereg.c namereg.h \
+		play-memchunk.c play-memchunk.h \
+		props.c props.h \
+		queue.c queue.h \
+		random.c random.h \
+		resampler.c resampler.h \
+		sample.c sample.h \
+		sample-util.c sample-util.h \
+		scache.c scache.h \
+		sconv.c sconv.h \
+		sconv-s16be.c sconv-s16be.h \
+		sconv-s16le.c sconv-s16le.h \
+		sink.c sink.h \
+		sink-input.c sink-input.h \
+		sioman.c sioman.h \
+		sound-file.c sound-file.h \
+		sound-file-stream.c sound-file-stream.h \
+		source.c source.h \
+		source-output.c source-output.h \
+		strbuf.c strbuf.h \
+		subscribe.c subscripe.h \
+		tokenizer.c tokenizer.h \
+		typeid.c typeid.h \
+		util.c util.h \
+		xmalloc.c xmalloc.h
+
+libpolypcore_la_CPPFLAGS = $(AM_CPPFLAGS)
+libpolypcore_la_LDFLAGS = -avoid-version
+libpolypcore_la_LIBADD = $(AM_LIBADD) $(LIBLTDL) $(LIBSAMPLERATE_LIBS) $(LIBSNDFILE_LIBS) $(WINSOCK_LIBS)
+
+###################################
+#   Plug-in support libraries     #
+###################################
+
 ### Warning! Due to an obscure bug in libtool/automake it is required
 ### that the libraries in modlib_LTLIBRARIES are specified in-order,
 ### i.e. libraries near the end of the list depend on libraries near
 ### the head, and not the other way!
 
-modlib_LTLIBRARIES= \
+modlib_LTLIBRARIES = \
 		libsocket-util.la \
 		libiochannel.la \
 		libsocket-server.la \
@@ -90,7 +458,6 @@ modlib_LTLIBRARIES= \
 		libparseaddr.la \
 		libpacket.la \
 		libpstream.la \
-		liboss-util.la \
 		libioline.la \
 		libcli.la \
 		libprotocol-cli.la \
@@ -103,163 +470,49 @@ modlib_LTLIBRARIES= \
 		libprotocol-simple.la \
 		libprotocol-esound.la \
 		libprotocol-native.la \
-		libprotocol-http.la \
-		module-cli.la \
-		module-cli-protocol-tcp.la \
-		module-cli-protocol-tcp6.la \
-		module-cli-protocol-unix.la \
-		module-pipe-sink.la \
-		module-pipe-source.la \
-		module-oss.la \
-		module-oss-mmap.la \
-		module-simple-protocol-tcp.la \
-		module-simple-protocol-tcp6.la \
-		module-simple-protocol-unix.la \
-		module-esound-protocol-tcp.la \
-		module-esound-protocol-tcp6.la \
-		module-esound-protocol-unix.la \
-		module-native-protocol-tcp.la \
-		module-native-protocol-tcp6.la \
-		module-native-protocol-unix.la \
-		module-native-protocol-fd.la \
-		module-sine.la \
-		module-combine.la \
-		module-esound-compat-spawnfd.la \
-		module-esound-compat-spawnpid.la \
-		module-match.la \
-		module-tunnel-sink.la \
-		module-tunnel-source.la \
-		module-null-sink.la \
-		module-esound-sink.la \
-		module-http-protocol-tcp.la \
-		module-http-protocol-tcp6.la \
-		module-http-protocol-unix.la
-
-SYMDEF_FILES= \
-		module-cli-symdef.h \
-		module-cli-protocol-tcp-symdef.h \
-		module-cli-protocol-tcp6-symdef.h \
-		module-cli-protocol-unix-symdef.h \
-		module-pipe-sink-symdef.h \
-		module-pipe-source-symdef.h \
-		module-oss-symdef.h \
-		module-oss-mmap-symdef.h \
-		module-simple-protocol-tcp-symdef.h \
-		module-simple-protocol-tcp6-symdef.h \
-		module-simple-protocol-unix-symdef.h \
-		module-esound-protocol-tcp-symdef.h \
-		module-esound-protocol-tcp6-symdef.h \
-		module-esound-protocol-unix-symdef.h \
-		module-native-protocol-tcp-symdef.h \
-		module-native-protocol-tcp6-symdef.h \
-		module-native-protocol-unix-symdef.h \
-		module-native-protocol-fd-symdef.h \
-		module-sine-symdef.h \
-		module-combine-symdef.h \
-		module-esound-compat-spawnfd-symdef.h \
-		module-esound-compat-spawnpid-symdef.h \
-		module-match-symdef.h \
-		module-tunnel-sink-symdef.h \
-		module-tunnel-source-symdef.h \
-		module-null-sink-symdef.h \
-		module-esound-sink-symdef.h \
-		module-zeroconf-publish-symdef.h \
-		module-lirc-symdef.h \
-		module-mmkbd-evdev-symdef.h \
-		module-http-protocol-tcp-symdef.h \
-		module-http-protocol-tcp6-symdef.h \
-		module-http-protocol-unix-symdef.h
+		libprotocol-http.la
 
-EXTRA_DIST+=$(SYMDEF_FILES)
-BUILT_SOURCES+=$(SYMDEF_FILES)
+if HAVE_X11
+modlib_LTLIBRARIES += \
+		libx11wrap.la \
+		libx11prop.la
+endif
 
-lib_LTLIBRARIES= \
-		libpolyp- at PA_MAJORMINOR@.la \
-		libpolyp-error- at PA_MAJORMINOR@.la \
-		libpolyp-mainloop- at PA_MAJORMINOR@.la \
-		libpolyp-simple- at PA_MAJORMINOR@.la
+if !OS_IS_WIN32
+modlib_LTLIBRARIES += \
+		liboss-util.la
+endif
 
-polypaudio_SOURCES = idxset.c idxset.h \
-		queue.c queue.h \
-		strbuf.c strbuf.h \
-		main.c \
-		mainloop.c mainloop.h \
-		memblock.c memblock.h \
-		sample.c sample.h \
-		sample-util.c sample-util.h \
-		memblockq.c memblockq.h \
-		client.c client.h \
-		core.c core.h \
-		source-output.c source-output.h \
-		sink-input.c sink-input.h \
-		source.c source.h \
-		sink.c sink.h \
-		module.c module.h \
-		mainloop-signal.c mainloop-signal.h \
-		mainloop-api.c mainloop-api.h \
-		util.c util.h \
-		hashmap.c hashmap.h \
-		namereg.c namereg.h \
-		sconv.c sconv.h \
-		resampler.c resampler.h \
-		endianmacros.h \
-		memchunk.c memchunk.h \
-		sconv-s16le.c sconv-s16le.h \
-		sconv-s16be.c sconv-s16be.h \
-		sioman.c sioman.h \
-		modargs.c modargs.h \
-		cmdline.c cmdline.h \
-		cli-command.c cli-command.h \
-		cli-text.c cli-text.h \
-		tokenizer.c tokenizer.h \
-		dynarray.c dynarray.h \
-		scache.c scache.h \
-		sound-file.c sound-file.h \
-		play-memchunk.c play-memchunk.h \
-		autoload.c autoload.h \
-		xmalloc.c xmalloc.h \
-		subscribe.h subscribe.c \
-		sound-file-stream.c sound-file-stream.h \
-		cpulimit.c cpulimit.h \
-		log.c log.h \
-		gcc-printf.h \
-		modinfo.c modinfo.h \
-		daemon-conf.c daemon-conf.h \
-		dumpmodules.c dumpmodules.h \
-		conf-parser.h conf-parser.c \
-		caps.h caps.c \
-		props.h props.c \
-		mcalign.c mcalign.h \
-		g711.c g711.h \
-		pid.c pid.h \
-		random.c random.h \
-		typeid.c typeid.h
+if HAVE_ALSA
+modlib_LTLIBRARIES += \
+		libalsa-util.la
+endif
 
-polypaudio_CFLAGS = $(AM_CFLAGS) $(LIBSAMPLERATE_CFLAGS) $(LIBSNDFILE_CFLAGS)
-polypaudio_CPPFLAGS = $(AM_CPPFLAGS) $(LTDLINCL)
-polypaudio_LDADD = $(AM_LDADD) $(LIBLTDL) $(LIBSAMPLERATE_LIBS) $(LIBSNDFILE_LIBS) $(CAP_LIBS)
-polypaudio_LDFLAGS= $(AM_LDFLAGS) -export-dynamic -dlopen force 
-#q-static $(foreach f,$(modlib_LTLIBRARIES),-dlpreopen $(f))
+if HAVE_HOWL
+modlib_LTLIBRARIES += \
+		libhowl-wrap.la
+endif
 
 libprotocol_simple_la_SOURCES = protocol-simple.c protocol-simple.h
 libprotocol_simple_la_LDFLAGS = -avoid-version
-libprotocol_simple_la_LIBADD = $(AM_LIBADD) libsocket-server.la libiochannel.la
+libprotocol_simple_la_LIBADD = $(AM_LIBADD) libpolypcore.la libsocket-server.la libiochannel.la
 
 libsocket_server_la_SOURCES = socket-server.c socket-server.h
 libsocket_server_la_LDFLAGS = -avoid-version
-libsocket_server_la_LIBADD = $(AM_LIBADD) libiochannel.la libsocket-util.la $(LIBWRAP_LIBS)
+libsocket_server_la_LIBADD = $(AM_LIBADD) libpolypcore.la libiochannel.la libsocket-util.la $(LIBWRAP_LIBS) $(WINSOCK_LIBS)
 
 libsocket_client_la_SOURCES = socket-client.c socket-client.h
 libsocket_client_la_LDFLAGS = -avoid-version
-libsocket_client_la_LIBADD = $(AM_LIBADD) libiochannel.la libsocket-util.la libparseaddr.la $(LIBASYNCNS_LIBS)
+libsocket_client_la_LIBADD = $(AM_LIBADD) libpolypcore.la libiochannel.la libsocket-util.la libparseaddr.la $(LIBASYNCNS_LIBS) $(WINSOCK_LIBS)
 libsocket_client_la_CFLAGS = $(AM_CFLAGS) $(LIBASYNCNS_CFLAGS)
 
 libparseaddr_la_SOURCES = parseaddr.c parseaddr.h
 libparseaddr_la_LDFLAGS = -avoid-version
+libparseaddr_la_LIBADD = $(AM_LIBADD) libpolypcore.la
 
 libpstream_la_SOURCES = pstream.c pstream.h
 libpstream_la_LDFLAGS = -avoid-version
-libpstream_la_LIBADD = $(AM_LIBADD) libpacket.la libiochannel.la
+libpstream_la_LIBADD = $(AM_LIBADD) libpolypcore.la libpacket.la libiochannel.la $(WINSOCK_LIBS)
 
 libpstream_util_la_SOURCES = pstream-util.c pstream-util.h
 libpstream_util_la_LDFLAGS = -avoid-version
@@ -267,326 +520,380 @@ libpstream_util_la_LIBADD = $(AM_LIBADD) libpacket.la libpstream.la libtagstruct
 
 libpdispatch_la_SOURCES = pdispatch.c pdispatch.h
 libpdispatch_la_LDFLAGS = -avoid-version
-libpdispatch_la_LIBADD = $(AM_LIBADD) libtagstruct.la
+libpdispatch_la_LIBADD = $(AM_LIBADD) libtagstruct.la libpolypcore.la
 
 libiochannel_la_SOURCES = iochannel.c iochannel.h
 libiochannel_la_LDFLAGS = -avoid-version
-libiochannel_la_LIBADD = $(AM_LIBADD) libsocket-util.la
+libiochannel_la_LIBADD = $(AM_LIBADD) libsocket-util.la libpolypcore.la
 
 libpacket_la_SOURCES = packet.c packet.h
 libpacket_la_LDFLAGS = -avoid-version
-
-liboss_util_la_SOURCES = oss-util.c oss-util.h
-liboss_util_la_LDFLAGS = -avoid-version
+libpacket_la_LIBADD = $(AM_LIBADD) libpolypcore.la
 
 libioline_la_SOURCES = ioline.c ioline.h
 libioline_la_LDFLAGS = -avoid-version
-libioline_la_LIBADD = $(AM_LIBADD) libiochannel.la
+libioline_la_LIBADD = $(AM_LIBADD) libiochannel.la libpolypcore.la
 
 libcli_la_SOURCES = cli.c cli.h
+libcli_la_CPPFLAGS = $(AM_CPPFLAGS)
 libcli_la_LDFLAGS = -avoid-version
-libcli_la_LIBADD = $(AM_LIBADD) libiochannel.la libioline.la
+libcli_la_LIBADD = $(AM_LIBADD) libiochannel.la libioline.la libpolypcore.la
 
 libstrlist_la_SOURCES = strlist.c strlist.h
 libstrlist_la_LDFLAGS = -avoid-version
-libstrlist_la_LIBADD = $(AM_LIBADD)
+libstrlist_la_LIBADD = $(AM_LIBADD) libpolypcore.la
 
 libprotocol_cli_la_SOURCES = protocol-cli.c protocol-cli.h
 libprotocol_cli_la_LDFLAGS = -avoid-version
-libprotocol_cli_la_LIBADD = $(AM_LIBADD) libsocket-server.la libiochannel.la libcli.la
+libprotocol_cli_la_LIBADD = $(AM_LIBADD) libsocket-server.la libiochannel.la libcli.la libpolypcore.la
 
 libprotocol_http_la_SOURCES = protocol-http.c protocol-http.h
 libprotocol_http_la_LDFLAGS = -avoid-version
-libprotocol_http_la_LIBADD = $(AM_LIBADD) libsocket-server.la libioline.la
+libprotocol_http_la_LIBADD = $(AM_LIBADD) libsocket-server.la libioline.la libpolypcore.la libiochannel.la
 
 libprotocol_native_la_SOURCES = protocol-native.c protocol-native.h native-common.h
 libprotocol_native_la_LDFLAGS = -avoid-version
-libprotocol_native_la_LIBADD = $(AM_LIBADD) libsocket-server.la libpstream.la libpstream-util.la libpdispatch.la libtagstruct.la libauthkey.la libauthkey-prop.la libstrlist.la
+libprotocol_native_la_LIBADD = $(AM_LIBADD) libsocket-server.la libpstream.la libpstream-util.la libpdispatch.la libtagstruct.la libauthkey.la libauthkey-prop.la libstrlist.la libpolypcore.la libiochannel.la
 
 libtagstruct_la_SOURCES = tagstruct.c tagstruct.h
 libtagstruct_la_LDFLAGS = -avoid-version
+libtagstruct_la_LIBADD = $(AM_LIBADD) libpolypcore.la $(WINSOCK_LIBS)
 
 libprotocol_esound_la_SOURCES = protocol-esound.c protocol-esound.h esound.h
 libprotocol_esound_la_LDFLAGS = -avoid-version
-libprotocol_esound_la_LIBADD = $(AM_LIBADD) libsocket-server.la libiochannel.la libauthkey.la
+libprotocol_esound_la_LIBADD = $(AM_LIBADD) libsocket-server.la libiochannel.la libauthkey.la libpolypcore.la
 
 libauthkey_la_SOURCES = authkey.c authkey.h
 libauthkey_la_LDFLAGS = -avoid-version
+libauthkey_la_LIBADD = $(AM_LIBADD) libpolypcore.la
 
 libauthkey_prop_la_SOURCES = authkey-prop.c authkey-prop.h
 libauthkey_prop_la_LDFLAGS = -avoid-version
+libauthkey_prop_la_LIBADD = $(AM_LIBADD) libpolypcore.la
 
 libsocket_util_la_SOURCES = socket-util.c socket-util.h
 libsocket_util_la_LDFLAGS = -avoid-version
+libsocket_util_la_LIBADD = $(AM_LIBADD) $(WINSOCK_LIBS)
+
+# X11
+
+libx11wrap_la_SOURCES = x11wrap.c x11wrap.h
+libx11wrap_la_LDFLAGS = -avoid-version
+libx11wrap_la_CFLAGS = $(AM_CFLAGS) $(X_CFLAGS)
+libx11wrap_la_LIBADD = $(AM_LIBADD) $(X_PRE_LIBS) -lX11 $(X_LIBS) $(X_EXTRA_LIBS)
+
+libx11prop_la_SOURCES = x11prop.c x11prop.h
+libx11prop_la_LDFLAGS = -avoid-version
+libx11prop_la_CFLAGS = $(AM_CFLAGS) $(X_CFLAGS)
+libx11prop_la_LIBADD = $(AM_LIBADD) $(X_PRE_LIBS) -lX11 $(X_LIBS) $(X_EXTRA_LIBS)
+
+# OSS
+
+liboss_util_la_SOURCES = oss-util.c oss-util.h
+liboss_util_la_LDFLAGS = -avoid-version
+
+# ALSA
+
+libalsa_util_la_SOURCES = alsa-util.c alsa-util.h
+libalsa_util_la_LDFLAGS = -avoid-version
+libalsa_util_la_LIBADD = $(AM_LIBADD) $(ASOUNDLIB_LIBS)
+libalsa_util_la_CFLAGS = $(AM_CFLAGS) $(ASOUNDLIB_CFLAGS)
+
+# HOWL
+
+libhowl_wrap_la_SOURCES = howl-wrap.c howl-wrap.h
+libhowl_wrap_la_LDFLAGS = -avoid-version
+libhowl_wrap_la_LIBADD = $(AM_LIBADD) $(HOWL_LIBS)
+libhowl_wrap_la_CFLAGS = $(AM_CFLAGS) $(HOWL_CFLAGS)
+
+###################################
+#        Plug-in libraries        #
+###################################
+
+modlib_LTLIBRARIES += \
+		module-cli.la \
+		module-cli-protocol-tcp.la \
+		module-cli-protocol-tcp6.la \
+		module-simple-protocol-tcp.la \
+		module-simple-protocol-tcp6.la \
+		module-esound-protocol-tcp.la \
+		module-esound-protocol-tcp6.la \
+		module-native-protocol-tcp.la \
+		module-native-protocol-tcp6.la \
+		module-native-protocol-fd.la \
+		module-sine.la \
+		module-combine.la \
+		module-tunnel-sink.la \
+		module-tunnel-source.la \
+		module-null-sink.la \
+		module-esound-sink.la \
+		module-http-protocol-tcp.la \
+		module-http-protocol-tcp6.la
+
+if HAVE_AF_UNIX
+modlib_LTLIBRARIES += \
+		module-cli-protocol-unix.la \
+		module-simple-protocol-unix.la \
+		module-esound-protocol-unix.la \
+		module-native-protocol-unix.la \
+		module-http-protocol-unix.la
+endif
+
+if HAVE_MKFIFO
+modlib_LTLIBRARIES += \
+		module-pipe-sink.la \
+		module-pipe-source.la
+endif
+
+if !OS_IS_WIN32
+modlib_LTLIBRARIES += \
+		module-esound-compat-spawnfd.la \
+		module-esound-compat-spawnpid.la
+endif
+
+if HAVE_REGEX
+modlib_LTLIBRARIES += \
+		module-match.la
+endif
+
+if HAVE_X11
+modlib_LTLIBRARIES += \
+		module-x11-bell.la \
+		module-x11-publish.la
+endif
+
+if !OS_IS_WIN32
+modlib_LTLIBRARIES += \
+		module-oss.la \
+		module-oss-mmap.la
+endif
+
+if HAVE_ALSA
+modlib_LTLIBRARIES += \
+		module-alsa-sink.la \
+		module-alsa-source.la
+endif
+
+if HAVE_HOWL
+modlib_LTLIBRARIES += \
+		module-zeroconf-publish.la
+endif
+
+if HAVE_LIRC
+modlib_LTLIBRARIES += \
+		module-lirc.la
+endif
+
+if HAVE_EVDEV
+modlib_LTLIBRARIES += \
+		module-mmkbd-evdev.la
+endif
+
+# These are generated by a M4 script
+
+SYMDEF_FILES = \
+		module-cli-symdef.h \
+		module-cli-protocol-tcp-symdef.h \
+		module-cli-protocol-tcp6-symdef.h \
+		module-cli-protocol-unix-symdef.h \
+		module-pipe-sink-symdef.h \
+		module-pipe-source-symdef.h \
+		module-simple-protocol-tcp-symdef.h \
+		module-simple-protocol-tcp6-symdef.h \
+		module-simple-protocol-unix-symdef.h \
+		module-esound-protocol-tcp-symdef.h \
+		module-esound-protocol-tcp6-symdef.h \
+		module-esound-protocol-unix-symdef.h \
+		module-native-protocol-tcp-symdef.h \
+		module-native-protocol-tcp6-symdef.h \
+		module-native-protocol-unix-symdef.h \
+		module-native-protocol-fd-symdef.h \
+		module-sine-symdef.h \
+		module-combine-symdef.h \
+		module-esound-compat-spawnfd-symdef.h \
+		module-esound-compat-spawnpid-symdef.h \
+		module-match-symdef.h \
+		module-tunnel-sink-symdef.h \
+		module-tunnel-source-symdef.h \
+		module-null-sink-symdef.h \
+		module-esound-sink-symdef.h \
+		module-zeroconf-publish-symdef.h \
+		module-lirc-symdef.h \
+		module-mmkbd-evdev-symdef.h \
+		module-http-protocol-tcp-symdef.h \
+		module-http-protocol-tcp6-symdef.h \
+		module-http-protocol-unix-symdef.h
+
+if HAVE_X11
+SYMDEF_FILES += \
+		module-x11-bell-symdef.h \
+		module-x11-publish-symdef.h
+endif
+
+if !OS_IS_WIN32
+SYMDEF_FILES += \
+		module-oss-symdef.h \
+		module-oss-mmap-symdef.h
+endif
+
+if HAVE_ALSA
+SYMDEF_FILES += \
+		module-alsa-sink-symdef.h \
+		module-alsa-source-symdef.h
+endif
+
+EXTRA_DIST += $(SYMDEF_FILES)
+BUILT_SOURCES += $(SYMDEF_FILES)
+
+$(SYMDEF_FILES): module-defs.h.m4
+	$(M4) -Dfname="$@" $< > $@
+
+# Simple protocol
 
 module_simple_protocol_tcp_la_SOURCES = module-protocol-stub.c
 module_simple_protocol_tcp_la_CFLAGS = -DUSE_TCP_SOCKETS -DUSE_PROTOCOL_SIMPLE $(AM_CFLAGS)
 module_simple_protocol_tcp_la_LDFLAGS = -module -avoid-version
-module_simple_protocol_tcp_la_LIBADD = $(AM_LIBADD) libprotocol-simple.la libsocket-server.la
+module_simple_protocol_tcp_la_LIBADD = $(AM_LIBADD) libpolypcore.la libprotocol-simple.la libsocket-server.la
 
 module_simple_protocol_tcp6_la_SOURCES = module-protocol-stub.c
 module_simple_protocol_tcp6_la_CFLAGS = -DUSE_TCP6_SOCKETS -DUSE_PROTOCOL_SIMPLE $(AM_CFLAGS)
 module_simple_protocol_tcp6_la_LDFLAGS = -module -avoid-version
-module_simple_protocol_tcp6_la_LIBADD = $(AM_LIBADD) libprotocol-simple.la libsocket-server.la
+module_simple_protocol_tcp6_la_LIBADD = $(AM_LIBADD) libpolypcore.la libprotocol-simple.la libsocket-server.la
 
 module_simple_protocol_unix_la_SOURCES = module-protocol-stub.c
 module_simple_protocol_unix_la_CFLAGS = -DUSE_UNIX_SOCKETS -DUSE_PROTOCOL_SIMPLE $(AM_CFLAGS)
 module_simple_protocol_unix_la_LDFLAGS = -module -avoid-version
-module_simple_protocol_unix_la_LIBADD = $(AM_LIBADD) libprotocol-simple.la libsocket-server.la libsocket-util.la
+module_simple_protocol_unix_la_LIBADD = $(AM_LIBADD) libpolypcore.la libprotocol-simple.la libsocket-server.la libsocket-util.la
+
+# CLI protocol
+
+module_cli_la_SOURCES = module-cli.c
+module_cli_la_LDFLAGS = -module -avoid-version
+module_cli_la_LIBADD = $(AM_LIBADD) libcli.la libiochannel.la libpolypcore.la
 
 module_cli_protocol_tcp_la_SOURCES = module-protocol-stub.c
 module_cli_protocol_tcp_la_CFLAGS = -DUSE_TCP_SOCKETS -DUSE_PROTOCOL_CLI $(AM_CFLAGS)
 module_cli_protocol_tcp_la_LDFLAGS = -module -avoid-version
-module_cli_protocol_tcp_la_LIBADD = $(AM_LIBADD) libprotocol-cli.la libsocket-server.la
+module_cli_protocol_tcp_la_LIBADD = $(AM_LIBADD) libpolypcore.la libprotocol-cli.la libsocket-server.la
 
 module_cli_protocol_tcp6_la_SOURCES = module-protocol-stub.c
 module_cli_protocol_tcp6_la_CFLAGS = -DUSE_TCP6_SOCKETS -DUSE_PROTOCOL_CLI $(AM_CFLAGS)
 module_cli_protocol_tcp6_la_LDFLAGS = -module -avoid-version
-module_cli_protocol_tcp6_la_LIBADD = $(AM_LIBADD) libprotocol-cli.la libsocket-server.la
+module_cli_protocol_tcp6_la_LIBADD = $(AM_LIBADD) libpolypcore.la libprotocol-cli.la libsocket-server.la
 
 module_cli_protocol_unix_la_SOURCES = module-protocol-stub.c
 module_cli_protocol_unix_la_CFLAGS = -DUSE_UNIX_SOCKETS -DUSE_PROTOCOL_CLI $(AM_CFLAGS)
 module_cli_protocol_unix_la_LDFLAGS = -module -avoid-version
-module_cli_protocol_unix_la_LIBADD = $(AM_LIBADD) libprotocol-cli.la libsocket-server.la libsocket-util.la
+module_cli_protocol_unix_la_LIBADD = $(AM_LIBADD) libpolypcore.la libprotocol-cli.la libsocket-server.la libsocket-util.la
+
+# HTTP protocol
 
 module_http_protocol_tcp_la_SOURCES = module-protocol-stub.c
 module_http_protocol_tcp_la_CFLAGS = -DUSE_TCP_SOCKETS -DUSE_PROTOCOL_HTTP $(AM_CFLAGS)
 module_http_protocol_tcp_la_LDFLAGS = -module -avoid-version
-module_http_protocol_tcp_la_LIBADD = $(AM_LIBADD) libprotocol-http.la libsocket-server.la
+module_http_protocol_tcp_la_LIBADD = $(AM_LIBADD) libpolypcore.la libprotocol-http.la libsocket-server.la
 
 module_http_protocol_tcp6_la_SOURCES = module-protocol-stub.c
 module_http_protocol_tcp6_la_CFLAGS = -DUSE_TCP6_SOCKETS -DUSE_PROTOCOL_HTTP $(AM_CFLAGS)
 module_http_protocol_tcp6_la_LDFLAGS = -module -avoid-version
-module_http_protocol_tcp6_la_LIBADD = $(AM_LIBADD) libprotocol-http.la libsocket-server.la
+module_http_protocol_tcp6_la_LIBADD = $(AM_LIBADD) libpolypcore.la libprotocol-http.la libsocket-server.la
 
 module_http_protocol_unix_la_SOURCES = module-protocol-stub.c
 module_http_protocol_unix_la_CFLAGS = -DUSE_UNIX_SOCKETS -DUSE_PROTOCOL_HTTP $(AM_CFLAGS)
 module_http_protocol_unix_la_LDFLAGS = -module -avoid-version
-module_http_protocol_unix_la_LIBADD = $(AM_LIBADD) libprotocol-http.la libsocket-server.la libsocket-util.la
+module_http_protocol_unix_la_LIBADD = $(AM_LIBADD) libpolypcore.la libprotocol-http.la libsocket-server.la libsocket-util.la
+
+# Native protocol
 
 module_native_protocol_tcp_la_SOURCES = module-protocol-stub.c
 module_native_protocol_tcp_la_CFLAGS = -DUSE_TCP_SOCKETS -DUSE_PROTOCOL_NATIVE $(AM_CFLAGS)
 module_native_protocol_tcp_la_LDFLAGS = -module -avoid-version
-module_native_protocol_tcp_la_LIBADD = $(AM_LIBADD) libprotocol-native.la libsocket-server.la
+module_native_protocol_tcp_la_LIBADD = $(AM_LIBADD) libpolypcore.la libprotocol-native.la libsocket-server.la
 
 module_native_protocol_tcp6_la_SOURCES = module-protocol-stub.c
 module_native_protocol_tcp6_la_CFLAGS = -DUSE_TCP6_SOCKETS -DUSE_PROTOCOL_NATIVE $(AM_CFLAGS)
 module_native_protocol_tcp6_la_LDFLAGS = -module -avoid-version
-module_native_protocol_tcp6_la_LIBADD = $(AM_LIBADD) libprotocol-native.la libsocket-server.la
+module_native_protocol_tcp6_la_LIBADD = $(AM_LIBADD) libpolypcore.la libprotocol-native.la libsocket-server.la
 
 module_native_protocol_unix_la_SOURCES = module-protocol-stub.c
 module_native_protocol_unix_la_CFLAGS = -DUSE_UNIX_SOCKETS -DUSE_PROTOCOL_NATIVE $(AM_CFLAGS)
 module_native_protocol_unix_la_LDFLAGS = -module -avoid-version
-module_native_protocol_unix_la_LIBADD = $(AM_LIBADD) libprotocol-native.la libsocket-server.la libsocket-util.la
+module_native_protocol_unix_la_LIBADD = $(AM_LIBADD) libpolypcore.la libprotocol-native.la libsocket-server.la libsocket-util.la
 
 module_native_protocol_fd_la_SOURCES = module-native-protocol-fd.c
 module_native_protocol_fd_la_CFLAGS = $(AM_CFLAGS)
 module_native_protocol_fd_la_LDFLAGS = -module -avoid-version
-module_native_protocol_fd_la_LIBADD = $(AM_LIBADD) libprotocol-native.la libsocket-server.la libsocket-util.la
+module_native_protocol_fd_la_LIBADD = $(AM_LIBADD) libpolypcore.la libprotocol-native.la libsocket-server.la libsocket-util.la libiochannel.la
+
+# EsounD protocol
 
 module_esound_protocol_tcp_la_SOURCES = module-protocol-stub.c
 module_esound_protocol_tcp_la_CFLAGS = -DUSE_TCP_SOCKETS -DUSE_PROTOCOL_ESOUND $(AM_CFLAGS)
 module_esound_protocol_tcp_la_LDFLAGS = -module -avoid-version
-module_esound_protocol_tcp_la_LIBADD = $(AM_LIBADD) libprotocol-esound.la libsocket-server.la
+module_esound_protocol_tcp_la_LIBADD = $(AM_LIBADD) libpolypcore.la libprotocol-esound.la libsocket-server.la
 
 module_esound_protocol_tcp6_la_SOURCES = module-protocol-stub.c
 module_esound_protocol_tcp6_la_CFLAGS = -DUSE_TCP6_SOCKETS -DUSE_PROTOCOL_ESOUND $(AM_CFLAGS)
 module_esound_protocol_tcp6_la_LDFLAGS = -module -avoid-version
-module_esound_protocol_tcp6_la_LIBADD = $(AM_LIBADD) libprotocol-esound.la libsocket-server.la
+module_esound_protocol_tcp6_la_LIBADD = $(AM_LIBADD) libpolypcore.la libprotocol-esound.la libsocket-server.la
 
 module_esound_protocol_unix_la_SOURCES = module-protocol-stub.c
 module_esound_protocol_unix_la_CFLAGS = -DUSE_UNIX_SOCKETS -DUSE_PROTOCOL_ESOUND $(AM_CFLAGS)
 module_esound_protocol_unix_la_LDFLAGS = -module -avoid-version
-module_esound_protocol_unix_la_LIBADD = $(AM_LIBADD) libprotocol-esound.la libsocket-server.la libsocket-util.la
+module_esound_protocol_unix_la_LIBADD = $(AM_LIBADD) libpolypcore.la libprotocol-esound.la libsocket-server.la libsocket-util.la
+
+module_esound_compat_spawnfd_la_SOURCES = module-esound-compat-spawnfd.c
+module_esound_compat_spawnfd_la_LDFLAGS = -module -avoid-version
+module_esound_compat_spawnfd_la_LIBADD = $(AM_LIBADD) libpolypcore.la
+
+module_esound_compat_spawnpid_la_SOURCES = module-esound-compat-spawnpid.c
+module_esound_compat_spawnpid_la_LDFLAGS = -module -avoid-version
+module_esound_compat_spawnpid_la_LIBADD = $(AM_LIBADD) libpolypcore.la
+
+module_esound_sink_la_SOURCES = module-esound-sink.c
+module_esound_sink_la_LDFLAGS = -module -avoid-version
+module_esound_sink_la_LIBADD = $(AM_LIBADD) libpolypcore.la libiochannel.la libsocket-client.la libauthkey.la
+
+# Pipes
 
 module_pipe_sink_la_SOURCES = module-pipe-sink.c
 module_pipe_sink_la_LDFLAGS = -module -avoid-version
-module_pipe_sink_la_LIBADD = $(AM_LIBADD) libiochannel.la
+module_pipe_sink_la_LIBADD = $(AM_LIBADD) libpolypcore.la libiochannel.la
 
 module_pipe_source_la_SOURCES = module-pipe-source.c
 module_pipe_source_la_LDFLAGS = -module -avoid-version
-module_pipe_source_la_LIBADD = $(AM_LIBADD) libiochannel.la
+module_pipe_source_la_LIBADD = $(AM_LIBADD) libpolypcore.la libiochannel.la
 
-module_oss_la_SOURCES = module-oss.c
-module_oss_la_LDFLAGS = -module -avoid-version
-module_oss_la_LIBADD = $(AM_LIBADD) libiochannel.la liboss-util.la
-
-module_oss_mmap_la_SOURCES = module-oss-mmap.c
-module_oss_mmap_la_LDFLAGS = -module -avoid-version
-module_oss_mmap_la_LIBADD = $(AM_LIBADD) liboss-util.la
-
-module_cli_la_SOURCES = module-cli.c
-module_cli_la_LDFLAGS = -module -avoid-version
-module_cli_la_LIBADD = $(AM_LIBADD) libcli.la libiochannel.la
+# Fake sources/sinks
 
 module_sine_la_SOURCES = module-sine.c
 module_sine_la_LDFLAGS = -module -avoid-version
-module_sine_la_LIBADD = $(AM_LIBADD)
-
-module_combine_la_SOURCES = module-combine.c
-module_combine_la_LDFLAGS = -module -avoid-version
-module_combine_la_LIBADD = $(AM_LIBADD)
+module_sine_la_LIBADD = $(AM_LIBADD) libpolypcore.la
 
 module_null_sink_la_SOURCES = module-null-sink.c
 module_null_sink_la_LDFLAGS = -module -avoid-version
-module_null_sink_la_LIBADD = $(AM_LIBADD)
+module_null_sink_la_LIBADD = $(AM_LIBADD) libpolypcore.la
+
+# Couplings
+
+module_combine_la_SOURCES = module-combine.c
+module_combine_la_LDFLAGS = -module -avoid-version
+module_combine_la_LIBADD = $(AM_LIBADD) libpolypcore.la
 
 module_match_la_SOURCES = module-match.c
 module_match_la_LDFLAGS = -module -avoid-version
-module_match_la_LIBADD = $(AM_LIBADD)
+module_match_la_LIBADD = $(AM_LIBADD) libpolypcore.la
 
 module_tunnel_sink_la_SOURCES = module-tunnel.c
 module_tunnel_sink_la_CFLAGS = -DTUNNEL_SINK=1 $(AM_CFLAGS)
 module_tunnel_sink_la_LDFLAGS = -module -avoid-version
-module_tunnel_sink_la_LIBADD = $(AM_LIBADD) libsocket-client.la libpstream.la libpstream-util.la libpdispatch.la libtagstruct.la libauthkey.la libauthkey-prop.la libsocket-util.la libiochannel.la
+module_tunnel_sink_la_LIBADD = $(AM_LIBADD) libpolypcore.la libsocket-client.la libpstream.la libpstream-util.la libpdispatch.la libtagstruct.la libauthkey.la libauthkey-prop.la libsocket-util.la libiochannel.la
 
 module_tunnel_source_la_SOURCES = module-tunnel.c
 module_tunnel_source_la_LDFLAGS = -module -avoid-version
-module_tunnel_source_la_LIBADD = $(AM_LIBADD) libsocket-client.la libpstream.la libpstream-util.la libpdispatch.la libtagstruct.la libauthkey.la libauthkey-prop.la libsocket-util.la libiochannel.la
-
-module_esound_compat_spawnfd_la_SOURCES = module-esound-compat-spawnfd.c
-module_esound_compat_spawnfd_la_LDFLAGS = -module -avoid-version
-module_esound_compat_spawnfd_la_LIBADD = $(AM_LIBADD)
-
-module_esound_compat_spawnpid_la_SOURCES = module-esound-compat-spawnpid.c
-module_esound_compat_spawnpid_la_LDFLAGS = -module -avoid-version
-module_esound_compat_spawnpid_la_LIBADD = $(AM_LIBADD)
-
-module_esound_sink_la_SOURCES = module-esound-sink.c
-module_esound_sink_la_LDFLAGS = -module -avoid-version
-module_esound_sink_la_LIBADD = $(AM_LIBADD) libsocket-client.la libauthkey.la
-
-libpolyp_ at PA_MAJORMINOR@_la_SOURCES = polyplib.h \
-		polyplib-def.h \
-		tagstruct.c tagstruct.h \
-		iochannel.c iochannel.h \
-		pstream.c pstream.h \
-		pstream-util.c pstream-util.h \
-		pdispatch.c pdispatch.h \
-		mainloop-api.c mainloop-api.h \
-		idxset.c idxset.h \
-		util.c util.h \
-		memblock.c memblock.h \
-		socket-client.c socket-client.h \
-		parseaddr.c parseaddr.h \
-		packet.c packet.h \
-		queue.c queue.h \
-		dynarray.c dynarray.h \
-		memchunk.c memchunk.h \
-		authkey.c authkey.h \
-		socket-util.c socket-util.h \
-		native-common.h \
-		sample.c sample.h \
-		xmalloc.c xmalloc.h \
-		polyplib-operation.c polyplib-operation.h \
-		polyplib-context.c polyplib-context.h \
-		polyplib-stream.c polyplib-stream.h \
-		polyplib-introspect.c polyplib-introspect.h \
-		polyplib-scache.c polyplib-scache.h \
-		polyplib-subscribe.c polyplib-subscribe.h \
-		polyplib-internal.h \
-		cdecl.h \
-		llist.h \
-		log.c log.h \
-		gcc-printf.h \
-		client-conf.c client-conf.h \
-		conf-parser.c conf-parser.h \
-		strlist.c strlist.h \
-		strbuf.c strbuf.h \
-		mcalign.c mcalign.h \
-		typeid.c typeid.h \
-		random.c random.h
-
-libpolyp_ at PA_MAJORMINOR@_la_CFLAGS = $(AM_CFLAGS)
-libpolyp_ at PA_MAJORMINOR@_la_LDFLAGS = -version-info 0:0:0
-libpolyp_ at PA_MAJORMINOR@_la_LIBADD = $(AM_LIBADD)
-
-libpolyp_mainloop_ at PA_MAJORMINOR@_la_SOURCES = mainloop-api.h mainloop-api.c \
-		mainloop.c mainloop.h \
-		mainloop-signal.c mainloop-signal.h
-libpolyp_mainloop_ at PA_MAJORMINOR@_la_CFLAGS = $(AM_CFLAGS)
-libpolyp_mainloop_ at PA_MAJORMINOR@_la_LIBADD = $(AM_LIBADD) libpolyp- at PA_MAJORMINOR@.la
-libpolyp_mainloop_ at PA_MAJORMINOR@_la_LDFLAGS = -version-info 0:0:0
-
-libpolyp_error_ at PA_MAJORMINOR@_la_SOURCES = polyplib-error.c polyplib-error.h
-libpolyp_error_ at PA_MAJORMINOR@_la_CFLAGS = $(AM_CFLAGS)
-libpolyp_error_ at PA_MAJORMINOR@_la_LIBADD = $(AM_LIBADD) libpolyp- at PA_MAJORMINOR@.la
-libpolyp_error_ at PA_MAJORMINOR@_la_LDFLAGS = -version-info 0:0:0
-
-libpolyp_simple_ at PA_MAJORMINOR@_la_SOURCES = polyplib-simple.c polyplib-simple.h 
-libpolyp_simple_ at PA_MAJORMINOR@_la_CFLAGS = $(AM_CFLAGS)
-libpolyp_simple_ at PA_MAJORMINOR@_la_LIBADD = $(AM_LIBADD) libpolyp- at PA_MAJORMINOR@.la libpolyp-mainloop- at PA_MAJORMINOR@.la
-libpolyp_simple_ at PA_MAJORMINOR@_la_LDFLAGS = -version-info 0:0:0
-
-pacat_SOURCES = pacat.c
-pacat_LDADD = $(AM_LDADD) libpolyp- at PA_MAJORMINOR@.la libpolyp-error- at PA_MAJORMINOR@.la libpolyp-mainloop- at PA_MAJORMINOR@.la
-pacat_CFLAGS = $(AM_CFLAGS) 
-
-paplay_SOURCES = paplay.c
-paplay_LDADD = $(AM_LDADD) libpolyp- at PA_MAJORMINOR@.la libpolyp-error- at PA_MAJORMINOR@.la libpolyp-mainloop- at PA_MAJORMINOR@.la $(LIBSNDFILE_LIBS)
-paplay_CFLAGS = $(AM_CFLAGS) $(LIBSNDFILE_CFLAGS)
+module_tunnel_source_la_LIBADD = $(AM_LIBADD) libpolypcore.la libsocket-client.la libpstream.la libpstream-util.la libpdispatch.la libtagstruct.la libauthkey.la libauthkey-prop.la libsocket-util.la libiochannel.la
 
-pactl_SOURCES = pactl.c
-pactl_LDADD = $(AM_LDADD) libpolyp- at PA_MAJORMINOR@.la libpolyp-error- at PA_MAJORMINOR@.la libpolyp-mainloop- at PA_MAJORMINOR@.la $(LIBSNDFILE_LIBS)
-pactl_CFLAGS = $(AM_CFLAGS) $(LIBSNDFILE_CFLAGS)
-
-pacat_simple_SOURCES = pacat-simple.c
-pacat_simple_LDADD = $(AM_LDADD) libpolyp- at PA_MAJORMINOR@.la libpolyp-simple- at PA_MAJORMINOR@.la libpolyp-error- at PA_MAJORMINOR@.la libpolyp-mainloop- at PA_MAJORMINOR@.la
-pacat_simple_CFLAGS = $(AM_CFLAGS)
-
-parec_simple_SOURCES = parec-simple.c
-parec_simple_LDADD = $(AM_LDADD) libpolyp- at PA_MAJORMINOR@.la libpolyp-simple- at PA_MAJORMINOR@.la libpolyp-error- at PA_MAJORMINOR@.la libpolyp-mainloop- at PA_MAJORMINOR@.la
-parec_simple_CFLAGS = $(AM_CFLAGS)
-
-mainloop_test_SOURCES = mainloop-test.c
-mainloop_test_CFLAGS = $(AM_CFLAGS)
-mainloop_test_LDADD = $(AM_LDADD) libpolyp-mainloop- at PA_MAJORMINOR@.la libpolyp- at PA_MAJORMINOR@.la
-
-voltest_SOURCES = voltest.c sample.c
-voltest_CFLAGS = $(AM_CFLAGS)
-voltest_LDADD = $(AM_LDADD)
-
-strlist_test_SOURCES = strlist-test.c strlist.c strlist.h strbuf.c strbuf.h util.c util.h xmalloc.c xmalloc.h log.c log.h
-strlist_test_CFLAGS = $(AM_CFLAGS)
-strlist_test_LDADD = $(AM_LDADD)
-
-mcalign_test_SOURCES = mcalign-test.c util.c util.h xmalloc.c xmalloc.h log.c log.h mcalign.c mcalign.h memchunk.c memchunk.h memblock.c memblock.h
-mcalign_test_CFLAGS = $(AM_CFLAGS)
-mcalign_test_LDADD = $(AM_LDADD)
-
-pacmd_SOURCES = pacmd.c util.c util.h xmalloc.c xmalloc.h log.c log.h pid.c pid.h
-pacmd_CFLAGS = $(AM_CFLAGS)
-pacmd_LDADD = $(AM_LDADD)
-
-cpulimit_test_SOURCES = cpulimit-test.c cpulimit.c util.c log.c cpulimit.h util.h log.h
-cpulimit_test_CFLAGS = $(AM_CFLAGS)
-cpulimit_test_LDADD = $(AM_LDADD) libpolyp-mainloop- at PA_MAJORMINOR@.la
-
-cpulimit_test2_SOURCES = cpulimit-test.c cpulimit.c util.c log.c cpulimit.h util.h log.h
-cpulimit_test2_CFLAGS = $(AM_CFLAGS) -DTEST2
-cpulimit_test2_LDADD = $(AM_LDADD) libpolyp-mainloop- at PA_MAJORMINOR@.la
-
-### X11 stuff
-
-if HAVE_X11
-modlib_LTLIBRARIES+= \
-		libx11wrap.la \
-		libx11prop.la \
-		module-x11-bell.la \
-		module-x11-publish.la
-SYMDEF_FILES += \
-		module-x11-bell-symdef.h \
-		module-x11-publish-symdef.h
-
-libx11wrap_la_SOURCES = x11wrap.c x11wrap.h
-libx11wrap_la_LDFLAGS = -avoid-version
-libx11wrap_la_CFLAGS = $(AM_CFLAGS) $(X_CFLAGS)
-libx11wrap_la_LIBADD = $(AM_LIBADD) $(X_PRE_LIBS) -lX11 $(X_LIBS) $(X_EXTRA_LIBS)
-
-libx11prop_la_SOURCES = x11prop.c x11prop.h
-libx11prop_la_LDFLAGS = -avoid-version
-libx11prop_la_CFLAGS = $(AM_CFLAGS) $(X_CFLAGS)
-libx11prop_la_LIBADD = $(AM_LIBADD) $(X_PRE_LIBS) -lX11 $(X_LIBS) $(X_EXTRA_LIBS)
+# X11
 
 module_x11_bell_la_SOURCES = module-x11-bell.c
 module_x11_bell_la_CFLAGS = $(AM_CFLAGS) $(X_CFLAGS)
@@ -598,41 +905,17 @@ module_x11_publish_la_CFLAGS = $(AM_CFLAGS) $(X_CFLAGS)
 module_x11_publish_la_LDFLAGS = -module -avoid-version
 module_x11_publish_la_LIBADD = $(AM_LIBADD) $(X_PRE_LIBS) -lX11 $(X_LIBS) $(X_EXTRA_LIBS) libx11wrap.la libauthkey.la libauthkey-prop.la libx11prop.la libstrlist.la
 
-bin_PROGRAMS+= \
-		pax11publish
+# OSS
 
-pax11publish_SOURCES = pax11publish.c util.c util.h xmalloc.c xmalloc.h log.c log.h authkey.c authkey.h client-conf.c client-conf.h conf-parser.c conf-parser.h x11prop.c x11prop.h random.c random.h
-pax11publish_CFLAGS = $(AM_CFLAGS) $(X_CFLAGS)
-pax11publish_LDADD = $(AM_LDADD) $(X_PRE_LIBS) -lX11 $(X_LIBS) $(X_EXTRA_LIBS)
-
-libpolyp_ at PA_MAJORMINOR@_la_CFLAGS += $(X_CFLAGS)
-libpolyp_ at PA_MAJORMINOR@_la_LDFLAGS += $(X_PRE_LIBS) -lX11 $(X_LIBS) $(X_EXTRA_LIBS)
-libpolyp_ at PA_MAJORMINOR@_la_SOURCES += x11prop.c x11prop.h client-conf-x11.c client-conf-x11.h
-
-endif
-
-### libasyncns stuff
-
-if HAVE_LIBASYNCNS
-libpolyp_ at PA_MAJORMINOR@_la_CFLAGS += $(LIBASYNCNS_CFLAGS)
-libpolyp_ at PA_MAJORMINOR@_la_LIBADD += $(LIBASYNCNS_LIBS)
-endif
-
-### ALSA modules
+module_oss_la_SOURCES = module-oss.c
+module_oss_la_LDFLAGS = -module -avoid-version
+module_oss_la_LIBADD = $(AM_LIBADD) libiochannel.la liboss-util.la
 
-if HAVE_ALSA
-modlib_LTLIBRARIES+= \
-		libalsa-util.la \
-		module-alsa-sink.la \
-		module-alsa-source.la
-SYMDEF_FILES += \
-		module-alsa-sink-symdef.h \
-		module-alsa-source-symdef.h
+module_oss_mmap_la_SOURCES = module-oss-mmap.c
+module_oss_mmap_la_LDFLAGS = -module -avoid-version
+module_oss_mmap_la_LIBADD = $(AM_LIBADD) liboss-util.la
 
-libalsa_util_la_SOURCES = alsa-util.c alsa-util.h
-libalsa_util_la_LDFLAGS = -avoid-version
-libalsa_util_la_LIBADD = $(AM_LIBADD) $(ASOUNDLIB_LIBS)
-libalsa_util_la_CFLAGS = $(AM_CFLAGS) $(ASOUNDLIB_CFLAGS)
+# ALSA
 
 module_alsa_sink_la_SOURCES = module-alsa-sink.c
 module_alsa_sink_la_LDFLAGS = -module -avoid-version
@@ -643,184 +926,31 @@ module_alsa_source_la_SOURCES = module-alsa-source.c
 module_alsa_source_la_LDFLAGS = -module -avoid-version
 module_alsa_source_la_LIBADD = $(AM_LIBADD) $(ASOUNDLIB_LIBS) libalsa-util.la
 module_alsa_source_la_CFLAGS = $(AM_CFLAGS) $(ASOUNDLIB_CFLAGS)
-endif
 
-### HOWL modules
-if HAVE_HOWL
-modlib_LTLIBRARIES+= \
-		libhowl-wrap.la \
-		module-zeroconf-publish.la
-
-libhowl_wrap_la_SOURCES = howl-wrap.c howl-wrap.h
-libhowl_wrap_la_LDFLAGS = -avoid-version
-libhowl_wrap_la_LIBADD = $(AM_LIBADD) $(HOWL_LIBS)
-libhowl_wrap_la_CFLAGS = $(AM_CFLAGS) $(HOWL_CFLAGS)
+# HOWL
 
 module_zeroconf_publish_la_SOURCES = module-zeroconf-publish.c
 module_zeroconf_publish_la_LDFLAGS = -module -avoid-version
 module_zeroconf_publish_la_LIBADD = $(AM_LIBADD) $(HOWL_LIBS) libhowl-wrap.la
 module_zeroconf_publish_la_CFLAGS = $(AM_CFLAGS) $(HOWL_CFLAGS)
 
-lib_LTLIBRARIES+= \
-		libpolyp-browse- at PA_MAJORMINOR@.la
-
-libpolyp_browse_ at PA_MAJORMINOR@_la_SOURCES = polyplib-browser.c polyplib-browser.h 
-libpolyp_browse_ at PA_MAJORMINOR@_la_CFLAGS = $(AM_CFLAGS) $(HOWL_CFLAGS)
-libpolyp_browse_ at PA_MAJORMINOR@_la_LIBADD = $(AM_LIBADD) libpolyp- at PA_MAJORMINOR@.la $(HOWL_LIBS)
-libpolyp_browse_ at PA_MAJORMINOR@_la_LDFLAGS = -version-info 0:0:0 
-
-bin_PROGRAMS += \
-		pabrowse
-
-pabrowse_SOURCES = pabrowse.c
-pabrowse_LDADD = $(AM_LDADD) libpolyp- at PA_MAJORMINOR@.la libpolyp-error- at PA_MAJORMINOR@.la libpolyp-mainloop- at PA_MAJORMINOR@.la libpolyp-browse- at PA_MAJORMINOR@.la
-pabrowse_CFLAGS = $(AM_CFLAGS)
-
-polypinclude_HEADERS+=polyplib-browser.h
-
-endif
-
-### GLIB 2.0 support
-
-if HAVE_GLIB20
-lib_LTLIBRARIES+= \
-		libpolyp-mainloop-glib- at PA_MAJORMINOR@.la
-
-noinst_PROGRAMS+= \
-		mainloop-test-glib
-
-libpolyp_mainloop_glib_ at PA_MAJORMINOR@_la_SOURCES = glib-mainloop.h glib-mainloop.c
-libpolyp_mainloop_glib_ at PA_MAJORMINOR@_la_CFLAGS = $(AM_CFLAGS) $(GLIB20_CFLAGS)
-libpolyp_mainloop_glib_ at PA_MAJORMINOR@_la_LIBADD = $(AM_LIBADD) libpolyp-mainloop- at PA_MAJORMINOR@.la $(GLIB20_LIBS)
-libpolyp_mainloop_glib_ at PA_MAJORMINOR@_la_LDFLAGS = -version-info 0:0:0
-
-mainloop_test_glib_SOURCES = $(mainloop_test_SOURCES)
-mainloop_test_glib_CFLAGS = $(mainloop_test_CFLAGS) $(GLIB20_CFLAGS) -DGLIB_MAIN_LOOP
-mainloop_test_glib_LDADD = $(mainloop_test_LDADD) $(GLIB20_LIBS) libpolyp-mainloop-glib- at PA_MAJORMINOR@.la
-endif
-
-### GLIB 1.2 support
-
-if HAVE_GLIB12
-
-lib_LTLIBRARIES+= \
-		libpolyp-mainloop-glib12- at PA_MAJORMINOR@.la
-
-noinst_PROGRAMS+= \
-		mainloop-test-glib12
-
-libpolyp_mainloop_glib12_ at PA_MAJORMINOR@_la_SOURCES = glib-mainloop.h glib12-mainloop.c
-libpolyp_mainloop_glib12_ at PA_MAJORMINOR@_la_CFLAGS = $(AM_CFLAGS) $(GLIB12_CFLAGS)
-libpolyp_mainloop_glib12_ at PA_MAJORMINOR@_la_LIBADD = $(AM_LIBADD) libpolyp-mainloop- at PA_MAJORMINOR@.la $(GLIB12_LIBS)
-libpolyp_mainloop_glib12_ at PA_MAJORMINOR@_la_LDFLAGS = -version-info 0:0:0
-
-mainloop_test_glib12_SOURCES = $(mainloop_test_SOURCES)
-mainloop_test_glib12_CFLAGS = $(mainloop_test_CFLAGS) $(GLIB12_CFLAGS) -DGLIB_MAIN_LOOP
-mainloop_test_glib12_LDADD = $(mainloop_test_LDADD) $(GLIB12_LIBS) libpolyp-mainloop-glib12- at PA_MAJORMINOR@.la
-
-endif
-
-### LIRC support
-
-if HAVE_LIRC
-
-modlib_LTLIBRARIES+= \
-		module-lirc.la
+# LIRC
 
 module_lirc_la_SOURCES = module-lirc.c
 module_lirc_la_LDFLAGS = -module -avoid-version
 module_lirc_la_LIBADD = $(AM_LIBADD) $(LIRC_LIBS) 
 module_lirc_la_CFLAGS = $(AM_CFLAGS) $(LIRC_CFLAGS)
 
-endif
-
-
-### Linux evdev
-
-if HAVE_EVDEV
-
-modlib_LTLIBRARIES+= \
-		module-mmkbd-evdev.la
+# Linux evdev
 
 module_mmkbd_evdev_la_SOURCES = module-mmkbd-evdev.c
 module_mmkbd_evdev_la_LDFLAGS = -module -avoid-version
 module_mmkbd_evdev_la_LIBADD = $(AM_LIBADD)
 module_mmkbd_evdev_la_CFLAGS = $(AM_CFLAGS)
 
-endif
-
-### libpolypcore (needs to be updated)
-
-if BUILD_LIBPOLYPCORE
-
-polypinclude_HEADERS+=cli-command.h\
-		client.h \
-		core.h \
-		dynarray.h \
-		endianmacros.h \
-		hashmap.h \
-		idxset.h \
-		iochannel.h \
-		memblock.h \
-		memblockq.h \
-		memchunk.h \
-		modargs.h \
-		module.h \
-		namereg.h \
-		queue.h \
-		resampler.h \
-		sample-util.h \
-		sink.h \
-		sink-input.h \
-		sioman.h \
-		socket-server.h \
-		socket-client.h \
-		socket-util.h \
-		source.h \
-		source-output.h \
-		strbuf.h \
-		tokenizer.h \
-		tagstruct.h \
-		util.h
-
-lib_LTLIBRARIES+= libpolypcore.la
-
-libpolypcore_la_SOURCES = idxset.c idxset.h \
-		queue.c queue.h \
-		strbuf.c strbuf.h \
-		mainloop.c mainloop.h \
-		memblock.c memblock.h \
-		sample.c sample.h \
-		sample-util.c sample-util.h \
-		memblockq.c memblockq.h \
-		client.c client.h \
-		core.c core.h \
-		source-output.c source-output.h \
-		sink-input.c sink-input.h \
-		source.c source.h \
-		sink.c sink.h \
-		module.c module.h \
-		mainloop-signal.c mainloop-signal.h \
-		mainloop-api.c mainloop-api.h \
-		util.c util.h \
-		hashmap.c hashmap.h \
-		namereg.c namereg.h \
-		sconv.c sconv.h \
-		resampler.c resampler.h \
-		endianmacros.h \
-		memchunk.c memchunk.h \
-		sconv-s16le.c sconv-s16le.h \
-		sconv-s16be.c sconv-s16be.h \
-		sioman.c sioman.h \
-		modargs.c modargs.h \
-		cli-command.c cli-command.h \
-		cli-text.c cli-text.h \
-		tokenizer.c tokenizer.h \
-		dynarray.c dynarray.h
-
-endif
-
-### Some minor stuff
+###################################
+#        Some minor stuff         #
+###################################
 
 suid: polypaudio
 	chown root $<
@@ -845,6 +975,3 @@ install-exec-hook:
 	chown root $(DESTDIR)$(bindir)/polypaudio ; true
 	chmod u+s $(DESTDIR)$(bindir)/polypaudio
 	ln -sf pacat $(DESTDIR)$(bindir)/parec
-
-$(SYMDEF_FILES): module-defs.h.m4
-	$(M4) -Dfname="$@" $< > $@

commit e8c71ed4c63a7ef123c122161b6a7cc3eafe7c85
Author: Pierre Ossman <ossman at cendio.se>
Date:   Thu Jan 5 13:14:21 2006 +0000

    Since README is generated conditionally we must make sure there are no
    dependencies on it when it's not built.
    
    
    git-svn-id: file:///home/lennart/svn/public/pulseaudio/branches/ossman@363 fefdeb5f-60dc-0310-8127-8f9354f1896f

diff --git a/Makefile.am b/Makefile.am
index a6a012a..2cf93c7 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -17,11 +17,11 @@
 # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
 # USA.
 
-EXTRA_DIST = bootstrap.sh README LICENSE doxygen/Makefile.am doxygen/Makefile.in doxygen/doxygen.conf.in libtool.m4 ltdl.m4
+EXTRA_DIST = bootstrap.sh LICENSE doxygen/Makefile.am doxygen/Makefile.in doxygen/doxygen.conf.in libtool.m4 ltdl.m4
 SUBDIRS=libltdl polyp doc
 
-MAINTAINERCLEANFILES=README
-noinst_DATA = README
+MAINTAINERCLEANFILES =
+noinst_DATA =
 
 pkgconfigdir = $(libdir)/pkgconfig
 pkgconfig_DATA = polyplib.pc polyplib-simple.pc polyplib-error.pc polyplib-mainloop.pc polyplib-browse.pc
@@ -36,10 +36,16 @@ pkgconfig_DATA += \
 	polyplib-glib12-mainloop.pc
 endif
 
+if USE_LYNX
+EXTRA_DIST += README
+MAINTAINERCLEANFILES += README
+noinst_DATA += README
+
 README:
 	rm -f README
 	$(MAKE) -C doc README
 	cd $(srcdir) && ln -s doc/README README
+endif
 
 homepage: all dist doxygen
 	test -d $$HOME/homepage/private
diff --git a/doc/Makefile.am b/doc/Makefile.am
index fff0655..c68c00f 100644
--- a/doc/Makefile.am
+++ b/doc/Makefile.am
@@ -16,7 +16,7 @@
 # along with polypaudio; if not, write to the Free Software Foundation,
 # Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
 
-noinst_DATA = README.html cli.html modules.html daemon.html README
+noinst_DATA = README.html cli.html modules.html daemon.html
 EXTRA_DIST = $(noinst_DATA) style.css README.html.in cli.html.in modules.html.in daemon.html.in todo FAQ.html.in
 
 MAINTAINERCLEANFILES = README.html cli.html modules.html daemon.html FAQ.html
@@ -26,6 +26,7 @@ if USE_LYNX
 README: README.html
 	lynx --dump $^ | sed 's,file://localhost/.*/doc/README.html,README,' > $@
 
+noinst_DATA += README
 CLEANFILES += README
 endif
 

commit 11a4c67a922c3af62c80500aca7f157430fdf926
Author: Pierre Ossman <ossman at cendio.se>
Date:   Thu Jan 5 13:15:38 2006 +0000

    Remove unused automake conditional.
    
    
    git-svn-id: file:///home/lennart/svn/public/pulseaudio/branches/ossman@364 fefdeb5f-60dc-0310-8127-8f9354f1896f

diff --git a/configure.ac b/configure.ac
index 362077f..0027339 100644
--- a/configure.ac
+++ b/configure.ac
@@ -283,8 +283,6 @@ AM_CONDITIONAL([HAVE_LIRC], [test "x$HAVE_LIRC" = x1])
 #            Output               #
 ###################################
 
-AM_CONDITIONAL(BUILD_LIBPOLYPCORE, false)
-
 AC_CONFIG_FILES([
 Makefile
 polyp/Makefile

commit 70710e14d8f8bbab4f1a42db4993f27cb2ca7bc5
Author: Pierre Ossman <ossman at cendio.se>
Date:   Thu Jan 5 13:20:20 2006 +0000

    Check for OSS by looking for its header. Win32 isn't the only platform
    where OSS isn't supported.
    
    
    git-svn-id: file:///home/lennart/svn/public/pulseaudio/branches/ossman@365 fefdeb5f-60dc-0310-8127-8f9354f1896f

diff --git a/configure.ac b/configure.ac
index 0027339..c851164 100644
--- a/configure.ac
+++ b/configure.ac
@@ -223,6 +223,12 @@ PKG_CHECK_MODULES(LIBSNDFILE, [ sndfile >= 1.0.10 ])
 AC_SUBST(LIBSNDFILE_CFLAGS)
 AC_SUBST(LIBSNDFILE_LIBS)
 
+#### OSS support (optional) ####
+
+AC_CHECK_HEADERS([sys/soundcard.h], [HAVE_OSS=1], [HAVE_OSS=0])
+AC_SUBST(HAVE_OSS)
+AM_CONDITIONAL([HAVE_OSS], [test "x$HAVE_OSS" = x1])
+
 #### ALSA support (optional) ####
 
 PKG_CHECK_MODULES(ASOUNDLIB, [ alsa >= 1.0.0 ], [HAVE_ALSA=1], [HAVE_ALSA=0])
diff --git a/polyp/Makefile.am b/polyp/Makefile.am
index 847be9a..2cd2a1f 100644
--- a/polyp/Makefile.am
+++ b/polyp/Makefile.am
@@ -478,7 +478,7 @@ modlib_LTLIBRARIES += \
 		libx11prop.la
 endif
 
-if !OS_IS_WIN32
+if HAVE_OSS
 modlib_LTLIBRARIES += \
 		liboss-util.la
 endif
@@ -662,7 +662,7 @@ modlib_LTLIBRARIES += \
 		module-x11-publish.la
 endif
 
-if !OS_IS_WIN32
+if HAVE_OSS
 modlib_LTLIBRARIES += \
 		module-oss.la \
 		module-oss-mmap.la

commit 687e2d7da5d55784bf0769774be7296254a08eba
Author: Pierre Ossman <ossman at cendio.se>
Date:   Thu Jan 5 16:38:09 2006 +0000

    Abstract the gettimeofday call into a utility function to ease porting.
    
    
    git-svn-id: file:///home/lennart/svn/public/pulseaudio/branches/ossman@366 fefdeb5f-60dc-0310-8127-8f9354f1896f

diff --git a/polyp/core.c b/polyp/core.c
index e2bebec..539c677 100644
--- a/polyp/core.c
+++ b/polyp/core.c
@@ -144,7 +144,7 @@ void pa_core_check_quit(struct pa_core *c) {
 
     if (!c->quit_event && c->exit_idle_time >= 0 && pa_idxset_ncontents(c->clients) == 0) {
         struct timeval tv;
-        gettimeofday(&tv, NULL);
+        pa_gettimeofday(&tv);
         tv.tv_sec+= c->exit_idle_time;
         c->quit_event = c->mainloop->time_new(c->mainloop, &tv, quit_callback, c);
     } else if (c->quit_event && pa_idxset_ncontents(c->clients) > 0) {
diff --git a/polyp/glib-mainloop.c b/polyp/glib-mainloop.c
index 809c0b0..0f96a59 100644
--- a/polyp/glib-mainloop.c
+++ b/polyp/glib-mainloop.c
@@ -241,7 +241,7 @@ static void glib_time_restart(struct pa_time_event*e, const struct timeval *tv)
     struct timeval now;
     assert(e && e->mainloop && !e->dead);
 
-    gettimeofday(&now, NULL);
+    pa_gettimeofday(&now);
     if (e->source) {
         g_source_destroy(e->source);
         g_source_unref(e->source);
diff --git a/polyp/glib12-mainloop.c b/polyp/glib12-mainloop.c
index 5f03734..c328471 100644
--- a/polyp/glib12-mainloop.c
+++ b/polyp/glib12-mainloop.c
@@ -233,7 +233,7 @@ static void glib_time_restart(struct pa_time_event*e, const struct timeval *tv)
     struct timeval now;
     assert(e && e->mainloop && !e->dead);
 
-    gettimeofday(&now, NULL);
+    pa_gettimeofday(&now);
     if (e->source != (guint) -1)
         g_source_remove(e->source);
 
diff --git a/polyp/mainloop-test.c b/polyp/mainloop-test.c
index 0d40e76..dd8f813 100644
--- a/polyp/mainloop-test.c
+++ b/polyp/mainloop-test.c
@@ -111,7 +111,7 @@ int main(int argc, char *argv[]) {
     de = a->defer_new(a, dcb, NULL);
     assert(de);
 
-    gettimeofday(&tv, NULL);
+    pa_gettimeofday(&tv);
     tv.tv_sec += 10;
     te = a->time_new(a, &tv, tcb, NULL);
 
diff --git a/polyp/mainloop.c b/polyp/mainloop.c
index f6bb414..a0d2782 100644
--- a/polyp/mainloop.c
+++ b/polyp/mainloop.c
@@ -457,7 +457,7 @@ static int calc_next_timeout(struct pa_mainloop *m) {
 
         /* Let's save a system call */
         if (!got_time) {
-            gettimeofday(&now, NULL);
+            pa_gettimeofday(&now);
             got_time = 1;
         }
 
@@ -498,7 +498,7 @@ static int dispatch_timeout(struct pa_mainloop *m) {
 
         /* Let's save a system call */
         if (!got_time) {
-            gettimeofday(&now, NULL);
+            pa_gettimeofday(&now);
             got_time = 1;
         }
         
diff --git a/polyp/module-combine.c b/polyp/module-combine.c
index ca79d7d..7283c55 100644
--- a/polyp/module-combine.c
+++ b/polyp/module-combine.c
@@ -157,7 +157,7 @@ static void time_callback(struct pa_mainloop_api*a, struct pa_time_event* e, con
 
     adjust_rates(u);
 
-    gettimeofday(&n, NULL);
+    pa_gettimeofday(&n);
     n.tv_sec += u->adjust_time;
     u->sink->core->mainloop->time_restart(e, &n);
 }
@@ -363,7 +363,7 @@ int pa__init(struct pa_core *c, struct pa_module*m) {
         pa_log_warn(__FILE__": WARNING: no slave sinks specified.\n");
 
     if (u->adjust_time > 0) {
-        gettimeofday(&tv, NULL);
+        pa_gettimeofday(&tv);
         tv.tv_sec += u->adjust_time;
         u->time_event = c->mainloop->time_new(c->mainloop, &tv, time_callback, u);
     }
diff --git a/polyp/module-null-sink.c b/polyp/module-null-sink.c
index fcac1ea..6c7a44f 100644
--- a/polyp/module-null-sink.c
+++ b/polyp/module-null-sink.c
@@ -117,7 +117,7 @@ int pa__init(struct pa_core *c, struct pa_module*m) {
     pa_sink_set_owner(u->sink, m);
     u->sink->description = pa_sprintf_malloc("NULL sink");
 
-    gettimeofday(&tv, NULL);
+    pa_gettimeofday(&tv);
     u->time_event = c->mainloop->time_new(c->mainloop, &tv, time_callback, u);
 
     u->block_size = pa_bytes_per_second(&ss) / 10;
diff --git a/polyp/module-tunnel.c b/polyp/module-tunnel.c
index 9da87b3..749aebf 100644
--- a/polyp/module-tunnel.c
+++ b/polyp/module-tunnel.c
@@ -284,7 +284,7 @@ static void stream_get_latency_callback(struct pa_pdispatch *pd, uint32_t comman
         return;
     }
 
-    gettimeofday(&now, NULL);
+    pa_gettimeofday(&now);
 
     if (pa_timeval_cmp(&local, &remote) < 0 && pa_timeval_cmp(&remote, &now)) {
         /* local and remote seem to have synchronized clocks */
@@ -324,7 +324,7 @@ static void request_latency(struct userdata *u) {
     pa_tagstruct_putu32(t, tag = u->ctag++);
     pa_tagstruct_putu32(t, u->channel);
 
-    gettimeofday(&now, NULL);
+    pa_gettimeofday(&now);
     pa_tagstruct_put_timeval(t, &now);
     pa_tagstruct_putu64(t, 0);
     
@@ -536,7 +536,7 @@ static void timeout_callback(struct pa_mainloop_api *m, struct pa_time_event*e,
 
     request_latency(u);
     
-    gettimeofday(&ntv, NULL);
+    pa_gettimeofday(&ntv);
     ntv.tv_sec += LATENCY_INTERVAL;
     m->time_restart(e, &ntv);
 }
@@ -650,7 +650,7 @@ int pa__init(struct pa_core *c, struct pa_module*m) {
     pa_source_set_owner(u->source, m);
 #endif
     
-    gettimeofday(&ntv, NULL);
+    pa_gettimeofday(&ntv);
     ntv.tv_sec += LATENCY_INTERVAL;
     u->time_event = c->mainloop->time_new(c->mainloop, &ntv, timeout_callback, u);
 
diff --git a/polyp/module.c b/polyp/module.c
index aedaae0..0a3d569 100644
--- a/polyp/module.c
+++ b/polyp/module.c
@@ -47,7 +47,7 @@ static void timeout_callback(struct pa_mainloop_api *m, struct pa_time_event*e,
 
     pa_module_unload_unused(c);
 
-    gettimeofday(&ntv, NULL);
+    pa_gettimeofday(&ntv);
     ntv.tv_sec += UNLOAD_POLL_TIME;
     m->time_restart(e, &ntv);
 }
@@ -98,7 +98,7 @@ struct pa_module* pa_module_load(struct pa_core *c, const char *name, const char
 
     if (!c->module_auto_unload_event) {
         struct timeval ntv;
-        gettimeofday(&ntv, NULL);
+        pa_gettimeofday(&ntv);
         ntv.tv_sec += UNLOAD_POLL_TIME;
         c->module_auto_unload_event = c->mainloop->time_new(c->mainloop, &ntv, timeout_callback, c);
     }
diff --git a/polyp/pdispatch.c b/polyp/pdispatch.c
index 7a9e9c6..9e80875 100644
--- a/polyp/pdispatch.c
+++ b/polyp/pdispatch.c
@@ -245,7 +245,7 @@ void pa_pdispatch_register_reply(struct pa_pdispatch *pd, uint32_t tag, int time
     r->userdata = userdata;
     r->tag = tag;
     
-    gettimeofday(&tv, NULL);
+    pa_gettimeofday(&tv);
     tv.tv_sec += timeout;
 
     r->time_event = pd->mainloop->time_new(pd->mainloop, &tv, timeout_callback, r);
diff --git a/polyp/polyplib-stream.c b/polyp/polyplib-stream.c
index 440217e..d4480f8 100644
--- a/polyp/polyplib-stream.c
+++ b/polyp/polyplib-stream.c
@@ -217,7 +217,7 @@ static void ipol_callback(struct pa_mainloop_api *m, struct pa_time_event *e, co
         s->ipol_requested = 1;
     }
     
-    gettimeofday(&tv2, NULL);
+    pa_gettimeofday(&tv2);
     pa_timeval_add(&tv2, LATENCY_IPOL_INTERVAL_USEC);
     
     m->time_restart(e, &tv2);
@@ -256,7 +256,7 @@ void pa_create_stream_callback(struct pa_pdispatch *pd, uint32_t command, uint32
         struct timeval tv;
         pa_operation_unref(pa_stream_get_latency_info(s, NULL, NULL));
 
-        gettimeofday(&tv, NULL);
+        pa_gettimeofday(&tv);
         tv.tv_usec += LATENCY_IPOL_INTERVAL_USEC; /* every 100 ms */
 
         assert(!s->ipol_event);
@@ -412,7 +412,7 @@ static void stream_get_latency_info_callback(struct pa_pdispatch *pd, uint32_t c
         pa_context_fail(o->context, PA_ERROR_PROTOCOL);
         goto finish;
     } else {
-        gettimeofday(&now, NULL);
+        pa_gettimeofday(&now);
         
         if (pa_timeval_cmp(&local, &remote) < 0 && pa_timeval_cmp(&remote, &now)) {
             /* local and remote seem to have synchronized clocks */
@@ -470,7 +470,7 @@ struct pa_operation* pa_stream_get_latency_info(struct pa_stream *s, void (*cb)(
     pa_tagstruct_putu32(t, tag = s->context->ctag++);
     pa_tagstruct_putu32(t, s->channel);
 
-    gettimeofday(&now, NULL);
+    pa_gettimeofday(&now);
     pa_tagstruct_put_timeval(t, &now);
     pa_tagstruct_putu64(t, s->counter);
     
@@ -581,7 +581,7 @@ struct pa_operation* pa_stream_cork(struct pa_stream *s, int b, void (*cb) (stru
             s->ipol_usec = pa_stream_get_interpolated_time(s);
         else if (s->corked && !b)
             /* Unpausing */
-            gettimeofday(&s->ipol_timestamp, NULL);
+            pa_gettimeofday(&s->ipol_timestamp);
     }
 
     s->corked = b;
diff --git a/polyp/protocol-esound.c b/polyp/protocol-esound.c
index d99b721..2af3cc8 100644
--- a/polyp/protocol-esound.c
+++ b/polyp/protocol-esound.c
@@ -1099,7 +1099,7 @@ static void on_connection(struct pa_socket_server*s, struct pa_iochannel *io, vo
 
     if (!c->authorized) {
         struct timeval tv;
-        gettimeofday(&tv, NULL);
+        pa_gettimeofday(&tv);
         tv.tv_sec += AUTH_TIMEOUT;
         c->auth_timeout_event = p->core->mainloop->time_new(p->core->mainloop, &tv, auth_timeout, c);
     } else
diff --git a/polyp/protocol-native.c b/polyp/protocol-native.c
index 7e1a889..90dbdaf 100644
--- a/polyp/protocol-native.c
+++ b/polyp/protocol-native.c
@@ -928,7 +928,7 @@ static void command_get_playback_latency(struct pa_pdispatch *pd, uint32_t comma
     pa_tagstruct_put_boolean(reply, pa_memblockq_is_readable(s->memblockq));
     pa_tagstruct_putu32(reply, pa_memblockq_get_length(s->memblockq));
     pa_tagstruct_put_timeval(reply, &tv);
-    gettimeofday(&now, NULL);
+    pa_gettimeofday(&now);
     pa_tagstruct_put_timeval(reply, &now);
     pa_tagstruct_putu64(reply, counter);
     pa_pstream_send_tagstruct(c->pstream, reply);
@@ -971,7 +971,7 @@ static void command_get_record_latency(struct pa_pdispatch *pd, uint32_t command
     pa_tagstruct_put_boolean(reply, 0);
     pa_tagstruct_putu32(reply, pa_memblockq_get_length(s->memblockq));
     pa_tagstruct_put_timeval(reply, &tv);
-    gettimeofday(&now, NULL);
+    pa_gettimeofday(&now);
     pa_tagstruct_put_timeval(reply, &now);
     pa_tagstruct_putu64(reply, counter);
     pa_pstream_send_tagstruct(c->pstream, reply);
@@ -2024,7 +2024,7 @@ static void on_connection(struct pa_socket_server*s, struct pa_iochannel *io, vo
 
     if (!c->authorized) {
         struct timeval tv;
-        gettimeofday(&tv, NULL);
+        pa_gettimeofday(&tv);
         tv.tv_sec += AUTH_TIMEOUT;
         c->auth_timeout_event = p->core->mainloop->time_new(p->core->mainloop, &tv, auth_timeout, c);
     } else
diff --git a/polyp/scache.c b/polyp/scache.c
index ccdc718..143f974 100644
--- a/polyp/scache.c
+++ b/polyp/scache.c
@@ -55,7 +55,7 @@ static void timeout_callback(struct pa_mainloop_api *m, struct pa_time_event*e,
 
     pa_scache_unload_unused(c);
 
-    gettimeofday(&ntv, NULL);
+    pa_gettimeofday(&ntv);
     ntv.tv_sec += UNLOAD_POLL_TIME;
     m->time_restart(e, &ntv);
 }
@@ -165,7 +165,7 @@ int pa_scache_add_file_lazy(struct pa_core *c, const char *name, const char *fil
     
     if (!c->scache_auto_unload_event) {
         struct timeval ntv;
-        gettimeofday(&ntv, NULL);
+        pa_gettimeofday(&ntv);
         ntv.tv_sec += UNLOAD_POLL_TIME;
         c->scache_auto_unload_event = c->mainloop->time_new(c->mainloop, &ntv, timeout_callback, c);
     }
diff --git a/polyp/socket-client.c b/polyp/socket-client.c
index 21563d3..f02b74b 100644
--- a/polyp/socket-client.c
+++ b/polyp/socket-client.c
@@ -377,7 +377,7 @@ static void start_timeout(struct pa_socket_client *c) {
     assert(c);
     assert(!c->timeout_event);
 
-    gettimeofday(&tv, NULL);
+    pa_gettimeofday(&tv);
     pa_timeval_add(&tv, CONNECT_TIMEOUT * 1000000);
     c->timeout_event = c->mainloop->time_new(c->mainloop, &tv, timeout_cb, c);
 }
diff --git a/polyp/util.c b/polyp/util.c
index ee3fa87..699480a 100644
--- a/polyp/util.c
+++ b/polyp/util.c
@@ -302,6 +302,14 @@ char *pa_strlcpy(char *b, const char *s, size_t l) {
     return b;
 }
 
+int pa_gettimeofday(struct timeval *tv) {
+#ifdef HAVE_GETTIMEOFDAY
+    return gettimeofday(tv, NULL);
+#else
+#error "Platform lacks gettimeofday() or equivalent function."
+#endif
+}
+
 /* Calculate the difference between the two specfified timeval
  * timestamsps. */
 pa_usec_t pa_timeval_diff(const struct timeval *a, const struct timeval *b) {
@@ -351,7 +359,7 @@ int pa_timeval_cmp(const struct timeval *a, const struct timeval *b) {
 pa_usec_t pa_timeval_age(const struct timeval *tv) {
     struct timeval now;
     assert(tv);
-    gettimeofday(&now, NULL);
+    pa_gettimeofday(&now);
     return pa_timeval_diff(&now, tv);
 }
 
diff --git a/polyp/util.h b/polyp/util.h
index 2cfc5f6..745d8f0 100644
--- a/polyp/util.h
+++ b/polyp/util.h
@@ -53,6 +53,7 @@ char *pa_get_home_dir(char *s, size_t l);
 
 char *pa_path_get_filename(const char *p);
 
+int pa_gettimeofday(struct timeval *tv);
 pa_usec_t pa_timeval_diff(const struct timeval *a, const struct timeval *b);
 int pa_timeval_cmp(const struct timeval *a, const struct timeval *b);
 pa_usec_t pa_timeval_age(const struct timeval *tv);

commit f6b0f87d0af87289204ee7b251bd9e23584ebc6b
Author: Pierre Ossman <ossman at cendio.se>
Date:   Thu Jan 5 16:42:00 2006 +0000

    Remove unnecessary dependency on timeval definition.
    
    
    git-svn-id: file:///home/lennart/svn/public/pulseaudio/branches/ossman@367 fefdeb5f-60dc-0310-8127-8f9354f1896f

diff --git a/polyp/util.h b/polyp/util.h
index 745d8f0..d9e18dd 100644
--- a/polyp/util.h
+++ b/polyp/util.h
@@ -30,6 +30,8 @@
 #include "gcc-printf.h"
 #include "sample.h"
 
+struct timeval;
+
 void pa_make_nonblock_fd(int fd);
 
 int pa_make_secure_dir(const char* dir);

commit 3f2ac7eb8ce8db8947f1bfc195f845be0d409fde
Author: Pierre Ossman <ossman at cendio.se>
Date:   Thu Jan 5 17:14:51 2006 +0000

    We have a generic function for extracting the filename, let's use it.
    
    
    git-svn-id: file:///home/lennart/svn/public/pulseaudio/branches/ossman@368 fefdeb5f-60dc-0310-8127-8f9354f1896f

diff --git a/polyp/scache.c b/polyp/scache.c
index 143f974..54563ba 100644
--- a/polyp/scache.c
+++ b/polyp/scache.c
@@ -303,10 +303,7 @@ static void add_file(struct pa_core *c, const char *pathname) {
     struct stat st;
     const char *e;
 
-    if (!(e = strrchr(pathname, '/')))
-        e = pathname;
-    else
-        e++;
+    e = pa_path_get_filename(pathname);
     
     if (stat(pathname, &st) < 0) {
         pa_log(__FILE__": stat('%s') failed: %s\n", pathname, strerror(errno));

commit 70223bac46f53f89041db61d2a06ea772968ce2d
Author: Pierre Ossman <ossman at cendio.se>
Date:   Thu Jan 5 17:43:06 2006 +0000

    Fallbacks for systems that do not have getaddrinfo(). Does not handle
    IPv6 though.
    
    
    git-svn-id: file:///home/lennart/svn/public/pulseaudio/branches/ossman@369 fefdeb5f-60dc-0310-8127-8f9354f1896f

diff --git a/configure.ac b/configure.ac
index c851164..450f18a 100644
--- a/configure.ac
+++ b/configure.ac
@@ -166,8 +166,8 @@ AC_CHECK_LIB([m], [pow])
 AC_FUNC_FORK
 AC_FUNC_GETGROUPS
 AC_FUNC_SELECT_ARGTYPES
-AC_CHECK_FUNCS([ftruncate getgrgid_r getpwuid_r gettimeofday getuid \
-    inet_ntop mkfifo nanosleep sigaction sleep])
+AC_CHECK_FUNCS([getaddrinfo ftruncate getgrgid_r getpwuid_r gettimeofday \
+    getuid inet_ntop mkfifo nanosleep sigaction sleep])
 
 AM_CONDITIONAL(HAVE_MKFIFO, test "x$HAVE_MKFIFO" = "x1")
 
diff --git a/polyp/socket-client.c b/polyp/socket-client.c
index f02b74b..40bbcc3 100644
--- a/polyp/socket-client.c
+++ b/polyp/socket-client.c
@@ -426,8 +426,9 @@ struct pa_socket_client* pa_socket_client_new_string(struct pa_mainloop_api *m,
                 assert(c->asyncns_query);
                 start_timeout(c);
             }
-#else
+#else /* HAVE_LIBASYNCNS */
             {
+#ifdef HAVE_GETADDRINFO
                 int ret;
                 struct addrinfo *res = NULL;
 
@@ -438,12 +439,37 @@ struct pa_socket_client* pa_socket_client_new_string(struct pa_mainloop_api *m,
 
                 if (res->ai_addr) {
                     if ((c = pa_socket_client_new_sockaddr(m, res->ai_addr, res->ai_addrlen)))
-                    	start_timeout(c);
+                        start_timeout(c);
 				}
                 
                 freeaddrinfo(res);
+#else /* HAVE_GETADDRINFO */
+                struct hostent *host = NULL;
+                struct sockaddr_in s;
+
+		/* FIXME: PF_INET6 support */
+                if (hints.ai_family != PF_INET)
+                    goto finish;
+
+                host = gethostbyname(a.path_or_host);
+                if (!host) {
+                    unsigned int addr = inet_addr(a.path_or_host);
+                    if (addr != INADDR_NONE)
+                        host = gethostbyaddr((char*)&addr, 4, AF_INET);
+                }
+
+                if (!host)
+                    goto finish;
+
+                s.sin_family = AF_INET;
+                memcpy(&s.sin_addr, host->h_addr, sizeof(struct in_addr));
+                s.sin_port = port;
+
+                if ((c = pa_socket_client_new_sockaddr(m, &s, sizeof(s))))
+                	start_timeout(c);
+#endif /* HAVE_GETADDRINFO */
             }
-#endif            
+#endif /* HAVE_LIBASYNCNS */
         }
     }
 
diff --git a/polyp/util.c b/polyp/util.c
index 699480a..2c4285f 100644
--- a/polyp/util.c
+++ b/polyp/util.c
@@ -831,11 +831,14 @@ size_t pa_parsehex(const char *p, uint8_t *d, size_t dlength) {
 /* Return the fully qualified domain name in *s */
 char *pa_get_fqdn(char *s, size_t l) {
     char hn[256];
+#ifdef HAVE_GETADDRINFO    
     struct addrinfo *a, hints;
+#endif
 
     if (!pa_get_host_name(hn, sizeof(hn)))
         return NULL;
 
+#ifdef HAVE_GETADDRINFO
     memset(&hints, 0, sizeof(hints));
     hints.ai_family = AF_UNSPEC;
     hints.ai_flags = AI_CANONNAME;
@@ -846,6 +849,9 @@ char *pa_get_fqdn(char *s, size_t l) {
     pa_strlcpy(s, a->ai_canonname, l);
     freeaddrinfo(a);
     return s;
+#else
+    return pa_strlcpy(s, hn, l);
+#endif
 }
 
 /* Returns nonzero when *s starts with *pfx */

commit 2ce05b2b4bda7933b419495e715c41909c3adf7e
Author: Pierre Ossman <ossman at cendio.se>
Date:   Thu Jan 5 17:49:45 2006 +0000

    Glob is not present on all systems.
    
    
    git-svn-id: file:///home/lennart/svn/public/pulseaudio/branches/ossman@370 fefdeb5f-60dc-0310-8127-8f9354f1896f

diff --git a/polyp/scache.c b/polyp/scache.c
index 54563ba..0dec33c 100644
--- a/polyp/scache.c
+++ b/polyp/scache.c
@@ -32,7 +32,10 @@
 #include <sys/stat.h>
 #include <errno.h>
 #include <limits.h>
+
+#ifdef HAVE_GLOB_H
 #include <glob.h>
+#endif
 
 #include "scache.h"
 #include "sink-input.h"
@@ -320,6 +323,7 @@ int pa_scache_add_directory_lazy(struct pa_core *c, const char *pathname) {
 
     /* First try to open this as directory */
     if (!(dir = opendir(pathname))) {
+#ifdef HAVE_GLOB_H
         glob_t p;
         unsigned int i;
         /* If that fails, try to open it as shell glob */
@@ -333,6 +337,9 @@ int pa_scache_add_directory_lazy(struct pa_core *c, const char *pathname) {
             add_file(c, p.gl_pathv[i]);
         
         globfree(&p);
+#else
+        return -1;
+#endif
     } else {
         struct dirent *e;
 

commit 3996c5f0485fd5bfbf401da846f53cf32aa474a8
Author: Pierre Ossman <ossman at cendio.se>
Date:   Thu Jan 5 17:59:32 2006 +0000

    SIXCPU isn't present on all platforms. Replace cpulimit with dummy functions
    on those systems.
    
    
    git-svn-id: file:///home/lennart/svn/public/pulseaudio/branches/ossman@371 fefdeb5f-60dc-0310-8127-8f9354f1896f

diff --git a/polyp/cpulimit.c b/polyp/cpulimit.c
index 0fab98a..f121123 100644
--- a/polyp/cpulimit.c
+++ b/polyp/cpulimit.c
@@ -23,6 +23,8 @@
 #include <config.h>
 #endif
 
+#ifdef HAVE_SIGXCPU
+
 #include <errno.h>
 #include <stdio.h>
 #include <string.h>
@@ -219,3 +221,16 @@ void pa_cpu_limit_done(void) {
         installed = 0;
     }
 }
+
+#else /* HAVE_SIGXCPU */
+
+struct pa_mainloop_api;
+
+int pa_cpu_limit_init(struct pa_mainloop_api *m) {
+    return 0;
+}
+
+void pa_cpu_limit_done(void) {
+}
+
+#endif

commit 8c5a75dfb2414aad449ad5de3354afdb48d556a7
Author: Pierre Ossman <ossman at cendio.se>
Date:   Thu Jan 5 18:00:39 2006 +0000

    Syslog is not present on all platforms.
    
    
    git-svn-id: file:///home/lennart/svn/public/pulseaudio/branches/ossman@372 fefdeb5f-60dc-0310-8127-8f9354f1896f

diff --git a/polyp/log.c b/polyp/log.c
index 78736a4..2bbf2e8 100644
--- a/polyp/log.c
+++ b/polyp/log.c
@@ -25,9 +25,12 @@
 
 #include <assert.h>
 #include <stdarg.h>
-#include <syslog.h>
 #include <stdio.h>
 
+#ifdef HAVE_SYSLOG_H
+#include <syslog.h>
+#endif
+
 #include "log.h"
 #include "xmalloc.h"
 #include "util.h"
@@ -39,6 +42,7 @@ static enum pa_log_target log_target = PA_LOG_STDERR;
 static void (*user_log_func)(enum pa_log_level l, const char *s) = NULL;
 static enum pa_log_level maximal_level = PA_LOG_NOTICE;
 
+#ifdef HAVE_SYSLOG_H
 static const int level_to_syslog[] = {
     [PA_LOG_ERROR] = LOG_ERR,
     [PA_LOG_WARN] = LOG_WARNING,
@@ -46,6 +50,7 @@ static const int level_to_syslog[] = {
     [PA_LOG_INFO] = LOG_INFO,
     [PA_LOG_DEBUG] = LOG_DEBUG
 };
+#endif
 
 void pa_log_set_ident(const char *p) {
     if (log_ident)
@@ -79,13 +84,15 @@ void pa_log_levelv(enum pa_log_level level, const char *format, va_list ap) {
         case PA_LOG_STDERR:
             vfprintf(stderr, format, ap);
             break;
-            
+
+#ifdef HAVE_SYSLOG_H            
         case PA_LOG_SYSLOG:
             openlog(log_ident ? log_ident : "???", LOG_PID, LOG_USER);
             vsyslog(level_to_syslog[level], format, ap);
             closelog();
-            break;
-            
+            break;            
+#endif
+
         case PA_LOG_USER: {
             char *t = pa_vsprintf_malloc(format, ap);
             assert(user_log_func);
@@ -94,6 +101,7 @@ void pa_log_levelv(enum pa_log_level level, const char *format, va_list ap) {
         }
             
         case PA_LOG_NULL:
+        default:
             break;
     }
 

commit eacffc3e4d581f0fe57536e7ccfba7293623586c
Author: Pierre Ossman <ossman at cendio.se>
Date:   Thu Jan 5 18:01:51 2006 +0000

    To access the new pa_gettimeofday() we need to include util.h.
    
    
    git-svn-id: file:///home/lennart/svn/public/pulseaudio/branches/ossman@373 fefdeb5f-60dc-0310-8127-8f9354f1896f

diff --git a/polyp/pdispatch.c b/polyp/pdispatch.c
index 9e80875..60dd911 100644
--- a/polyp/pdispatch.c
+++ b/polyp/pdispatch.c
@@ -32,6 +32,7 @@
 #include "xmalloc.h"
 #include "llist.h"
 #include "log.h"
+#include "util.h"
 
 /*#define DEBUG_OPCODES */
 

commit 7dcf4e45963b2aff840ea53bde4012e3c6cac9f8
Author: Pierre Ossman <ossman at cendio.se>
Date:   Thu Jan 5 18:09:46 2006 +0000

    The standard declares some signals as optional. Make sure we handle
    this gracefully.
    
    
    git-svn-id: file:///home/lennart/svn/public/pulseaudio/branches/ossman@374 fefdeb5f-60dc-0310-8127-8f9354f1896f

diff --git a/polyp/core.c b/polyp/core.c
index 539c677..6043924 100644
--- a/polyp/core.c
+++ b/polyp/core.c
@@ -89,7 +89,9 @@ struct pa_core* pa_core_new(struct pa_mainloop_api *m) {
 
     pa_random(&c->cookie, sizeof(c->cookie));
     
+#ifdef SIGPIPE
     pa_check_signal_is_blocked(SIGPIPE);
+#endif
     return c;
 }
 
diff --git a/polyp/main.c b/polyp/main.c
index 26fa4a8..2e97e5c 100644
--- a/polyp/main.c
+++ b/polyp/main.c
@@ -70,20 +70,26 @@ static void signal_callback(struct pa_mainloop_api*m, struct pa_signal_event *e,
     pa_log_info(__FILE__": Got signal %s.\n", pa_strsignal(sig));
 
     switch (sig) {
+#ifdef SIGUSR1
         case SIGUSR1:
             pa_module_load(userdata, "module-cli", NULL);
             break;
+#endif
             
+#ifdef SIGUSR2
         case SIGUSR2:
             pa_module_load(userdata, "module-cli-protocol-unix", NULL);
             break;
+#endif
 
+#ifdef SIGHUP
         case SIGHUP: {
             char *c = pa_full_status_string(userdata);
             pa_log_notice(c);
             pa_xfree(c);
             return;
         }
+#endif
 
         case SIGINT:
         case SIGTERM:
@@ -263,9 +269,15 @@ int main(int argc, char *argv[]) {
         open("/dev/null", O_WRONLY);
         open("/dev/null", O_WRONLY);
         
+#ifdef SIGTTOU
         signal(SIGTTOU, SIG_IGN);
+#endif
+#ifdef SIGTTIN
         signal(SIGTTIN, SIG_IGN);
+#endif
+#ifdef SIGTSTP
         signal(SIGTSTP, SIG_IGN);
+#endif
         
         if ((tty_fd = open("/dev/tty", O_RDWR)) >= 0) {
             ioctl(tty_fd, TIOCNOTTY, (char*) 0);
@@ -292,16 +304,24 @@ int main(int argc, char *argv[]) {
     assert(r == 0);
     pa_signal_new(SIGINT, signal_callback, c);
     pa_signal_new(SIGTERM, signal_callback, c);
+#ifdef SIGPIPE
     signal(SIGPIPE, SIG_IGN);
+#endif
 
     c = pa_core_new(pa_mainloop_get_api(mainloop));
     assert(c);
     if (conf->daemonize)
         c->running_as_daemon = 1;
     
+#ifdef SIGUSR1
     pa_signal_new(SIGUSR1, signal_callback, c);
+#endif
+#ifdef SIGUSR2
     pa_signal_new(SIGUSR2, signal_callback, c);
+#endif
+#ifdef SIGHUP
     pa_signal_new(SIGHUP, signal_callback, c);
+#endif
 
     r = pa_cpu_limit_init(pa_mainloop_get_api(mainloop));
     assert(r == 0);
diff --git a/polyp/pacat.c b/polyp/pacat.c
index 5910d13..1bba2ee 100644
--- a/polyp/pacat.c
+++ b/polyp/pacat.c
@@ -480,8 +480,12 @@ int main(int argc, char *argv[]) {
     assert(r == 0);
     pa_signal_new(SIGINT, exit_signal_callback, NULL);
     pa_signal_new(SIGTERM, exit_signal_callback, NULL);
+#ifdef SIGUSR1
     pa_signal_new(SIGUSR1, sigusr1_signal_callback, NULL);
+#endif
+#ifdef SIGPIPE
     signal(SIGPIPE, SIG_IGN);
+#endif
     
     if (!(stdio_event = mainloop_api->io_new(mainloop_api,
                                              mode == PLAYBACK ? STDIN_FILENO : STDOUT_FILENO,
diff --git a/polyp/pactl.c b/polyp/pactl.c
index 423cce9..725b546 100644
--- a/polyp/pactl.c
+++ b/polyp/pactl.c
@@ -739,7 +739,9 @@ int main(int argc, char *argv[]) {
     r = pa_signal_init(mainloop_api);
     assert(r == 0);
     pa_signal_new(SIGINT, exit_signal_callback, NULL);
+#ifdef SIGPIPE
     signal(SIGPIPE, SIG_IGN);
+#endif
     
     if (!(context = pa_context_new(mainloop_api, client_name))) {
         fprintf(stderr, "pa_context_new() failed.\n");
diff --git a/polyp/paplay.c b/polyp/paplay.c
index 2eaf07c..4ace197 100644
--- a/polyp/paplay.c
+++ b/polyp/paplay.c
@@ -338,7 +338,9 @@ int main(int argc, char *argv[]) {
     r = pa_signal_init(mainloop_api);
     assert(r == 0);
     pa_signal_new(SIGINT, exit_signal_callback, NULL);
+#ifdef SIGPIPE
     signal(SIGPIPE, SIG_IGN);
+#endif
     
     /* Create a new connection context */
     if (!(context = pa_context_new(mainloop_api, client_name))) {
diff --git a/polyp/polyplib-context.c b/polyp/polyplib-context.c
index bca7d7e..f54cabb 100644
--- a/polyp/polyplib-context.c
+++ b/polyp/polyplib-context.c
@@ -110,8 +110,10 @@ struct pa_context *pa_context_new(struct pa_mainloop_api *mainloop, const char *
     c->autospawn_lock_fd = -1;
     memset(&c->spawn_api, 0, sizeof(c->spawn_api));
     c->do_autospawn = 0;
-    
+
+#ifdef SIGPIPE    
     pa_check_signal_is_blocked(SIGPIPE);
+#endif
 
     c->conf = pa_client_conf_new();
     pa_client_conf_load(c->conf, NULL);
diff --git a/polyp/util.c b/polyp/util.c
index 2c4285f..fdafe25 100644
--- a/polyp/util.c
+++ b/polyp/util.c
@@ -527,12 +527,24 @@ const char *pa_strsignal(int sig) {
     switch(sig) {
         case SIGINT: return "SIGINT";
         case SIGTERM: return "SIGTERM";
+#ifdef SIGUSR1
         case SIGUSR1: return "SIGUSR1";
+#endif
+#ifdef SIGUSR2
         case SIGUSR2: return "SIGUSR2";
+#endif
+#ifdef SIGXCPU
         case SIGXCPU: return "SIGXCPU";
+#endif
+#ifdef SIGPIPE
         case SIGPIPE: return "SIGPIPE";
+#endif
+#ifdef SIGCHLD
         case SIGCHLD: return "SIGCHLD";
+#endif
+#ifdef SIGHUP
         case SIGHUP: return "SIGHUP";
+#endif
         default: return "UNKNOWN SIGNAL";
     }
 }

commit dbad54a20bf323d35176b1faba4fdd4b425f9ad9
Author: Pierre Ossman <ossman at cendio.se>
Date:   Thu Jan 5 18:20:14 2006 +0000

    Remove any warnings about incorrect type to setsockopt() (char* vs void*).
    
    
    git-svn-id: file:///home/lennart/svn/public/pulseaudio/branches/ossman@375 fefdeb5f-60dc-0310-8127-8f9354f1896f

diff --git a/polyp/socket-client.c b/polyp/socket-client.c
index 40bbcc3..3cd3e94 100644
--- a/polyp/socket-client.c
+++ b/polyp/socket-client.c
@@ -120,7 +120,7 @@ static void do_call(struct pa_socket_client *c) {
         goto finish;
     
     lerror = sizeof(error);
-    if (getsockopt(c->fd, SOL_SOCKET, SO_ERROR, &error, &lerror) < 0) {
+    if (getsockopt(c->fd, SOL_SOCKET, SO_ERROR, (void*)&error, &lerror) < 0) {
         pa_log(__FILE__": getsockopt(): %s\n", strerror(errno));
         goto finish;
     }
diff --git a/polyp/socket-server.c b/polyp/socket-server.c
index e67a9da..282f1eb 100644
--- a/polyp/socket-server.c
+++ b/polyp/socket-server.c
@@ -197,7 +197,7 @@ struct pa_socket_server* pa_socket_server_new_ipv4(struct pa_mainloop_api *m, ui
 
     pa_fd_set_cloexec(fd, 1);
 
-    if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)) < 0)
+    if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (void*)&on, sizeof(on)) < 0)
         pa_log(__FILE__": setsockopt(): %s\n", strerror(errno));
 
     pa_socket_tcp_low_delay(fd);
@@ -246,7 +246,7 @@ struct pa_socket_server* pa_socket_server_new_ipv6(struct pa_mainloop_api *m, ui
 
     pa_fd_set_cloexec(fd, 1);
 
-    if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)) < 0)
+    if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (void*)&on, sizeof(on)) < 0)
         pa_log(__FILE__": setsockopt(): %s\n", strerror(errno));
 
     pa_socket_tcp_low_delay(fd);
diff --git a/polyp/socket-util.c b/polyp/socket-util.c
index 495ee1b..7b32f4e 100644
--- a/polyp/socket-util.c
+++ b/polyp/socket-util.c
@@ -99,7 +99,7 @@ int pa_socket_low_delay(int fd) {
 
 #ifdef SO_PRIORITY
     priority = 7;
-    if (setsockopt(fd, SOL_SOCKET, SO_PRIORITY, &priority, sizeof(priority)) < 0)
+    if (setsockopt(fd, SOL_SOCKET, SO_PRIORITY, (void*)&priority, sizeof(priority)) < 0)
         return -1;
 #endif
 
@@ -117,9 +117,9 @@ int pa_socket_tcp_low_delay(int fd) {
 
 #if defined(SOL_TCP) || defined(IPPROTO_TCP)
 #if defined(SOL_TCP)
-    if (setsockopt(fd, SOL_TCP, TCP_NODELAY, &on, sizeof(on)) < 0)
+    if (setsockopt(fd, SOL_TCP, TCP_NODELAY, (void*)&on, sizeof(on)) < 0)
 #else
-    if (setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, &on, sizeof(on)) < 0)
+    if (setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, (void*)&on, sizeof(on)) < 0)
 #endif
         ret = -1;
 #endif
@@ -128,9 +128,9 @@ int pa_socket_tcp_low_delay(int fd) {
 	defined(IPPROTO_IP))
     tos = IPTOS_LOWDELAY;
 #ifdef SOL_IP
-    if (setsockopt(fd, SOL_IP, IP_TOS, &tos, sizeof(tos)) < 0)
+    if (setsockopt(fd, SOL_IP, IP_TOS, (void*)&tos, sizeof(tos)) < 0)
 #else
-    if (setsockopt(fd, IPPROTO_IP, IP_TOS, &tos, sizeof(tos)) < 0)
+    if (setsockopt(fd, IPPROTO_IP, IP_TOS, (void*)&tos, sizeof(tos)) < 0)
 #endif
         ret = -1;
 #endif
@@ -142,7 +142,7 @@ int pa_socket_tcp_low_delay(int fd) {
 int pa_socket_set_rcvbuf(int fd, size_t l) {
     assert(fd >= 0);
 
-/*     if (setsockopt(fd, SOL_SOCKET, SO_RCVBUF, &l, sizeof(l)) < 0) { */
+/*     if (setsockopt(fd, SOL_SOCKET, SO_RCVBUF, (void*)&l, sizeof(l)) < 0) { */
 /*         pa_log(__FILE__": SO_RCVBUF: %s\n", strerror(errno)); */
 /*         return -1; */
 /*     } */
@@ -153,7 +153,7 @@ int pa_socket_set_rcvbuf(int fd, size_t l) {
 int pa_socket_set_sndbuf(int fd, size_t l) {
     assert(fd >= 0);
 
-/*     if (setsockopt(fd, SOL_SOCKET, SO_SNDBUF, &l, sizeof(l)) < 0) { */
+/*     if (setsockopt(fd, SOL_SOCKET, SO_SNDBUF, (void*)&l, sizeof(l)) < 0) { */
 /*         pa_log(__FILE__": SO_SNDBUF: %s\n", strerror(errno)); */
 /*         return -1; */
 /*     } */

commit 3a3b4aff37397b786782d5a7e1f106b83d272abd
Author: Pierre Ossman <ossman at cendio.se>
Date:   Thu Jan 5 18:27:09 2006 +0000

    AF_UNIX and PF_UNIX is more portable than the _LOCAL equivalent.
    
    
    git-svn-id: file:///home/lennart/svn/public/pulseaudio/branches/ossman@376 fefdeb5f-60dc-0310-8127-8f9354f1896f

diff --git a/polyp/socket-client.c b/polyp/socket-client.c
index 3cd3e94..2eecc34 100644
--- a/polyp/socket-client.c
+++ b/polyp/socket-client.c
@@ -203,7 +203,7 @@ struct pa_socket_client* pa_socket_client_new_unix(struct pa_mainloop_api *m, co
     assert(m && filename);
     
     memset(&sa, 0, sizeof(sa));
-    sa.sun_family = AF_LOCAL;
+    sa.sun_family = AF_UNIX;
     strncpy(sa.sun_path, filename, sizeof(sa.sun_path)-1);
     sa.sun_path[sizeof(sa.sun_path) - 1] = 0;
 
diff --git a/polyp/socket-server.c b/polyp/socket-server.c
index 282f1eb..7d6035c 100644
--- a/polyp/socket-server.c
+++ b/polyp/socket-server.c
@@ -144,14 +144,14 @@ struct pa_socket_server* pa_socket_server_new_unix(struct pa_mainloop_api *m, co
     
     assert(m && filename);
 
-    if ((fd = socket(PF_LOCAL, SOCK_STREAM, 0)) < 0) {
+    if ((fd = socket(PF_UNIX, SOCK_STREAM, 0)) < 0) {
         pa_log(__FILE__": socket(): %s\n", strerror(errno));
         goto fail;
     }
 
     pa_fd_set_cloexec(fd, 1);
 
-    sa.sun_family = AF_LOCAL;
+    sa.sun_family = AF_UNIX;
     strncpy(sa.sun_path, filename, sizeof(sa.sun_path)-1);
     sa.sun_path[sizeof(sa.sun_path) - 1] = 0;
 
diff --git a/polyp/socket-util.c b/polyp/socket-util.c
index 7b32f4e..cd132d7 100644
--- a/polyp/socket-util.c
+++ b/polyp/socket-util.c
@@ -77,7 +77,7 @@ void pa_socket_peer_to_string(int fd, char *c, size_t l) {
                          ip & 0xFF,
                          ntohs(sa.in.sin_port));
                 return;
-            } else if (sa.sa.sa_family == AF_LOCAL) {
+            } else if (sa.sa.sa_family == AF_UNIX) {
                 snprintf(c, l, "UNIX socket client");
                 return;
             }
@@ -165,12 +165,12 @@ int pa_unix_socket_is_stale(const char *fn) {
     struct sockaddr_un sa;
     int fd = -1, ret = -1;
 
-    if ((fd = socket(PF_LOCAL, SOCK_STREAM, 0)) < 0) {
+    if ((fd = socket(PF_UNIX, SOCK_STREAM, 0)) < 0) {
         pa_log(__FILE__": socket(): %s\n", strerror(errno));
         goto finish;
     }
 
-    sa.sun_family = AF_LOCAL;
+    sa.sun_family = AF_UNIX;
     strncpy(sa.sun_path, fn, sizeof(sa.sun_path)-1);
     sa.sun_path[sizeof(sa.sun_path) - 1] = 0;
 

commit 13496bb73ecd2a76a83bf528d9a180084c8c006d
Author: Pierre Ossman <ossman at cendio.se>
Date:   Thu Jan 5 18:43:10 2006 +0000

    Handle when the platform doesn't have UNIX sockets.
    
    
    git-svn-id: file:///home/lennart/svn/public/pulseaudio/branches/ossman@377 fefdeb5f-60dc-0310-8127-8f9354f1896f

diff --git a/polyp/socket-client.c b/polyp/socket-client.c
index 2eecc34..a55fd4b 100644
--- a/polyp/socket-client.c
+++ b/polyp/socket-client.c
@@ -31,10 +31,14 @@
 #include <string.h>
 #include <assert.h>
 #include <stdlib.h>
-#include <sys/un.h>
 #include <netinet/in.h>
 #include <arpa/inet.h>
 #include <netdb.h>
+
+#ifdef HAVE_SYS_UN_H
+#include <sys/un.h>
+#endif
+
 #ifdef HAVE_LIBASYNCNS
 #include <asyncns.h>
 #endif
@@ -198,6 +202,8 @@ struct pa_socket_client* pa_socket_client_new_ipv4(struct pa_mainloop_api *m, ui
     return pa_socket_client_new_sockaddr(m, (struct sockaddr*) &sa, sizeof(sa));
 }
 
+#ifdef HAVE_SYS_UN_H
+
 struct pa_socket_client* pa_socket_client_new_unix(struct pa_mainloop_api *m, const char *filename) {
     struct sockaddr_un sa;
     assert(m && filename);
@@ -210,6 +216,14 @@ struct pa_socket_client* pa_socket_client_new_unix(struct pa_mainloop_api *m, co
     return pa_socket_client_new_sockaddr(m, (struct sockaddr*) &sa, sizeof(sa));
 }
 
+#else /* HAVE_SYS_UN_H */
+
+struct pa_socket_client* pa_socket_client_new_unix(struct pa_mainloop_api *m, const char *filename) {
+    return NULL;
+}
+
+#endif /* HAVE_SYS_UN_H */
+
 static int sockaddr_prepare(struct pa_socket_client *c, const struct sockaddr *sa, size_t salen) {
     assert(c);
     assert(sa);
diff --git a/polyp/socket-server.c b/polyp/socket-server.c
index 7d6035c..d46db6c 100644
--- a/polyp/socket-server.c
+++ b/polyp/socket-server.c
@@ -31,10 +31,13 @@
 #include <sys/socket.h>
 #include <stdio.h>
 #include <unistd.h>
-#include <sys/un.h>
 #include <netinet/in.h>
 #include <arpa/inet.h>
 
+#ifdef HAVE_SYS_UN_H
+#include <sys/un.h>
+#endif
+
 #ifdef HAVE_LIBWRAP
 #include <tcpd.h>
 #endif
@@ -137,6 +140,8 @@ struct pa_socket_server* pa_socket_server_ref(struct pa_socket_server *s) {
     return s;
 }
 
+#ifdef HAVE_SYS_UN_H
+
 struct pa_socket_server* pa_socket_server_new_unix(struct pa_mainloop_api *m, const char *filename) {
     int fd = -1;
     struct sockaddr_un sa;
@@ -182,6 +187,14 @@ fail:
     return NULL;
 }
 
+#else /* HAVE_SYS_UN_H */
+
+struct pa_socket_server* pa_socket_server_new_unix(struct pa_mainloop_api *m, const char *filename) {
+    return NULL;
+}
+
+#endif /* HAVE_SYS_UN_H */
+
 struct pa_socket_server* pa_socket_server_new_ipv4(struct pa_mainloop_api *m, uint32_t address, uint16_t port, const char *tcpwrap_service) {
     struct pa_socket_server *ss;
     int fd = -1;
diff --git a/polyp/socket-util.c b/polyp/socket-util.c
index cd132d7..4204ec9 100644
--- a/polyp/socket-util.c
+++ b/polyp/socket-util.c
@@ -31,7 +31,6 @@
 #include <string.h>
 #include <stdio.h>
 #include <sys/types.h>
-#include <sys/un.h>
 #include <netinet/in.h>
 #include <fcntl.h>
 #include <unistd.h>
@@ -42,6 +41,10 @@
 #include <sys/stat.h>
 #include <netdb.h>
 
+#ifdef HAVE_SYS_UN_H
+#include <sys/un.h>
+#endif
+
 #include "socket-util.h"
 #include "util.h"
 #include "xmalloc.h"
@@ -161,6 +164,8 @@ int pa_socket_set_sndbuf(int fd, size_t l) {
     return 0;
 }
 
+#ifdef HAVE_SYS_UN_H
+
 int pa_unix_socket_is_stale(const char *fn) {
     struct sockaddr_un sa;
     int fd = -1, ret = -1;
@@ -202,3 +207,15 @@ int pa_unix_socket_remove_stale(const char *fn) {
 
     return 0;
 }
+
+#else /* HAVE_SYS_UN_H */
+
+int pa_unix_socket_is_stale(const char *fn) {
+    return -1;
+}
+
+int pa_unix_socket_remove_stale(const char *fn) {
+    return -1;
+}
+
+#endif /* HAVE_SYS_UN_H */

commit cd3691dff79e18a288b7371bd0bed92d3abb5991
Author: Pierre Ossman <ossman at cendio.se>
Date:   Thu Jan 5 18:50:08 2006 +0000

    PIPE_BUF has nothing to do with the esound buffers.
    
    
    git-svn-id: file:///home/lennart/svn/public/pulseaudio/branches/ossman@378 fefdeb5f-60dc-0310-8127-8f9354f1896f

diff --git a/polyp/module-esound-sink.c b/polyp/module-esound-sink.c
index 82c38cc..1910650 100644
--- a/polyp/module-esound-sink.c
+++ b/polyp/module-esound-sink.c
@@ -144,7 +144,7 @@ static int do_write(struct userdata *u) {
         pa_module_set_used(u->module, pa_idxset_ncontents(u->sink->inputs) + pa_idxset_ncontents(u->sink->monitor_source->outputs));
         
         if (!u->memchunk.length)
-            if (pa_sink_render(u->sink, PIPE_BUF, &u->memchunk) < 0)
+            if (pa_sink_render(u->sink, 8192, &u->memchunk) < 0)
                 return 0;
 
         assert(u->memchunk.memblock && u->memchunk.length);

commit 456e25634ce860d1576b6f09f11cdab8f9d8e685
Author: Pierre Ossman <ossman at cendio.se>
Date:   Thu Jan 5 18:51:46 2006 +0000

    Fix some compiler warnings about unused variables.
    
    
    git-svn-id: file:///home/lennart/svn/public/pulseaudio/branches/ossman@379 fefdeb5f-60dc-0310-8127-8f9354f1896f

diff --git a/polyp/socket-util.c b/polyp/socket-util.c
index 4204ec9..eb6b424 100644
--- a/polyp/socket-util.c
+++ b/polyp/socket-util.c
@@ -97,10 +97,10 @@ void pa_socket_peer_to_string(int fd, char *c, size_t l) {
 }
 
 int pa_socket_low_delay(int fd) {
+#ifdef SO_PRIORITY
     int priority;
     assert(fd >= 0);
 
-#ifdef SO_PRIORITY
     priority = 7;
     if (setsockopt(fd, SOL_SOCKET, SO_PRIORITY, (void*)&priority, sizeof(priority)) < 0)
         return -1;
@@ -117,6 +117,7 @@ int pa_socket_tcp_low_delay(int fd) {
     ret = pa_socket_low_delay(fd);
     
     on = 1;
+    tos = 0;
 
 #if defined(SOL_TCP) || defined(IPPROTO_TCP)
 #if defined(SOL_TCP)

commit ff49e63b49dcd107e2680587b796c9c5998b1854
Author: Pierre Ossman <ossman at cendio.se>
Date:   Thu Jan 5 18:55:10 2006 +0000

    inet_ntop can't be found on all platforms. Do a stupid emulation when
    not found.
    
    
    git-svn-id: file:///home/lennart/svn/public/pulseaudio/branches/ossman@380 fefdeb5f-60dc-0310-8127-8f9354f1896f

diff --git a/polyp/socket-server.c b/polyp/socket-server.c
index d46db6c..096d8a4 100644
--- a/polyp/socket-server.c
+++ b/polyp/socket-server.c
@@ -350,10 +350,22 @@ char *pa_socket_server_get_address(struct pa_socket_server *s, char *c, size_t l
             } else {
                 char ip[INET6_ADDRSTRLEN];
                 
+#ifdef HAVE_INET_NTOP
                 if (!inet_ntop(AF_INET6, &sa.sin6_addr, ip, sizeof(ip))) {
                     pa_log(__FILE__": inet_ntop() failed: %s\n", strerror(errno));
                     return NULL;
                 }
+#else
+                snprintf(ip, INET6_ADDRSTRLEN, "%x:%x:%x:%x:%x:%x:%x:%x",
+                    sa.sin6_addr.s6_addr[ 0] << 8 | sa.sin6_addr.s6_addr[ 1],
+                    sa.sin6_addr.s6_addr[ 2] << 8 | sa.sin6_addr.s6_addr[ 3],
+                    sa.sin6_addr.s6_addr[ 4] << 8 | sa.sin6_addr.s6_addr[ 5],
+                    sa.sin6_addr.s6_addr[ 6] << 8 | sa.sin6_addr.s6_addr[ 7],
+                    sa.sin6_addr.s6_addr[ 8] << 8 | sa.sin6_addr.s6_addr[ 9],
+                    sa.sin6_addr.s6_addr[10] << 8 | sa.sin6_addr.s6_addr[11],
+                    sa.sin6_addr.s6_addr[12] << 8 | sa.sin6_addr.s6_addr[13],
+                    sa.sin6_addr.s6_addr[14] << 8 | sa.sin6_addr.s6_addr[15]);
+#endif
                 
                 snprintf(c, l, "tcp6:[%s]:%u", ip, (unsigned) ntohs(sa.sin6_port));
             }
@@ -385,10 +397,25 @@ char *pa_socket_server_get_address(struct pa_socket_server *s, char *c, size_t l
             } else {
                 char ip[INET_ADDRSTRLEN];
 
+#ifdef HAVE_INET_NTOP
                 if (!inet_ntop(AF_INET, &sa.sin_addr, ip, sizeof(ip))) {
                     pa_log(__FILE__": inet_ntop() failed: %s\n", strerror(errno));
                     return NULL;
                 }
+#else /* HAVE_INET_NTOP */
+                snprintf(ip, INET_ADDRSTRLEN, "%d.%d.%d.%d",
+#ifdef WORDS_BIGENDIAN
+                    (int)(sa.sin_addr.s_addr >> 24) & 0xff,
+                    (int)(sa.sin_addr.s_addr >> 16) & 0xff,
+                    (int)(sa.sin_addr.s_addr >>  8) & 0xff,
+                    (int)(sa.sin_addr.s_addr >>  0) & 0xff);
+#else
+                    (int)(sa.sin_addr.s_addr >>  0) & 0xff,
+                    (int)(sa.sin_addr.s_addr >>  8) & 0xff,
+                    (int)(sa.sin_addr.s_addr >> 16) & 0xff,
+                    (int)(sa.sin_addr.s_addr >> 24) & 0xff);
+#endif
+#endif /* HAVE_INET_NTOP */
                 
                 snprintf(c, l, "tcp:[%s]:%u", ip, (unsigned) ntohs(sa.sin_port));
 

commit 4384d3126b362c3aa261f4f0c815221b2cc5c647
Author: Pierre Ossman <ossman at cendio.se>
Date:   Thu Jan 5 18:56:23 2006 +0000

    Fix warning.
    
    
    git-svn-id: file:///home/lennart/svn/public/pulseaudio/branches/ossman@381 fefdeb5f-60dc-0310-8127-8f9354f1896f

diff --git a/polyp/socket-server.c b/polyp/socket-server.c
index 096d8a4..f200212 100644
--- a/polyp/socket-server.c
+++ b/polyp/socket-server.c
@@ -377,7 +377,7 @@ char *pa_socket_server_get_address(struct pa_socket_server *s, char *c, size_t l
             struct sockaddr_in sa;
             socklen_t l = sizeof(sa);
 
-            if (getsockname(s->fd, &sa, &l) < 0) {
+            if (getsockname(s->fd, (struct sockaddr*) &sa, &l) < 0) {
                 pa_log(__FILE__": getsockname() failed: %s\n", strerror(errno));
                 return NULL;
             }

commit f0e8c652397d512ed12939c3e2cbcbb4ec6cef75
Author: Pierre Ossman <ossman at cendio.se>
Date:   Thu Jan 5 18:57:19 2006 +0000

    Two variables with the same name causing corrupt strings.
    
    
    git-svn-id: file:///home/lennart/svn/public/pulseaudio/branches/ossman@382 fefdeb5f-60dc-0310-8127-8f9354f1896f

diff --git a/polyp/socket-server.c b/polyp/socket-server.c
index f200212..ed86bc2 100644
--- a/polyp/socket-server.c
+++ b/polyp/socket-server.c
@@ -327,9 +327,9 @@ char *pa_socket_server_get_address(struct pa_socket_server *s, char *c, size_t l
     switch (s->type) {
         case SOCKET_SERVER_IPV6: {
             struct sockaddr_in6 sa;
-            socklen_t l = sizeof(sa);
+            socklen_t sa_len = sizeof(sa);
 
-            if (getsockname(s->fd, (struct sockaddr*) &sa, &l) < 0) {
+            if (getsockname(s->fd, (struct sockaddr*) &sa, &sa_len) < 0) {
                 pa_log(__FILE__": getsockname() failed: %s\n", strerror(errno));
                 return NULL;
             }
@@ -375,9 +375,9 @@ char *pa_socket_server_get_address(struct pa_socket_server *s, char *c, size_t l
 
         case SOCKET_SERVER_IPV4: {
             struct sockaddr_in sa;
-            socklen_t l = sizeof(sa);
+            socklen_t sa_len = sizeof(sa);
 
-            if (getsockname(s->fd, (struct sockaddr*) &sa, &l) < 0) {
+            if (getsockname(s->fd, (struct sockaddr*) &sa, &sa_len) < 0) {
                 pa_log(__FILE__": getsockname() failed: %s\n", strerror(errno));
                 return NULL;
             }

commit 14474ae4528456b6be243d75116a6080df50399e
Author: Pierre Ossman <ossman at cendio.se>
Date:   Thu Jan 5 18:59:24 2006 +0000

    Esound latency should not include buffer length. This added an extra second
    to esound already horrible latency calculations.
    
    
    git-svn-id: file:///home/lennart/svn/public/pulseaudio/branches/ossman@383 fefdeb5f-60dc-0310-8127-8f9354f1896f

diff --git a/polyp/protocol-esound.c b/polyp/protocol-esound.c
index 2af3cc8..5705d3f 100644
--- a/polyp/protocol-esound.c
+++ b/polyp/protocol-esound.c
@@ -426,7 +426,6 @@ static int esd_proto_get_latency(struct connection *c, esd_proto_t request, cons
         latency = 0;
     else {
         double usec = pa_sink_get_latency(sink);
-        usec += PLAYBACK_BUFFER_SECONDS*1000000;          /* A better estimation would be a good idea! */
         latency = (int) ((usec*44100)/1000000);
     }
     

commit 4deeaefbe116f6374b3cdb7a4186bb1bf7afefe2
Author: Pierre Ossman <ossman at cendio.se>
Date:   Thu Jan 5 19:11:23 2006 +0000

    Don't include sys/socket.h in the header when we do not need to.
    
    
    git-svn-id: file:///home/lennart/svn/public/pulseaudio/branches/ossman@384 fefdeb5f-60dc-0310-8127-8f9354f1896f

diff --git a/polyp/socket-client.c b/polyp/socket-client.c
index a55fd4b..58bc7e8 100644
--- a/polyp/socket-client.c
+++ b/polyp/socket-client.c
@@ -31,6 +31,7 @@
 #include <string.h>
 #include <assert.h>
 #include <stdlib.h>
+#include <sys/socket.h>
 #include <netinet/in.h>
 #include <arpa/inet.h>
 #include <netdb.h>
diff --git a/polyp/socket-client.h b/polyp/socket-client.h
index 9c3e0b3..b8c73ed 100644
--- a/polyp/socket-client.h
+++ b/polyp/socket-client.h
@@ -23,11 +23,12 @@
 ***/
 
 #include <inttypes.h>
-#include <sys/socket.h>
 
 #include "mainloop-api.h"
 #include "iochannel.h"
 
+struct sockaddr;
+
 struct pa_socket_client;
 
 struct pa_socket_client* pa_socket_client_new_ipv4(struct pa_mainloop_api *m, uint32_t address, uint16_t port);

commit c5bee95cdf30661b4090d86f4e0ab36109228fae
Author: Pierre Ossman <ossman at cendio.se>
Date:   Thu Jan 5 19:13:11 2006 +0000

    Fix correct type.
    
    
    git-svn-id: file:///home/lennart/svn/public/pulseaudio/branches/ossman@385 fefdeb5f-60dc-0310-8127-8f9354f1896f

diff --git a/polyp/sample-util.c b/polyp/sample-util.c
index d521afe..bf8be34 100644
--- a/polyp/sample-util.c
+++ b/polyp/sample-util.c
@@ -161,7 +161,7 @@ size_t pa_mix(struct pa_mix_info channels[], unsigned nchannels, void *data, siz
         size_t d;
         
         for (d = 0;; d += sizeof(float)) {
-            float_t sum = 0;
+            pa_volume_t sum = 0;
             unsigned c;
             
             if (d >= length)

commit 719223825e56e580dd0c02e09d13f8a7be8c89a3
Author: Pierre Ossman <ossman at cendio.se>
Date:   Thu Jan 5 19:14:13 2006 +0000

    Old kernel headers didn't define the input_id structure. Therefore we cannot
    rely on it.
    
    
    git-svn-id: file:///home/lennart/svn/public/pulseaudio/branches/ossman@386 fefdeb5f-60dc-0310-8127-8f9354f1896f

diff --git a/polyp/module-mmkbd-evdev.c b/polyp/module-mmkbd-evdev.c
index 758aaae..5368af5 100644
--- a/polyp/module-mmkbd-evdev.c
+++ b/polyp/module-mmkbd-evdev.c
@@ -49,6 +49,17 @@ PA_MODULE_USAGE("device=<evdev device> sink=<sink name>")
 
 #define DEFAULT_DEVICE "/dev/input/event0"
 
+/*
+ * This isn't defined in older kernel headers and there is no way of
+ * detecting it.
+ */
+struct _input_id {
+    __u16 bustype;
+    __u16 vendor;
+    __u16 product;
+    __u16 version;
+};
+
 static const char* const valid_modargs[] = {
     "device",
     "sink",
@@ -136,7 +147,7 @@ int pa__init(struct pa_core *c, struct pa_module*m) {
     struct pa_modargs *ma = NULL;
     struct userdata *u;
     int version;
-    struct input_id input_id;
+    struct _input_id input_id;
     char name[256];
     uint8_t evtype_bitmask[EV_MAX/8 + 1];
     assert(c && m);

commit b69d881eb2555f40795d5d930a84e4a7d7e4b598
Author: Pierre Ossman <ossman at cendio.se>
Date:   Thu Jan 5 19:14:58 2006 +0000

    Fix printf string.
    
    
    git-svn-id: file:///home/lennart/svn/public/pulseaudio/branches/ossman@387 fefdeb5f-60dc-0310-8127-8f9354f1896f

diff --git a/polyp/mcalign-test.c b/polyp/mcalign-test.c
index e4a6a23..2ace6e5 100644
--- a/polyp/mcalign-test.c
+++ b/polyp/mcalign-test.c
@@ -66,7 +66,7 @@ int main(int argc, char *argv[]) {
 
         c.length = r;
         pa_mcalign_push(a, &c);
-        fprintf(stderr, "Read %u bytes\n", r);
+        fprintf(stderr, "Read %d bytes\n", r);
 
         c.index += r;
 

commit 3728854bc924ad4cfe72d9d83e040a888a715822
Author: Pierre Ossman <ossman at cendio.se>
Date:   Thu Jan 5 19:16:01 2006 +0000

    Make sure the array is never too small.
    
    
    git-svn-id: file:///home/lennart/svn/public/pulseaudio/branches/ossman@388 fefdeb5f-60dc-0310-8127-8f9354f1896f

diff --git a/polyp/oss-util.c b/polyp/oss-util.c
index 8c83cbb..799bc40 100644
--- a/polyp/oss-util.c
+++ b/polyp/oss-util.c
@@ -92,7 +92,7 @@ fail:
 
 int pa_oss_auto_format(int fd, struct pa_sample_spec *ss) {
     int format, channels, speed, reqformat;
-    static const int format_trans[] = {
+    static const int format_trans[PA_SAMPLE_MAX] = {
         [PA_SAMPLE_U8] = AFMT_U8,
         [PA_SAMPLE_ALAW] = AFMT_A_LAW,
         [PA_SAMPLE_ULAW] = AFMT_MU_LAW,

commit b8859b4b60152403058884ee7d28f48d67a418a9
Author: Pierre Ossman <ossman at cendio.se>
Date:   Thu Jan 5 19:17:53 2006 +0000

    Compiler warning about uninitialized variable.
    
    
    git-svn-id: file:///home/lennart/svn/public/pulseaudio/branches/ossman@389 fefdeb5f-60dc-0310-8127-8f9354f1896f

diff --git a/polyp/authkey.c b/polyp/authkey.c
index e16883d..35d97b7 100644
--- a/polyp/authkey.c
+++ b/polyp/authkey.c
@@ -63,7 +63,7 @@ static int generate(int fd, void *ret_data, size_t length) {
 static int load(const char *fn, void *data, size_t length) {
     int fd = -1;
     int writable = 1;
-    int unlock = 0, ret;
+    int unlock = 0, ret = -1;
     ssize_t r;
     assert(fn && data && length);
 

commit 3ed983c945f2bd6ad7503c969a5506bae41a823b
Author: Pierre Ossman <ossman at cendio.se>
Date:   Thu Jan 5 19:18:42 2006 +0000

    SIGQUIT is an optional signal.
    
    
    git-svn-id: file:///home/lennart/svn/public/pulseaudio/branches/ossman@390 fefdeb5f-60dc-0310-8127-8f9354f1896f

diff --git a/polyp/xmalloc.c b/polyp/xmalloc.c
index 7ddefa9..f2751e5 100644
--- a/polyp/xmalloc.c
+++ b/polyp/xmalloc.c
@@ -45,7 +45,9 @@
 static void oom(void) {
     static const char e[] = "Not enough memory\n";
     pa_loop_write(STDERR_FILENO, e, sizeof(e)-1);
+#ifdef SIGQUIT
     raise(SIGQUIT);
+#endif
     _exit(1);
 }
 

commit ec87cb1571c293ff40b1191796c71275b6564694
Author: Pierre Ossman <ossman at cendio.se>
Date:   Thu Jan 5 19:25:21 2006 +0000

    Fall back to signal() when sigaction isn't supported.
    
    
    git-svn-id: file:///home/lennart/svn/public/pulseaudio/branches/ossman@391 fefdeb5f-60dc-0310-8127-8f9354f1896f

diff --git a/polyp/mainloop-signal.c b/polyp/mainloop-signal.c
index 89f195e..eb3f5dd 100644
--- a/polyp/mainloop-signal.c
+++ b/polyp/mainloop-signal.c
@@ -30,6 +30,7 @@
 #include <stdlib.h>
 #include <string.h>
 #include <unistd.h>
+#include <fcntl.h>
 
 #include "mainloop-signal.h"
 #include "util.h"
@@ -38,7 +39,11 @@
 
 struct pa_signal_event {
     int sig;
+#ifdef HAVE_SIGACTION
     struct sigaction saved_sigaction;
+#else
+    void (*saved_handler)(int sig);
+#endif
     void (*callback) (struct pa_mainloop_api*a, struct pa_signal_event *e, int signal, void *userdata);
     void *userdata;
     void (*destroy_callback) (struct pa_mainloop_api*a, struct pa_signal_event*e, void *userdata);
@@ -51,6 +56,9 @@ static struct pa_io_event* io_event = NULL;
 static struct pa_signal_event *signals = NULL;
 
 static void signal_handler(int sig) {
+#ifndef HAVE_SIGACTION
+    signal(sig, signal_handler);
+#endif
     write(signal_pipe[1], &sig, sizeof(sig));
 }
 
@@ -108,7 +116,7 @@ void pa_signal_done(void) {
         pa_signal_free(signals);
 
 
-        api->io_free(io_event);
+    api->io_free(io_event);
     io_event = NULL;
 
     close(signal_pipe[0]);
@@ -120,7 +128,11 @@ void pa_signal_done(void) {
 
 struct pa_signal_event* pa_signal_new(int sig, void (*callback) (struct pa_mainloop_api *api, struct pa_signal_event*e, int sig, void *userdata), void *userdata) {
     struct pa_signal_event *e = NULL;
+
+#ifdef HAVE_SIGACTION
     struct sigaction sa;
+#endif
+
     assert(sig > 0 && callback);
     
     for (e = signals; e; e = e->next)
@@ -133,12 +145,16 @@ struct pa_signal_event* pa_signal_new(int sig, void (*callback) (struct pa_mainl
     e->userdata = userdata;
     e->destroy_callback = NULL;
 
+#ifdef HAVE_SIGACTION
     memset(&sa, 0, sizeof(sa));
     sa.sa_handler = signal_handler;
     sigemptyset(&sa.sa_mask);
     sa.sa_flags = SA_RESTART;
     
     if (sigaction(sig, &sa, &e->saved_sigaction) < 0)
+#else
+    if ((e->saved_handler = signal(sig, signal_handler)) == SIG_ERR)
+#endif
         goto fail;
 
     e->previous = NULL;
@@ -162,7 +178,11 @@ void pa_signal_free(struct pa_signal_event *e) {
     else
         signals = e->next;
 
+#ifdef HAVE_SIGACTION
     sigaction(e->sig, &e->saved_sigaction, NULL);
+#else
+    signal(e->sig, e->saved_handler);
+#endif
 
     if (e->destroy_callback)
         e->destroy_callback(api, e, e->userdata);
diff --git a/polyp/util.c b/polyp/util.c
index fdafe25..a7dc3b1 100644
--- a/polyp/util.c
+++ b/polyp/util.c
@@ -153,6 +153,7 @@ ssize_t pa_loop_write(int fd, const void*data, size_t size) {
 /* Print a warning messages in case that the given signal is not
  * blocked or trapped */
 void pa_check_signal_is_blocked(int sig) {
+#ifdef HAVE_SIGACTION
     struct sigaction sa;
     sigset_t set;
 
@@ -185,6 +186,9 @@ void pa_check_signal_is_blocked(int sig) {
         return;
     
     pa_log(__FILE__": WARNING: %s is not trapped. This might cause malfunction!\n", pa_strsignal(sig));
+#else /* HAVE_SIGACTION */
+    pa_log(__FILE__": WARNING: %s might not be trapped. This might cause malfunction!\n", pa_strsignal(sig));
+#endif
 }
 
 /* The following function is based on an example from the GNU libc

commit 59aa6ca514101d50dea7bd56147a6984b8abb3bf
Author: Pierre Ossman <ossman at cendio.se>
Date:   Thu Jan 5 19:30:59 2006 +0000

    There was a race condition here that caused latency calculation to fail
    miserably under some conditions.
    
    
    git-svn-id: file:///home/lennart/svn/public/pulseaudio/branches/ossman@392 fefdeb5f-60dc-0310-8127-8f9354f1896f

diff --git a/polyp/polyplib-internal.h b/polyp/polyplib-internal.h
index d1b3a27..9417430 100644
--- a/polyp/polyplib-internal.h
+++ b/polyp/polyplib-internal.h
@@ -92,7 +92,6 @@ struct pa_stream {
     enum pa_stream_direction direction;
     uint32_t requested_bytes;
     uint64_t counter;
-    pa_usec_t previous_time;
     enum pa_stream_state state;
     struct pa_mcalign *mcalign;
 
diff --git a/polyp/polyplib-stream.c b/polyp/polyplib-stream.c
index d4480f8..c7c40c0 100644
--- a/polyp/polyplib-stream.c
+++ b/polyp/polyplib-stream.c
@@ -65,7 +65,6 @@ struct pa_stream *pa_stream_new(struct pa_context *c, const char *name, const st
     s->mcalign = pa_mcalign_new(pa_frame_size(ss), c->memblock_stat);
 
     s->counter = 0;
-    s->previous_time = 0;
 
     s->corked = 0;
     s->interpolate = 0;
@@ -698,11 +697,6 @@ pa_usec_t pa_stream_get_time(struct pa_stream *s, const struct pa_latency_info *
         }
     }
 
-    if (usec < s->previous_time)
-        usec = s->previous_time;
-
-    s->previous_time = usec;
-    
     return usec;
 }
 
@@ -762,10 +756,6 @@ pa_usec_t pa_stream_get_interpolated_time(struct pa_stream *s) {
             usec = s->ipol_usec + pa_timeval_age(&s->ipol_timestamp);
     }
     
-    if (usec < s->previous_time)
-        usec = s->previous_time;
-
-    s->previous_time = usec;
     return usec;
 }
 

commit e9be6fa6d397a59ee4566d6674b9ed2cb3d04402
Author: Pierre Ossman <ossman at cendio.se>
Date:   Thu Jan 5 19:43:29 2006 +0000

    Handle platforms that do not support the UNIX user/group database.
    
    
    git-svn-id: file:///home/lennart/svn/public/pulseaudio/branches/ossman@393 fefdeb5f-60dc-0310-8127-8f9354f1896f

diff --git a/polyp/util.c b/polyp/util.c
index a7dc3b1..2ac5540 100644
--- a/polyp/util.c
+++ b/polyp/util.c
@@ -34,7 +34,6 @@
 #include <unistd.h>
 #include <sys/types.h>
 #include <sys/stat.h>
-#include <pwd.h>
 #include <signal.h>
 #include <pthread.h>
 #include <sys/time.h>
@@ -42,11 +41,17 @@
 #include <sys/resource.h>
 #include <limits.h>
 #include <unistd.h>
-#include <grp.h>
 #include <netdb.h>
 
 #include <samplerate.h>
 
+#ifdef HAVE_PWD_H
+#include <pwd.h>
+#endif
+#ifdef HAVE_GRP_H
+#include <grp.h>
+#endif
+
 #include "util.h"
 #include "xmalloc.h"
 #include "log.h"
@@ -244,12 +249,17 @@ char *pa_vsprintf_malloc(const char *format, va_list ap) {
 
 /* Return the current username in the specified string buffer. */
 char *pa_get_user_name(char *s, size_t l) {
-    struct passwd pw, *r;
-    char buf[1024];
     char *p;
+
+#ifdef HAVE_PWD_H
+    char buf[1024];
+    struct passwd pw, *r;
+#endif
+
     assert(s && l > 0);
 
     if (!(p = getenv("USER")) && !(p = getenv("LOGNAME")) && !(p = getenv("USERNAME"))) {
+#ifdef HAVE_PWD_H
         
 #ifdef HAVE_GETPWUID_R
         if (getpwuid_r(getuid(), &pw, buf, sizeof(buf), &r) != 0 || !r) {
@@ -263,6 +273,9 @@ char *pa_get_user_name(char *s, size_t l) {
             }
             
             p = r->pw_name;
+#else /* HAVE_PWD_H */
+            return NULL;
+#endif /* HAVE_PWD_H */
         }
 
     return pa_strlcpy(s, p, l);
@@ -282,19 +295,34 @@ char *pa_get_host_name(char *s, size_t l) {
 /* Return the home directory of the current user */
 char *pa_get_home_dir(char *s, size_t l) {
     char *e;
+
+#ifdef HAVE_PWD_H
     char buf[1024];
     struct passwd pw, *r;
+#endif
+
     assert(s && l);
 
     if ((e = getenv("HOME")))
         return pa_strlcpy(s, e, l);
 
+#ifdef HAVE_PWD_H
+#ifdef HAVE_GETPWUID_R
     if (getpwuid_r(getuid(), &pw, buf, sizeof(buf), &r) != 0 || !r) {
         pa_log(__FILE__": getpwuid_r() failed\n");
+#else
+    /* XXX Not thread-safe, but needed on OSes (e.g. FreeBSD 4.X)
+        * that do not support getpwuid_r. */
+    if ((r = getpwuid(getuid())) == NULL) {
+        pa_log(__FILE__": getpwuid_r() failed\n");
+#endif
         return NULL;
     }
 
     return pa_strlcpy(s, r->pw_dir, l);
+#else /* HAVE_PWD_H */
+    return NULL;
+#endif
 }
 
 /* Similar to OpenBSD's strlcpy() function */
@@ -553,6 +581,7 @@ const char *pa_strsignal(int sig) {
     }
 }
 
+#ifdef HAVE_GRP_H
 
 /* Check whether the specified GID and the group name match */
 static int is_group(gid_t gid, const char *name) {
@@ -633,6 +662,14 @@ finish:
     return r;
 }
 
+#else /* HAVE_GRP_H */
+
+int pa_uid_in_group(const char *name, gid_t *gid) {
+    return -1;
+}
+
+#endif
+
 /* Lock or unlock a file entirely. (advisory) */
 int pa_lock_fd(int fd, int b) {
     struct flock flock;

commit a24102cda46ffdc0b3a6a0b82b13cf0ee80beb98
Author: Pierre Ossman <ossman at cendio.se>
Date:   Thu Jan 5 19:44:33 2006 +0000

    Fix indentation.
    
    
    git-svn-id: file:///home/lennart/svn/public/pulseaudio/branches/ossman@394 fefdeb5f-60dc-0310-8127-8f9354f1896f

diff --git a/polyp/util.c b/polyp/util.c
index 2ac5540..9e8dc5e 100644
--- a/polyp/util.c
+++ b/polyp/util.c
@@ -264,22 +264,22 @@ char *pa_get_user_name(char *s, size_t l) {
 #ifdef HAVE_GETPWUID_R
         if (getpwuid_r(getuid(), &pw, buf, sizeof(buf), &r) != 0 || !r) {
 #else
-            /* XXX Not thread-safe, but needed on OSes (e.g. FreeBSD 4.X)
-             * that do not support getpwuid_r. */
-            if ((r = getpwuid(getuid())) == NULL) {
+        /* XXX Not thread-safe, but needed on OSes (e.g. FreeBSD 4.X)
+            * that do not support getpwuid_r. */
+        if ((r = getpwuid(getuid())) == NULL) {
 #endif
-                snprintf(s, l, "%lu", (unsigned long) getuid());
-                return s;
-            }
-            
-            p = r->pw_name;
+            snprintf(s, l, "%lu", (unsigned long) getuid());
+            return s;
+        }
+        
+        p = r->pw_name;
 #else /* HAVE_PWD_H */
-            return NULL;
+        return NULL;
 #endif /* HAVE_PWD_H */
-        }
+    }
 
     return pa_strlcpy(s, p, l);
-    }
+}
 
 /* Return the current hostname in the specified buffer. */
 char *pa_get_host_name(char *s, size_t l) {

commit 5cd8703f0de35ed38ddd79974b5a7e70af8203ce
Author: Pierre Ossman <ossman at cendio.se>
Date:   Thu Jan 5 20:25:05 2006 +0000

    Remove ftruncate test since we're not doing anything with the result.
    
    
    git-svn-id: file:///home/lennart/svn/public/pulseaudio/branches/ossman@395 fefdeb5f-60dc-0310-8127-8f9354f1896f

diff --git a/configure.ac b/configure.ac
index 450f18a..eb4c941 100644
--- a/configure.ac
+++ b/configure.ac
@@ -166,8 +166,8 @@ AC_CHECK_LIB([m], [pow])
 AC_FUNC_FORK
 AC_FUNC_GETGROUPS
 AC_FUNC_SELECT_ARGTYPES
-AC_CHECK_FUNCS([getaddrinfo ftruncate getgrgid_r getpwuid_r gettimeofday \
-    getuid inet_ntop mkfifo nanosleep sigaction sleep])
+AC_CHECK_FUNCS([getaddrinfo getgrgid_r getpwuid_r gettimeofday getuid \
+    inet_ntop mkfifo nanosleep sigaction sleep])
 
 AM_CONDITIONAL(HAVE_MKFIFO, test "x$HAVE_MKFIFO" = "x1")
 

commit d3bc7b27b7b0da1a8d9de2cd93ac10096b6b0b17
Author: Pierre Ossman <ossman at cendio.se>
Date:   Thu Jan 5 20:31:48 2006 +0000

    Fix test for mkfifo(). HAVE_MKFIFO is only generated as a config.h define by
    default.
    
    
    git-svn-id: file:///home/lennart/svn/public/pulseaudio/branches/ossman@396 fefdeb5f-60dc-0310-8127-8f9354f1896f

diff --git a/configure.ac b/configure.ac
index eb4c941..2d75332 100644
--- a/configure.ac
+++ b/configure.ac
@@ -167,7 +167,8 @@ AC_FUNC_FORK
 AC_FUNC_GETGROUPS
 AC_FUNC_SELECT_ARGTYPES
 AC_CHECK_FUNCS([getaddrinfo getgrgid_r getpwuid_r gettimeofday getuid \
-    inet_ntop mkfifo nanosleep sigaction sleep])
+    inet_ntop nanosleep sigaction sleep])
+AC_CHECK_FUNCS([mkfifo], [HAVE_MKFIFO=1], [HAVE_MKFIFO=0])
 
 AM_CONDITIONAL(HAVE_MKFIFO, test "x$HAVE_MKFIFO" = "x1")
 

commit 29a5b850a7d8e9c4fc878afae336e16cba0c6c25
Author: Pierre Ossman <ossman at cendio.se>
Date:   Thu Jan 5 20:56:17 2006 +0000

    Emulate poll() through select() where needed.
    
    
    git-svn-id: file:///home/lennart/svn/public/pulseaudio/branches/ossman@397 fefdeb5f-60dc-0310-8127-8f9354f1896f

diff --git a/polyp/Makefile.am b/polyp/Makefile.am
index 2cd2a1f..6ec75d4 100644
--- a/polyp/Makefile.am
+++ b/polyp/Makefile.am
@@ -327,7 +327,8 @@ libpolyp_error_ at PA_MAJORMINOR@_la_LDFLAGS = -version-info 0:0:0
 libpolyp_mainloop_ at PA_MAJORMINOR@_la_SOURCES = \
 		mainloop.c mainloop.h \
 		mainloop-api.h mainloop-api.c \
-		mainloop-signal.c mainloop-signal.h
+		mainloop-signal.c mainloop-signal.h \
+		poll.c poll.h
 libpolyp_mainloop_ at PA_MAJORMINOR@_la_CFLAGS = $(AM_CFLAGS)
 libpolyp_mainloop_ at PA_MAJORMINOR@_la_LIBADD = $(AM_LIBADD) libpolyp- at PA_MAJORMINOR@.la $(WINSOCK_LIBS)
 libpolyp_mainloop_ at PA_MAJORMINOR@_la_LDFLAGS = -version-info 0:0:0
@@ -413,6 +414,7 @@ libpolypcore_la_SOURCES = \
 		module.c module.h \
 		namereg.c namereg.h \
 		play-memchunk.c play-memchunk.h \
+		poll.c poll.h \
 		props.c props.h \
 		queue.c queue.h \
 		random.c random.h \
diff --git a/polyp/mainloop.c b/polyp/mainloop.c
index a0d2782..90243bd 100644
--- a/polyp/mainloop.c
+++ b/polyp/mainloop.c
@@ -26,13 +26,18 @@
 #include <stdio.h>
 #include <signal.h>
 #include <unistd.h>
-#include <sys/poll.h>
 #include <stdlib.h>
 #include <string.h>
 #include <assert.h>
 #include <fcntl.h>
 #include <errno.h>
 
+#ifdef HAVE_SYS_POLL_H
+#include <sys/poll.h>
+#else
+#include "poll.h"
+#endif
+
 #include "mainloop.h"
 #include "util.h"
 #include "idxset.h"
diff --git a/polyp/module-alsa-sink.c b/polyp/module-alsa-sink.c
index 69db287..dde5d8b 100644
--- a/polyp/module-alsa-sink.c
+++ b/polyp/module-alsa-sink.c
@@ -25,7 +25,12 @@
 
 #include <assert.h>
 #include <stdio.h>
+
+#ifdef HAVE_SYS_POLL_H
 #include <sys/poll.h>
+#else
+#include "poll.h"
+#endif
 
 #include <asoundlib.h>
 
diff --git a/polyp/module-alsa-source.c b/polyp/module-alsa-source.c
index 55abe8e..5b4076f 100644
--- a/polyp/module-alsa-source.c
+++ b/polyp/module-alsa-source.c
@@ -25,7 +25,12 @@
 
 #include <assert.h>
 #include <stdio.h>
+
+#ifdef HAVE_SYS_POLL_H
 #include <sys/poll.h>
+#else
+#include "poll.h"
+#endif
 
 #include <asoundlib.h>
 
diff --git a/polyp/poll.c b/polyp/poll.c
new file mode 100644
index 0000000..82ea3d8
--- /dev/null
+++ b/polyp/poll.c
@@ -0,0 +1,173 @@
+/* $Id: mainloop.c 302 2004-11-21 17:02:25Z lennart $ */
+
+/***
+   Copyright (C) 1994, 1996, 1997 Free Software Foundation, Inc.
+   Copyright (C) 2005, Cendio AB.
+   This file is part of polypaudio.
+   Based on work for the GNU C Library.
+
+   polypaudio is free software; you can redistribute it and/or modify it
+   under the terms of the GNU Library General Public License as published
+   by the Free Software Foundation; either version 2 of the License, or
+   (at your option) any later version.
+
+   polypaudio 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
+   Library General Public License for more details.
+
+   You should have received a copy of the GNU Library General Public
+   License along with polypaudio; If not, write to the Free Software
+   Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
+   USA.
+***/
+
+/* Poll the file descriptors described by the NFDS structures starting at
+   FDS.  If TIMEOUT is nonzero and not -1, allow TIMEOUT milliseconds for
+   an event to occur; if TIMEOUT is -1, block until an event occurs.
+   Returns the number of file descriptors with events, zero if timed out,
+   or -1 for errors.  */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#ifdef HAVE_SYS_SELECT_H
+#include <sys/select.h>
+#endif
+
+#ifndef HAVE_SYS_POLL_H
+
+#include "util.h"
+#include "poll.h"
+
+int poll (struct pollfd *fds, unsigned long int nfds, int timeout) {
+    struct timeval tv;
+    fd_set rset, wset, xset;
+    struct pollfd *f;
+    int ready;
+    int maxfd = 0;
+    char data[64];
+
+    FD_ZERO (&rset);
+    FD_ZERO (&wset);
+    FD_ZERO (&xset);
+
+    if (nfds == 0) {
+        if (timeout >= 0) {
+            pa_msleep(timeout);
+            return 0;
+        }
+
+        return select(0, NULL, NULL, NULL, NULL);
+    }
+
+    for (f = fds; f < &fds[nfds]; ++f) {
+        if (f->fd != -1) {
+            if (f->events & POLLIN)
+                FD_SET (f->fd, &rset);
+            if (f->events & POLLOUT)
+                FD_SET (f->fd, &wset);
+            if (f->events & POLLPRI)
+                FD_SET (f->fd, &xset);
+            if (f->fd > maxfd && (f->events & (POLLIN|POLLOUT|POLLPRI)))
+                maxfd = f->fd;
+        }
+    }
+
+    tv.tv_sec = timeout / 1000;
+    tv.tv_usec = (timeout % 1000) * 1000;
+
+    ready = select ((SELECT_TYPE_ARG1) maxfd + 1, SELECT_TYPE_ARG234 &rset,
+                    SELECT_TYPE_ARG234 &wset, SELECT_TYPE_ARG234 &xset,
+                    SELECT_TYPE_ARG5 (timeout == -1 ? NULL : &tv));
+    if ((ready == -1) && (errno == EBADF)) {
+        ready = 0;
+
+        FD_ZERO (&rset);
+        FD_ZERO (&wset);
+        FD_ZERO (&xset);
+
+        maxfd = -1;
+
+        for (f = fds; f < &fds[nfds]; ++f) {
+            if (f->fd != -1) {
+                fd_set sngl_rset, sngl_wset, sngl_xset;
+
+                FD_ZERO (&sngl_rset);
+                FD_ZERO (&sngl_wset);
+                FD_ZERO (&sngl_xset);
+
+                if (f->events & POLLIN)
+                    FD_SET (f->fd, &sngl_rset);
+                if (f->events & POLLOUT)
+                    FD_SET (f->fd, &sngl_wset);
+                if (f->events & POLLPRI)
+                    FD_SET (f->fd, &sngl_xset);
+                if (f->events & (POLLIN|POLLOUT|POLLPRI)) {
+                    struct timeval singl_tv;
+
+                    singl_tv.tv_sec = 0;
+                    singl_tv.tv_usec = 0;
+
+                    if (select((SELECT_TYPE_ARG1) f->fd, SELECT_TYPE_ARG234 &rset,
+                               SELECT_TYPE_ARG234 &wset, SELECT_TYPE_ARG234 &xset,
+                               SELECT_TYPE_ARG5 &singl_tv) != -1) {
+                        if (f->events & POLLIN)
+                            FD_SET (f->fd, &rset);
+                        if (f->events & POLLOUT)
+                            FD_SET (f->fd, &wset);
+                        if (f->events & POLLPRI)
+                            FD_SET (f->fd, &xset);
+                        if (f->fd > maxfd && (f->events & (POLLIN|POLLOUT|POLLPRI)))
+                            maxfd = f->fd;
+                        ++ready;
+                    } else if (errno == EBADF)
+                        f->revents |= POLLNVAL;
+                }
+            }
+        }
+
+        if (ready) {
+        /* Linux alters the tv struct... but it shouldn't matter here ...
+         * as we're going to be a little bit out anyway as we've just eaten
+         * more than a couple of cpu cycles above */
+            ready = select ((SELECT_TYPE_ARG1) maxfd + 1, SELECT_TYPE_ARG234 &rset,
+                            SELECT_TYPE_ARG234 &wset, SELECT_TYPE_ARG234 &xset,
+                            SELECT_TYPE_ARG5 (timeout == -1 ? NULL : &tv));
+        }
+    }
+
+    if (ready > 0) {
+        ready = 0;
+        for (f = fds; f < &fds[nfds]; ++f) {
+            f->revents = 0;
+            if (f->fd != -1) {
+                if (FD_ISSET (f->fd, &rset)) {
+                    /* support for POLLHUP.  An hung up descriptor does not
+                       increase the return value! */
+                    if (recv (f->fd, data, 64, MSG_PEEK) == -1) {
+                        if (errno == ESHUTDOWN || errno == ECONNRESET ||
+                            errno == ECONNABORTED || errno == ENETRESET) {
+                            fprintf(stderr, "Hangup\n");
+                            f->revents |= POLLHUP;
+                        }
+                    }
+
+                    if (f->revents == 0)
+                        f->revents |= POLLIN;
+                }
+                if (FD_ISSET (f->fd, &wset))
+                    f->revents |= POLLOUT;
+                if (FD_ISSET (f->fd, &xset))
+                    f->revents |= POLLPRI;
+            }
+            if (f->revents)
+                ready++;
+        }
+    }
+
+    return ready;
+}
+
+#endif /* HAVE_SYS_POLL_H */
diff --git a/polyp/poll.h b/polyp/poll.h
new file mode 100644
index 0000000..573f90e
--- /dev/null
+++ b/polyp/poll.h
@@ -0,0 +1,57 @@
+/* $Id: mainloop.c 302 2004-11-21 17:02:25Z lennart $ */
+
+/***
+   Compatibility definitions for System V `poll' interface.
+   Copyright (C) 1994,96,97,98,99,2000,2001,2004 Free Software Foundation, Inc.
+   Copyright (C) 2005, Cendio AB.
+   This file is part of polypaudio.
+   Based on work for the GNU C Library.
+
+   polypaudio is free software; you can redistribute it and/or modify it
+   under the terms of the GNU Library General Public License as published
+   by the Free Software Foundation; either version 2 of the License, or
+   (at your option) any later version.
+
+   polypaudio 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
+   Library General Public License for more details.
+
+   You should have received a copy of the GNU Library General Public
+   License along with polypaudio; If not, write to the Free Software
+   Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
+   USA.
+***/
+
+/* Event types that can be polled for.  These bits may be set in `events'
+   to indicate the interesting event types; they will appear in `revents'
+   to indicate the status of the file descriptor.  */
+#define POLLIN          0x001           /* There is data to read.  */
+#define POLLPRI         0x002           /* There is urgent data to read.  */
+#define POLLOUT         0x004           /* Writing now will not block.  */
+
+/* Event types always implicitly polled for.  These bits need not be set in
+   `events', but they will appear in `revents' to indicate the status of
+   the file descriptor.  */
+#define POLLERR         0x008           /* Error condition.  */
+#define POLLHUP         0x010           /* Hung up.  */
+#define POLLNVAL        0x020           /* Invalid polling request.  */
+
+
+/* Type used for the number of file descriptors.  */
+typedef unsigned long int nfds_t;
+
+/* Data structure describing a polling request.  */
+struct pollfd
+  {
+    int fd;                     /* File descriptor to poll.  */
+    short int events;           /* Types of events poller cares about.  */
+    short int revents;          /* Types of events that actually occurred.  */
+  };
+
+/* Poll the file descriptors described by the NFDS structures starting at
+   FDS.  If TIMEOUT is nonzero and not -1, allow TIMEOUT milliseconds for
+   an event to occur; if TIMEOUT is -1, block until an event occurs.
+   Returns the number of file descriptors with events, zero if timed out,
+   or -1 for errors.  */
+extern int poll (struct pollfd *__fds, nfds_t __nfds, int __timeout);

commit e28ce8c59f193f53f1c722f3d54238e6d35de731
Author: Pierre Ossman <ossman at cendio.se>
Date:   Thu Jan 5 21:01:52 2006 +0000

    Use pa_get_path_filename() instead of duplicating code.
    
    
    git-svn-id: file:///home/lennart/svn/public/pulseaudio/branches/ossman@398 fefdeb5f-60dc-0310-8127-8f9354f1896f

diff --git a/polyp/dumpmodules.c b/polyp/dumpmodules.c
index 1dc14ed..5aaa108 100644
--- a/polyp/dumpmodules.c
+++ b/polyp/dumpmodules.c
@@ -31,6 +31,7 @@
 
 #include "dumpmodules.h"
 #include "modinfo.h"
+#include "util.h"
 
 #define PREFIX "module-"
 
@@ -80,10 +81,7 @@ static int callback(const char *path, lt_ptr data) {
     const char *e;
     struct pa_daemon_conf *c = (data);
 
-    if ((e = (const char*) strrchr(path, '/')))
-        e++;
-    else
-        e = path;
+    e = pa_path_get_filename(path);
 
     if (strlen(e) > sizeof(PREFIX)-1 && !strncmp(e, PREFIX, sizeof(PREFIX)-1))
         show_info(e, path, c->log_level >= PA_LOG_INFO ? long_info : short_info);

commit 8f3c364b4700c8e459269ff00dbe810503038639
Author: Pierre Ossman <ossman at cendio.se>
Date:   Thu Jan 5 21:15:09 2006 +0000

    Make sure all socket headers are protected by ifdefs.
    
    
    git-svn-id: file:///home/lennart/svn/public/pulseaudio/branches/ossman@399 fefdeb5f-60dc-0310-8127-8f9354f1896f

diff --git a/configure.ac b/configure.ac
index 2d75332..8200383 100644
--- a/configure.ac
+++ b/configure.ac
@@ -119,9 +119,9 @@ AM_CONDITIONAL(OS_IS_WIN32, test "x$os_is_win32" = "x1")
 AC_HEADER_STDC
 
 # POSIX
-AC_CHECK_HEADERS([glob.h grp.h netdb.h netinet/in.h netinet/tcp.h pwd.h \
-    sched.h sys/capability.h sys/resource.h sys/select.h sys/socket.h \
-    syslog.h])
+AC_CHECK_HEADERS([arpa/inet.h glob.h grp.h netdb.h netinet/in.h \
+    netinet/in_systm.h netinet/ip.h netinet/tcp.h pwd.h sched.h \
+    sys/capability.h sys/resource.h sys/select.h sys/socket.h syslog.h])
 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])
 
diff --git a/polyp/module-protocol-stub.c b/polyp/module-protocol-stub.c
index 1569758..0b91c68 100644
--- a/polyp/module-protocol-stub.c
+++ b/polyp/module-protocol-stub.c
@@ -27,9 +27,14 @@
 #include <errno.h>
 #include <stdio.h>
 #include <assert.h>
-#include <arpa/inet.h>
 #include <unistd.h>
+
+#ifdef HAVE_ARPA_INET_H
+#include <arpa/inet.h>
+#endif
+#ifdef HAVE_NETINET_IN_H
 #include <netinet/in.h>
+#endif
 
 #include "module.h"
 #include "socket-server.h"
diff --git a/polyp/polyplib-context.c b/polyp/polyplib-context.c
index f54cabb..f85c5a4 100644
--- a/polyp/polyplib-context.c
+++ b/polyp/polyplib-context.c
@@ -28,14 +28,19 @@
 #include <stdlib.h>
 #include <string.h>
 #include <sys/types.h>
-#include <sys/socket.h>
-#include <netdb.h>
 #include <unistd.h>
 #include <sys/stat.h>
 #include <errno.h>
 #include <sys/wait.h>
 #include <signal.h>
 
+#ifdef HAVE_SYS_SOCKET_H
+#include <sys/socket.h>
+#endif
+#ifdef HAVE_NETDB_H
+#include <netdb.h>
+#endif
+
 #include "polyplib-internal.h"
 #include "polyplib-context.h"
 #include "native-common.h"
diff --git a/polyp/pstream.c b/polyp/pstream.c
index c081c24..a64856d 100644
--- a/polyp/pstream.c
+++ b/polyp/pstream.c
@@ -27,7 +27,10 @@
 #include <stdlib.h>
 #include <assert.h>
 #include <unistd.h>
+
+#ifdef HAVE_NETINET_IN_H
 #include <netinet/in.h>
+#endif
 
 #include "pstream.h"
 #include "queue.h"
diff --git a/polyp/socket-client.c b/polyp/socket-client.c
index 58bc7e8..0d712fa 100644
--- a/polyp/socket-client.c
+++ b/polyp/socket-client.c
@@ -31,14 +31,22 @@
 #include <string.h>
 #include <assert.h>
 #include <stdlib.h>
-#include <sys/socket.h>
-#include <netinet/in.h>
-#include <arpa/inet.h>
-#include <netdb.h>
 
+#ifdef HAVE_SYS_SOCKET_H
+#include <sys/socket.h>
+#endif
 #ifdef HAVE_SYS_UN_H
 #include <sys/un.h>
 #endif
+#ifdef HAVE_ARPA_INET_H
+#include <arpa/inet.h>
+#endif
+#ifdef HAVE_NETINET_IN_H
+#include <netinet/in.h>
+#endif
+#ifdef HAVE_NETDB_H
+#include <netdb.h>
+#endif
 
 #ifdef HAVE_LIBASYNCNS
 #include <asyncns.h>
diff --git a/polyp/socket-server.c b/polyp/socket-server.c
index ed86bc2..0cca4ae 100644
--- a/polyp/socket-server.c
+++ b/polyp/socket-server.c
@@ -28,15 +28,21 @@
 #include <errno.h>
 #include <string.h>
 #include <sys/types.h>
-#include <sys/socket.h>
 #include <stdio.h>
 #include <unistd.h>
-#include <netinet/in.h>
-#include <arpa/inet.h>
 
+#ifdef HAVE_SYS_SOCKET_H
+#include <sys/socket.h>
+#endif
 #ifdef HAVE_SYS_UN_H
 #include <sys/un.h>
 #endif
+#ifdef HAVE_ARPA_INET_H
+#include <arpa/inet.h>
+#endif
+#ifdef HAVE_NETINET_IN_H
+#include <netinet/in.h>
+#endif
 
 #ifdef HAVE_LIBWRAP
 #include <tcpd.h>
diff --git a/polyp/socket-util.c b/polyp/socket-util.c
index eb6b424..60f8d16 100644
--- a/polyp/socket-util.c
+++ b/polyp/socket-util.c
@@ -31,19 +31,31 @@
 #include <string.h>
 #include <stdio.h>
 #include <sys/types.h>
-#include <netinet/in.h>
 #include <fcntl.h>
 #include <unistd.h>
-#include <netinet/in_systm.h>
-#include <netinet/tcp.h>
-#include <netinet/ip.h>
-#include <sys/socket.h>
 #include <sys/stat.h>
-#include <netdb.h>
 
+#ifdef HAVE_SYS_SOCKET_H
+#include <sys/socket.h>
+#endif
 #ifdef HAVE_SYS_UN_H
 #include <sys/un.h>
 #endif
+#ifdef HAVE_NETINET_IN_H
+#include <netinet/in.h>
+#endif
+#ifdef HAVE_NETINET_IN_SYSTM_H
+#include <netinet/in_systm.h>
+#endif
+#ifdef HAVE_NETINET_IP_H
+#include <netinet/ip.h>
+#endif
+#ifdef HAVE_NETINET_TCP_H
+#include <netinet/tcp.h>
+#endif
+#ifdef HAVE_NETDB_H
+#include <netdb.h>
+#endif
 
 #include "socket-util.h"
 #include "util.h"
diff --git a/polyp/tagstruct.c b/polyp/tagstruct.c
index a6dad86..a3bd7d9 100644
--- a/polyp/tagstruct.c
+++ b/polyp/tagstruct.c
@@ -27,9 +27,12 @@
 #include <string.h>
 #include <unistd.h>
 #include <sys/time.h>
-#include <netinet/in.h>
 #include <assert.h>
 
+#ifdef HAVE_NETINET_IN_H
+#include <netinet/in.h>
+#endif
+
 #include "tagstruct.h"
 #include "xmalloc.h"
 
diff --git a/polyp/util.c b/polyp/util.c
index 9e8dc5e..67eaeda 100644
--- a/polyp/util.c
+++ b/polyp/util.c
@@ -41,7 +41,10 @@
 #include <sys/resource.h>
 #include <limits.h>
 #include <unistd.h>
+
+#ifdef HAVE_NETDB_H
 #include <netdb.h>
+#endif
 
 #include <samplerate.h>
 

commit 268aebb2e44d772e3cff25d40403a720f80abd09
Author: Pierre Ossman <ossman at cendio.se>
Date:   Thu Jan 5 21:21:51 2006 +0000

    Protect sys/wait.h with an ifdef.
    
    
    git-svn-id: file:///home/lennart/svn/public/pulseaudio/branches/ossman@400 fefdeb5f-60dc-0310-8127-8f9354f1896f

diff --git a/configure.ac b/configure.ac
index 8200383..981c74c 100644
--- a/configure.ac
+++ b/configure.ac
@@ -121,7 +121,8 @@ AC_HEADER_STDC
 # POSIX
 AC_CHECK_HEADERS([arpa/inet.h glob.h grp.h netdb.h netinet/in.h \
     netinet/in_systm.h netinet/ip.h netinet/tcp.h pwd.h sched.h \
-    sys/capability.h sys/resource.h sys/select.h sys/socket.h syslog.h])
+    sys/capability.h sys/resource.h sys/select.h sys/socket.h sys/wait.h \
+    syslog.h])
 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])
 
diff --git a/polyp/polyplib-context.c b/polyp/polyplib-context.c
index f85c5a4..1b9d7de 100644
--- a/polyp/polyplib-context.c
+++ b/polyp/polyplib-context.c
@@ -31,9 +31,12 @@
 #include <unistd.h>
 #include <sys/stat.h>
 #include <errno.h>
-#include <sys/wait.h>
 #include <signal.h>
 
+#ifdef HAVE_SYS_WAIT_H
+#include <sys/wait.h>
+#endif
+
 #ifdef HAVE_SYS_SOCKET_H
 #include <sys/socket.h>
 #endif

commit e2495c7600f45cd3803cdc86fe0fe0cb11d6dfd5
Author: Pierre Ossman <ossman at cendio.se>
Date:   Thu Jan 5 21:24:39 2006 +0000

    We need explicit actions here.
    
    
    git-svn-id: file:///home/lennart/svn/public/pulseaudio/branches/ossman@401 fefdeb5f-60dc-0310-8127-8f9354f1896f

diff --git a/configure.ac b/configure.ac
index 981c74c..5411296 100644
--- a/configure.ac
+++ b/configure.ac
@@ -155,7 +155,7 @@ AC_TYPE_OFF_T
 AC_TYPE_SIGNAL
 AC_TYPE_UID_T
 
-AC_CHECK_DEFINE([SIGXCPU], [signal.h])
+AC_CHECK_DEFINE([SIGXCPU], [signal.h], [HAVE_SIGXCPU=1], [HAVE_SIGXCPU=0])
 AM_CONDITIONAL(HAVE_SIGXCPU, test "x$HAVE_SIGXCPU" = "x1")
 
 #### Check for functions ####

commit 971e370a2fdc6496fab680844393955de8d3eed2
Author: Pierre Ossman <ossman at cendio.se>
Date:   Thu Jan 5 21:33:01 2006 +0000

    Add possibility for linking semi-static executables (libtools definition
    of static).
    
    
    git-svn-id: file:///home/lennart/svn/public/pulseaudio/branches/ossman@402 fefdeb5f-60dc-0310-8127-8f9354f1896f

diff --git a/configure.ac b/configure.ac
index 5411296..08f7e2b 100644
--- a/configure.ac
+++ b/configure.ac
@@ -291,6 +291,12 @@ AM_CONDITIONAL([HAVE_LIRC], [test "x$HAVE_LIRC" = x1])
 #            Output               #
 ###################################
 
+AC_ARG_ENABLE(
+        [static-bins],
+        AC_HELP_STRING([--enable-static-bins],[Statically link executables.]),
+        [STATIC_BINS=1], [STATIC_BINS=0])
+AM_CONDITIONAL([STATIC_BINS], [test "x$STATIC_BINS" = "x1"])
+
 AC_CONFIG_FILES([
 Makefile
 polyp/Makefile
diff --git a/polyp/Makefile.am b/polyp/Makefile.am
index 6ec75d4..2e8361c 100644
--- a/polyp/Makefile.am
+++ b/polyp/Makefile.am
@@ -47,6 +47,10 @@ AM_LDADD = $(PTHREAD_LIBS)
 # Only required on some platforms but defined for all to avoid errors
 AM_LDFLAGS = -no-undefined
 
+if STATIC_BINS
+BINLDFLAGS = -static
+endif
+
 if OS_IS_WIN32
 AM_LDFLAGS+=-Wl,--export-all-symbols
 WINSOCK_LIBS=-lwsock32 -lws2_32 -lwininet
@@ -89,7 +93,7 @@ polypaudio_CFLAGS = $(AM_CFLAGS)
 polypaudio_CPPFLAGS = $(AM_CPPFLAGS)
 polypaudio_LDADD = $(AM_LDADD) libpolypcore.la $(LIBLTDL) \
 		$(LIBSAMPLERATE_LIBS) $(LIBSNDFILE_LIBS) $(CAP_LIBS)
-polypaudio_LDFLAGS= $(AM_LDFLAGS) -dlopen force 
+polypaudio_LDFLAGS= $(AM_LDFLAGS) $(BINLDFLAGS) -dlopen force 
 #q-static $(foreach f,$(modlib_LTLIBRARIES),-dlpreopen $(f))
 
 ###################################
@@ -118,26 +122,32 @@ bin_SCRIPTS = esdcompat.sh
 pacat_SOURCES = pacat.c
 pacat_LDADD = $(AM_LDADD) libpolyp- at PA_MAJORMINOR@.la libpolyp-error- at PA_MAJORMINOR@.la libpolyp-mainloop- at PA_MAJORMINOR@.la
 pacat_CFLAGS = $(AM_CFLAGS) 
+pacat_LDFLAGS = $(AM_LDFLAGS) $(BINLDFLAGS)
 
 paplay_SOURCES = paplay.c
 paplay_LDADD = $(AM_LDADD) libpolyp- at PA_MAJORMINOR@.la libpolyp-error- at PA_MAJORMINOR@.la libpolyp-mainloop- at PA_MAJORMINOR@.la $(LIBSNDFILE_LIBS)
 paplay_CFLAGS = $(AM_CFLAGS) $(LIBSNDFILE_CFLAGS)
+paplay_LDFLAGS = $(AM_LDFLAGS) $(BINLDFLAGS)
 
 pactl_SOURCES = pactl.c
 pactl_LDADD = $(AM_LDADD) libpolyp- at PA_MAJORMINOR@.la libpolyp-error- at PA_MAJORMINOR@.la libpolyp-mainloop- at PA_MAJORMINOR@.la $(LIBSNDFILE_LIBS)
 pactl_CFLAGS = $(AM_CFLAGS) $(LIBSNDFILE_CFLAGS)
+pactl_LDFLAGS = $(AM_LDFLAGS) $(BINLDFLAGS)
 
 pacmd_SOURCES = pacmd.c util.c util.h xmalloc.c xmalloc.h log.c log.h pid.c pid.h
 pacmd_CFLAGS = $(AM_CFLAGS)
 pacmd_LDADD = $(AM_LDADD)
+pacmd_LDFLAGS = $(AM_LDFLAGS) $(BINLDFLAGS)
 
 pax11publish_SOURCES = pax11publish.c util.c util.h xmalloc.c xmalloc.h log.c log.h authkey.c authkey.h client-conf.c client-conf.h conf-parser.c conf-parser.h x11prop.c x11prop.h random.c random.h
 pax11publish_CFLAGS = $(AM_CFLAGS) $(X_CFLAGS)
 pax11publish_LDADD = $(AM_LDADD) $(X_PRE_LIBS) -lX11 $(X_LIBS) $(X_EXTRA_LIBS)
+pax11publish_LDFLAGS = $(AM_LDFLAGS) $(BINLDFLAGS)
 
 pabrowse_SOURCES = pabrowse.c
 pabrowse_LDADD = $(AM_LDADD) libpolyp- at PA_MAJORMINOR@.la libpolyp-error- at PA_MAJORMINOR@.la libpolyp-mainloop- at PA_MAJORMINOR@.la libpolyp-browse- at PA_MAJORMINOR@.la
 pabrowse_CFLAGS = $(AM_CFLAGS)
+pabrowse_LDFLAGS = $(AM_LDFLAGS) $(BINLDFLAGS)
 
 ###################################
 #         Test programs           #
@@ -170,42 +180,52 @@ endif
 mainloop_test_SOURCES = mainloop-test.c
 mainloop_test_CFLAGS = $(AM_CFLAGS)
 mainloop_test_LDADD = $(AM_LDADD) libpolyp-mainloop- at PA_MAJORMINOR@.la libpolyp- at PA_MAJORMINOR@.la
+mainloop_test_LDFLAGS = $(AM_LDFLAGS) $(BINLDFLAGS)
 
 mcalign_test_SOURCES = mcalign-test.c util.c util.h xmalloc.c xmalloc.h log.c log.h mcalign.c mcalign.h memchunk.c memchunk.h memblock.c memblock.h
 mcalign_test_CFLAGS = $(AM_CFLAGS)
 mcalign_test_LDADD = $(AM_LDADD) $(WINSOCK_LIBS)
+mcalign_test_LDFLAGS = $(AM_LDFLAGS) $(BINLDFLAGS)
 
 pacat_simple_SOURCES = pacat-simple.c
 pacat_simple_LDADD = $(AM_LDADD) libpolyp- at PA_MAJORMINOR@.la libpolyp-simple- at PA_MAJORMINOR@.la libpolyp-error- at PA_MAJORMINOR@.la libpolyp-mainloop- at PA_MAJORMINOR@.la
 pacat_simple_CFLAGS = $(AM_CFLAGS)
+pacat_simple_LDFLAGS = $(AM_LDFLAGS) $(BINLDFLAGS)
 
 parec_simple_SOURCES = parec-simple.c
 parec_simple_LDADD = $(AM_LDADD) libpolyp- at PA_MAJORMINOR@.la libpolyp-simple- at PA_MAJORMINOR@.la libpolyp-error- at PA_MAJORMINOR@.la libpolyp-mainloop- at PA_MAJORMINOR@.la
 parec_simple_CFLAGS = $(AM_CFLAGS)
+parec_simple_LDFLAGS = $(AM_LDFLAGS) $(BINLDFLAGS)
 
 strlist_test_SOURCES = strlist-test.c strlist.c strlist.h strbuf.c strbuf.h util.c util.h xmalloc.c xmalloc.h log.c log.h
 strlist_test_CFLAGS = $(AM_CFLAGS)
 strlist_test_LDADD = $(AM_LDADD) $(WINSOCK_LIBS)
+strlist_test_LDFLAGS = $(AM_LDFLAGS) $(BINLDFLAGS)
 
 voltest_SOURCES = voltest.c sample.c
 voltest_CFLAGS = $(AM_CFLAGS)
 voltest_LDADD = $(AM_LDADD)
+voltest_LDFLAGS = $(AM_LDFLAGS) $(BINLDFLAGS)
 
 cpulimit_test_SOURCES = cpulimit-test.c cpulimit.c util.c log.c cpulimit.h util.h log.h
 cpulimit_test_CFLAGS = $(AM_CFLAGS)
 cpulimit_test_LDADD = $(AM_LDADD) libpolyp-mainloop- at PA_MAJORMINOR@.la
+cpulimit_test_LDFLAGS = $(AM_LDFLAGS) $(BINLDFLAGS)
 
 cpulimit_test2_SOURCES = cpulimit-test.c cpulimit.c util.c log.c cpulimit.h util.h log.h
 cpulimit_test2_CFLAGS = $(AM_CFLAGS) -DTEST2
 cpulimit_test2_LDADD = $(AM_LDADD) libpolyp-mainloop- at PA_MAJORMINOR@.la
+cpulimit_test2_LDFLAGS = $(AM_LDFLAGS) $(BINLDFLAGS)
 
 mainloop_test_glib_SOURCES = $(mainloop_test_SOURCES)
 mainloop_test_glib_CFLAGS = $(mainloop_test_CFLAGS) $(GLIB20_CFLAGS) -DGLIB_MAIN_LOOP
 mainloop_test_glib_LDADD = $(mainloop_test_LDADD) $(GLIB20_LIBS) libpolyp-mainloop-glib- at PA_MAJORMINOR@.la
+mainloop_test_glib_LDFLAGS = $(AM_LDFLAGS) $(BINLDFLAGS)
 
 mainloop_test_glib12_SOURCES = $(mainloop_test_SOURCES)
 mainloop_test_glib12_CFLAGS = $(mainloop_test_CFLAGS) $(GLIB12_CFLAGS) -DGLIB_MAIN_LOOP
 mainloop_test_glib12_LDADD = $(mainloop_test_LDADD) $(GLIB12_LIBS) libpolyp-mainloop-glib12- at PA_MAJORMINOR@.la
+mainloop_test_glib12_LDFLAGS = $(AM_LDFLAGS) $(BINLDFLAGS)
 
 ###################################
 #         Client library          #

commit 9550c8ed80dee1aa7ced2d18144fd7b1a3b5a395
Author: Pierre Ossman <ossman at cendio.se>
Date:   Thu Jan 5 21:37:00 2006 +0000

    No need for conditional generation of symdef files.
    
    
    git-svn-id: file:///home/lennart/svn/public/pulseaudio/branches/ossman@403 fefdeb5f-60dc-0310-8127-8f9354f1896f

diff --git a/polyp/Makefile.am b/polyp/Makefile.am
index 2e8361c..614a187 100644
--- a/polyp/Makefile.am
+++ b/polyp/Makefile.am
@@ -744,25 +744,13 @@ SYMDEF_FILES = \
 		module-mmkbd-evdev-symdef.h \
 		module-http-protocol-tcp-symdef.h \
 		module-http-protocol-tcp6-symdef.h \
-		module-http-protocol-unix-symdef.h
-
-if HAVE_X11
-SYMDEF_FILES += \
+		module-http-protocol-unix-symdef.h \
 		module-x11-bell-symdef.h \
-		module-x11-publish-symdef.h
-endif
-
-if !OS_IS_WIN32
-SYMDEF_FILES += \
+		module-x11-publish-symdef.h \
 		module-oss-symdef.h \
-		module-oss-mmap-symdef.h
-endif
-
-if HAVE_ALSA
-SYMDEF_FILES += \
+		module-oss-mmap-symdef.h \
 		module-alsa-sink-symdef.h \
 		module-alsa-source-symdef.h
-endif
 
 EXTRA_DIST += $(SYMDEF_FILES)
 BUILT_SOURCES += $(SYMDEF_FILES)

commit be2ba901751755f1673b0559a29fdcb9ca651405
Author: Pierre Ossman <ossman at cendio.se>
Date:   Thu Jan 5 21:39:49 2006 +0000

    Add option to select which modules get linked in during static builds.
    
    
    git-svn-id: file:///home/lennart/svn/public/pulseaudio/branches/ossman@404 fefdeb5f-60dc-0310-8127-8f9354f1896f

diff --git a/configure.ac b/configure.ac
index 08f7e2b..941be8b 100644
--- a/configure.ac
+++ b/configure.ac
@@ -297,6 +297,20 @@ AC_ARG_ENABLE(
         [STATIC_BINS=1], [STATIC_BINS=0])
 AM_CONDITIONAL([STATIC_BINS], [test "x$STATIC_BINS" = "x1"])
 
+AC_ARG_WITH(
+        [preopen-mods],
+        AC_HELP_STRING([--with-preopen-mods],[Modules to preopen in daemon (default: all).]),
+        [PREOPEN_MODS=$withval], [PREOPEN_MODS="all"])
+AM_CONDITIONAL([PREOPEN_MODS], [test "x$PREOPEN_MODS" != "xall"])
+if test "x$PREOPEN_MODS" != "xall" ; then
+    tmpLIBS=""
+    for mod in $PREOPEN_MODS; do
+        tmpLIBS="$tmpLIBS module-$mod.la"
+    done
+    PREOPEN_MODS="$tmpLIBS"
+    AC_SUBST(PREOPEN_MODS)
+fi
+
 AC_CONFIG_FILES([
 Makefile
 polyp/Makefile
diff --git a/polyp/Makefile.am b/polyp/Makefile.am
index 614a187..a066813 100644
--- a/polyp/Makefile.am
+++ b/polyp/Makefile.am
@@ -93,8 +93,13 @@ polypaudio_CFLAGS = $(AM_CFLAGS)
 polypaudio_CPPFLAGS = $(AM_CPPFLAGS)
 polypaudio_LDADD = $(AM_LDADD) libpolypcore.la $(LIBLTDL) \
 		$(LIBSAMPLERATE_LIBS) $(LIBSNDFILE_LIBS) $(CAP_LIBS)
-polypaudio_LDFLAGS= $(AM_LDFLAGS) $(BINLDFLAGS) -dlopen force 
-#q-static $(foreach f,$(modlib_LTLIBRARIES),-dlpreopen $(f))
+polypaudio_LDFLAGS = $(AM_LDFLAGS) $(BINLDFLAGS) -dlopen force $(foreach f,$(PREOPEN_LIBS),-dlopen $(f))
+
+if PREOPEN_MODS
+PREOPEN_LIBS = $(PREOPEN_MODS)
+else
+PREOPEN_LIBS = $(modlib_LTLIBRARIES)
+endif
 
 ###################################
 #       Utility programs          #

commit 08bbfd2169ff81e37f0e5bd911490fc07b8f05f9
Author: Pierre Ossman <ossman at cendio.se>
Date:   Thu Jan 5 21:46:10 2006 +0000

    Make it possible to disable caps support since it breaks fully static
    builds.
    
    
    git-svn-id: file:///home/lennart/svn/public/pulseaudio/branches/ossman@405 fefdeb5f-60dc-0310-8127-8f9354f1896f

diff --git a/configure.ac b/configure.ac
index 941be8b..5f8da07 100644
--- a/configure.ac
+++ b/configure.ac
@@ -210,7 +210,15 @@ fi
 
 #### Capabilities (optional) ####
 
-AC_CHECK_LIB(cap, cap_init, [CAP_LIBS='-lcap'], [CAP_LIBS=''])
+CAP_LIBS=''
+
+AC_ARG_WITH(
+        [caps],
+        AC_HELP_STRING([--without-caps],[Omit support for POSIX capabilities.]))
+
+if test "x${with_caps}" != "xno"; then
+    AC_CHECK_LIB(cap, cap_init, [CAP_LIBS='-lcap'], [CAP_LIBS=''])
+fi
 AC_SUBST(CAP_LIBS)
 
 #### Sample rate conversion ####

commit 2cf165db8bbcf43d9be3404f9566d523c8d6e323
Author: Pierre Ossman <ossman at cendio.se>
Date:   Thu Jan 5 21:49:22 2006 +0000

    ifdef-protect setpgid and setsid.
    
    
    git-svn-id: file:///home/lennart/svn/public/pulseaudio/branches/ossman@406 fefdeb5f-60dc-0310-8127-8f9354f1896f

diff --git a/configure.ac b/configure.ac
index 5f8da07..1899e92 100644
--- a/configure.ac
+++ b/configure.ac
@@ -168,7 +168,7 @@ AC_FUNC_FORK
 AC_FUNC_GETGROUPS
 AC_FUNC_SELECT_ARGTYPES
 AC_CHECK_FUNCS([getaddrinfo getgrgid_r getpwuid_r gettimeofday getuid \
-    inet_ntop nanosleep sigaction sleep])
+    inet_ntop nanosleep setpgid setsid sigaction sleep])
 AC_CHECK_FUNCS([mkfifo], [HAVE_MKFIFO=1], [HAVE_MKFIFO=0])
 
 AM_CONDITIONAL(HAVE_MKFIFO, test "x$HAVE_MKFIFO" = "x1")
diff --git a/polyp/main.c b/polyp/main.c
index 2e97e5c..a56d2f1 100644
--- a/polyp/main.c
+++ b/polyp/main.c
@@ -258,8 +258,12 @@ int main(int argc, char *argv[]) {
         if (conf->auto_log_target)
             pa_log_set_target(PA_LOG_SYSLOG, NULL);
 
+#ifdef HAVE_SETSID
         setsid();
+#endif
+#ifdef HAVE_SETPGID
         setpgid(0,0);
+#endif
         
         close(0);
         close(1);

commit 7aba34bc4e3835dd84f13506555702993a3eeacc
Author: Pierre Ossman <ossman at cendio.se>
Date:   Thu Jan 5 21:56:33 2006 +0000

    config.h should always be included so that necessary fixes can take effect.
    
    
    git-svn-id: file:///home/lennart/svn/public/pulseaudio/branches/ossman@407 fefdeb5f-60dc-0310-8127-8f9354f1896f

diff --git a/polyp/conf-parser.c b/polyp/conf-parser.c
index b25508e..8d2f2f6 100644
--- a/polyp/conf-parser.c
+++ b/polyp/conf-parser.c
@@ -19,6 +19,10 @@
   USA.
 ***/
 
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
 #include <assert.h>
 #include <string.h>
 #include <stdio.h>

commit 983fdb3238ec717208cd354fc4e487bd69bf1d30
Author: Pierre Ossman <ossman at cendio.se>
Date:   Thu Jan 5 22:05:20 2006 +0000

    Stub uses socket defines so include the header.
    
    
    git-svn-id: file:///home/lennart/svn/public/pulseaudio/branches/ossman@408 fefdeb5f-60dc-0310-8127-8f9354f1896f

diff --git a/polyp/module-protocol-stub.c b/polyp/module-protocol-stub.c
index 0b91c68..37a17c8 100644
--- a/polyp/module-protocol-stub.c
+++ b/polyp/module-protocol-stub.c
@@ -29,6 +29,9 @@
 #include <assert.h>
 #include <unistd.h>
 
+#ifdef HAVE_SYS_SOCKET_H
+#include <sys/socket.h>
+#endif
 #ifdef HAVE_ARPA_INET_H
 #include <arpa/inet.h>
 #endif

commit ecaf8d805e8d061d1f882132012cf0c1060d1b04
Author: Pierre Ossman <ossman at cendio.se>
Date:   Thu Jan 5 22:06:52 2006 +0000

    PATH_MAX is defined in limits.h.
    
    
    git-svn-id: file:///home/lennart/svn/public/pulseaudio/branches/ossman@409 fefdeb5f-60dc-0310-8127-8f9354f1896f

diff --git a/polyp/module-protocol-stub.c b/polyp/module-protocol-stub.c
index 37a17c8..7cd5ed3 100644
--- a/polyp/module-protocol-stub.c
+++ b/polyp/module-protocol-stub.c
@@ -28,6 +28,7 @@
 #include <stdio.h>
 #include <assert.h>
 #include <unistd.h>
+#include <limits.h>
 
 #ifdef HAVE_SYS_SOCKET_H
 #include <sys/socket.h>

commit 5ac2cb90f73116f7c3ccadd4d89c26c01e3c6c0e
Author: Pierre Ossman <ossman at cendio.se>
Date:   Thu Jan 5 22:09:40 2006 +0000

    No regexp funtions are used in this file.
    
    
    git-svn-id: file:///home/lennart/svn/public/pulseaudio/branches/ossman@410 fefdeb5f-60dc-0310-8127-8f9354f1896f

diff --git a/polyp/module-tunnel.c b/polyp/module-tunnel.c
index 749aebf..c6a35ca 100644
--- a/polyp/module-tunnel.c
+++ b/polyp/module-tunnel.c
@@ -28,7 +28,6 @@
 #include <string.h>
 #include <errno.h>
 #include <sys/types.h>
-#include <regex.h>
 #include <stdio.h>
 #include <stdlib.h>
 

commit 010476f226124292e05d26ddbb931827beccd39e
Author: Pierre Ossman <ossman at cendio.se>
Date:   Thu Jan 5 22:12:25 2006 +0000

    Protect getuid() with an ifdef.
    
    
    git-svn-id: file:///home/lennart/svn/public/pulseaudio/branches/ossman@411 fefdeb5f-60dc-0310-8127-8f9354f1896f

diff --git a/polyp/caps.c b/polyp/caps.c
index 739e707..4ecb584 100644
--- a/polyp/caps.c
+++ b/polyp/caps.c
@@ -35,6 +35,8 @@
 #include "log.h"
 #include "caps.h"
 
+#ifdef HAVE_GETUID
+
 /* Drop root rights when called SUID root */
 void pa_drop_root(void) {
     uid_t uid = getuid();
@@ -54,6 +56,13 @@ void pa_drop_root(void) {
 #endif
 }
 
+#else
+
+void pa_drop_root(void) {
+}
+
+#endif
+
 #ifdef HAVE_SYS_CAPABILITY_H
 
 /* Limit capabilities set to CAPSYS_NICE */
diff --git a/polyp/main.c b/polyp/main.c
index a56d2f1..12b6b83 100644
--- a/polyp/main.c
+++ b/polyp/main.c
@@ -117,18 +117,25 @@ int main(int argc, char *argv[]) {
     char *s;
     int r, retval = 1, d = 0;
     int daemon_pipe[2] = { -1, -1 };
-    gid_t gid = (gid_t) -1;
     int suid_root;
     int valid_pid_file = 0;
 
+#ifdef HAVE_GETUID
+    gid_t gid = (gid_t) -1;
+#endif
+
     pa_limit_caps();
 
+#ifdef HAVE_GETUID
     suid_root = getuid() != 0 && geteuid() == 0;
     
     if (suid_root && (pa_uid_in_group("realtime", &gid) <= 0 || gid >= 1000)) {
         pa_log_warn(__FILE__": WARNING: called SUID root, but not in group 'realtime'.\n");
         pa_drop_root();
     }
+#else
+    suid_root = 0;
+#endif
     
     LTDL_SET_PRELOADED_SYMBOLS();
     

commit e72bbdb21744fe5c0ab3494126656518f4bcb524
Author: Pierre Ossman <ossman at cendio.se>
Date:   Thu Jan 5 22:14:22 2006 +0000

    c was used before it was assigned.
    
    
    git-svn-id: file:///home/lennart/svn/public/pulseaudio/branches/ossman@412 fefdeb5f-60dc-0310-8127-8f9354f1896f

diff --git a/polyp/main.c b/polyp/main.c
index 12b6b83..3f9f359 100644
--- a/polyp/main.c
+++ b/polyp/main.c
@@ -311,6 +311,9 @@ int main(int argc, char *argv[]) {
     mainloop = pa_mainloop_new();
     assert(mainloop);
 
+    c = pa_core_new(pa_mainloop_get_api(mainloop));
+    assert(c);
+
     r = pa_signal_init(pa_mainloop_get_api(mainloop));
     assert(r == 0);
     pa_signal_new(SIGINT, signal_callback, c);
@@ -319,8 +322,6 @@ int main(int argc, char *argv[]) {
     signal(SIGPIPE, SIG_IGN);
 #endif
 
-    c = pa_core_new(pa_mainloop_get_api(mainloop));
-    assert(c);
     if (conf->daemonize)
         c->running_as_daemon = 1;
     

commit 2c4d42e7817d2bac20bcd71d603be1389b8d9337
Author: Pierre Ossman <ossman at cendio.se>
Date:   Thu Jan 5 22:27:14 2006 +0000

    ctime_r() is not available everywhere.
    
    
    git-svn-id: file:///home/lennart/svn/public/pulseaudio/branches/ossman@413 fefdeb5f-60dc-0310-8127-8f9354f1896f

diff --git a/polyp/cli-command.c b/polyp/cli-command.c
index 0e8e09a..1244787 100644
--- a/polyp/cli-command.c
+++ b/polyp/cli-command.c
@@ -641,7 +641,11 @@ static int pa_cli_command_dump(struct pa_core *c, struct pa_tokenizer *t, struct
 
     time(&now);
 
+#ifdef HAVE_CTIME_R
     pa_strbuf_printf(buf, "### Configuration dump generated at %s\n", ctime_r(&now, txt));
+#else
+    pa_strbuf_printf(buf, "### Configuration dump generated at %s\n", ctime(&now));
+#endif
 
     
     for (m = pa_idxset_first(c->modules, &index); m; m = pa_idxset_next(c->modules, &index)) {

commit 57dccd259269003aace56bbb8a1a24dad42f10f2
Author: Pierre Ossman <ossman at cendio.se>
Date:   Thu Jan 5 22:32:00 2006 +0000

    Replace paths with defines.
    
    
    git-svn-id: file:///home/lennart/svn/public/pulseaudio/branches/ossman@414 fefdeb5f-60dc-0310-8127-8f9354f1896f

diff --git a/polyp/Makefile.am b/polyp/Makefile.am
index a066813..beac830 100644
--- a/polyp/Makefile.am
+++ b/polyp/Makefile.am
@@ -28,6 +28,17 @@ polypconfdir=$(sysconfdir)/polypaudio
 modlibdir=$(libdir)/polypaudio- at PA_MAJORMINOR@
 
 ###################################
+#            Defines              #
+###################################
+
+POLYPAUDIO_BINARY=$(bindir)/polypaudio$(EXEEXT)
+if OS_IS_WIN32
+DEFAULT_CONFIG_DIR=%POLYP_ROOT%
+else
+DEFAULT_CONFIG_DIR=$(polypconfdir)
+endif
+
+###################################
 #     Compiler/linker flags       #
 ###################################
 
@@ -35,8 +46,8 @@ AM_CFLAGS  = -D_GNU_SOURCE  -I$(top_srcdir)
 AM_CFLAGS += $(PTHREAD_CFLAGS) $(LTDLINCL)
 AM_CFLAGS += $(LIBSAMPLERATE_CFLAGS) $(LIBSNDFILE_CFLAGS)
 AM_CFLAGS += -DDLSEARCHPATH=\"$(modlibdir)\"
-AM_CFLAGS += -DDEFAULT_CONFIG_DIR=\"$(polypconfdir)\"
-AM_CFLAGS += -DPOLYPAUDIO_BINARY=\"$(bindir)/polypaudio$(EXEEXT)\"
+AM_CFLAGS += -DDEFAULT_CONFIG_DIR=\"$(DEFAULT_CONFIG_DIR)\"
+AM_CFLAGS += -DPOLYPAUDIO_BINARY=\"$(POLYPAUDIO_BINARY)\"
 
 # This cool debug trap works on i386/gcc only
 AM_CFLAGS += '-DDEBUG_TRAP=__asm__("int $$3")'
@@ -974,17 +985,17 @@ suid: polypaudio
 esdcompat.sh: esdcompat.sh.in Makefile
 	sed -e 's, at PACKAGE_VERSION\@,$(PACKAGE_VERSION),g' \
 		-e 's, at PACKAGE_NAME\@,$(PACKAGE_NAME),g' \
-		-e 's, at POLYPAUDIO_BINARY\@,$(bindir)/polypaudio,g' < $< > $@
+		-e 's, at POLYPAUDIO_BINARY\@,$(POLYPAUDIO_BINARY),g' < $< > $@
 
 client.conf: client.conf.in Makefile
-	sed -e 's, at POLYPAUDIO_BINARY\@,$(bindir)/polypaudio,g' < $< > $@
+	sed -e 's, at POLYPAUDIO_BINARY\@,$(POLYPAUDIO_BINARY),g' < $< > $@
 
 default.pa: default.pa.in Makefile
-	sed -e 's, at POLYPAUDIO_BINARY\@,$(bindir)/polypaudio,g' < $< > $@
+	sed -e 's, at POLYPAUDIO_BINARY\@,$(POLYPAUDIO_BINARY),g' < $< > $@
 
 daemon.conf: daemon.conf.in Makefile
 	sed -e 's, at DLSEARCHPATH\@,$(modlibdir),g' \
-		-e 's, at DEFAULT_CONFIG_FILE\@,$(polypconfdir)/daemon.conf,g' < $< > $@
+		-e 's, at DEFAULT_CONFIG_FILE\@,$(DEFAULT_CONFIG_DIR),g' < $< > $@
 
 install-exec-hook:
 	chown root $(DESTDIR)$(bindir)/polypaudio ; true

commit 67833c2bcf1019f48df2cbabd654c67a6d4b7fef
Author: Pierre Ossman <ossman at cendio.se>
Date:   Thu Jan 5 22:40:45 2006 +0000

    Protect sched.h with ifdef.
    
    
    git-svn-id: file:///home/lennart/svn/public/pulseaudio/branches/ossman@415 fefdeb5f-60dc-0310-8127-8f9354f1896f

diff --git a/polyp/util.c b/polyp/util.c
index 67eaeda..a05e601 100644
--- a/polyp/util.c
+++ b/polyp/util.c
@@ -37,11 +37,14 @@
 #include <signal.h>
 #include <pthread.h>
 #include <sys/time.h>
-#include <sched.h>
 #include <sys/resource.h>
 #include <limits.h>
 #include <unistd.h>
 
+#ifdef HAVE_SCHED_H
+#include <sched.h>
+#endif
+
 #ifdef HAVE_NETDB_H
 #include <netdb.h>
 #endif

commit bdc02f71f505b6a7b6874a7b3f6beff31355bb7c
Author: Pierre Ossman <ossman at cendio.se>
Date:   Thu Jan 5 22:42:26 2006 +0000

    Protect sys/resource.h with an ifdef.
    
    
    git-svn-id: file:///home/lennart/svn/public/pulseaudio/branches/ossman@416 fefdeb5f-60dc-0310-8127-8f9354f1896f

diff --git a/polyp/cpulimit.c b/polyp/cpulimit.c
index f121123..53920f5 100644
--- a/polyp/cpulimit.c
+++ b/polyp/cpulimit.c
@@ -30,10 +30,13 @@
 #include <string.h>
 #include <assert.h>
 #include <sys/time.h>
-#include <sys/resource.h>
 #include <unistd.h>
 #include <signal.h>
 
+#ifdef HAVE_SYS_RESOURCE_H
+#include <sys/resource.h>
+#endif
+
 #include "cpulimit.h"
 #include "util.h"
 #include "log.h"
diff --git a/polyp/util.c b/polyp/util.c
index a05e601..cccb665 100644
--- a/polyp/util.c
+++ b/polyp/util.c
@@ -37,7 +37,6 @@
 #include <signal.h>
 #include <pthread.h>
 #include <sys/time.h>
-#include <sys/resource.h>
 #include <limits.h>
 #include <unistd.h>
 
@@ -45,6 +44,10 @@
 #include <sched.h>
 #endif
 
+#ifdef HAVE_SYS_RESOURCE_H
+#include <sys/resource.h>
+#endif
+
 #ifdef HAVE_NETDB_H
 #include <netdb.h>
 #endif

commit 2f74bb9d437fc165695e1d4bb7516ca979962a49
Author: Pierre Ossman <ossman at cendio.se>
Date:   Thu Jan 5 22:44:23 2006 +0000

    Protect pthread.h with an ifdef.
    
    
    git-svn-id: file:///home/lennart/svn/public/pulseaudio/branches/ossman@417 fefdeb5f-60dc-0310-8127-8f9354f1896f

diff --git a/polyp/util.c b/polyp/util.c
index cccb665..acfa031 100644
--- a/polyp/util.c
+++ b/polyp/util.c
@@ -35,7 +35,6 @@
 #include <sys/types.h>
 #include <sys/stat.h>
 #include <signal.h>
-#include <pthread.h>
 #include <sys/time.h>
 #include <limits.h>
 #include <unistd.h>
@@ -48,6 +47,10 @@
 #include <sys/resource.h>
 #endif
 
+#ifdef HAVE_PTHREAD
+#include <pthread.h>
+#endif
+
 #ifdef HAVE_NETDB_H
 #include <netdb.h>
 #endif

commit 19d9fcbda8637099854f2d8147b402b4420d19f5
Author: Pierre Ossman <ossman at cendio.se>
Date:   Thu Jan 5 22:51:37 2006 +0000

    Port to Windows. This is mostly glue layers for the poor POSIX support
    on Windows. A few notes
    
     * Only sockets behave somewhat like file descriptors in UNIX.
    
     * There are no fixed paths. Closes thing is environment variables that point
       to system directories. We also figure out where the binary/dll is
       located and use that as configuration directory.
    
    
    git-svn-id: file:///home/lennart/svn/public/pulseaudio/branches/ossman@418 fefdeb5f-60dc-0310-8127-8f9354f1896f

diff --git a/configure.ac b/configure.ac
index 1899e92..5ff28a5 100644
--- a/configure.ac
+++ b/configure.ac
@@ -138,7 +138,7 @@ AC_CHECK_HEADERS([linux/input.h], [HAVE_EVDEV=1], [HAVE_EVDEV=0])
 AM_CONDITIONAL([HAVE_EVDEV], [test "x$HAVE_EVDEV" = "x1"])
 
 # Windows
-AC_CHECK_HEADERS([winsock2.h ws2tcpip.h])
+AC_CHECK_HEADERS([windows.h winsock2.h ws2tcpip.h])
 
 # Other
 AC_CHECK_HEADERS([sys/ioctl.h])
diff --git a/polyp/Makefile.am b/polyp/Makefile.am
index beac830..dcd3fc1 100644
--- a/polyp/Makefile.am
+++ b/polyp/Makefile.am
@@ -298,6 +298,7 @@ libpolyp_ at PA_MAJORMINOR@_la_SOURCES = \
 		cdecl.h \
 		client-conf.c client-conf.h \
 		conf-parser.c conf-parser.h \
+		dllmain.c \
 		dynarray.c dynarray.h \
 		gcc-printf.h \
 		idxset.c idxset.h \
@@ -432,6 +433,7 @@ libpolypcore_la_SOURCES = \
 		cli-text.c cli-text.h \
 		client.c client.h \
 		core.c core.h \
+		dllmain.c \
 		dynarray.c dynarray.h \
 		endianmacros.h \
 		g711.c g711.h \
@@ -562,7 +564,7 @@ libpdispatch_la_LIBADD = $(AM_LIBADD) libtagstruct.la libpolypcore.la
 
 libiochannel_la_SOURCES = iochannel.c iochannel.h
 libiochannel_la_LDFLAGS = -avoid-version
-libiochannel_la_LIBADD = $(AM_LIBADD) libsocket-util.la libpolypcore.la
+libiochannel_la_LIBADD = $(AM_LIBADD) libsocket-util.la libpolypcore.la $(WINSOCK_LIBS)
 
 libpacket_la_SOURCES = packet.c packet.h
 libpacket_la_LDFLAGS = -avoid-version
@@ -727,6 +729,11 @@ modlib_LTLIBRARIES += \
 		module-mmkbd-evdev.la
 endif
 
+if OS_IS_WIN32
+modlib_LTLIBRARIES += \
+		module-waveout.la
+endif
+
 # These are generated by a M4 script
 
 SYMDEF_FILES = \
@@ -766,7 +773,8 @@ SYMDEF_FILES = \
 		module-oss-symdef.h \
 		module-oss-mmap-symdef.h \
 		module-alsa-sink-symdef.h \
-		module-alsa-source-symdef.h
+		module-alsa-source-symdef.h \
+		module-waveout-symdef.h
 
 EXTRA_DIST += $(SYMDEF_FILES)
 BUILT_SOURCES += $(SYMDEF_FILES)
@@ -974,6 +982,13 @@ module_mmkbd_evdev_la_LDFLAGS = -module -avoid-version
 module_mmkbd_evdev_la_LIBADD = $(AM_LIBADD)
 module_mmkbd_evdev_la_CFLAGS = $(AM_CFLAGS)
 
+# Windows waveout
+
+module_waveout_la_SOURCES = module-waveout.c
+module_waveout_la_LDFLAGS = -module -avoid-version
+module_waveout_la_LIBADD = $(AM_LIBADD) libpolypcore.la -lwinmm
+module_waveout_la_CFLAGS = $(AM_CFLAGS)
+
 ###################################
 #        Some minor stuff         #
 ###################################
@@ -990,8 +1005,13 @@ esdcompat.sh: esdcompat.sh.in Makefile
 client.conf: client.conf.in Makefile
 	sed -e 's, at POLYPAUDIO_BINARY\@,$(POLYPAUDIO_BINARY),g' < $< > $@
 
+if OS_IS_WIN32    
+default.pa: default.pa.win32
+	cp $< $@
+else
 default.pa: default.pa.in Makefile
 	sed -e 's, at POLYPAUDIO_BINARY\@,$(POLYPAUDIO_BINARY),g' < $< > $@
+endif
 
 daemon.conf: daemon.conf.in Makefile
 	sed -e 's, at DLSEARCHPATH\@,$(modlibdir),g' \
diff --git a/polyp/client-conf.c b/polyp/client-conf.c
index 4906383..04c3d2e 100644
--- a/polyp/client-conf.c
+++ b/polyp/client-conf.c
@@ -19,6 +19,10 @@
   USA.
 ***/
 
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
 #include <stdlib.h>
 #include <assert.h>
 #include <unistd.h>
@@ -33,11 +37,21 @@
 #include "authkey.h"
 
 #ifndef DEFAULT_CONFIG_DIR
-#define DEFAULT_CONFIG_DIR "/etc/polypaudio"
+# ifndef OS_IS_WIN32
+#  define DEFAULT_CONFIG_DIR "/etc/polypaudio"
+# else
+#  define DEFAULT_CONFIG_DIR "%POLYP_ROOT%"
+# endif
+#endif
+
+#ifndef OS_IS_WIN32
+# define PATH_SEP "/"
+#else
+# define PATH_SEP "\\"
 #endif
 
-#define DEFAULT_CLIENT_CONFIG_FILE DEFAULT_CONFIG_DIR"/client.conf"
-#define DEFAULT_CLIENT_CONFIG_FILE_USER ".polypaudio/client.conf"
+#define DEFAULT_CLIENT_CONFIG_FILE DEFAULT_CONFIG_DIR PATH_SEP "client.conf"
+#define DEFAULT_CLIENT_CONFIG_FILE_USER ".polypaudio" PATH_SEP "client.conf"
 
 #define ENV_CLIENT_CONFIG_FILE "POLYP_CLIENTCONFIG"
 #define ENV_DEFAULT_SINK "POLYP_SINK"
diff --git a/polyp/daemon-conf.c b/polyp/daemon-conf.c
index a6afd05..780581b 100644
--- a/polyp/daemon-conf.c
+++ b/polyp/daemon-conf.c
@@ -37,13 +37,23 @@
 #include "resampler.h"
 
 #ifndef DEFAULT_CONFIG_DIR
-#define DEFAULT_CONFIG_DIR "/etc/polypaudio"
+# ifndef OS_IS_WIN32
+#  define DEFAULT_CONFIG_DIR "/etc/polypaudio"
+# else
+#  define DEFAULT_CONFIG_DIR "%POLYP_ROOT%"
+# endif
 #endif
 
-#define DEFAULT_SCRIPT_FILE DEFAULT_CONFIG_DIR"/default.pa"
-#define DEFAULT_SCRIPT_FILE_USER ".polypaudio/default.pa"
-#define DEFAULT_CONFIG_FILE DEFAULT_CONFIG_DIR"/daemon.conf"
-#define DEFAULT_CONFIG_FILE_USER ".polypaudio/daemon.conf"
+#ifndef OS_IS_WIN32
+# define PATH_SEP "/"
+#else
+# define PATH_SEP "\\"
+#endif
+
+#define DEFAULT_SCRIPT_FILE DEFAULT_CONFIG_DIR PATH_SEP "default.pa"
+#define DEFAULT_SCRIPT_FILE_USER ".polypaudio" PATH_SEP "default.pa"
+#define DEFAULT_CONFIG_FILE DEFAULT_CONFIG_DIR PATH_SEP "daemon.conf"
+#define DEFAULT_CONFIG_FILE_USER ".polypaudio" PATH_SEP "daemon.conf"
 
 #define ENV_SCRIPT_FILE "POLYP_SCRIPT"
 #define ENV_CONFIG_FILE "POLYP_CONFIG"
diff --git a/polyp/default.pa.win32 b/polyp/default.pa.win32
new file mode 100644
index 0000000..3478ada
--- /dev/null
+++ b/polyp/default.pa.win32
@@ -0,0 +1,43 @@
+#
+# This file is part of polypaudio.
+#
+# polypaudio 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 of the License, or
+# (at your option) any later version.
+#
+# polypaudio 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 polypaudio; if not, write to the Free Software Foundation,
+# Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+
+
+# Load audio drivers statically
+
+load-module module-waveout sink_name=output source_name=input
+load-module module-null-sink
+
+# Load audio drivers automatically on access
+
+#add-autoload-sink output module-waveout sink_name=output source_name=input
+#add-autoload-source input module-waveout sink_name=output source_name=input
+
+# Load several protocols
+#load-module module-esound-protocol-tcp
+#load-module module-native-protocol-tcp
+#load-module module-simple-protocol-tcp
+#load-module module-cli-protocol-tcp
+
+# Make some devices default
+set-default-sink output
+set-default-source input
+
+.nofail
+
+# Load something to the sample cache
+load-sample x11-bell %WINDIR%\Media\ding.wav
+load-sample-dir-lazy %WINDIR%\Media\*.wav
diff --git a/polyp/dllmain.c b/polyp/dllmain.c
new file mode 100644
index 0000000..34d0eed
--- /dev/null
+++ b/polyp/dllmain.c
@@ -0,0 +1,46 @@
+/* $Id: dllmain.c 317 2004-12-11 00:10:41Z lennart $ */
+
+/***
+  This file is part of polypaudio.
+
+  polypaudio 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 of the License,
+  or (at your option) any later version.
+
+  polypaudio 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 polypaudio; if not, write to the Free Software
+  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+  USA.
+***/
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#ifdef OS_IS_WIN32
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+
+#include <windows.h>
+
+extern pa_set_root(HANDLE handle);
+
+BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved) {
+    if (fdwReason != DLL_PROCESS_ATTACH)
+        return TRUE;
+
+    if (!pa_set_root(hinstDLL))
+        return FALSE;
+
+    return TRUE;
+}
+
+#endif /* OS_IS_WIN32 */
diff --git a/polyp/iochannel.c b/polyp/iochannel.c
index 0e7e8db..08a4e36 100644
--- a/polyp/iochannel.c
+++ b/polyp/iochannel.c
@@ -28,6 +28,10 @@
 #include <fcntl.h>
 #include <unistd.h>
 
+#ifdef HAVE_WINSOCK2_H
+#include <winsock2.h>
+#endif
+
 #include "iochannel.h"
 #include "util.h"
 #include "socket-util.h"
@@ -189,7 +193,19 @@ ssize_t pa_iochannel_write(struct pa_iochannel*io, const void*data, size_t l) {
     ssize_t r;
     assert(io && data && l && io->ofd >= 0);
 
-    if ((r = write(io->ofd, data, l)) >= 0) {
+#ifdef OS_IS_WIN32
+    r = send(io->ofd, data, l, 0);
+    if (r < 0) {
+        if (WSAGetLastError() != WSAENOTSOCK) {
+            errno = WSAGetLastError();
+            return r;
+        }
+    }
+
+    if (r < 0)
+#endif
+        r = write(io->ofd, data, l);
+    if (r >= 0) {
         io->writable = 0;
         enable_mainloop_sources(io);
     }
@@ -201,7 +217,19 @@ ssize_t pa_iochannel_read(struct pa_iochannel*io, void*data, size_t l) {
     ssize_t r;
     assert(io && data && io->ifd >= 0);
     
-    if ((r = read(io->ifd, data, l)) >= 0) {
+#ifdef OS_IS_WIN32
+    r = recv(io->ifd, data, l, 0);
+    if (r < 0) {
+        if (WSAGetLastError() != WSAENOTSOCK) {
+            errno = WSAGetLastError();
+            return r;
+        }
+    }
+
+    if (r < 0)
+#endif
+        r = read(io->ifd, data, l);
+    if (r >= 0) {
         io->readable = 0;
         enable_mainloop_sources(io);
     }
diff --git a/polyp/main.c b/polyp/main.c
index 3f9f359..437f0a4 100644
--- a/polyp/main.c
+++ b/polyp/main.c
@@ -35,7 +35,16 @@
 #include <memblock.h>
 #include <limits.h>
 #include <fcntl.h>
+#include <unistd.h>
+#include <sys/types.h>
+
+#ifdef HAVE_SYS_IOCTL_H
 #include <sys/ioctl.h>
+#endif
+
+#ifdef HAVE_WINSOCK2_H
+#include <winsock2.h>
+#endif
 
 #ifdef HAVE_LIBWRAP
 #include <syslog.h>
@@ -66,6 +75,23 @@ int allow_severity = LOG_INFO;
 int deny_severity = LOG_WARNING;
 #endif
 
+#ifdef OS_IS_WIN32
+
+static void message_cb(struct pa_mainloop_api*a, struct pa_defer_event *e, void *userdata) {
+    MSG msg;
+
+    while(PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) {
+        if (msg.message == WM_QUIT)
+            raise(SIGTERM);
+        else {
+            TranslateMessage(&msg);
+            DispatchMessage(&msg);
+        }
+    }
+}
+
+#endif
+
 static void signal_callback(struct pa_mainloop_api*m, struct pa_signal_event *e, int sig, void *userdata) {
     pa_log_info(__FILE__": Got signal %s.\n", pa_strsignal(sig));
 
@@ -124,6 +150,10 @@ int main(int argc, char *argv[]) {
     gid_t gid = (gid_t) -1;
 #endif
 
+#ifdef OS_IS_WIN32
+    struct pa_defer_event *defer;
+#endif
+
     pa_limit_caps();
 
 #ifdef HAVE_GETUID
@@ -142,6 +172,13 @@ int main(int argc, char *argv[]) {
     r = lt_dlinit();
     assert(r == 0);
 
+#ifdef OS_IS_WIN32
+    {
+        WSADATA data;
+        WSAStartup(MAKEWORD(2, 0), &data);
+    }
+#endif
+
     pa_log_set_ident("polypaudio");
     
     conf = pa_daemon_conf_new();
@@ -230,6 +267,7 @@ int main(int argc, char *argv[]) {
             goto finish;
         }
 
+#ifdef HAVE_FORK
         if (pipe(daemon_pipe) < 0) {
             pa_log(__FILE__": failed to create pipe.\n");
             goto finish;
@@ -261,6 +299,7 @@ int main(int argc, char *argv[]) {
 
         close(daemon_pipe[0]);
         daemon_pipe[0] = -1;
+#endif
 
         if (conf->auto_log_target)
             pa_log_set_target(PA_LOG_SYSLOG, NULL);
@@ -271,7 +310,8 @@ int main(int argc, char *argv[]) {
 #ifdef HAVE_SETPGID
         setpgid(0,0);
 #endif
-        
+
+#ifndef OS_IS_WIN32
         close(0);
         close(1);
         close(2);
@@ -279,7 +319,10 @@ int main(int argc, char *argv[]) {
         open("/dev/null", O_RDONLY);
         open("/dev/null", O_WRONLY);
         open("/dev/null", O_WRONLY);
-        
+#else
+        FreeConsole();
+#endif
+
 #ifdef SIGTTOU
         signal(SIGTTOU, SIG_IGN);
 #endif
@@ -290,18 +333,23 @@ int main(int argc, char *argv[]) {
         signal(SIGTSTP, SIG_IGN);
 #endif
         
+#ifdef TIOCNOTTY
         if ((tty_fd = open("/dev/tty", O_RDWR)) >= 0) {
             ioctl(tty_fd, TIOCNOTTY, (char*) 0);
             close(tty_fd);
         }
+#endif
     }
 
     chdir("/");
     
     if (conf->use_pid_file) {
         if (pa_pid_file_create() < 0) {
+            pa_log(__FILE__": pa_pid_file_create() failed.\n");
+#ifdef HAVE_FORK
             if (conf->daemonize)
                 pa_loop_write(daemon_pipe[1], &retval, sizeof(retval));
+#endif
             goto finish;
         }
 
@@ -322,9 +370,14 @@ int main(int argc, char *argv[]) {
     signal(SIGPIPE, SIG_IGN);
 #endif
 
+#ifdef OS_IS_WIN32
+    defer = pa_mainloop_get_api(mainloop)->defer_new(pa_mainloop_get_api(mainloop), message_cb, NULL);
+    assert(defer);
+#endif
+
     if (conf->daemonize)
         c->running_as_daemon = 1;
-    
+
 #ifdef SIGUSR1
     pa_signal_new(SIGUSR1, signal_callback, c);
 #endif
@@ -350,17 +403,23 @@ int main(int argc, char *argv[]) {
     
     if (r < 0 && conf->fail) {
         pa_log(__FILE__": failed to initialize daemon.\n");
+#ifdef HAVE_FORK
         if (conf->daemonize)
             pa_loop_write(daemon_pipe[1], &retval, sizeof(retval));
+#endif
     } else if (!c->modules || pa_idxset_ncontents(c->modules) == 0) {
         pa_log(__FILE__": daemon startup without any loaded modules, refusing to work.\n");
+#ifdef HAVE_FORK
         if (conf->daemonize)
             pa_loop_write(daemon_pipe[1], &retval, sizeof(retval));
+#endif
     } else {
 
         retval = 0;
+#ifdef HAVE_FORK
         if (conf->daemonize)
             pa_loop_write(daemon_pipe[1], &retval, sizeof(retval));
+#endif
 
         c->disallow_module_loading = conf->disallow_module_loading;
         c->exit_idle_time = conf->exit_idle_time;
@@ -378,7 +437,11 @@ int main(int argc, char *argv[]) {
             pa_log_info(__FILE__": Daemon shutdown initiated.\n");
         }
     }
-        
+
+#ifdef OS_IS_WIN32
+    pa_mainloop_get_api(mainloop)->defer_free(defer);
+#endif
+
     pa_core_free(c);
 
     pa_cpu_limit_done();
@@ -397,6 +460,10 @@ finish:
     
     close_pipe(daemon_pipe);
 
+#ifdef OS_IS_WIN32
+    WSACleanup();
+#endif
+
     lt_dlexit();
     
     return retval;
diff --git a/polyp/mainloop-signal.c b/polyp/mainloop-signal.c
index eb3f5dd..432498a 100644
--- a/polyp/mainloop-signal.c
+++ b/polyp/mainloop-signal.c
@@ -32,6 +32,10 @@
 #include <unistd.h>
 #include <fcntl.h>
 
+#ifdef HAVE_WINDOWS_H
+#include <windows.h>
+#endif
+
 #include "mainloop-signal.h"
 #include "util.h"
 #include "xmalloc.h"
@@ -53,19 +57,70 @@ struct pa_signal_event {
 static struct pa_mainloop_api *api = NULL;
 static int signal_pipe[2] = { -1, -1 };
 static struct pa_io_event* io_event = NULL;
+static struct pa_defer_event *defer_event = NULL;
 static struct pa_signal_event *signals = NULL;
 
+#ifdef OS_IS_WIN32
+static unsigned int waiting_signals = 0;
+static CRITICAL_SECTION crit;
+#endif
+
 static void signal_handler(int sig) {
 #ifndef HAVE_SIGACTION
     signal(sig, signal_handler);
 #endif
     write(signal_pipe[1], &sig, sizeof(sig));
+
+#ifdef OS_IS_WIN32
+    EnterCriticalSection(&crit);
+    waiting_signals++;
+    LeaveCriticalSection(&crit);
+#endif
+}
+
+static void dispatch(struct pa_mainloop_api*a, int sig) {
+    struct pa_signal_event*s;
+
+    for (s = signals; s; s = s->next) 
+        if (s->sig == sig) {
+            assert(s->callback);
+            s->callback(a, s, sig, s->userdata);
+            break;
+        }
+}
+
+static void defer(struct pa_mainloop_api*a, struct pa_defer_event*e, void *userdata) {
+    ssize_t r;
+    int sig;
+    unsigned int sigs;
+
+#ifdef OS_IS_WIN32
+    EnterCriticalSection(&crit);
+    sigs = waiting_signals;
+    waiting_signals = 0;
+    LeaveCriticalSection(&crit);
+#endif
+
+    while (sigs) {
+        if ((r = read(signal_pipe[0], &sig, sizeof(sig))) < 0) {
+            pa_log(__FILE__": read(): %s\n", strerror(errno));
+            return;
+        }
+        
+        if (r != sizeof(sig)) {
+            pa_log(__FILE__": short read()\n");
+            return;
+        }
+
+        dispatch(a, sig);
+
+        sigs--;
+    }
 }
 
 static void callback(struct pa_mainloop_api*a, struct pa_io_event*e, int fd, enum pa_io_event_flags f, void *userdata) {
     ssize_t r;
     int sig;
-    struct pa_signal_event*s;
     assert(a && e && f == PA_IO_EVENT_INPUT && e == io_event && fd == signal_pipe[0]);
 
         
@@ -81,19 +136,18 @@ static void callback(struct pa_mainloop_api*a, struct pa_io_event*e, int fd, enu
         pa_log(__FILE__": short read()\n");
         return;
     }
-    
-    for (s = signals; s; s = s->next) 
-        if (s->sig == sig) {
-            assert(s->callback);
-            s->callback(a, s, sig, s->userdata);
-            break;
-        }
+
+    dispatch(a, sig);
 }
 
 int pa_signal_init(struct pa_mainloop_api *a) {
-    assert(!api && a && signal_pipe[0] == -1 && signal_pipe[1] == -1 && !io_event);
-    
+    assert(!api && a && signal_pipe[0] == -1 && signal_pipe[1] == -1 && !io_event && !defer_event);
+
+#ifdef OS_IS_WIN32
+    if (_pipe(signal_pipe, 200, _O_BINARY) < 0) {
+#else
     if (pipe(signal_pipe) < 0) {
+#endif
         pa_log(__FILE__": pipe() failed: %s\n", strerror(errno));
         return -1;
     }
@@ -104,20 +158,36 @@ int pa_signal_init(struct pa_mainloop_api *a) {
     pa_fd_set_cloexec(signal_pipe[1], 1);
 
     api = a;
+
+#ifndef OS_IS_WIN32
     io_event = api->io_new(api, signal_pipe[0], PA_IO_EVENT_INPUT, callback, NULL);
     assert(io_event);
+#else
+    defer_event = api->defer_new(api, defer, NULL);
+    assert(defer_event);
+
+    InitializeCriticalSection(&crit);
+#endif
+
     return 0;
 }
 
 void pa_signal_done(void) {
-    assert(api && signal_pipe[0] >= 0 && signal_pipe[1] >= 0 && io_event);
+    assert(api && signal_pipe[0] >= 0 && signal_pipe[1] >= 0 && (io_event || defer_event));
 
     while (signals)
         pa_signal_free(signals);
 
 
+#ifndef OS_IS_WIN32
     api->io_free(io_event);
     io_event = NULL;
+#else
+    api->defer_free(defer_event);
+    defer_event = NULL;
+
+    DeleteCriticalSection(&crit);
+#endif
 
     close(signal_pipe[0]);
     close(signal_pipe[1]);
diff --git a/polyp/mainloop.c b/polyp/mainloop.c
index 90243bd..9cfd539 100644
--- a/polyp/mainloop.c
+++ b/polyp/mainloop.c
@@ -38,6 +38,10 @@
 #include "poll.h"
 #endif
 
+#ifdef HAVE_WINSOCK2_H
+#include <winsock2.h>
+#endif
+
 #include "mainloop.h"
 #include "util.h"
 #include "idxset.h"
@@ -108,6 +112,26 @@ static struct pa_io_event* mainloop_io_new(struct pa_mainloop_api*a, int fd, enu
     e->destroy_callback = NULL;
     e->pollfd = NULL;
 
+#ifdef OS_IS_WIN32
+    {
+        fd_set xset;
+        struct timeval tv;
+
+        tv.tv_sec = 0;
+        tv.tv_usec = 0;
+
+        FD_ZERO (&xset);
+        FD_SET (fd, &xset);
+
+        if ((select((SELECT_TYPE_ARG1) fd, NULL, NULL, SELECT_TYPE_ARG234 &xset,
+                    SELECT_TYPE_ARG5 &tv) == -1) &&
+             (WSAGetLastError() == WSAENOTSOCK)) {
+            pa_log_warn(__FILE__": WARNING: cannot monitor non-socket file descriptors.\n");
+            e->dead = 1;
+        }
+    }
+#endif
+
     pa_idxset_put(m->io_events, e, NULL);
     m->rebuild_pollfds = 1;
     return e;
diff --git a/polyp/module-protocol-stub.c b/polyp/module-protocol-stub.c
index 7cd5ed3..8c06a61 100644
--- a/polyp/module-protocol-stub.c
+++ b/polyp/module-protocol-stub.c
@@ -40,6 +40,13 @@
 #include <netinet/in.h>
 #endif
 
+#ifdef HAVE_WINSOCK2_H
+#include <winsock2.h>
+#endif
+#ifdef HAVE_WS2TCPIP_H
+#include <ws2tcpip.h>
+#endif
+
 #include "module.h"
 #include "socket-server.h"
 #include "socket-util.h"
diff --git a/polyp/pid.c b/polyp/pid.c
index 2fac687..ae3dc7f 100644
--- a/polyp/pid.c
+++ b/polyp/pid.c
@@ -35,6 +35,10 @@
 #include <limits.h>
 #include <signal.h>
 
+#ifdef HAVE_WINDOWS_H
+#include <windows.h>
+#endif
+
 #include "pid.h"
 #include "util.h"
 #include "log.h"
@@ -130,6 +134,10 @@ int pa_pid_file_create(void) {
     pid_t pid;
     size_t l;
 
+#ifdef OS_IS_WIN32
+    HANDLE process;
+#endif
+
     pa_runtime_path("pid", fn, sizeof(fn));
 
     if ((fd = open_pid_file(fn, O_CREAT|O_RDWR)) < 0)
@@ -138,7 +146,12 @@ int pa_pid_file_create(void) {
     if ((pid = read_pid(fn, fd)) == (pid_t) -1)
         pa_log(__FILE__": corrupt PID file, overwriting.\n");
     else if (pid > 0) {
+#ifdef OS_IS_WIN32
+        if ((process = OpenProcess(PROCESS_QUERY_INFORMATION, FALSE, pid)) != NULL) {
+            CloseHandle(process);
+#else
         if (kill(pid, 0) >= 0 || errno != ESRCH) {
+#endif
             pa_log(__FILE__": daemon already running.\n");
             goto fail;
         }
@@ -198,6 +211,12 @@ int pa_pid_file_remove(void) {
         goto fail;
     }
 
+#ifdef OS_IS_WIN32
+    pa_lock_fd(fd, 0);
+    close(fd);
+    fd = -1;
+#endif
+
     if (unlink(fn) < 0) {
         pa_log(__FILE__": failed to remove PID file '%s': %s\n", fn, strerror(errno));
         goto fail;
@@ -223,6 +242,8 @@ int pa_pid_file_check_running(pid_t *pid) {
     return pa_pid_file_kill(0, pid);
 }
 
+#ifndef OS_IS_WIN32
+
 /* Kill a current running daemon. Return non-zero on success, -1
  * otherwise. If successful *pid contains the PID of the daemon
  * process. */
@@ -242,7 +263,7 @@ int pa_pid_file_kill(int sig, pid_t *pid) {
     
     if ((*pid = read_pid(fn, fd)) == (pid_t) -1)
         goto fail;
-    
+
     ret = kill(*pid, sig);
     
 fail:
@@ -255,3 +276,11 @@ fail:
     return ret;
     
 }
+
+#else /* OS_IS_WIN32 */
+
+int pa_pid_file_kill(int sig, pid_t *pid) {
+    return -1;
+}
+
+#endif
diff --git a/polyp/poll.c b/polyp/poll.c
index 82ea3d8..7c25f34 100644
--- a/polyp/poll.c
+++ b/polyp/poll.c
@@ -36,6 +36,17 @@
 #include <sys/select.h>
 #endif
 
+#ifdef HAVE_WINSOCK2_H
+#include <winsock2.h>
+
+#define EBADF           WSAEBADF
+#define ESHUTDOWN       WSAESHUTDOWN
+#define ECONNRESET      WSAECONNRESET
+#define ECONNABORTED    WSAECONNABORTED
+#define ENETRESET       WSAENETRESET
+
+#endif /* HAVE_WINSOCK2_H */
+
 #ifndef HAVE_SYS_POLL_H
 
 #include "util.h"
@@ -59,7 +70,16 @@ int poll (struct pollfd *fds, unsigned long int nfds, int timeout) {
             return 0;
         }
 
+#ifdef OS_IS_WIN32
+        /*
+         * Windows does not support signals properly so waiting for them would
+         * mean a deadlock.
+         */
+        pa_msleep(100);
+        return 0;
+#else
         return select(0, NULL, NULL, NULL, NULL);
+#endif
     }
 
     for (f = fds; f < &fds[nfds]; ++f) {
@@ -138,6 +158,10 @@ int poll (struct pollfd *fds, unsigned long int nfds, int timeout) {
         }
     }
 
+#ifdef OS_IS_WIN32
+    errno = WSAGetLastError();
+#endif
+
     if (ready > 0) {
         ready = 0;
         for (f = fds; f < &fds[nfds]; ++f) {
diff --git a/polyp/polyplib-context.c b/polyp/polyplib-context.c
index 1b9d7de..da91995 100644
--- a/polyp/polyplib-context.c
+++ b/polyp/polyplib-context.c
@@ -32,6 +32,7 @@
 #include <sys/stat.h>
 #include <errno.h>
 #include <signal.h>
+#include <limits.h>
 
 #ifdef HAVE_SYS_WAIT_H
 #include <sys/wait.h>
@@ -44,6 +45,13 @@
 #include <netdb.h>
 #endif
 
+#ifdef HAVE_WINSOCK2_H
+#include <winsock2.h>
+#define ETIMEDOUT       WSAETIMEDOUT
+#define ECONNREFUSED    WSAECONNREFUSED
+#define EHOSTUNREACH    WSAEHOSTUNREACH
+#endif
+
 #include "polyplib-internal.h"
 #include "polyplib-context.h"
 #include "native-common.h"
@@ -382,6 +390,8 @@ finish:
 
 static void on_connection(struct pa_socket_client *client, struct pa_iochannel*io, void *userdata);
 
+#ifndef OS_IS_WIN32
+
 static int context_connect_spawn(struct pa_context *c) {
     pid_t pid;
     int status, r;
@@ -495,6 +505,8 @@ fail:
     return -1;
 }
 
+#endif /* OS_IS_WIN32 */
+
 static int try_next_connection(struct pa_context *c) {
     char *u = NULL;
     int r = -1;
@@ -509,10 +521,12 @@ static int try_next_connection(struct pa_context *c) {
         
         if (!u) {
 
+#ifndef OS_IS_WIN32
             if (c->do_autospawn) {
                 r = context_connect_spawn(c);
                 goto finish;
             }
+#endif
             
             pa_context_fail(c, PA_ERROR_CONNECTIONREFUSED);
             goto finish;
diff --git a/polyp/pstream.c b/polyp/pstream.c
index a64856d..607b0c1 100644
--- a/polyp/pstream.c
+++ b/polyp/pstream.c
@@ -32,6 +32,10 @@
 #include <netinet/in.h>
 #endif
 
+#ifdef HAVE_WINSOCK2_H
+#include <winsock2.h>
+#endif
+
 #include "pstream.h"
 #include "queue.h"
 #include "xmalloc.h"
diff --git a/polyp/random.c b/polyp/random.c
index 456954a..12f27bf 100644
--- a/polyp/random.c
+++ b/polyp/random.c
@@ -19,6 +19,10 @@
   USA.
 ***/
 
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
 #include <fcntl.h>
 #include <unistd.h>
 #include <errno.h>
@@ -31,13 +35,16 @@
 #include "util.h"
 #include "log.h"
 
+#ifndef OS_IS_WIN32
 #define RANDOM_DEVICE "/dev/urandom"
+#endif
 
 void pa_random(void *ret_data, size_t length) {
     int fd;
     ssize_t r = 0;
     assert(ret_data && length);
-    
+
+#ifdef RANDOM_DEVICE
     if ((fd = open(RANDOM_DEVICE, O_RDONLY)) >= 0) {
 
         if ((r = pa_loop_read(fd, ret_data, length)) < 0 || (size_t) r != length)
@@ -45,17 +52,20 @@ void pa_random(void *ret_data, size_t length) {
 
         close(fd);
     }
+#endif
 
     if ((size_t) r != length) {
         uint8_t *p;
         size_t l;
-        
+
+#ifdef RANDOM_DEVICE        
         pa_log_warn(__FILE__": WARNING: Failed to open entropy device '"RANDOM_DEVICE"': %s"
                     ", falling back to unsecure pseudo RNG.\n", strerror(errno));
+#endif
 
-        srandom(time(NULL));
+        srand(time(NULL));
         
         for (p = ret_data, l = length; l > 0; p++, l--)
-            *p = (uint8_t) random();
+            *p = (uint8_t) rand();
     }
 }
diff --git a/polyp/scache.c b/polyp/scache.c
index 0dec33c..2953145 100644
--- a/polyp/scache.c
+++ b/polyp/scache.c
@@ -37,6 +37,10 @@
 #include <glob.h>
 #endif
 
+#ifdef HAVE_WINDOWS_H
+#include <windows.h>
+#endif
+
 #include "scache.h"
 #include "sink-input.h"
 #include "mainloop.h"
@@ -147,6 +151,13 @@ int pa_scache_add_file(struct pa_core *c, const char *name, const char *filename
     struct pa_memchunk chunk;
     int r;
 
+#ifdef OS_IS_WIN32
+    char buf[MAX_PATH];
+
+    if (ExpandEnvironmentStrings(filename, buf, MAX_PATH))
+        filename = buf;
+#endif
+
     if (pa_sound_file_load(filename, &ss, &chunk, c->memblock_stat) < 0)
         return -1;
         
@@ -158,6 +169,14 @@ int pa_scache_add_file(struct pa_core *c, const char *name, const char *filename
 
 int pa_scache_add_file_lazy(struct pa_core *c, const char *name, const char *filename, uint32_t *index) {
     struct pa_scache_entry *e;
+
+#ifdef OS_IS_WIN32
+    char buf[MAX_PATH];
+
+    if (ExpandEnvironmentStrings(filename, buf, MAX_PATH))
+        filename = buf;
+#endif
+
     assert(c && name);
 
     if (!(e = scache_add_item(c, name)))
@@ -313,7 +332,9 @@ static void add_file(struct pa_core *c, const char *pathname) {
         return;
     }
 
+#if defined(S_ISREG) && defined(S_ISLNK)
     if (S_ISREG(st.st_mode) || S_ISLNK(st.st_mode))
+#endif
         pa_scache_add_file_lazy(c, e, pathname, NULL);
 }
 
diff --git a/polyp/socket-client.c b/polyp/socket-client.c
index 0d712fa..6d8cb2a 100644
--- a/polyp/socket-client.c
+++ b/polyp/socket-client.c
@@ -48,6 +48,15 @@
 #include <netdb.h>
 #endif
 
+#ifdef HAVE_WINSOCK2_H
+#include <winsock2.h>
+#define EINPROGRESS     WSAEINPROGRESS
+#define ETIMEDOUT       WSAETIMEDOUT
+#endif
+#ifdef HAVE_WS2TCPIP_H
+#include <ws2tcpip.h>
+#endif
+
 #ifdef HAVE_LIBASYNCNS
 #include <asyncns.h>
 #endif
diff --git a/polyp/socket-server.c b/polyp/socket-server.c
index 0cca4ae..b7e4fed 100644
--- a/polyp/socket-server.c
+++ b/polyp/socket-server.c
@@ -44,6 +44,13 @@
 #include <netinet/in.h>
 #endif
 
+#ifdef HAVE_WINSOCK2_H
+#include <winsock2.h>
+#endif
+#ifdef HAVE_WS2TCPIP_H
+#include <ws2tcpip.h>
+#endif
+
 #ifdef HAVE_LIBWRAP
 #include <tcpd.h>
 #endif
diff --git a/polyp/socket-util.c b/polyp/socket-util.c
index 60f8d16..699b28c 100644
--- a/polyp/socket-util.c
+++ b/polyp/socket-util.c
@@ -57,6 +57,11 @@
 #include <netdb.h>
 #endif
 
+#ifdef HAVE_WINSOCK2_H
+#include <winsock2.h>
+#define ETIMEDOUT       WSAETIMEDOUT
+#endif
+
 #include "socket-util.h"
 #include "util.h"
 #include "xmalloc.h"
@@ -72,6 +77,7 @@ void pa_socket_peer_to_string(int fd, char *c, size_t l) {
         return;
     }
 
+#ifndef OS_IS_WIN32
     if (S_ISSOCK(st.st_mode)) {
         union {
             struct sockaddr sa;
@@ -104,6 +110,7 @@ void pa_socket_peer_to_string(int fd, char *c, size_t l) {
         snprintf(c, l, "STDIN/STDOUT client");
         return;
     }
+#endif /* OS_IS_WIN32 */
 
     snprintf(c, l, "Unknown client");
 }
diff --git a/polyp/tagstruct.c b/polyp/tagstruct.c
index a3bd7d9..59178bf 100644
--- a/polyp/tagstruct.c
+++ b/polyp/tagstruct.c
@@ -33,6 +33,10 @@
 #include <netinet/in.h>
 #endif
 
+#ifdef HAVE_WINSOCK2_H
+#include <winsock2.h>
+#endif
+
 #include "tagstruct.h"
 #include "xmalloc.h"
 
diff --git a/polyp/util.c b/polyp/util.c
index acfa031..0495896 100644
--- a/polyp/util.c
+++ b/polyp/util.c
@@ -32,12 +32,12 @@
 #include <stdio.h>
 #include <fcntl.h>
 #include <unistd.h>
+#include <limits.h>
+#include <time.h>
+#include <ctype.h>
 #include <sys/types.h>
 #include <sys/stat.h>
-#include <signal.h>
 #include <sys/time.h>
-#include <limits.h>
-#include <unistd.h>
 
 #ifdef HAVE_SCHED_H
 #include <sched.h>
@@ -55,6 +55,17 @@
 #include <netdb.h>
 #endif
 
+#ifdef HAVE_WINDOWS_H
+#include <windows.h>
+#endif
+
+#ifdef HAVE_WINSOCK2_H
+#include <winsock2.h>
+#endif
+#ifdef HAVE_WS2TCPIP_H
+#include <ws2tcpip.h>
+#endif
+
 #include <samplerate.h>
 
 #ifdef HAVE_PWD_H
@@ -68,16 +79,56 @@
 #include "xmalloc.h"
 #include "log.h"
 
+#ifndef OS_IS_WIN32
 #define PA_RUNTIME_PATH_PREFIX "/tmp/polypaudio-"
+#define PATH_SEP '/'
+#else
+#define PA_RUNTIME_PATH_PREFIX "%TEMP%\\polypaudio-"
+#define PATH_SEP '\\'
+#endif
+
+#ifdef OS_IS_WIN32
+
+#define POLYP_ROOTENV "POLYP_ROOT"
+
+int pa_set_root(HANDLE handle) {
+    char library_path[MAX_PATH + sizeof(POLYP_ROOTENV) + 1], *sep;
+
+    strcpy(library_path, POLYP_ROOTENV "=");
+
+    if (!GetModuleFileName(handle, library_path + sizeof(POLYP_ROOTENV), MAX_PATH))
+        return 0;
+
+    sep = strrchr(library_path, '\\');
+    if (sep)
+        *sep = '\0';
+
+    if (_putenv(library_path) < 0)
+        return 0;
+
+    return 1;
+}
+
+#endif
 
 /** Make a file descriptor nonblock. Doesn't do any error checking */
 void pa_make_nonblock_fd(int fd) {
+#ifdef O_NONBLOCK
     int v;
     assert(fd >= 0);
 
     if ((v = fcntl(fd, F_GETFL)) >= 0)
         if (!(v & O_NONBLOCK))
             fcntl(fd, F_SETFL, v|O_NONBLOCK);
+#elif defined(OS_IS_WIN32)
+    u_long arg = 1;
+    if (ioctlsocket(fd, FIONBIO, &arg) < 0) {
+        if (WSAGetLastError() == WSAENOTSOCK)
+            pa_log_warn(__FILE__": WARNING: Only sockets can be made non-blocking!\n");
+    }
+#else
+    pa_log_warn(__FILE__": WARNING: Non-blocking I/O not supported.!\n");
+#endif
 }
 
 /** Creates a directory securely */
@@ -85,15 +136,27 @@ int pa_make_secure_dir(const char* dir) {
     struct stat st;
     assert(dir);
 
-    if (mkdir(dir, 0700) < 0) 
+#ifdef OS_IS_WIN32
+    if (mkdir(dir) < 0)
+#else
+    if (mkdir(dir, 0700) < 0)
+#endif
         if (errno != EEXIST)
             return -1;
-    
-    if (lstat(dir, &st) < 0) 
+
+#ifdef OS_IS_WIN32
+    if (stat(dir, &st) < 0)
+#else
+    if (lstat(dir, &st) < 0)
+#endif
         goto fail;
-    
+
+#ifndef OS_IS_WIN32
     if (!S_ISDIR(st.st_mode) || (st.st_uid != getuid()) || ((st.st_mode & 0777) != 0700))
         goto fail;
+#else
+    fprintf(stderr, "FIXME: pa_make_secure_dir()\n");
+#endif
     
     return 0;
     
@@ -106,10 +169,11 @@ fail:
 int pa_make_secure_parent_dir(const char *fn) {
     int ret = -1;
     char *slash, *dir = pa_xstrdup(fn);
-    
-    if (!(slash = strrchr(dir, '/')))
+
+    slash = pa_path_get_filename(dir);
+    if (slash == fn)
         goto finish;
-    *slash = 0;
+    *(slash-1) = 0;
     
     if (pa_make_secure_dir(dir) < 0)
         goto finish;
@@ -285,6 +349,15 @@ char *pa_get_user_name(char *s, size_t l) {
         }
         
         p = r->pw_name;
+
+#elif defined(OS_IS_WIN32) /* HAVE_PWD_H */
+        DWORD size = sizeof(buf);
+
+        if (!GetUserName(buf, &size))
+            return NULL;
+
+        p = buf;
+
 #else /* HAVE_PWD_H */
         return NULL;
 #endif /* HAVE_PWD_H */
@@ -318,6 +391,9 @@ char *pa_get_home_dir(char *s, size_t l) {
     if ((e = getenv("HOME")))
         return pa_strlcpy(s, e, l);
 
+    if ((e = getenv("USERPROFILE")))
+        return pa_strlcpy(s, e, l);
+
 #ifdef HAVE_PWD_H
 #ifdef HAVE_GETPWUID_R
     if (getpwuid_r(getuid(), &pw, buf, sizeof(buf), &r) != 0 || !r) {
@@ -349,6 +425,34 @@ char *pa_strlcpy(char *b, const char *s, size_t l) {
 int pa_gettimeofday(struct timeval *tv) {
 #ifdef HAVE_GETTIMEOFDAY
     return gettimeofday(tv, NULL);
+#elif 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;
+
+    if (tv) {
+        GetSystemTimeAsFileTime(&ft);
+        li.LowPart  = ft.dwLowDateTime;
+        li.HighPart = ft.dwHighDateTime;
+        t  = li.QuadPart;       /* In 100-nanosecond intervals */
+        t -= EPOCHFILETIME;     /* Offset to the Epoch time */
+        t /= 10;                /* In microseconds */
+        tv->tv_sec  = (long)(t / 1000000);
+        tv->tv_usec = (long)(t % 1000000);
+    }
+
+    return 0;
 #else
 #error "Platform lacks gettimeofday() or equivalent function."
 #endif
@@ -432,10 +536,12 @@ sensible: set the nice level to -15 and enable realtime scheduling if
 supported.*/
 void pa_raise_priority(void) {
 
+#ifdef HAVE_SYS_RESOURCE_H
     if (setpriority(PRIO_PROCESS, 0, NICE_LEVEL) < 0)
         pa_log_warn(__FILE__": setpriority() failed: %s\n", strerror(errno));
     else 
         pa_log_info(__FILE__": Successfully gained nice level %i.\n", NICE_LEVEL); 
+#endif
     
 #ifdef _POSIX_PRIORITY_SCHEDULING
     {
@@ -455,10 +561,21 @@ void pa_raise_priority(void) {
         pa_log_info(__FILE__": Successfully enabled SCHED_FIFO scheduling.\n"); 
     }
 #endif
+
+#ifdef OS_IS_WIN32
+    if (!SetPriorityClass(GetCurrentProcess(), HIGH_PRIORITY_CLASS))
+        pa_log_warn(__FILE__": SetPriorityClass() failed: 0x%08X\n", GetLastError());
+    else
+        pa_log_info(__FILE__": Successfully gained high priority class.\n"); 
+#endif
 }
 
 /* Reset the priority to normal, inverting the changes made by pa_raise_priority() */
 void pa_reset_priority(void) {
+#ifdef OS_IS_WIN32
+    SetPriorityClass(GetCurrentProcess(), NORMAL_PRIORITY_CLASS);
+#endif
+
 #ifdef _POSIX_PRIORITY_SCHEDULING
     {
         struct sched_param sp;
@@ -468,11 +585,15 @@ void pa_reset_priority(void) {
     }
 #endif
 
+#ifdef HAVE_SYS_RESOURCE_H
     setpriority(PRIO_PROCESS, 0, 0);
+#endif
 }
 
 /* Set the FD_CLOEXEC flag for a fd */
 int pa_fd_set_cloexec(int fd, int b) {
+
+#ifdef FD_CLOEXEC
     int v;
     assert(fd >= 0);
 
@@ -483,7 +604,8 @@ int pa_fd_set_cloexec(int fd, int b) {
     
     if (fcntl(fd, F_SETFD, v) < 0)
         return -1;
-    
+#endif    
+
     return 0;
 }
 
@@ -491,6 +613,8 @@ int pa_fd_set_cloexec(int fd, int b) {
  * only. This shoul be used for eyecandy only, don't rely on return
  * non-NULL! */
 char *pa_get_binary_name(char *s, size_t l) {
+
+#ifdef HAVE_READLINK
     char path[PATH_MAX];
     int i;
     assert(s && l);
@@ -503,6 +627,15 @@ char *pa_get_binary_name(char *s, size_t l) {
 
     s[i] = 0;
     return s;
+#elif defined(OS_IS_WIN32)
+    char path[PATH_MAX];
+    if (!GetModuleFileName(NULL, path, PATH_MAX))
+        return NULL;
+    pa_strlcpy(s, pa_path_get_filename(path), l);
+    return s;
+#else
+    return NULL;
+#endif
 }
 
 /* Return a pointer to the filename inside a path (which is the last
@@ -510,7 +643,7 @@ char *pa_get_binary_name(char *s, size_t l) {
 char *pa_path_get_filename(const char *p) {
     char *fn;
 
-    if ((fn = strrchr(p, '/')))
+    if ((fn = strrchr(p, PATH_SEP)))
         return fn+1;
 
     return (char*) p;
@@ -684,6 +817,7 @@ int pa_uid_in_group(const char *name, gid_t *gid) {
 
 /* Lock or unlock a file entirely. (advisory) */
 int pa_lock_fd(int fd, int b) {
+#ifdef F_SETLKW
     struct flock flock;
 
     /* Try a R/W lock first */
@@ -704,6 +838,19 @@ int pa_lock_fd(int fd, int b) {
     }
         
     pa_log(__FILE__": %slock failed: %s\n", !b ? "un" : "", strerror(errno));
+#endif
+
+#ifdef OS_IS_WIN32
+    HANDLE h = (HANDLE)_get_osfhandle(fd);
+
+    if (b && LockFile(h, 0, 0, 0xFFFFFFFF, 0xFFFFFFFF))
+        return 0;
+    if (!b && UnlockFile(h, 0, 0, 0xFFFFFFFF, 0xFFFFFFFF))
+        return 0;
+
+    pa_log(__FILE__": %slock failed: 0x%08X\n", !b ? "un" : "", GetLastError());
+#endif
+
     return -1;
 }
 
@@ -795,31 +942,51 @@ int pa_unlock_lockfile(const char *fn, int fd) {
  * allocated buffer containing the used configuration file is
  * stored there.*/
 FILE *pa_open_config_file(const char *global, const char *local, const char *env, char **result) {
-    const char *e;
+    const char *fn;
     char h[PATH_MAX];
 
-    if (env && (e = getenv(env))) {
+#ifdef OS_IS_WIN32
+    char buf[PATH_MAX];
+
+    if (!getenv(POLYP_ROOTENV))
+        pa_set_root(NULL);
+#endif
+
+    if (env && (fn = getenv(env))) {
+#ifdef OS_IS_WIN32
+        if (!ExpandEnvironmentStrings(fn, buf, PATH_MAX))
+            return NULL;
+        fn = buf;
+#endif
+
         if (result)
-            *result = pa_xstrdup(e);
-        return fopen(e, "r");
+            *result = pa_xstrdup(fn);
+
+        return fopen(fn, "r");
     }
 
     if (local && pa_get_home_dir(h, sizeof(h))) {
         FILE *f;
-        char *l;
+        char *lfn;
         
-        l = pa_sprintf_malloc("%s/%s", h, local);
-        f = fopen(l, "r");
+        lfn = pa_sprintf_malloc("%s/%s", h, local);
+
+#ifdef OS_IS_WIN32
+        if (!ExpandEnvironmentStrings(lfn, buf, PATH_MAX))
+            return NULL;
+        lfn = buf;
+#endif
+
+        f = fopen(lfn, "r");
 
         if (f || errno != ENOENT) {
             if (result)
-                *result = l;
-            else
-                pa_xfree(l);
+                *result = pa_xstrdup(lfn);
+            pa_xfree(lfn);
             return f;
         }
         
-        pa_xfree(l);
+        pa_xfree(lfn);
     }
 
     if (!global) {
@@ -829,6 +996,12 @@ FILE *pa_open_config_file(const char *global, const char *local, const char *env
         return NULL;
     }
 
+#ifdef OS_IS_WIN32
+    if (!ExpandEnvironmentStrings(global, buf, PATH_MAX))
+        return NULL;
+    global = buf;
+#endif
+
     if (result)
         *result = pa_xstrdup(global);
     
@@ -934,21 +1107,44 @@ int pa_startswith(const char *s, const char *pfx) {
 char *pa_runtime_path(const char *fn, char *s, size_t l) {
     char u[256];
 
+#ifndef OS_IS_WIN32
     if (fn && *fn == '/')
+#else
+    if (fn && strlen(fn) >= 3 && isalpha(fn[0]) && fn[1] == ':' && fn[2] == '\\')
+#endif
         return pa_strlcpy(s, fn, l);
-    
-    snprintf(s, l, PA_RUNTIME_PATH_PREFIX"%s%s%s", pa_get_user_name(u, sizeof(u)), fn ? "/" : "", fn ? fn : "");
+
+    if (fn)    
+        snprintf(s, l, "%s%s%c%s", PA_RUNTIME_PATH_PREFIX, pa_get_user_name(u, sizeof(u)), PATH_SEP, fn);
+    else
+        snprintf(s, l, "%s%s", PA_RUNTIME_PATH_PREFIX, pa_get_user_name(u, sizeof(u)));
+
+#ifdef OS_IS_WIN32
+    {
+        char buf[l];
+        strcpy(buf, s);
+        ExpandEnvironmentStrings(buf, s, l);
+    }
+#endif
+
     return s;
 }
 
 /* Wait t milliseconds */
 int pa_msleep(unsigned long t) {
+#ifdef OS_IS_WIN32
+    Sleep(t);
+    return 0;
+#elif defined(HAVE_NANOSLEEP)
     struct timespec ts;
 
     ts.tv_sec = t/1000;
     ts.tv_nsec = (t % 1000) * 1000000;
 
     return nanosleep(&ts, NULL);
+#else
+#error "Platform lacks a sleep function."
+#endif
 }
 
 /* Convert the string s to a signed integer in *ret_i */

commit 6781628ebd29423eb843b6acd71aaff5a744dd9c
Author: Pierre Ossman <ossman at cendio.se>
Date:   Thu Jan 5 22:58:01 2006 +0000

    The Windows sound interface module.
    
    
    git-svn-id: file:///home/lennart/svn/public/pulseaudio/branches/ossman@419 fefdeb5f-60dc-0310-8127-8f9354f1896f

diff --git a/polyp/module-waveout.c b/polyp/module-waveout.c
new file mode 100644
index 0000000..4e01bc7
--- /dev/null
+++ b/polyp/module-waveout.c
@@ -0,0 +1,583 @@
+/* $Id: module-waveout.c 333 2005-01-08 21:36:53Z lennart $ */
+
+/***
+  This file is part of polypaudio.
+ 
+  polypaudio 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 of the License,
+  or (at your option) any later version.
+ 
+  polypaudio 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 polypaudio; if not, write to the Free Software
+  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+  USA.
+***/
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <windows.h>
+#include <mmsystem.h>
+#include <assert.h>
+
+#include "sink.h"
+#include "source.h"
+#include "module.h"
+#include "mainloop-api.h"
+#include "modargs.h"
+#include "sample-util.h"
+#include "util.h"
+#include "log.h"
+#include "xmalloc.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_USAGE("sink_name=<name for the sink> source_name=<name for the source> record=<enable source?> playback=<enable sink?> format=<sample format> channels=<number of channels> rate=<sample rate> fragments=<number of fragments> fragment_size=<fragment size>")
+
+#define PA_TYPEID_WAVEOUT PA_TYPEID_MAKE('W', 'A', 'V', 'E')
+
+#define DEFAULT_SINK_NAME "wave_output"
+#define DEFAULT_SOURCE_NAME "wave_input"
+
+struct userdata {
+    struct pa_sink *sink;
+    struct pa_source *source;
+    struct pa_core *core;
+    struct pa_time_event *event;
+    struct pa_defer_event *defer;
+    pa_usec_t poll_timeout;
+
+    uint32_t fragments, fragment_size;
+
+    uint32_t free_ofrags, free_ifrags;
+
+    DWORD written_bytes;
+
+    int cur_ohdr, cur_ihdr;
+    unsigned int oremain;
+    WAVEHDR *ohdrs, *ihdrs;
+    struct pa_memchunk silence;
+
+    HWAVEOUT hwo;
+    HWAVEIN hwi;
+    struct pa_module *module;
+
+    CRITICAL_SECTION crit;
+};
+
+static const char* const valid_modargs[] = {
+    "sink_name",
+    "source_name",
+    "record",
+    "playback",
+    "fragments",
+    "fragment_size",
+    "format",
+    "rate",
+    "channels",
+    NULL
+};
+
+static void update_usage(struct userdata *u) {
+   pa_module_set_used(u->module,
+                      (u->sink ? pa_idxset_ncontents(u->sink->inputs) : 0) +
+                      (u->sink ? pa_idxset_ncontents(u->sink->monitor_source->outputs) : 0) +
+                      (u->source ? pa_idxset_ncontents(u->source->outputs) : 0));
+}
+
+static void do_write(struct userdata *u)
+{
+    uint32_t free_frags, remain;
+    struct pa_memchunk memchunk, *cur_chunk;
+    WAVEHDR *hdr;
+    MMRESULT res;
+
+    if (!u->sink)
+        return;
+
+    EnterCriticalSection(&u->crit);
+
+    free_frags = u->free_ofrags;
+    u->free_ofrags = 0;
+
+    LeaveCriticalSection(&u->crit);
+
+    while (free_frags) {
+        hdr = &u->ohdrs[u->cur_ohdr];
+        if (hdr->dwFlags & WHDR_PREPARED)
+            waveOutUnprepareHeader(u->hwo, hdr, sizeof(WAVEHDR));
+
+        remain = u->oremain;
+        while (remain) {
+            cur_chunk = &memchunk;
+
+            if (pa_sink_render(u->sink, remain, cur_chunk) < 0) {
+                /*
+                 * Don't fill with silence unless we're getting close to
+                 * underflowing.
+                 */
+                if (free_frags > u->fragments/2)
+                    cur_chunk = &u->silence;
+                else {
+                    EnterCriticalSection(&u->crit);
+
+                    u->free_ofrags += free_frags;
+
+                    LeaveCriticalSection(&u->crit);
+
+                    u->oremain = remain;
+                    return;
+                }
+            }
+
+            assert(cur_chunk->memblock);
+            assert(cur_chunk->memblock->data);
+            assert(cur_chunk->length);
+
+            memcpy(hdr->lpData + u->fragment_size - remain,
+                (char*)cur_chunk->memblock->data + cur_chunk->index,
+                (cur_chunk->length < remain)?cur_chunk->length:remain);
+
+            remain -= (cur_chunk->length < remain)?cur_chunk->length:remain;
+
+            if (cur_chunk != &u->silence) {
+                pa_memblock_unref(cur_chunk->memblock);
+                cur_chunk->memblock = NULL;
+            }
+        }
+
+        res = waveOutPrepareHeader(u->hwo, hdr, sizeof(WAVEHDR));
+        if (res != MMSYSERR_NOERROR) {
+            pa_log_error(__FILE__ ": ERROR: Unable to prepare waveOut block: %d\n",
+                res);
+        }
+        res = waveOutWrite(u->hwo, hdr, sizeof(WAVEHDR));
+        if (res != MMSYSERR_NOERROR) {
+            pa_log_error(__FILE__ ": ERROR: Unable to write waveOut block: %d\n",
+                res);
+        }
+        
+        u->written_bytes += u->fragment_size;
+
+        free_frags--;
+        u->cur_ohdr++;
+        u->cur_ohdr %= u->fragments;
+        u->oremain = u->fragment_size;
+    }
+}
+
+static void do_read(struct userdata *u)
+{
+    uint32_t free_frags;
+    struct pa_memchunk memchunk;
+    WAVEHDR *hdr;
+    MMRESULT res;
+
+    if (!u->source)
+        return;
+
+    EnterCriticalSection(&u->crit);
+
+    free_frags = u->free_ifrags;
+    u->free_ifrags = 0;
+
+    LeaveCriticalSection(&u->crit);
+
+    while (free_frags) {
+        hdr = &u->ihdrs[u->cur_ihdr];
+        if (hdr->dwFlags & WHDR_PREPARED)
+            waveInUnprepareHeader(u->hwi, hdr, sizeof(WAVEHDR));
+
+        if (hdr->dwBytesRecorded) {
+            memchunk.memblock = pa_memblock_new(hdr->dwBytesRecorded, u->core->memblock_stat);
+            assert(memchunk.memblock);
+
+            memcpy((char*)memchunk.memblock->data, hdr->lpData, hdr->dwBytesRecorded);
+
+            memchunk.length = memchunk.memblock->length = hdr->dwBytesRecorded;
+            memchunk.index = 0;
+
+            pa_source_post(u->source, &memchunk);
+            pa_memblock_unref(memchunk.memblock);
+        }
+
+        res = waveInPrepareHeader(u->hwi, hdr, sizeof(WAVEHDR));
+        if (res != MMSYSERR_NOERROR) {
+            pa_log_error(__FILE__ ": ERROR: Unable to prepare waveIn block: %d\n",
+                res);
+        }
+        res = waveInAddBuffer(u->hwi, hdr, sizeof(WAVEHDR));
+        if (res != MMSYSERR_NOERROR) {
+            pa_log_error(__FILE__ ": ERROR: Unable to add waveIn block: %d\n",
+                res);
+        }
+        
+        free_frags--;
+        u->cur_ihdr++;
+        u->cur_ihdr %= u->fragments;
+    }
+}
+
+static void poll_cb(struct pa_mainloop_api*a, struct pa_time_event *e, const struct timeval *tv, void *userdata) {
+    struct userdata *u = userdata;
+    struct timeval ntv;
+
+    assert(u);
+
+    update_usage(u);
+
+    do_write(u);
+    do_read(u);
+
+    pa_gettimeofday(&ntv);
+    pa_timeval_add(&ntv, u->poll_timeout);
+
+    a->time_restart(e, &ntv);
+}
+
+static void defer_cb(struct pa_mainloop_api*a, struct pa_defer_event *e, void *userdata) {
+    struct userdata *u = userdata;
+
+    assert(u);
+
+    a->defer_enable(e, 0);
+
+    do_write(u);
+    do_read(u);
+}
+
+static void CALLBACK chunk_done_cb(HWAVEOUT hwo, UINT msg, DWORD_PTR inst, DWORD param1, DWORD param2) {
+    struct userdata *u = (struct userdata *)inst;
+
+    if (msg != WOM_DONE)
+        return;
+
+    EnterCriticalSection(&u->crit);
+
+    u->free_ofrags++;
+    assert(u->free_ofrags <= u->fragments);
+
+    LeaveCriticalSection(&u->crit);
+}
+
+static void CALLBACK chunk_ready_cb(HWAVEIN hwi, UINT msg, DWORD_PTR inst, DWORD param1, DWORD param2) {
+    struct userdata *u = (struct userdata *)inst;
+
+    if (msg != WIM_DATA)
+        return;
+
+    EnterCriticalSection(&u->crit);
+
+    u->free_ifrags++;
+    assert(u->free_ifrags <= u->fragments);
+
+    LeaveCriticalSection(&u->crit);
+}
+
+static pa_usec_t sink_get_latency_cb(struct pa_sink *s) {
+    struct userdata *u = s->userdata;
+    uint32_t free_frags;
+    MMTIME mmt;
+    assert(s && u && 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);
+    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);
+    }
+}
+
+static pa_usec_t source_get_latency_cb(struct pa_source *s) {
+    pa_usec_t r = 0;
+    struct userdata *u = s->userdata;
+    uint32_t free_frags;
+    assert(s && u && u->sink);
+
+    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);
+
+    fprintf(stderr, "Latency: %d us\n", (int)r);
+
+    return r;
+}
+
+static void notify_sink_cb(struct pa_sink *s) {
+    struct userdata *u = s->userdata;
+    assert(u);
+
+    u->core->mainloop->defer_enable(u->defer, 1);
+}
+
+static void notify_source_cb(struct pa_source *s) {
+    struct userdata *u = s->userdata;
+    assert(u);
+
+    u->core->mainloop->defer_enable(u->defer, 1);
+}
+
+static int ss_to_waveformat(struct pa_sample_spec *ss, LPWAVEFORMATEX wf) {
+    wf->wFormatTag = WAVE_FORMAT_PCM;
+
+    if (ss->channels > 2) {
+        pa_log_error(__FILE__": ERROR: More than two channels not supported.\n");
+        return -1;
+    }
+
+    wf->nChannels = ss->channels;
+
+    switch (ss->rate) {
+    case 8000:
+    case 11025:
+    case 22005:
+    case 44100:
+        break;
+    default:
+        pa_log_error(__FILE__": ERROR: Unsupported sample rate.\n");
+        return -1;
+    }
+
+    wf->nSamplesPerSec = ss->rate;
+
+    if (ss->format == PA_SAMPLE_U8)
+        wf->wBitsPerSample = 8;
+    else if (ss->format == PA_SAMPLE_S16NE)
+        wf->wBitsPerSample = 16;
+    else {
+        pa_log_error(__FILE__": ERROR: Unsupported sample format.\n");
+        return -1;
+    }
+
+    wf->nBlockAlign = wf->nChannels * wf->wBitsPerSample/8;
+    wf->nAvgBytesPerSec = wf->nSamplesPerSec * wf->nBlockAlign;
+
+    wf->cbSize = 0;
+
+    return 0;
+}
+
+int pa__init(struct pa_core *c, struct 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;
+    struct pa_sample_spec ss;
+    struct pa_modargs *ma = NULL;
+    unsigned int i;
+    struct timeval tv;
+
+    assert(c && m);
+
+    if (!(ma = pa_modargs_new(m->argument, valid_modargs))) {
+        pa_log(__FILE__": failed to parse module arguments.\n");
+        goto fail;
+    }
+
+    if (pa_modargs_get_value_boolean(ma, "record", &record) < 0 || pa_modargs_get_value_boolean(ma, "playback", &playback) < 0) {
+        pa_log(__FILE__": record= and playback= expect boolean argument.\n");
+        goto fail;
+    }
+
+    if (!playback && !record) {
+        pa_log(__FILE__": neither playback nor record enabled for device.\n");
+        goto fail;
+    }
+
+    nfrags = 20;
+    frag_size = 1024;
+    if (pa_modargs_get_value_s32(ma, "fragments", &nfrags) < 0 || pa_modargs_get_value_s32(ma, "fragment_size", &frag_size) < 0) {
+        pa_log(__FILE__": failed to parse fragments arguments\n");
+        goto fail;
+    }
+
+    ss = c->default_sample_spec;
+    if (pa_modargs_get_sample_spec(ma, &ss) < 0) {
+        pa_log(__FILE__": failed to parse sample specification\n");
+        goto fail;
+    }
+
+    if (ss_to_waveformat(&ss, &wf) < 0)
+        goto fail;
+
+    u = pa_xmalloc(sizeof(struct userdata));
+
+    if (record) {
+        if (waveInOpen(&hwi, WAVE_MAPPER, &wf, (DWORD_PTR)chunk_ready_cb, (DWORD_PTR)u, CALLBACK_FUNCTION) != MMSYSERR_NOERROR)
+            goto fail;
+        if (waveInStart(hwi) != MMSYSERR_NOERROR)
+            goto fail;
+        pa_log_debug(__FILE__": Opened waveIn subsystem.\n");
+    }
+
+    if (playback) {
+        if (waveOutOpen(&hwo, WAVE_MAPPER, &wf, (DWORD_PTR)chunk_done_cb, (DWORD_PTR)u, CALLBACK_FUNCTION) != MMSYSERR_NOERROR)
+            goto fail;
+        pa_log_debug(__FILE__": Opened waveOut subsystem.\n");
+    }
+
+    InitializeCriticalSection(&u->crit);
+
+    if (hwi != INVALID_HANDLE_VALUE) {
+        u->source = pa_source_new(c, PA_TYPEID_WAVEOUT, pa_modargs_get_value(ma, "source_name", DEFAULT_SOURCE_NAME), 0, &ss);
+        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);
+        u->source->description = pa_sprintf_malloc("Windows waveIn PCM");
+    } else
+        u->source = NULL;
+
+    if (hwo != INVALID_HANDLE_VALUE) {
+        u->sink = pa_sink_new(c, PA_TYPEID_WAVEOUT, pa_modargs_get_value(ma, "sink_name", DEFAULT_SINK_NAME), 0, &ss);
+        assert(u->sink);
+        u->sink->notify = notify_sink_cb;
+        u->sink->get_latency = sink_get_latency_cb;
+        u->sink->userdata = u;
+        pa_sink_set_owner(u->sink, m);
+        u->sink->description = pa_sprintf_malloc("Windows waveOut PCM");
+    } else
+        u->sink = NULL;
+
+    assert(u->source || u->sink);
+
+    u->core = c;
+    u->hwi = hwi;
+    u->hwo = hwo;
+
+    u->fragments = nfrags;
+    u->free_ifrags = u->fragments;
+    u->free_ofrags = u->fragments;
+    u->fragment_size = frag_size - (frag_size % pa_frame_size(&ss));
+
+    u->written_bytes = 0;
+
+    u->oremain = u->fragment_size;
+
+    u->poll_timeout = pa_bytes_to_usec(u->fragments * u->fragment_size / 3, &ss);
+
+    pa_gettimeofday(&tv);
+    pa_timeval_add(&tv, u->poll_timeout);
+
+    u->event = c->mainloop->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);
+    u->ohdrs = pa_xmalloc0(sizeof(WAVEHDR) * u->fragments);
+    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);
+        u->ohdrs[i].lpData = pa_xmalloc(u->fragment_size);
+        assert(u->ohdrs);
+    }
+    
+    u->silence.length = u->fragment_size;
+    u->silence.memblock = pa_memblock_new(u->silence.length, u->core->memblock_stat);
+    assert(u->silence.memblock);
+    pa_silence_memblock(u->silence.memblock, &ss);
+    u->silence.index = 0;
+
+    u->module = m;
+    m->userdata = u;
+
+    pa_modargs_free(ma);
+
+    return 0;
+
+fail:
+   if (hwi != INVALID_HANDLE_VALUE)
+        waveInClose(hwi);
+
+   if (hwo != INVALID_HANDLE_VALUE)
+        waveOutClose(hwo);
+
+    if (u)
+        pa_xfree(u);
+
+    if (ma)
+        pa_modargs_free(ma);
+    
+    return -1;
+}
+
+void pa__done(struct pa_core *c, struct pa_module*m) {
+    struct userdata *u;
+    unsigned int i;
+
+    assert(c && m);
+
+    if (!(u = m->userdata))
+        return;
+    
+    if (u->event)
+        c->mainloop->time_free(u->event);
+
+    if (u->defer)
+        c->mainloop->defer_free(u->defer);
+
+    if (u->sink) {
+        pa_sink_disconnect(u->sink);
+        pa_sink_unref(u->sink);
+    }
+    
+    if (u->source) {
+        pa_source_disconnect(u->source);
+        pa_source_unref(u->source);
+    }
+    
+    if (u->hwi != INVALID_HANDLE_VALUE) {
+        waveInReset(u->hwi);
+        waveInClose(u->hwi);
+    }
+
+    if (u->hwo != INVALID_HANDLE_VALUE) {
+        waveOutReset(u->hwo);
+        waveOutClose(u->hwo);
+    }
+
+    for (i = 0;i < u->fragments;i++) {
+        pa_xfree(u->ihdrs[i].lpData);
+        pa_xfree(u->ohdrs[i].lpData);
+    }
+
+    pa_xfree(u->ihdrs);
+    pa_xfree(u->ohdrs);
+
+    DeleteCriticalSection(&u->crit);
+    
+    pa_xfree(u);
+}

commit 1b472f76ec950e4337b9de1bc7617dbd89449e98
Author: Pierre Ossman <ossman at cendio.se>
Date:   Thu Jan 5 23:06:11 2006 +0000

    Solaris support.
    
    
    git-svn-id: file:///home/lennart/svn/public/pulseaudio/branches/ossman@420 fefdeb5f-60dc-0310-8127-8f9354f1896f

diff --git a/configure.ac b/configure.ac
index 5ff28a5..7737d17 100644
--- a/configure.ac
+++ b/configure.ac
@@ -158,6 +158,10 @@ AC_TYPE_UID_T
 AC_CHECK_DEFINE([SIGXCPU], [signal.h], [HAVE_SIGXCPU=1], [HAVE_SIGXCPU=0])
 AM_CONDITIONAL(HAVE_SIGXCPU, test "x$HAVE_SIGXCPU" = "x1")
 
+# Solaris lacks this
+AC_CHECK_DEFINE([INADDR_NONE], [netinet/in.h], [],
+    [AC_DEFINE([INADDR_NONE],  [0xffffffff], [Define INADDR_NONE if not found in <netinet/in.h>])])
+
 #### Check for functions ####
 
 # ISO
@@ -167,6 +171,7 @@ AC_CHECK_LIB([m], [pow])
 AC_FUNC_FORK
 AC_FUNC_GETGROUPS
 AC_FUNC_SELECT_ARGTYPES
+AC_CHECK_LIB([rt], [sched_setscheduler])
 AC_CHECK_FUNCS([getaddrinfo getgrgid_r getpwuid_r gettimeofday getuid \
     inet_ntop nanosleep setpgid setsid sigaction sleep])
 AC_CHECK_FUNCS([mkfifo], [HAVE_MKFIFO=1], [HAVE_MKFIFO=0])
@@ -179,6 +184,9 @@ AC_CHECK_FUNCS([readlink])
 # SUSv2
 AC_CHECK_FUNCS([ctime_r usleep])
 
+# BSD
+AC_CHECK_LIB([socket], [connect])
+
 # Non-standard
 
 AC_CHECK_FUNCS(setresuid)
@@ -247,6 +255,12 @@ AC_SUBST(ASOUNDLIB_LIBS)
 AC_SUBST(HAVE_ALSA)
 AM_CONDITIONAL([HAVE_ALSA], [test "x$HAVE_ALSA" = x1])
 
+#### Solaris audio support (optional) ####
+
+AC_CHECK_HEADERS([sys/audio.h], [HAVE_SOLARIS=1], [HAVE_SOLARIS=0])
+AC_SUBST(HAVE_SOLARIS)
+AM_CONDITIONAL([HAVE_SOLARIS], [test "x$HAVE_SOLARIS" = x1])
+
 #### GLib 2 support (optional) ####
 
 PKG_CHECK_MODULES(GLIB20, [ glib-2.0 >= 2.4.0 ], HAVE_GLIB20=1, HAVE_GLIB20=0)
diff --git a/polyp/Makefile.am b/polyp/Makefile.am
index dcd3fc1..5f57142 100644
--- a/polyp/Makefile.am
+++ b/polyp/Makefile.am
@@ -43,7 +43,8 @@ endif
 ###################################
 
 AM_CFLAGS  = -D_GNU_SOURCE  -I$(top_srcdir)
-AM_CFLAGS += $(PTHREAD_CFLAGS) $(LTDLINCL)
+AM_CFLAGS += $(PTHREAD_CFLAGS) -D_POSIX_PTHREAD_SEMANTICS
+AM_CFLAGS += $(LTDLINCL)
 AM_CFLAGS += $(LIBSAMPLERATE_CFLAGS) $(LIBSNDFILE_CFLAGS)
 AM_CFLAGS += -DDLSEARCHPATH=\"$(modlibdir)\"
 AM_CFLAGS += -DDEFAULT_CONFIG_DIR=\"$(DEFAULT_CONFIG_DIR)\"
@@ -714,6 +715,11 @@ modlib_LTLIBRARIES += \
 		module-alsa-source.la
 endif
 
+if HAVE_SOLARIS
+modlib_LTLIBRARIES += \
+		module-solaris.la
+endif
+
 if HAVE_HOWL
 modlib_LTLIBRARIES += \
 		module-zeroconf-publish.la
@@ -774,6 +780,7 @@ SYMDEF_FILES = \
 		module-oss-mmap-symdef.h \
 		module-alsa-sink-symdef.h \
 		module-alsa-source-symdef.h \
+		module-solaris-symdef.h \
 		module-waveout-symdef.h
 
 EXTRA_DIST += $(SYMDEF_FILES)
@@ -961,6 +968,12 @@ module_alsa_source_la_LDFLAGS = -module -avoid-version
 module_alsa_source_la_LIBADD = $(AM_LIBADD) $(ASOUNDLIB_LIBS) libalsa-util.la
 module_alsa_source_la_CFLAGS = $(AM_CFLAGS) $(ASOUNDLIB_CFLAGS)
 
+# Solaris
+
+module_solaris_la_SOURCES = module-solaris.c
+module_solaris_la_LDFLAGS = -module -avoid-version
+module_solaris_la_LIBADD = $(AM_LIBADD) libiochannel.la
+
 # HOWL
 
 module_zeroconf_publish_la_SOURCES = module-zeroconf-publish.c
diff --git a/polyp/module-solaris.c b/polyp/module-solaris.c
new file mode 100644
index 0000000..3eb6646
--- /dev/null
+++ b/polyp/module-solaris.c
@@ -0,0 +1,436 @@
+/* $Id: module-oss.c 333 2005-01-08 21:36:53Z lennart $ */
+
+/***
+  This file is part of polypaudio.
+ 
+  polypaudio 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 of the License,
+  or (at your option) any later version.
+ 
+  polypaudio 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 polypaudio; if not, write to the Free Software
+  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+  USA.
+***/
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <assert.h>
+#include <errno.h>
+#include <string.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <limits.h>
+#include <sys/ioctl.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+
+#include <stropts.h>
+#include <sys/conf.h>
+#include <sys/audio.h>
+
+#include "iochannel.h"
+#include "sink.h"
+#include "source.h"
+#include "module.h"
+#include "sample-util.h"
+#include "util.h"
+#include "modargs.h"
+#include "xmalloc.h"
+#include "log.h"
+#include "module-solaris-symdef.h"
+
+PA_MODULE_AUTHOR("Pierre Ossman")
+PA_MODULE_DESCRIPTION("Solaris Sink/Source")
+PA_MODULE_VERSION(PACKAGE_VERSION)
+PA_MODULE_USAGE("sink_name=<name for the sink> source_name=<name for the source> device=<OSS device> record=<enable source?> playback=<enable sink?> format=<sample format> channels=<number of channels> rate=<sample rate> buffer_size=<record buffer size>")
+
+#define PA_TYPEID_SOLARIS PA_TYPEID_MAKE('S', 'L', 'R', 'S')
+
+struct userdata {
+    struct pa_sink *sink;
+    struct pa_source *source;
+    struct pa_iochannel *io;
+    struct pa_core *core;
+
+    struct pa_memchunk memchunk, silence;
+
+    uint32_t sample_size;
+    unsigned int written_bytes, read_bytes;
+
+    int fd;
+    struct pa_module *module;
+};
+
+static const char* const valid_modargs[] = {
+    "sink_name",
+    "source_name",
+    "device",
+    "record",
+    "playback",
+    "buffer_size",
+    "format",
+    "rate",
+    "channels",
+    NULL
+};
+
+#define DEFAULT_SINK_NAME "solaris_output"
+#define DEFAULT_SOURCE_NAME "solaris_input"
+#define DEFAULT_DEVICE "/dev/audio"
+
+#define CHUNK_SIZE 2048
+
+static void update_usage(struct userdata *u) {
+   pa_module_set_used(u->module,
+                      (u->sink ? pa_idxset_ncontents(u->sink->inputs) : 0) +
+                      (u->sink ? pa_idxset_ncontents(u->sink->monitor_source->outputs) : 0) +
+                      (u->source ? pa_idxset_ncontents(u->source->outputs) : 0));
+}
+
+static void do_write(struct userdata *u) {
+    struct pa_memchunk *memchunk;
+    ssize_t r;
+    
+    assert(u);
+
+    if (!u->sink || !pa_iochannel_is_writable(u->io))
+        return;
+
+    update_usage(u);
+
+    memchunk = &u->memchunk;
+    
+    if (!memchunk->length)
+        if (pa_sink_render(u->sink, CHUNK_SIZE, memchunk) < 0)
+            memchunk = &u->silence;
+    
+    assert(memchunk->memblock);
+    assert(memchunk->memblock->data);
+    assert(memchunk->length);
+    
+    if ((r = pa_iochannel_write(u->io, (uint8_t*) memchunk->memblock->data + memchunk->index, memchunk->length)) < 0) {
+        pa_log(__FILE__": write() failed: %s\n", strerror(errno));
+        return;
+    }
+    
+    if (memchunk == &u->silence)
+        assert(r % u->sample_size == 0);
+    else {
+        u->memchunk.index += r;
+        u->memchunk.length -= r;
+        
+        if (u->memchunk.length <= 0) {
+            pa_memblock_unref(u->memchunk.memblock);
+            u->memchunk.memblock = NULL;
+        }
+    }
+
+    u->written_bytes += r;
+}
+
+static void do_read(struct userdata *u) {
+    struct pa_memchunk memchunk;
+    int err, l;
+    ssize_t r;
+    assert(u);
+    
+    if (!u->source || !pa_iochannel_is_readable(u->io))
+        return;
+
+    update_usage(u);
+
+    err = ioctl(u->fd, I_NREAD, &l);
+    assert(err >= 0);
+
+    memchunk.memblock = pa_memblock_new(l, u->core->memblock_stat);
+    assert(memchunk.memblock);
+    if ((r = pa_iochannel_read(u->io, memchunk.memblock->data, memchunk.memblock->length)) < 0) {
+        pa_memblock_unref(memchunk.memblock);
+        if (errno != EAGAIN)
+            pa_log(__FILE__": read() failed: %s\n", strerror(errno));
+        return;
+    }
+    
+    assert(r <= (ssize_t) memchunk.memblock->length);
+    memchunk.length = memchunk.memblock->length = r;
+    memchunk.index = 0;
+    
+    pa_source_post(u->source, &memchunk);
+    pa_memblock_unref(memchunk.memblock);
+
+    u->read_bytes += r;
+}
+
+static void io_callback(struct pa_iochannel *io, void*userdata) {
+    struct userdata *u = userdata;
+    assert(u);
+    do_write(u);
+    do_read(u);
+}
+
+static pa_usec_t sink_get_latency_cb(struct pa_sink *s) {
+    pa_usec_t r = 0;
+    audio_info_t info;
+    int err;
+    struct userdata *u = s->userdata;
+    assert(s && u && u->sink);
+
+    err = ioctl(u->fd, AUDIO_GETINFO, &info);
+    assert(err >= 0);
+
+    r += pa_bytes_to_usec(u->written_bytes, &s->sample_spec);
+    r -= pa_bytes_to_usec(info.play.samples * u->sample_size, &s->sample_spec);
+
+    if (u->memchunk.memblock)
+        r += pa_bytes_to_usec(u->memchunk.length, &s->sample_spec);
+
+    return r;
+}
+
+static pa_usec_t source_get_latency_cb(struct pa_source *s) {
+    pa_usec_t r = 0;
+    struct userdata *u = s->userdata;
+    audio_info_t info;
+    int err;
+    assert(s && u && u->source);
+
+    err = ioctl(u->fd, AUDIO_GETINFO, &info);
+    assert(err >= 0);
+
+    r += pa_bytes_to_usec(info.record.samples * u->sample_size, &s->sample_spec);
+    r -= pa_bytes_to_usec(u->read_bytes, &s->sample_spec);
+
+    return r;
+}
+
+static int pa_solaris_auto_format(int fd, int mode, struct pa_sample_spec *ss) {
+    audio_info_t info;
+
+    AUDIO_INITINFO(&info);
+
+    if (mode != O_RDONLY) {
+        info.play.sample_rate = ss->rate;
+        info.play.channels = ss->channels;
+        switch (ss->format) {
+        case PA_SAMPLE_U8:
+            info.play.precision = 8;
+            info.play.encoding = AUDIO_ENCODING_LINEAR;
+            break;
+        case PA_SAMPLE_ALAW:
+            info.play.precision = 8;
+            info.play.encoding = AUDIO_ENCODING_ALAW;
+            break;
+        case PA_SAMPLE_ULAW:
+            info.play.precision = 8;
+            info.play.encoding = AUDIO_ENCODING_ULAW;
+            break;
+        case PA_SAMPLE_S16NE:
+            info.play.precision = 16;
+            info.play.encoding = AUDIO_ENCODING_LINEAR;
+            break;
+        default:
+            return -1;
+        }
+    }
+
+    if (mode != O_WRONLY) {
+        info.record.sample_rate = ss->rate;
+        info.record.channels = ss->channels;
+        switch (ss->format) {
+        case PA_SAMPLE_U8:
+            info.record.precision = 8;
+            info.record.encoding = AUDIO_ENCODING_LINEAR;
+            break;
+        case PA_SAMPLE_ALAW:
+            info.record.precision = 8;
+            info.record.encoding = AUDIO_ENCODING_ALAW;
+            break;
+        case PA_SAMPLE_ULAW:
+            info.record.precision = 8;
+            info.record.encoding = AUDIO_ENCODING_ULAW;
+            break;
+        case PA_SAMPLE_S16NE:
+            info.record.precision = 16;
+            info.record.encoding = AUDIO_ENCODING_LINEAR;
+            break;
+        default:
+            return -1;
+        }
+    }
+
+    if (ioctl(fd, AUDIO_SETINFO, &info) < 0) {
+        if (errno == EINVAL)
+            pa_log(__FILE__": AUDIO_SETINFO: Unsupported sample format.\n");
+        else
+            pa_log(__FILE__": AUDIO_SETINFO: %s\n", strerror(errno));
+        return -1;
+    }
+
+    return 0;
+}
+
+static int pa_solaris_set_buffer(int fd, int buffer_size) {
+    audio_info_t info;
+
+    AUDIO_INITINFO(&info);
+
+    info.record.buffer_size = buffer_size;
+
+    if (ioctl(fd, AUDIO_SETINFO, &info) < 0) {
+        if (errno == EINVAL)
+            pa_log(__FILE__": AUDIO_SETINFO: Unsupported buffer size.\n");
+        else
+            pa_log(__FILE__": AUDIO_SETINFO: %s\n", strerror(errno));
+        return -1;
+    }
+
+    return 0;
+}
+
+int pa__init(struct pa_core *c, struct pa_module*m) {
+    struct userdata *u = NULL;
+    const char *p;
+    int fd = -1;
+    int buffer_size;
+    int mode;
+    int record = 1, playback = 1;
+    struct pa_sample_spec ss;
+    struct pa_modargs *ma = NULL;
+    assert(c && m);
+
+    if (!(ma = pa_modargs_new(m->argument, valid_modargs))) {
+        pa_log(__FILE__": failed to parse module arguments.\n");
+        goto fail;
+    }
+    
+    if (pa_modargs_get_value_boolean(ma, "record", &record) < 0 || pa_modargs_get_value_boolean(ma, "playback", &playback) < 0) {
+        pa_log(__FILE__": record= and playback= expect numeric argument.\n");
+        goto fail;
+    }
+
+    if (!playback && !record) {
+        pa_log(__FILE__": neither playback nor record enabled for device.\n");
+        goto fail;
+    }
+
+    mode = (playback&&record) ? O_RDWR : (playback ? O_WRONLY : (record ? O_RDONLY : 0));
+
+    buffer_size = -1;    
+    if (pa_modargs_get_value_s32(ma, "buffer_size", &buffer_size) < 0) {
+        pa_log(__FILE__": failed to parse buffer size argument\n");
+        goto fail;
+    }
+
+    ss = c->default_sample_spec;
+    if (pa_modargs_get_sample_spec(ma, &ss) < 0) {
+        pa_log(__FILE__": failed to parse sample specification\n");
+        goto fail;
+    }
+    
+    if ((fd = open(p = pa_modargs_get_value(ma, "device", DEFAULT_DEVICE), mode)) < 0)
+        goto fail;
+
+    pa_log_info(__FILE__": device opened in %s mode.\n", mode == O_WRONLY ? "O_WRONLY" : (mode == O_RDONLY ? "O_RDONLY" : "O_RDWR"));
+
+    if (pa_solaris_auto_format(fd, mode, &ss) < 0)
+        goto fail;
+
+    if ((mode != O_WRONLY) && (buffer_size >= 1))
+        if (pa_solaris_set_buffer(fd, buffer_size) < 0)
+            goto fail;
+
+    u = pa_xmalloc(sizeof(struct userdata));
+    u->core = c;
+
+    if (mode != O_WRONLY) {
+        u->source = pa_source_new(c, PA_TYPEID_SOLARIS, pa_modargs_get_value(ma, "source_name", DEFAULT_SOURCE_NAME), 0, &ss);
+        assert(u->source);
+        u->source->userdata = u;
+        u->source->get_latency = source_get_latency_cb;
+        pa_source_set_owner(u->source, m);
+        u->source->description = pa_sprintf_malloc("Solaris PCM on '%s'", p);
+    } else
+        u->source = NULL;
+
+    if (mode != O_RDONLY) {
+        u->sink = pa_sink_new(c, PA_TYPEID_SOLARIS, pa_modargs_get_value(ma, "sink_name", DEFAULT_SINK_NAME), 0, &ss);
+        assert(u->sink);
+        u->sink->get_latency = sink_get_latency_cb;
+        u->sink->userdata = u;
+        pa_sink_set_owner(u->sink, m);
+        u->sink->description = pa_sprintf_malloc("Solaris PCM on '%s'", p);
+    } else
+        u->sink = NULL;
+
+    assert(u->source || u->sink);
+
+    u->io = pa_iochannel_new(c->mainloop, u->source ? fd : -1, u->sink ? fd : 0);
+    assert(u->io);
+    pa_iochannel_set_callback(u->io, io_callback, u);
+    u->fd = fd;
+
+    u->memchunk.memblock = NULL;
+    u->memchunk.length = 0;
+    u->sample_size = pa_frame_size(&ss);
+
+    u->silence.memblock = pa_memblock_new(u->silence.length = CHUNK_SIZE, u->core->memblock_stat);
+    assert(u->silence.memblock);
+    pa_silence_memblock(u->silence.memblock, &ss);
+    u->silence.index = 0;
+
+    u->written_bytes = 0;
+    u->read_bytes = 0;
+
+    u->module = m;
+    m->userdata = u;
+
+    pa_modargs_free(ma);
+
+    return 0;
+
+fail:
+    if (fd >= 0)
+        close(fd);
+
+    if (ma)
+        pa_modargs_free(ma);
+    
+    return -1;
+}
+
+void pa__done(struct pa_core *c, struct pa_module*m) {
+    struct userdata *u;
+    assert(c && m);
+
+    if (!(u = m->userdata))
+        return;
+    
+    if (u->memchunk.memblock)
+        pa_memblock_unref(u->memchunk.memblock);
+    if (u->silence.memblock)
+        pa_memblock_unref(u->silence.memblock);
+
+    if (u->sink) {
+        pa_sink_disconnect(u->sink);
+        pa_sink_unref(u->sink);
+    }
+    
+    if (u->source) {
+        pa_source_disconnect(u->source);
+        pa_source_unref(u->source);
+    }
+    
+    pa_iochannel_free(u->io);
+    pa_xfree(u);
+}
diff --git a/polyp/socket-server.c b/polyp/socket-server.c
index b7e4fed..c27979d 100644
--- a/polyp/socket-server.c
+++ b/polyp/socket-server.c
@@ -36,6 +36,10 @@
 #endif
 #ifdef HAVE_SYS_UN_H
 #include <sys/un.h>
+#ifndef SUN_LEN
+#define SUN_LEN(ptr) \
+    ((size_t)(((struct sockaddr_un *) 0)->sun_path) + strlen((ptr)->sun_path))
+#endif
 #endif
 #ifdef HAVE_ARPA_INET_H
 #include <arpa/inet.h>

commit 72795fcaa6778d3612ec04f9e5bde9a0eb2b1682
Author: Pierre Ossman <ossman at cendio.se>
Date:   Thu Jan 5 23:11:15 2006 +0000

    Use autoconf detected define for getgroups() type.
    
    
    git-svn-id: file:///home/lennart/svn/public/pulseaudio/branches/ossman@422 fefdeb5f-60dc-0310-8127-8f9354f1896f

diff --git a/polyp/module-protocol-stub.c b/polyp/module-protocol-stub.c
index 8c06a61..b41515f 100644
--- a/polyp/module-protocol-stub.c
+++ b/polyp/module-protocol-stub.c
@@ -62,6 +62,10 @@
 #elif defined(USE_TCP6_SOCKETS)
 #define SOCKET_DESCRIPTION "(TCP/IPv6 sockets)"
 #define SOCKET_USAGE "port=<TCP port number> loopback=<listen on loopback device only?>"
+#ifdef OS_IS_WIN32
+static const struct in6_addr in6addr_any = {{ IN6ADDR_ANY_INIT }};
+static const struct in6_addr in6addr_loopback = {{ IN6ADDR_LOOPBACK_INIT }};
+#endif
 #else
 #define SOCKET_DESCRIPTION "(UNIX sockets)"
 #define SOCKET_USAGE "socket=<path to UNIX socket>"
diff --git a/polyp/polyplib-context.c b/polyp/polyplib-context.c
index da91995..fe5b306 100644
--- a/polyp/polyplib-context.c
+++ b/polyp/polyplib-context.c
@@ -367,12 +367,12 @@ static void setup_context(struct pa_context *c, struct pa_iochannel *io) {
     assert(!c->pdispatch);
     c->pdispatch = pa_pdispatch_new(c->mainloop, command_table, PA_COMMAND_MAX);
     assert(c->pdispatch);
-
+/*
     if (!c->conf->cookie_valid) {
         pa_context_fail(c, PA_ERROR_AUTHKEY);
         goto finish;
     }
-
+*/
     t = pa_tagstruct_new(NULL, 0);
     assert(t);
     pa_tagstruct_putu32(t, PA_COMMAND_AUTH);
diff --git a/polyp/socket-client.c b/polyp/socket-client.c
index 6d8cb2a..201733a 100644
--- a/polyp/socket-client.c
+++ b/polyp/socket-client.c
@@ -70,6 +70,10 @@
 
 #define CONNECT_TIMEOUT 5
 
+#ifdef OS_IS_WIN32
+static const struct in6_addr in6addr_loopback = {{ IN6ADDR_LOOPBACK_INIT }};
+#endif
+
 struct pa_socket_client {
     int ref;
     struct pa_mainloop_api *mainloop;
diff --git a/polyp/socket-server.c b/polyp/socket-server.c
index c27979d..2d5e5ac 100644
--- a/polyp/socket-server.c
+++ b/polyp/socket-server.c
@@ -65,6 +65,11 @@
 #include "util.h"
 #include "log.h"
 
+#ifdef OS_IS_WIN32
+static const struct in6_addr in6addr_any = {{ IN6ADDR_ANY_INIT }};
+static const struct in6_addr in6addr_loopback = {{ IN6ADDR_LOOPBACK_INIT }};
+#endif
+
 struct pa_socket_server {
     int ref;
     int fd;
diff --git a/polyp/util.c b/polyp/util.c
index 0495896..ff27430 100644
--- a/polyp/util.c
+++ b/polyp/util.c
@@ -773,7 +773,7 @@ finish:
 /* Check the current user is member of the specified group */
 int pa_uid_in_group(const char *name, gid_t *gid) {
     gid_t *gids, tgid;
-    long n = sysconf(_SC_NGROUPS_MAX);
+    GETGROUPS_T n = sysconf(_SC_NGROUPS_MAX);
     int r = -1, i;
 
     assert(n > 0);

commit 067c00ff5d3df79829a3b582bb6ac3079c3738de
Author: Pierre Ossman <ossman at cendio.se>
Date:   Thu Jan 5 23:13:54 2006 +0000

    Reversing incorrect commit.
    
    
    git-svn-id: file:///home/lennart/svn/public/pulseaudio/branches/ossman@423 fefdeb5f-60dc-0310-8127-8f9354f1896f

diff --git a/polyp/module-protocol-stub.c b/polyp/module-protocol-stub.c
index b41515f..8c06a61 100644
--- a/polyp/module-protocol-stub.c
+++ b/polyp/module-protocol-stub.c
@@ -62,10 +62,6 @@
 #elif defined(USE_TCP6_SOCKETS)
 #define SOCKET_DESCRIPTION "(TCP/IPv6 sockets)"
 #define SOCKET_USAGE "port=<TCP port number> loopback=<listen on loopback device only?>"
-#ifdef OS_IS_WIN32
-static const struct in6_addr in6addr_any = {{ IN6ADDR_ANY_INIT }};
-static const struct in6_addr in6addr_loopback = {{ IN6ADDR_LOOPBACK_INIT }};
-#endif
 #else
 #define SOCKET_DESCRIPTION "(UNIX sockets)"
 #define SOCKET_USAGE "socket=<path to UNIX socket>"
diff --git a/polyp/polyplib-context.c b/polyp/polyplib-context.c
index fe5b306..da91995 100644
--- a/polyp/polyplib-context.c
+++ b/polyp/polyplib-context.c
@@ -367,12 +367,12 @@ static void setup_context(struct pa_context *c, struct pa_iochannel *io) {
     assert(!c->pdispatch);
     c->pdispatch = pa_pdispatch_new(c->mainloop, command_table, PA_COMMAND_MAX);
     assert(c->pdispatch);
-/*
+
     if (!c->conf->cookie_valid) {
         pa_context_fail(c, PA_ERROR_AUTHKEY);
         goto finish;
     }
-*/
+
     t = pa_tagstruct_new(NULL, 0);
     assert(t);
     pa_tagstruct_putu32(t, PA_COMMAND_AUTH);
diff --git a/polyp/socket-client.c b/polyp/socket-client.c
index 201733a..6d8cb2a 100644
--- a/polyp/socket-client.c
+++ b/polyp/socket-client.c
@@ -70,10 +70,6 @@
 
 #define CONNECT_TIMEOUT 5
 
-#ifdef OS_IS_WIN32
-static const struct in6_addr in6addr_loopback = {{ IN6ADDR_LOOPBACK_INIT }};
-#endif
-
 struct pa_socket_client {
     int ref;
     struct pa_mainloop_api *mainloop;
diff --git a/polyp/socket-server.c b/polyp/socket-server.c
index 2d5e5ac..c27979d 100644
--- a/polyp/socket-server.c
+++ b/polyp/socket-server.c
@@ -65,11 +65,6 @@
 #include "util.h"
 #include "log.h"
 
-#ifdef OS_IS_WIN32
-static const struct in6_addr in6addr_any = {{ IN6ADDR_ANY_INIT }};
-static const struct in6_addr in6addr_loopback = {{ IN6ADDR_LOOPBACK_INIT }};
-#endif
-
 struct pa_socket_server {
     int ref;
     int fd;

commit 8a323571a4fae25602133cc87656706ada9c0112
Author: Pierre Ossman <ossman at cendio.se>
Date:   Mon Jan 9 11:54:49 2006 +0000

    Make sure the data gets endianness conversion.
    
    
    git-svn-id: file:///home/lennart/svn/public/pulseaudio/branches/ossman@424 fefdeb5f-60dc-0310-8127-8f9354f1896f

diff --git a/polyp/protocol-esound.c b/polyp/protocol-esound.c
index 5705d3f..18ecb0a 100644
--- a/polyp/protocol-esound.c
+++ b/polyp/protocol-esound.c
@@ -239,11 +239,14 @@ static void* connection_write(struct connection *c, size_t length) {
     return (uint8_t*) c->write_data+i;
 }
 
-static void format_esd2native(int format, struct pa_sample_spec *ss) {
+static void format_esd2native(int format, int swap_bytes, struct pa_sample_spec *ss) {
     assert(ss);
 
     ss->channels = ((format & ESD_MASK_CHAN) == ESD_STEREO) ? 2 : 1;
-    ss->format = ((format & ESD_MASK_BITS) == ESD_BITS16) ? PA_SAMPLE_S16NE : PA_SAMPLE_U8;
+    if ((format & ESD_MASK_BITS) == ESD_BITS16)
+        ss->format = swap_bytes ? PA_SAMPLE_S16RE : PA_SAMPLE_S16NE;
+    else
+        ss->format = PA_SAMPLE_U8;
 }
 
 static int format_native2esd(struct pa_sample_spec *ss) {
@@ -303,7 +306,7 @@ static int esd_proto_stream_play(struct connection *c, esd_proto_t request, cons
     rate = maybe_swap_endian_32(c->swap_byte_order, *((int*)data + 1));
 
     ss.rate = rate;
-    format_esd2native(format, &ss);
+    format_esd2native(format, c->swap_byte_order, &ss);
 
     if (!pa_sample_spec_valid(&ss)) {
         pa_log(__FILE__": invalid sample specification\n");
@@ -359,7 +362,7 @@ static int esd_proto_stream_record(struct connection *c, esd_proto_t request, co
     rate = maybe_swap_endian_32(c->swap_byte_order, *((int*)data + 1));
 
     ss.rate = rate;
-    format_esd2native(format, &ss);
+    format_esd2native(format, c->swap_byte_order, &ss);
 
     if (!pa_sample_spec_valid(&ss)) {
         pa_log(__FILE__": invalid sample specification.\n");
@@ -602,7 +605,7 @@ static int esd_proto_sample_cache(struct connection *c, esd_proto_t request, con
     rate = maybe_swap_endian_32(c->swap_byte_order, *((int*)data + 1));
     
     ss.rate = rate;
-    format_esd2native(format, &ss);
+    format_esd2native(format, c->swap_byte_order, &ss);
 
     sc_length = (size_t) maybe_swap_endian_32(c->swap_byte_order, (*((int*)data + 2)));
 
diff --git a/polyp/sample.h b/polyp/sample.h
index 0494c7d..82c1461 100644
--- a/polyp/sample.h
+++ b/polyp/sample.h
@@ -51,11 +51,19 @@ enum pa_sample_format {
 #define PA_SAMPLE_S16NE PA_SAMPLE_S16BE
 /** 32 Bit IEEE floating point, native endian */
 #define PA_SAMPLE_FLOAT32NE PA_SAMPLE_FLOAT32BE
+/** Signed 16 Bit PCM reverse endian */
+#define PA_SAMPLE_S16RE PA_SAMPLE_S16LE
+/** 32 Bit IEEE floating point, reverse endian */
+#define PA_SAMPLE_FLOAT32RE PA_SAMPLE_FLOAT32LE
 #else
 /** Signed 16 Bit PCM, native endian */
 #define PA_SAMPLE_S16NE PA_SAMPLE_S16LE
 /** 32 Bit IEEE floating point, native endian */
 #define PA_SAMPLE_FLOAT32NE PA_SAMPLE_FLOAT32LE
+/** Signed 16 Bit PCM reverse endian */
+#define PA_SAMPLE_S16RE PA_SAMPLE_S16BE
+/** 32 Bit IEEE floating point, reverse endian */
+#define PA_SAMPLE_FLOAT32RE PA_SAMPLE_FLOAT32BE
 #endif
 
 /** A Shortcut for PA_SAMPLE_FLOAT32NE */

commit 9818d67ec27bbc39feaf4c1a1f3d35a029484cc9
Author: Pierre Ossman <ossman at cendio.se>
Date:   Mon Jan 9 14:39:40 2006 +0000

    Make the tagstruct handling safe on machines with alignment restrictions.
    
    
    git-svn-id: file:///home/lennart/svn/public/pulseaudio/branches/ossman@427 fefdeb5f-60dc-0310-8127-8f9354f1896f

diff --git a/polyp/tagstruct.c b/polyp/tagstruct.c
index 59178bf..ff444e3 100644
--- a/polyp/tagstruct.c
+++ b/polyp/tagstruct.c
@@ -125,7 +125,8 @@ void pa_tagstruct_putu32(struct pa_tagstruct*t, uint32_t i) {
     assert(t);
     extend(t, 5);
     t->data[t->length] = TAG_U32;
-    *((uint32_t*) (t->data+t->length+1)) = htonl(i);
+    i = htonl(i);
+    memcpy(t->data+t->length+1, &i, 4);
     t->length += 5;
 }
 
@@ -138,12 +139,14 @@ void pa_tagstruct_putu8(struct pa_tagstruct*t, uint8_t c) {
 }
 
 void pa_tagstruct_put_sample_spec(struct pa_tagstruct *t, const struct pa_sample_spec *ss) {
+    uint32_t rate;
     assert(t && ss);
     extend(t, 7);
     t->data[t->length] = TAG_SAMPLE_SPEC;
     t->data[t->length+1] = (uint8_t) ss->format;
     t->data[t->length+2] = ss->channels;
-    *(uint32_t*) (t->data+t->length+3) = htonl(ss->rate);
+    rate = htonl(ss->rate);
+    memcpy(t->data+t->length+3, &rate, 4);
     t->length += 7;
 }
 
@@ -152,9 +155,10 @@ void pa_tagstruct_put_arbitrary(struct pa_tagstruct *t, const void *p, size_t le
 
     extend(t, 5+length);
     t->data[t->length] = TAG_ARBITRARY;
-    *((uint32_t*) (t->data+t->length+1)) = htonl(length);
     if (length)
         memcpy(t->data+t->length+5, p, length);
+    length = htonl(length);
+    memcpy(t->data+t->length+1, &length, 4);
     t->length += 5+length;
 }
 
@@ -166,29 +170,38 @@ void pa_tagstruct_put_boolean(struct pa_tagstruct*t, int b) {
 }
 
 void pa_tagstruct_put_timeval(struct pa_tagstruct*t, const struct timeval *tv) {
+    uint32_t tmp;
     assert(t);
     extend(t, 9);
     t->data[t->length] = TAG_TIMEVAL;
-    *((uint32_t*) (t->data+t->length+1)) = htonl(tv->tv_sec);
-    *((uint32_t*) (t->data+t->length+5)) = htonl(tv->tv_usec);
+    tmp = htonl(tv->tv_sec);
+    memcpy(t->data+t->length+1, &tmp, 4);
+    tmp = htonl(tv->tv_usec);
+    memcpy(t->data+t->length+5, &tmp, 4);
     t->length += 9;
 }
 
 void pa_tagstruct_put_usec(struct pa_tagstruct*t, pa_usec_t u) {
+    uint32_t tmp;
     assert(t);
     extend(t, 9);
     t->data[t->length] = TAG_USEC;
-    *((uint32_t*) (t->data+t->length+1)) = htonl((uint32_t) (u >> 32));
-    *((uint32_t*) (t->data+t->length+5)) = htonl((uint32_t) u);
+    tmp = htonl((uint32_t) (u >> 32));
+    memcpy(t->data+t->length+1, &tmp, 4);
+    tmp = htonl((uint32_t) u);
+    memcpy(t->data+t->length+5, &tmp, 4);
     t->length += 9;
 }
 
 void pa_tagstruct_putu64(struct pa_tagstruct*t, uint64_t u) {
+    uint32_t tmp;
     assert(t);
     extend(t, 9);
     t->data[t->length] = TAG_U64;
-    *((uint32_t*) (t->data+t->length+1)) = htonl((uint32_t) (u >> 32));
-    *((uint32_t*) (t->data+t->length+5)) = htonl((uint32_t) u);
+    tmp = htonl((uint32_t) (u >> 32));
+    memcpy(t->data+t->length+1, &tmp, 4);
+    tmp = htonl((uint32_t) u);
+    memcpy(t->data+t->length+5, &tmp, 4);
     t->length += 9;
 }
 
@@ -237,8 +250,9 @@ int pa_tagstruct_getu32(struct pa_tagstruct*t, uint32_t *i) {
 
     if (t->data[t->rindex] != TAG_U32)
         return -1;
-    
-    *i = ntohl(*((uint32_t*) (t->data+t->rindex+1)));
+
+    memcpy(i, t->data+t->rindex+1, 4);
+    *i = ntohl(*i);
     t->rindex += 5;
     return 0;
 }
@@ -268,13 +282,15 @@ int pa_tagstruct_get_sample_spec(struct pa_tagstruct *t, struct pa_sample_spec *
     
     ss->format = t->data[t->rindex+1];
     ss->channels = t->data[t->rindex+2];
-    ss->rate = ntohl(*(uint32_t*) (t->data+t->rindex+3));
+    memcpy(&ss->rate, t->data+t->rindex+3, 4);
+    ss->rate = ntohl(ss->rate);
     
     t->rindex += 7;
     return 0;
 }
 
 int pa_tagstruct_get_arbitrary(struct pa_tagstruct *t, const void **p, size_t length) {
+    uint32_t len;
     assert(t && p);
     
     if (t->rindex+5+length > t->length)
@@ -283,7 +299,8 @@ int pa_tagstruct_get_arbitrary(struct pa_tagstruct *t, const void **p, size_t le
     if (t->data[t->rindex] != TAG_ARBITRARY)
         return -1;
 
-    if (ntohl(*((uint32_t*) (t->data+t->rindex+1))) != length)
+    memcpy(&len, t->data+t->rindex+1, 4);
+    if (ntohl(len) != length)
         return -1;
 
     *p = t->data+t->rindex+5;
@@ -326,15 +343,18 @@ int pa_tagstruct_get_timeval(struct pa_tagstruct*t, struct timeval *tv) {
 
     if (t->data[t->rindex] != TAG_TIMEVAL)
         return -1;
-    
-    tv->tv_sec = ntohl(*((uint32_t*) (t->data+t->rindex+1)));
-    tv->tv_usec = ntohl(*((uint32_t*) (t->data+t->rindex+5)));
+
+    memcpy(&tv->tv_sec, t->data+t->rindex+1, 4);
+    tv->tv_sec = ntohl(tv->tv_sec);
+    memcpy(&tv->tv_usec, t->data+t->rindex+5, 4);
+    tv->tv_usec = ntohl(tv->tv_usec);
     t->rindex += 9;
     return 0;
     
 }
 
 int pa_tagstruct_get_usec(struct pa_tagstruct*t, pa_usec_t *u) {
+    uint32_t tmp;
     assert(t && u);
 
     if (t->rindex+9 > t->length)
@@ -343,13 +363,16 @@ int pa_tagstruct_get_usec(struct pa_tagstruct*t, pa_usec_t *u) {
     if (t->data[t->rindex] != TAG_USEC)
         return -1;
 
-    *u = (pa_usec_t) ntohl(*((uint32_t*) (t->data+t->rindex+1))) << 32;
-    *u |= (pa_usec_t) ntohl(*((uint32_t*) (t->data+t->rindex+5)));
+    memcpy(&tmp, t->data+t->rindex+1, 4);
+    *u = (pa_usec_t) ntohl(tmp) << 32;
+    memcpy(&tmp, t->data+t->rindex+5, 4);
+    *u |= (pa_usec_t) ntohl(tmp);
     t->rindex +=9;
     return 0;
 }
 
 int pa_tagstruct_getu64(struct pa_tagstruct*t, uint64_t *u) {
+    uint32_t tmp;
     assert(t && u);
 
     if (t->rindex+9 > t->length)
@@ -358,8 +381,10 @@ int pa_tagstruct_getu64(struct pa_tagstruct*t, uint64_t *u) {
     if (t->data[t->rindex] != TAG_U64)
         return -1;
 
-    *u = (uint64_t) ntohl(*((uint32_t*) (t->data+t->rindex+1))) << 32;
-    *u |= (uint64_t) ntohl(*((uint32_t*) (t->data+t->rindex+5)));
+    memcpy(&tmp, t->data+t->rindex+1, 4);
+    *u = (pa_usec_t) ntohl(tmp) << 32;
+    memcpy(&tmp, t->data+t->rindex+5, 4);
+    *u |= (pa_usec_t) ntohl(tmp);
     t->rindex +=9;
     return 0;
 }

commit 5fcbf04f5b95cccc61b2986a6582fa475e4d9c8b
Author: Pierre Ossman <ossman at cendio.se>
Date:   Mon Jan 9 16:50:39 2006 +0000

    Condense winsock includes and defines into one header.
    
    
    git-svn-id: file:///home/lennart/svn/public/pulseaudio/branches/ossman@428 fefdeb5f-60dc-0310-8127-8f9354f1896f

diff --git a/polyp/Makefile.am b/polyp/Makefile.am
index 5f57142..ab7dfe5 100644
--- a/polyp/Makefile.am
+++ b/polyp/Makefile.am
@@ -335,6 +335,7 @@ libpolyp_ at PA_MAJORMINOR@_la_SOURCES = \
 		tagstruct.c tagstruct.h \
 		typeid.c typeid.h \
 		util.c util.h \
+		winsock.h \
 		xmalloc.c xmalloc.h
 
 if HAVE_X11
@@ -476,6 +477,7 @@ libpolypcore_la_SOURCES = \
 		tokenizer.c tokenizer.h \
 		typeid.c typeid.h \
 		util.c util.h \
+		winsock.h \
 		xmalloc.c xmalloc.h
 
 libpolypcore_la_CPPFLAGS = $(AM_CPPFLAGS)
diff --git a/polyp/iochannel.c b/polyp/iochannel.c
index 08a4e36..1a0dbf9 100644
--- a/polyp/iochannel.c
+++ b/polyp/iochannel.c
@@ -28,9 +28,7 @@
 #include <fcntl.h>
 #include <unistd.h>
 
-#ifdef HAVE_WINSOCK2_H
-#include <winsock2.h>
-#endif
+#include "winsock.h"
 
 #include "iochannel.h"
 #include "util.h"
diff --git a/polyp/main.c b/polyp/main.c
index 437f0a4..e481fce 100644
--- a/polyp/main.c
+++ b/polyp/main.c
@@ -42,15 +42,13 @@
 #include <sys/ioctl.h>
 #endif
 
-#ifdef HAVE_WINSOCK2_H
-#include <winsock2.h>
-#endif
-
 #ifdef HAVE_LIBWRAP
 #include <syslog.h>
 #include <tcpd.h>
 #endif
 
+#include "winsock.h"
+
 #include "core.h"
 #include "mainloop.h"
 #include "module.h"
diff --git a/polyp/mainloop.c b/polyp/mainloop.c
index 9cfd539..ada74af 100644
--- a/polyp/mainloop.c
+++ b/polyp/mainloop.c
@@ -38,9 +38,7 @@
 #include "poll.h"
 #endif
 
-#ifdef HAVE_WINSOCK2_H
-#include <winsock2.h>
-#endif
+#include "winsock.h"
 
 #include "mainloop.h"
 #include "util.h"
diff --git a/polyp/module-protocol-stub.c b/polyp/module-protocol-stub.c
index 8c06a61..141eadd 100644
--- a/polyp/module-protocol-stub.c
+++ b/polyp/module-protocol-stub.c
@@ -40,12 +40,7 @@
 #include <netinet/in.h>
 #endif
 
-#ifdef HAVE_WINSOCK2_H
-#include <winsock2.h>
-#endif
-#ifdef HAVE_WS2TCPIP_H
-#include <ws2tcpip.h>
-#endif
+#include "winsock.h"
 
 #include "module.h"
 #include "socket-server.h"
diff --git a/polyp/poll.c b/polyp/poll.c
index 7c25f34..cb7e3e7 100644
--- a/polyp/poll.c
+++ b/polyp/poll.c
@@ -36,16 +36,7 @@
 #include <sys/select.h>
 #endif
 
-#ifdef HAVE_WINSOCK2_H
-#include <winsock2.h>
-
-#define EBADF           WSAEBADF
-#define ESHUTDOWN       WSAESHUTDOWN
-#define ECONNRESET      WSAECONNRESET
-#define ECONNABORTED    WSAECONNABORTED
-#define ENETRESET       WSAENETRESET
-
-#endif /* HAVE_WINSOCK2_H */
+#include "winsock.h"
 
 #ifndef HAVE_SYS_POLL_H
 
diff --git a/polyp/polyplib-context.c b/polyp/polyplib-context.c
index da91995..f97d9b8 100644
--- a/polyp/polyplib-context.c
+++ b/polyp/polyplib-context.c
@@ -45,12 +45,7 @@
 #include <netdb.h>
 #endif
 
-#ifdef HAVE_WINSOCK2_H
-#include <winsock2.h>
-#define ETIMEDOUT       WSAETIMEDOUT
-#define ECONNREFUSED    WSAECONNREFUSED
-#define EHOSTUNREACH    WSAEHOSTUNREACH
-#endif
+#include "winsock.h"
 
 #include "polyplib-internal.h"
 #include "polyplib-context.h"
diff --git a/polyp/pstream.c b/polyp/pstream.c
index 607b0c1..6f98328 100644
--- a/polyp/pstream.c
+++ b/polyp/pstream.c
@@ -32,9 +32,7 @@
 #include <netinet/in.h>
 #endif
 
-#ifdef HAVE_WINSOCK2_H
-#include <winsock2.h>
-#endif
+#include "winsock.h"
 
 #include "pstream.h"
 #include "queue.h"
diff --git a/polyp/socket-client.c b/polyp/socket-client.c
index 6d8cb2a..51134b8 100644
--- a/polyp/socket-client.c
+++ b/polyp/socket-client.c
@@ -48,19 +48,12 @@
 #include <netdb.h>
 #endif
 
-#ifdef HAVE_WINSOCK2_H
-#include <winsock2.h>
-#define EINPROGRESS     WSAEINPROGRESS
-#define ETIMEDOUT       WSAETIMEDOUT
-#endif
-#ifdef HAVE_WS2TCPIP_H
-#include <ws2tcpip.h>
-#endif
-
 #ifdef HAVE_LIBASYNCNS
 #include <asyncns.h>
 #endif
 
+#include "winsock.h"
+
 #include "socket-client.h"
 #include "socket-util.h"
 #include "util.h"
diff --git a/polyp/socket-server.c b/polyp/socket-server.c
index c27979d..18122f3 100644
--- a/polyp/socket-server.c
+++ b/polyp/socket-server.c
@@ -48,17 +48,12 @@
 #include <netinet/in.h>
 #endif
 
-#ifdef HAVE_WINSOCK2_H
-#include <winsock2.h>
-#endif
-#ifdef HAVE_WS2TCPIP_H
-#include <ws2tcpip.h>
-#endif
-
 #ifdef HAVE_LIBWRAP
 #include <tcpd.h>
 #endif
 
+#include "winsock.h"
+
 #include "socket-server.h"
 #include "socket-util.h"
 #include "xmalloc.h"
diff --git a/polyp/socket-util.c b/polyp/socket-util.c
index 699b28c..381502b 100644
--- a/polyp/socket-util.c
+++ b/polyp/socket-util.c
@@ -57,10 +57,7 @@
 #include <netdb.h>
 #endif
 
-#ifdef HAVE_WINSOCK2_H
-#include <winsock2.h>
-#define ETIMEDOUT       WSAETIMEDOUT
-#endif
+#include "winsock.h"
 
 #include "socket-util.h"
 #include "util.h"
diff --git a/polyp/tagstruct.c b/polyp/tagstruct.c
index ff444e3..1e44f8e 100644
--- a/polyp/tagstruct.c
+++ b/polyp/tagstruct.c
@@ -33,9 +33,7 @@
 #include <netinet/in.h>
 #endif
 
-#ifdef HAVE_WINSOCK2_H
-#include <winsock2.h>
-#endif
+#include "winsock.h"
 
 #include "tagstruct.h"
 #include "xmalloc.h"
diff --git a/polyp/util.c b/polyp/util.c
index ff27430..f1f4b2c 100644
--- a/polyp/util.c
+++ b/polyp/util.c
@@ -59,13 +59,6 @@
 #include <windows.h>
 #endif
 
-#ifdef HAVE_WINSOCK2_H
-#include <winsock2.h>
-#endif
-#ifdef HAVE_WS2TCPIP_H
-#include <ws2tcpip.h>
-#endif
-
 #include <samplerate.h>
 
 #ifdef HAVE_PWD_H
@@ -75,6 +68,8 @@
 #include <grp.h>
 #endif
 
+#include "winsock.h"
+
 #include "util.h"
 #include "xmalloc.h"
 #include "log.h"
diff --git a/polyp/winsock.h b/polyp/winsock.h
new file mode 100644
index 0000000..60fac87
--- /dev/null
+++ b/polyp/winsock.h
@@ -0,0 +1,23 @@
+#ifndef foowinsockhfoo
+#define foowinsockhfoo
+
+#ifdef HAVE_WINSOCK2_H
+#include <winsock2.h>
+
+#define EBADF           WSAEBADF
+#define ESHUTDOWN       WSAESHUTDOWN
+#define ECONNRESET      WSAECONNRESET
+#define ECONNABORTED    WSAECONNABORTED
+#define ENETRESET       WSAENETRESET
+#define EINPROGRESS     WSAEINPROGRESS
+#define ETIMEDOUT       WSAETIMEDOUT
+#define ECONNREFUSED    WSAECONNREFUSED
+#define EHOSTUNREACH    WSAEHOSTUNREACH
+
+#endif
+
+#ifdef HAVE_WS2TCPIP_H
+#include <ws2tcpip.h>
+#endif
+
+#endif

commit 8258146625050d242b9bc3dc5f175985feb5e2bd
Author: Pierre Ossman <ossman at cendio.se>
Date:   Mon Jan 9 16:56:41 2006 +0000

    Generalise lstat fallback.
    
    
    git-svn-id: file:///home/lennart/svn/public/pulseaudio/branches/ossman@429 fefdeb5f-60dc-0310-8127-8f9354f1896f

diff --git a/configure.ac b/configure.ac
index 7737d17..8030e6a 100644
--- a/configure.ac
+++ b/configure.ac
@@ -186,6 +186,7 @@ AC_CHECK_FUNCS([ctime_r usleep])
 
 # BSD
 AC_CHECK_LIB([socket], [connect])
+AC_CHECK_FUNCS([lstat])
 
 # Non-standard
 
diff --git a/polyp/util.c b/polyp/util.c
index f1f4b2c..b2f61d5 100644
--- a/polyp/util.c
+++ b/polyp/util.c
@@ -139,10 +139,10 @@ int pa_make_secure_dir(const char* dir) {
         if (errno != EEXIST)
             return -1;
 
-#ifdef OS_IS_WIN32
-    if (stat(dir, &st) < 0)
-#else
+#ifdef HAVE_LSTAT
     if (lstat(dir, &st) < 0)
+#else
+    if (stat(dir, &st) < 0)
 #endif
         goto fail;
 

commit 160d886c0d8f783765d06662d87c01a3603e1c4c
Author: Pierre Ossman <ossman at cendio.se>
Date:   Mon Jan 9 16:57:42 2006 +0000

    Merge with trunk.
    
    
    git-svn-id: file:///home/lennart/svn/public/pulseaudio/branches/ossman@430 fefdeb5f-60dc-0310-8127-8f9354f1896f

diff --git a/polyp/polyplib-stream.c b/polyp/polyplib-stream.c
index c7c40c0..7058b54 100644
--- a/polyp/polyplib-stream.c
+++ b/polyp/polyplib-stream.c
@@ -413,7 +413,7 @@ static void stream_get_latency_info_callback(struct pa_pdispatch *pd, uint32_t c
     } else {
         pa_gettimeofday(&now);
         
-        if (pa_timeval_cmp(&local, &remote) < 0 && pa_timeval_cmp(&remote, &now)) {
+        if (pa_timeval_cmp(&local, &remote) <= 0 && pa_timeval_cmp(&remote, &now) <= 0) {
             /* local and remote seem to have synchronized clocks */
             
             if (o->stream->direction == PA_STREAM_PLAYBACK)

commit d3cb1448b4765705ed14aee5b40b87459a4e302d
Author: Pierre Ossman <ossman at cendio.se>
Date:   Mon Jan 9 16:59:12 2006 +0000

    Update comment for pa_lock_fd() to reflect that locks are mandatory
    on Windows.
    
    
    git-svn-id: file:///home/lennart/svn/public/pulseaudio/branches/ossman@431 fefdeb5f-60dc-0310-8127-8f9354f1896f

diff --git a/polyp/util.c b/polyp/util.c
index b2f61d5..569412d 100644
--- a/polyp/util.c
+++ b/polyp/util.c
@@ -810,7 +810,8 @@ int pa_uid_in_group(const char *name, gid_t *gid) {
 
 #endif
 
-/* Lock or unlock a file entirely. (advisory) */
+/* Lock or unlock a file entirely.
+  (advisory on UNIX, mandatory on Windows) */
 int pa_lock_fd(int fd, int b) {
 #ifdef F_SETLKW
     struct flock flock;

commit 76bc56cf3b50e5d446046536f22a3dfd372f11c7
Author: Pierre Ossman <ossman at cendio.se>
Date:   Mon Jan 9 17:14:30 2006 +0000

    Put inet_ntop() emulation in a seperate file.
    
    
    git-svn-id: file:///home/lennart/svn/public/pulseaudio/branches/ossman@432 fefdeb5f-60dc-0310-8127-8f9354f1896f

diff --git a/polyp/Makefile.am b/polyp/Makefile.am
index ab7dfe5..22e8da3 100644
--- a/polyp/Makefile.am
+++ b/polyp/Makefile.am
@@ -540,7 +540,9 @@ libprotocol_simple_la_SOURCES = protocol-simple.c protocol-simple.h
 libprotocol_simple_la_LDFLAGS = -avoid-version
 libprotocol_simple_la_LIBADD = $(AM_LIBADD) libpolypcore.la libsocket-server.la libiochannel.la
 
-libsocket_server_la_SOURCES = socket-server.c socket-server.h
+libsocket_server_la_SOURCES = \
+		inet_ntop.c inet_ntop.h \
+		socket-server.c socket-server.h
 libsocket_server_la_LDFLAGS = -avoid-version
 libsocket_server_la_LIBADD = $(AM_LIBADD) libpolypcore.la libiochannel.la libsocket-util.la $(LIBWRAP_LIBS) $(WINSOCK_LIBS)
 
diff --git a/polyp/inet_ntop.c b/polyp/inet_ntop.c
new file mode 100644
index 0000000..19f29f8
--- /dev/null
+++ b/polyp/inet_ntop.c
@@ -0,0 +1,78 @@
+/* $Id: inet_ntop.c 428 2006-01-09 16:50:39Z ossman $ */
+
+/***
+  This file is part of polypaudio.
+ 
+  polypaudio 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.
+ 
+  polypaudio 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
+  Lesser General Public License for more details.
+ 
+  You should have received a copy of the GNU Lesser General Public
+  License along with polypaudio; if not, write to the Free Software
+  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+  USA.
+***/
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdio.h>
+
+#ifndef HAVE_INET_NTOP
+
+#ifdef HAVE_SYS_SOCKET_H
+#include <sys/socket.h>
+#endif
+
+#include "winsock.h"
+
+#include "inet_ntop.h"
+
+const char *inet_ntop(int af, const void *src, char *dst, socklen_t cnt) {
+    struct in_addr *in = (struct in_addr*)src;
+    struct in6_addr *in6 = (struct in6_addr*)src;
+
+    assert(src && dst);
+
+    switch (af) {
+    case AF_INET:
+        snprintf(dst, cnt, "%d.%d.%d.%d",
+#ifdef WORDS_BIGENDIAN
+            (int)(in->s_addr >> 24) & 0xff,
+            (int)(in->s_addr >> 16) & 0xff,
+            (int)(in->s_addr >>  8) & 0xff,
+            (int)(in->s_addr >>  0) & 0xff);
+#else
+            (int)(in->s_addr >>  0) & 0xff,
+            (int)(in->s_addr >>  8) & 0xff,
+            (int)(in->s_addr >> 16) & 0xff,
+            (int)(in->s_addr >> 24) & 0xff);
+#endif
+        break;
+    case AF_INET6:
+        snprintf(dst, cnt, "%x:%x:%x:%x:%x:%x:%x:%x",
+            in6->s6_addr[ 0] << 8 | in6->s6_addr[ 1],
+            in6->s6_addr[ 2] << 8 | in6->s6_addr[ 3],
+            in6->s6_addr[ 4] << 8 | in6->s6_addr[ 5],
+            in6->s6_addr[ 6] << 8 | in6->s6_addr[ 7],
+            in6->s6_addr[ 8] << 8 | in6->s6_addr[ 9],
+            in6->s6_addr[10] << 8 | in6->s6_addr[11],
+            in6->s6_addr[12] << 8 | in6->s6_addr[13],
+            in6->s6_addr[14] << 8 | in6->s6_addr[15]);
+        break;
+    default:
+        errno = EAFNOSUPPORT;
+        return NULL;
+    }
+
+    return dst;
+}
+
+#endif /* INET_NTOP */
diff --git a/polyp/inet_ntop.h b/polyp/inet_ntop.h
new file mode 100644
index 0000000..11bc611
--- /dev/null
+++ b/polyp/inet_ntop.h
@@ -0,0 +1,6 @@
+#ifndef fooinet_ntophfoo
+#define fooinet_ntophfoo
+
+const char *inet_ntop(int af, const void *src, char *dst, socklen_t cnt);
+
+#endif
diff --git a/polyp/socket-server.c b/polyp/socket-server.c
index 18122f3..a78f04c 100644
--- a/polyp/socket-server.c
+++ b/polyp/socket-server.c
@@ -52,6 +52,10 @@
 #include <tcpd.h>
 #endif
 
+#ifndef HAVE_INET_NTOP
+#include "inet_ntop.h"
+#endif
+
 #include "winsock.h"
 
 #include "socket-server.h"
@@ -362,22 +366,10 @@ char *pa_socket_server_get_address(struct pa_socket_server *s, char *c, size_t l
             } else {
                 char ip[INET6_ADDRSTRLEN];
                 
-#ifdef HAVE_INET_NTOP
                 if (!inet_ntop(AF_INET6, &sa.sin6_addr, ip, sizeof(ip))) {
                     pa_log(__FILE__": inet_ntop() failed: %s\n", strerror(errno));
                     return NULL;
                 }
-#else
-                snprintf(ip, INET6_ADDRSTRLEN, "%x:%x:%x:%x:%x:%x:%x:%x",
-                    sa.sin6_addr.s6_addr[ 0] << 8 | sa.sin6_addr.s6_addr[ 1],
-                    sa.sin6_addr.s6_addr[ 2] << 8 | sa.sin6_addr.s6_addr[ 3],
-                    sa.sin6_addr.s6_addr[ 4] << 8 | sa.sin6_addr.s6_addr[ 5],
-                    sa.sin6_addr.s6_addr[ 6] << 8 | sa.sin6_addr.s6_addr[ 7],
-                    sa.sin6_addr.s6_addr[ 8] << 8 | sa.sin6_addr.s6_addr[ 9],
-                    sa.sin6_addr.s6_addr[10] << 8 | sa.sin6_addr.s6_addr[11],
-                    sa.sin6_addr.s6_addr[12] << 8 | sa.sin6_addr.s6_addr[13],
-                    sa.sin6_addr.s6_addr[14] << 8 | sa.sin6_addr.s6_addr[15]);
-#endif
                 
                 snprintf(c, l, "tcp6:[%s]:%u", ip, (unsigned) ntohs(sa.sin6_port));
             }
@@ -409,25 +401,10 @@ char *pa_socket_server_get_address(struct pa_socket_server *s, char *c, size_t l
             } else {
                 char ip[INET_ADDRSTRLEN];
 
-#ifdef HAVE_INET_NTOP
                 if (!inet_ntop(AF_INET, &sa.sin_addr, ip, sizeof(ip))) {
                     pa_log(__FILE__": inet_ntop() failed: %s\n", strerror(errno));
                     return NULL;
                 }
-#else /* HAVE_INET_NTOP */
-                snprintf(ip, INET_ADDRSTRLEN, "%d.%d.%d.%d",
-#ifdef WORDS_BIGENDIAN
-                    (int)(sa.sin_addr.s_addr >> 24) & 0xff,
-                    (int)(sa.sin_addr.s_addr >> 16) & 0xff,
-                    (int)(sa.sin_addr.s_addr >>  8) & 0xff,
-                    (int)(sa.sin_addr.s_addr >>  0) & 0xff);
-#else
-                    (int)(sa.sin_addr.s_addr >>  0) & 0xff,
-                    (int)(sa.sin_addr.s_addr >>  8) & 0xff,
-                    (int)(sa.sin_addr.s_addr >> 16) & 0xff,
-                    (int)(sa.sin_addr.s_addr >> 24) & 0xff);
-#endif
-#endif /* HAVE_INET_NTOP */
                 
                 snprintf(c, l, "tcp:[%s]:%u", ip, (unsigned) ntohs(sa.sin_port));
 

commit f5a2cf1e86c1b67c1bc8ae5e03f13b9b3d19eefb
Author: Pierre Ossman <ossman at cendio.se>
Date:   Tue Jan 10 07:50:50 2006 +0000

    getopt_long resides in libiberty on many platforms.
    
    
    git-svn-id: file:///home/lennart/svn/public/pulseaudio/branches/ossman@433 fefdeb5f-60dc-0310-8127-8f9354f1896f

diff --git a/configure.ac b/configure.ac
index 8030e6a..815629f 100644
--- a/configure.ac
+++ b/configure.ac
@@ -192,6 +192,7 @@ AC_CHECK_FUNCS([lstat])
 
 AC_CHECK_FUNCS(setresuid)
 AC_CHECK_FUNCS(setreuid)
+AC_CHECK_LIB([iberty], [getopt_long])
 
 #### POSIX threads ####
 

commit ff4cc6273d5db325433dbe01d4c7af242951c69e
Author: Pierre Ossman <ossman at cendio.se>
Date:   Tue Jan 10 08:35:14 2006 +0000

    Move library checks to a separate section and make sure it's before
    function checks. It could miss functions because they are hidden in
    extra libs otherwise.
    
    
    git-svn-id: file:///home/lennart/svn/public/pulseaudio/branches/ossman@434 fefdeb5f-60dc-0310-8127-8f9354f1896f

diff --git a/configure.ac b/configure.ac
index 815629f..d450f4a 100644
--- a/configure.ac
+++ b/configure.ac
@@ -162,16 +162,26 @@ AM_CONDITIONAL(HAVE_SIGXCPU, test "x$HAVE_SIGXCPU" = "x1")
 AC_CHECK_DEFINE([INADDR_NONE], [netinet/in.h], [],
     [AC_DEFINE([INADDR_NONE],  [0xffffffff], [Define INADDR_NONE if not found in <netinet/in.h>])])
 
-#### Check for functions ####
+#### Check for libs ####
 
 # ISO
 AC_CHECK_LIB([m], [pow])
 
 # POSIX
+AC_CHECK_LIB([rt], [sched_setscheduler])
+
+# BSD
+AC_CHECK_LIB([socket], [connect])
+
+# Non-standard
+AC_CHECK_LIB([iberty], [getopt_long])
+
+#### Check for functions ####
+
+# POSIX
 AC_FUNC_FORK
 AC_FUNC_GETGROUPS
 AC_FUNC_SELECT_ARGTYPES
-AC_CHECK_LIB([rt], [sched_setscheduler])
 AC_CHECK_FUNCS([getaddrinfo getgrgid_r getpwuid_r gettimeofday getuid \
     inet_ntop nanosleep setpgid setsid sigaction sleep])
 AC_CHECK_FUNCS([mkfifo], [HAVE_MKFIFO=1], [HAVE_MKFIFO=0])
@@ -185,14 +195,12 @@ AC_CHECK_FUNCS([readlink])
 AC_CHECK_FUNCS([ctime_r usleep])
 
 # BSD
-AC_CHECK_LIB([socket], [connect])
 AC_CHECK_FUNCS([lstat])
 
 # Non-standard
 
 AC_CHECK_FUNCS(setresuid)
 AC_CHECK_FUNCS(setreuid)
-AC_CHECK_LIB([iberty], [getopt_long])
 
 #### POSIX threads ####
 

commit 5e5808ab08cacb7bff8ab2df584f2d0f3af0fca9
Author: Pierre Ossman <ossman at cendio.se>
Date:   Tue Jan 10 09:13:48 2006 +0000

    Static libs bork the creation of dlls and AC_CHECK_LIB isn't very bright,
    so we have to do a test first to see if getopt_long() is included in the
    system libs.
    
    
    git-svn-id: file:///home/lennart/svn/public/pulseaudio/branches/ossman@435 fefdeb5f-60dc-0310-8127-8f9354f1896f

diff --git a/configure.ac b/configure.ac
index d450f4a..1a002e5 100644
--- a/configure.ac
+++ b/configure.ac
@@ -174,7 +174,10 @@ AC_CHECK_LIB([rt], [sched_setscheduler])
 AC_CHECK_LIB([socket], [connect])
 
 # Non-standard
-AC_CHECK_LIB([iberty], [getopt_long])
+
+# This magic is needed so we do not needlessly add static libs to the win32
+# build, disabling its ability to make dlls.
+AC_CHECK_FUNCS([getopt_long], [], [AC_CHECK_LIB([iberty], [getopt_long])])
 
 #### Check for functions ####
 

commit 357ab88ab55ede0e5a1173ce7b7a727ba3204087
Author: Pierre Ossman <ossman at cendio.se>
Date:   Tue Jan 10 09:14:41 2006 +0000

    Make sure socklen_t is defined.
    
    
    git-svn-id: file:///home/lennart/svn/public/pulseaudio/branches/ossman@436 fefdeb5f-60dc-0310-8127-8f9354f1896f

diff --git a/polyp/inet_ntop.h b/polyp/inet_ntop.h
index 11bc611..7fb67b4 100644
--- a/polyp/inet_ntop.h
+++ b/polyp/inet_ntop.h
@@ -1,6 +1,12 @@
 #ifndef fooinet_ntophfoo
 #define fooinet_ntophfoo
 
+#ifdef HAVE_SYS_SOCKET_H
+#include <sys/socket.h>
+#endif
+
+#include "winsock.h"
+
 const char *inet_ntop(int af, const void *src, char *dst, socklen_t cnt);
 
 #endif

commit ba06340ab8476733a0b84d0b97fa04a029cf2713
Author: Pierre Ossman <ossman at cendio.se>
Date:   Tue Jan 10 09:15:13 2006 +0000

    Add some required headers.
    
    
    git-svn-id: file:///home/lennart/svn/public/pulseaudio/branches/ossman@437 fefdeb5f-60dc-0310-8127-8f9354f1896f

diff --git a/polyp/inet_ntop.c b/polyp/inet_ntop.c
index 19f29f8..ac2b529 100644
--- a/polyp/inet_ntop.c
+++ b/polyp/inet_ntop.c
@@ -24,6 +24,8 @@
 #endif
 
 #include <stdio.h>
+#include <errno.h>
+#include <assert.h>
 
 #ifndef HAVE_INET_NTOP
 
diff --git a/polyp/poll.c b/polyp/poll.c
index cb7e3e7..6a260da 100644
--- a/polyp/poll.c
+++ b/polyp/poll.c
@@ -32,6 +32,8 @@
 #include <config.h>
 #endif
 
+#include <errno.h>
+
 #ifdef HAVE_SYS_SELECT_H
 #include <sys/select.h>
 #endif

commit 0a9abdd9d141b12a475c43bf924eb7569debe9a5
Author: Pierre Ossman <ossman at cendio.se>
Date:   Tue Jan 10 09:15:56 2006 +0000

    Unfortunately Windows has two different values for EBADF depending on
    if it's a file or a socket. We'll have to deal with these as they show
    up.
    
    
    git-svn-id: file:///home/lennart/svn/public/pulseaudio/branches/ossman@438 fefdeb5f-60dc-0310-8127-8f9354f1896f

diff --git a/polyp/winsock.h b/polyp/winsock.h
index 60fac87..89ef7ba 100644
--- a/polyp/winsock.h
+++ b/polyp/winsock.h
@@ -4,7 +4,6 @@
 #ifdef HAVE_WINSOCK2_H
 #include <winsock2.h>
 
-#define EBADF           WSAEBADF
 #define ESHUTDOWN       WSAESHUTDOWN
 #define ECONNRESET      WSAECONNRESET
 #define ECONNABORTED    WSAECONNABORTED

commit abdf9b1c3fb371637c73fa635d089178dea5d902
Author: Pierre Ossman <ossman at cendio.se>
Date:   Tue Jan 10 09:16:20 2006 +0000

    Add needed error code.
    
    
    git-svn-id: file:///home/lennart/svn/public/pulseaudio/branches/ossman@439 fefdeb5f-60dc-0310-8127-8f9354f1896f

diff --git a/polyp/winsock.h b/polyp/winsock.h
index 89ef7ba..b1e0f7d 100644
--- a/polyp/winsock.h
+++ b/polyp/winsock.h
@@ -9,6 +9,7 @@
 #define ECONNABORTED    WSAECONNABORTED
 #define ENETRESET       WSAENETRESET
 #define EINPROGRESS     WSAEINPROGRESS
+#define EAFNOSUPPORT    WSAEAFNOSUPPORT
 #define ETIMEDOUT       WSAETIMEDOUT
 #define ECONNREFUSED    WSAECONNREFUSED
 #define EHOSTUNREACH    WSAEHOSTUNREACH

commit 11c6cac3241bf7bc647f3e8b7da751e0c88982ea
Author: Pierre Ossman <ossman at cendio.se>
Date:   Tue Jan 10 09:16:39 2006 +0000

    buf is needed on Windows aswell.
    
    
    git-svn-id: file:///home/lennart/svn/public/pulseaudio/branches/ossman@440 fefdeb5f-60dc-0310-8127-8f9354f1896f

diff --git a/polyp/util.c b/polyp/util.c
index 569412d..26d7120 100644
--- a/polyp/util.c
+++ b/polyp/util.c
@@ -321,9 +321,9 @@ char *pa_vsprintf_malloc(const char *format, va_list ap) {
 /* Return the current username in the specified string buffer. */
 char *pa_get_user_name(char *s, size_t l) {
     char *p;
+    char buf[1024];
 
 #ifdef HAVE_PWD_H
-    char buf[1024];
     struct passwd pw, *r;
 #endif
 

commit d429222476ce224a86428f8d0527e61a672edf2b
Author: Pierre Ossman <ossman at cendio.se>
Date:   Tue Jan 10 12:37:41 2006 +0000

    Accidental use of a swapped int.
    
    
    git-svn-id: file:///home/lennart/svn/public/pulseaudio/branches/ossman@441 fefdeb5f-60dc-0310-8127-8f9354f1896f

diff --git a/polyp/tagstruct.c b/polyp/tagstruct.c
index 1e44f8e..1ff09cd 100644
--- a/polyp/tagstruct.c
+++ b/polyp/tagstruct.c
@@ -149,14 +149,15 @@ void pa_tagstruct_put_sample_spec(struct pa_tagstruct *t, const struct pa_sample
 }
 
 void pa_tagstruct_put_arbitrary(struct pa_tagstruct *t, const void *p, size_t length) {
+    uint32_t tmp;
     assert(t && p);
 
     extend(t, 5+length);
     t->data[t->length] = TAG_ARBITRARY;
+    tmp = htonl(length);
+    memcpy(t->data+t->length+1, &tmp, 4);
     if (length)
         memcpy(t->data+t->length+5, p, length);
-    length = htonl(length);
-    memcpy(t->data+t->length+1, &length, 4);
     t->length += 5+length;
 }
 

commit 1015ea42413eb14b1a027a665df6af12344d097d
Author: Pierre Ossman <ossman at cendio.se>
Date:   Tue Jan 10 12:45:11 2006 +0000

    Store previous reported time in order to assure a monotonic clock.
    
    This is a resurrection of a feature previously removed. The new version
    is without the race condition of the original one.
    
    
    git-svn-id: file:///home/lennart/svn/public/pulseaudio/branches/ossman@442 fefdeb5f-60dc-0310-8127-8f9354f1896f

diff --git a/polyp/polyplib-internal.h b/polyp/polyplib-internal.h
index 9417430..8677c81 100644
--- a/polyp/polyplib-internal.h
+++ b/polyp/polyplib-internal.h
@@ -92,6 +92,8 @@ struct pa_stream {
     enum pa_stream_direction direction;
     uint32_t requested_bytes;
     uint64_t counter;
+    pa_usec_t previous_time;
+    pa_usec_t previous_ipol_time;
     enum pa_stream_state state;
     struct pa_mcalign *mcalign;
 
diff --git a/polyp/polyplib-stream.c b/polyp/polyplib-stream.c
index 7058b54..b6a091b 100644
--- a/polyp/polyplib-stream.c
+++ b/polyp/polyplib-stream.c
@@ -65,6 +65,8 @@ struct pa_stream *pa_stream_new(struct pa_context *c, const char *name, const st
     s->mcalign = pa_mcalign_new(pa_frame_size(ss), c->memblock_stat);
 
     s->counter = 0;
+    s->previous_time = 0;
+    s->previous_ipol_time = 0;
 
     s->corked = 0;
     s->interpolate = 0;
@@ -697,6 +699,11 @@ pa_usec_t pa_stream_get_time(struct pa_stream *s, const struct pa_latency_info *
         }
     }
 
+    if (usec < s->previous_time)
+        usec = s->previous_time;
+
+    s->previous_time = usec;
+
     return usec;
 }
 
@@ -756,6 +763,11 @@ pa_usec_t pa_stream_get_interpolated_time(struct pa_stream *s) {
             usec = s->ipol_usec + pa_timeval_age(&s->ipol_timestamp);
     }
     
+    if (usec < s->previous_ipol_time)
+        usec = s->previous_ipol_time;
+
+    s->previous_ipol_time = usec;
+
     return usec;
 }
 

commit 29118f50cb848076c89aee54829f4da6d7b8df77
Author: Pierre Ossman <ossman at cendio.se>
Date:   Tue Jan 10 13:19:03 2006 +0000

    Make sure the caps header check can also be disabled.
    
    
    git-svn-id: file:///home/lennart/svn/public/pulseaudio/branches/ossman@443 fefdeb5f-60dc-0310-8127-8f9354f1896f

diff --git a/configure.ac b/configure.ac
index 1a002e5..e5e03d0 100644
--- a/configure.ac
+++ b/configure.ac
@@ -121,7 +121,7 @@ AC_HEADER_STDC
 # POSIX
 AC_CHECK_HEADERS([arpa/inet.h glob.h grp.h netdb.h netinet/in.h \
     netinet/in_systm.h netinet/ip.h netinet/tcp.h pwd.h sched.h \
-    sys/capability.h sys/resource.h sys/select.h sys/socket.h sys/wait.h \
+    sys/resource.h sys/select.h sys/socket.h sys/wait.h \
     syslog.h])
 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])
@@ -239,6 +239,7 @@ AC_ARG_WITH(
 
 if test "x${with_caps}" != "xno"; then
     AC_CHECK_LIB(cap, cap_init, [CAP_LIBS='-lcap'], [CAP_LIBS=''])
+    AC_CHECK_HEADERS([sys/capability.h])
 fi
 AC_SUBST(CAP_LIBS)
 

commit 34e81ffb350540004b3aa9f5614f6b511ab96b37
Author: Pierre Ossman <ossman at cendio.se>
Date:   Tue Jan 10 16:56:59 2006 +0000

    Handle Windows paths when normalizing authkey path.
    
    
    git-svn-id: file:///home/lennart/svn/public/pulseaudio/branches/ossman@444 fefdeb5f-60dc-0310-8127-8f9354f1896f

diff --git a/polyp/authkey.c b/polyp/authkey.c
index 35d97b7..969f09d 100644
--- a/polyp/authkey.c
+++ b/polyp/authkey.c
@@ -128,12 +128,20 @@ int pa_authkey_load(const char *path, void *data, size_t length) {
 static const char *normalize_path(const char *fn, char *s, size_t l) {
     assert(fn && s && l > 0);
 
+#ifndef OS_IS_WIN32
     if (fn[0] != '/') {
+#else
+    if (strlen(fn) < 3 || !isalpha(fn[0]) || fn[1] != ':' || fn[2] != '\\') {
+#endif
         char homedir[PATH_MAX];
         if (!pa_get_home_dir(homedir, sizeof(homedir)))
             return NULL;
         
+#ifndef OS_IS_WIN32
         snprintf(s, l, "%s/%s", homedir, fn);
+#else
+        snprintf(s, l, "%s\\%s", homedir, fn);
+#endif
         return s;
     }
 

commit 00da37f2c448096cdd54481b072db47b2f253141
Author: Lennart Poettering <lennart at poettering.net>
Date:   Mon Jun 11 12:08:37 2007 +0000

    Merge HUGE set of changes temporarily into a branch, to allow me to move them from one machine to another (lock-free and stuff)
    
    git-svn-id: file:///home/lennart/svn/public/pulseaudio/branches/lennart@1469 fefdeb5f-60dc-0310-8127-8f9354f1896f

diff --git a/src/Makefile.am b/src/Makefile.am
index d90361f..eab465c 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -78,13 +78,15 @@ if OS_IS_WIN32
 PA_THREAD_OBJS = \
 		pulsecore/once-win32.c pulsecore/once.h \
 		pulsecore/mutex-win32.c pulsecore/mutex.h \
-		pulsecore/thread-win32.c pulsecore/thread.h
+		pulsecore/thread-win32.c pulsecore/thread.h \
+		pulsecore/semaphore-win32.c pulsecore/semaphore.h
 else
 PA_THREAD_OBJS = \
 		pulsecore/atomic.h \
 		pulsecore/once-posix.c pulsecore/once.h \
 		pulsecore/mutex-posix.c pulsecore/mutex.h \
-		pulsecore/thread-posix.c pulsecore/thread.h
+		pulsecore/thread-posix.c pulsecore/thread.h \
+		pulsecore/semaphore-posix.c pulsecore/semaphore.h
 endif
 
 ###################################
@@ -219,7 +221,9 @@ noinst_PROGRAMS = \
 		hook-list-test \
 		memblock-test \
 		thread-test \
-		flist-test
+		flist-test \
+		asyncq-test \
+		asyncmsgq-test
 
 if HAVE_SIGXCPU
 noinst_PROGRAMS += \
@@ -274,13 +278,21 @@ thread_test_CFLAGS = $(AM_CFLAGS)
 thread_test_LDADD = $(AM_LDADD) libpulsecore.la
 thread_test_LDFLAGS = $(AM_LDFLAGS) $(BINLDFLAGS)
 
-flist_test_SOURCES = tests/flist-test.c \
-		pulsecore/atomic.h \
-		pulsecore/flist.c pulsecore/flist.h
+flist_test_SOURCES = tests/flist-test.c
 flist_test_CFLAGS = $(AM_CFLAGS)
 flist_test_LDADD = $(AM_LDADD) libpulsecore.la
 flist_test_LDFLAGS = $(AM_LDFLAGS) $(BINLDFLAGS)
 
+asyncq_test_SOURCES = tests/asyncq-test.c pulsecore/thread-posix.c pulsecore/thread.h pulsecore/asyncq.c pulsecore/asyncq.h pulsecore/core-util.c pulsecore/core-util.h pulse/xmalloc.c pulse/xmalloc.h pulsecore/log.h pulsecore/log.c pulsecore/core-error.h pulsecore/core-error.c pulsecore/once-posix.c pulsecore/once.h pulsecore/mutex-posix.c pulsecore/mutex.h pulse/utf8.c pulse/utf8.h pulse/util.h pulse/util.c
+asyncq_test_CFLAGS = $(AM_CFLAGS)
+asyncq_test_LDADD = $(AM_LDADD) #libpulsecore.la
+asyncq_test_LDFLAGS = $(AM_LDFLAGS) $(BINLDFLAGS)
+
+asyncmsgq_test_SOURCES = tests/asyncmsgq-test.c pulsecore/thread-posix.c pulsecore/thread.h pulsecore/asyncq.c pulsecore/asyncq.h pulsecore/asyncmsgq.c pulsecore/asyncmsgq.h pulsecore/core-util.c pulsecore/core-util.h pulse/xmalloc.c pulse/xmalloc.h pulsecore/log.h pulsecore/log.c pulsecore/core-error.h pulsecore/core-error.c pulsecore/once-posix.c pulsecore/once.h pulsecore/mutex-posix.c pulsecore/mutex.h pulse/utf8.c pulse/utf8.h pulse/util.h pulse/util.c pulsecore/semaphore.h pulsecore/semaphore-posix.c pulsecore/flist.h pulsecore/flist.c
+asyncmsgq_test_CFLAGS = $(AM_CFLAGS)
+asyncmsgq_test_LDADD = $(AM_LDADD) #libpulsecore.la
+asyncmsgq_test_LDFLAGS = $(AM_LDFLAGS) $(BINLDFLAGS)
+
 mcalign_test_SOURCES = tests/mcalign-test.c
 mcalign_test_CFLAGS = $(AM_CFLAGS)
 mcalign_test_LDADD = $(AM_LDADD) $(WINSOCK_LIBS) libpulsecore.la
@@ -455,6 +467,9 @@ libpulse_la_SOURCES += \
 		pulsecore/core-error.c pulsecore/core-error.h \
 		pulsecore/winsock.h pulsecore/creds.h \
 		pulsecore/shm.c pulsecore/shm.h \
+		pulsecore/flist.c pulsecore/flist.h \
+		pulsecore/object.c pulsecore/object.h \
+		pulsecore/msgobject.c pulsecore/msgobject.h \
 		$(PA_THREAD_OBJS)
 
 if OS_IS_WIN32
@@ -567,6 +582,7 @@ pulsecoreinclude_HEADERS = \
 		pulsecore/refcnt.h \
 		pulsecore/mutex.h \
 		pulsecore/thread.h \
+		pulsecore/semaphore.h \
 		pulsecore/once.h
 
 lib_LTLIBRARIES += libpulsecore.la
@@ -636,6 +652,8 @@ libpulsecore_la_SOURCES += \
 		pulsecore/core-error.c pulsecore/core-error.h \
 		pulsecore/hook-list.c pulsecore/hook-list.h \
 		pulsecore/shm.c pulsecore/shm.h \
+		pulsecore/flist.c pulsecore/flist.h \
+		pulsecore/anotify.c pulsecore/anotify.h \
 		$(PA_THREAD_OBJS)
 
 if OS_IS_WIN32
@@ -851,34 +869,34 @@ modlibexec_LTLIBRARIES += \
 		module-cli.la \
 		module-cli-protocol-tcp.la \
 		module-simple-protocol-tcp.la \
-		module-esound-protocol-tcp.la \
-		module-native-protocol-tcp.la \
-		module-native-protocol-fd.la \
-		module-sine.la \
-		module-combine.la \
-		module-tunnel-sink.la \
-		module-tunnel-source.la \
-		module-null-sink.la \
-		module-esound-sink.la \
-		module-http-protocol-tcp.la \
-		module-detect.la \
-		module-volume-restore.la \
-		module-rescue-streams.la
+		module-null-sink.la
+#		module-esound-protocol-tcp.la \
+#		module-native-protocol-tcp.la \
+#		module-native-protocol-fd.la \
+#		module-sine.la \
+#		module-combine.la \
+#		module-tunnel-sink.la \
+#		module-tunnel-source.la \
+#		module-esound-sink.la \
+#		module-http-protocol-tcp.la \
+#		module-detect.la \
+#		module-volume-restore.la \
+#		module-rescue-streams.la
 
 # See comment at librtp.la above
-if !OS_IS_WIN32
-modlibexec_LTLIBRARIES += \
-		module-rtp-send.la \
-		module-rtp-recv.la
-endif
+#if !OS_IS_WIN32
+#modlibexec_LTLIBRARIES += \
+#		module-rtp-send.la \
+#		module-rtp-recv.la
+#endif
 
 if HAVE_AF_UNIX
 modlibexec_LTLIBRARIES += \
 		module-cli-protocol-unix.la \
-		module-simple-protocol-unix.la \
-		module-esound-protocol-unix.la \
-		module-native-protocol-unix.la \
-		module-http-protocol-unix.la
+		module-simple-protocol-unix.la
+#		module-esound-protocol-unix.la \
+#		module-native-protocol-unix.la \
+#		module-http-protocol-unix.la
 endif
 
 if HAVE_MKFIFO
@@ -887,11 +905,11 @@ modlibexec_LTLIBRARIES += \
 		module-pipe-source.la
 endif
 
-if !OS_IS_WIN32
-modlibexec_LTLIBRARIES += \
-		module-esound-compat-spawnfd.la \
-		module-esound-compat-spawnpid.la
-endif
+#if !OS_IS_WIN32
+#modlibexec_LTLIBRARIES += \
+#		module-esound-compat-spawnfd.la \
+#		module-esound-compat-spawnpid.la
+#endif
 
 if HAVE_REGEX
 modlibexec_LTLIBRARIES += \
@@ -904,19 +922,19 @@ modlibexec_LTLIBRARIES += \
 		module-x11-publish.la
 endif
 
-if HAVE_OSS
-modlibexec_LTLIBRARIES += \
-		liboss-util.la \
-		module-oss.la \
-		module-oss-mmap.la
-endif
+#if HAVE_OSS
+#modlibexec_LTLIBRARIES += \
+#		liboss-util.la \
+#		module-oss.la \
+#		module-oss-mmap.la
+#endif
 
-if HAVE_ALSA
-modlibexec_LTLIBRARIES += \
-		libalsa-util.la \
-		module-alsa-sink.la \
-		module-alsa-source.la
-endif
+#if HAVE_ALSA
+#modlibexec_LTLIBRARIES += \
+#		libalsa-util.la \
+#		module-alsa-sink.la \
+#		module-alsa-source.la
+#endif
 
 if HAVE_SOLARIS
 modlibexec_LTLIBRARIES += \
@@ -938,11 +956,11 @@ modlibexec_LTLIBRARIES += \
 		module-mmkbd-evdev.la
 endif
 
-if HAVE_JACK
-modlibexec_LTLIBRARIES += \
-		module-jack-sink.la \
-		module-jack-source.la
-endif
+#if HAVE_JACK
+#modlibexec_LTLIBRARIES += \
+#		module-jack-sink.la \
+#		module-jack-source.la
+#endif
 
 if HAVE_GCONF
 modlibexec_LTLIBRARIES += \
diff --git a/src/modules/module-alsa-sink.c b/src/modules/module-alsa-sink.c
index 3d9f757..f9c4efd 100644
--- a/src/modules/module-alsa-sink.c
+++ b/src/modules/module-alsa-sink.c
@@ -174,6 +174,7 @@ static void do_write(struct userdata *u) {
     update_usage(u);
 
     for (;;) {
+        void *p;
         pa_memchunk *memchunk = NULL;
         snd_pcm_sframes_t frames;
 
@@ -185,14 +186,15 @@ static void do_write(struct userdata *u) {
             else
                 memchunk = &u->memchunk;
         }
-
         assert(memchunk->memblock);
-        assert(memchunk->memblock->data);
         assert(memchunk->length);
-        assert(memchunk->memblock->length);
         assert((memchunk->length % u->frame_size) == 0);
 
-        if ((frames = snd_pcm_writei(u->pcm_handle, (uint8_t*) memchunk->memblock->data + memchunk->index, memchunk->length / u->frame_size)) < 0) {
+        p = pa_memblock_acquire(memchunk->memblock);
+
+        if ((frames = snd_pcm_writei(u->pcm_handle, (uint8_t*) p + memchunk->index, memchunk->length / u->frame_size)) < 0) {
+            pa_memblock_release(memchunk->memblock);
+
             if (frames == -EAGAIN)
                 return;
 
@@ -217,6 +219,8 @@ static void do_write(struct userdata *u) {
             return;
         }
 
+        pa_memblock_release(memchunk->memblock);
+
         if (memchunk == &u->memchunk) {
             size_t l = frames * u->frame_size;
             memchunk->index += l;
diff --git a/src/modules/module-alsa-source.c b/src/modules/module-alsa-source.c
index 4061d66..6d7e09e 100644
--- a/src/modules/module-alsa-source.c
+++ b/src/modules/module-alsa-source.c
@@ -180,6 +180,7 @@ static void do_read(struct userdata *u) {
         pa_memchunk post_memchunk;
         snd_pcm_sframes_t frames;
         size_t l;
+        void *p;
 
         if (!u->memchunk.memblock) {
             u->memchunk.memblock = pa_memblock_new(u->source->core->mempool, u->memchunk.length = u->fragment_size);
@@ -188,11 +189,13 @@ static void do_read(struct userdata *u) {
 
         assert(u->memchunk.memblock);
         assert(u->memchunk.length);
-        assert(u->memchunk.memblock->data);
-        assert(u->memchunk.memblock->length);
         assert(u->memchunk.length % u->frame_size == 0);
 
-        if ((frames = snd_pcm_readi(u->pcm_handle, (uint8_t*) u->memchunk.memblock->data + u->memchunk.index, u->memchunk.length / u->frame_size)) < 0) {
+        p = pa_memblock_acquire(u->memchunk.memblock);
+
+        if ((frames = snd_pcm_readi(u->pcm_handle, (uint8_t*) p + u->memchunk.index, u->memchunk.length / u->frame_size)) < 0) {
+            pa_memblock_release(u->memchunk.memblock);
+
             if (frames == -EAGAIN)
                 return;
 
@@ -216,6 +219,7 @@ static void do_read(struct userdata *u) {
             pa_module_unload_request(u->module);
             return;
         }
+        pa_memblock_release(u->memchunk.memblock);
 
         l = frames * u->frame_size;
 
diff --git a/src/modules/module-esound-sink.c b/src/modules/module-esound-sink.c
index 26638d9..39886d0 100644
--- a/src/modules/module-esound-sink.c
+++ b/src/modules/module-esound-sink.c
@@ -144,18 +144,25 @@ static int do_write(struct userdata *u) {
             u->write_index = u->write_length = 0;
         }
     } else if (u->state == STATE_RUNNING) {
+        void *p;
+
         pa_module_set_used(u->module, pa_sink_used_by(u->sink));
 
         if (!u->memchunk.length)
             if (pa_sink_render(u->sink, 8192, &u->memchunk) < 0)
                 return 0;
 
-        assert(u->memchunk.memblock && u->memchunk.length);
+        assert(u->memchunk.memblock);
+        assert(u->memchunk.length);
+
+        p = pa_memblock_acquire(u->memchunk.memblock);
 
-        if ((r = pa_iochannel_write(u->io, (uint8_t*) u->memchunk.memblock->data + u->memchunk.index, u->memchunk.length)) < 0) {
+        if ((r = pa_iochannel_write(u->io, (uint8_t*) p + u->memchunk.index, u->memchunk.length)) < 0) {
+            pa_memblock_release(u->memchunk.memblock);
             pa_log("write() failed: %s", pa_cstrerror(errno));
             return -1;
         }
+        pa_memblock_release(u->memchunk.memblock);
 
         u->memchunk.index += r;
         u->memchunk.length -= r;
diff --git a/src/modules/module-jack-sink.c b/src/modules/module-jack-sink.c
index c6a7e33..1092aed 100644
--- a/src/modules/module-jack-sink.c
+++ b/src/modules/module-jack-sink.c
@@ -137,22 +137,25 @@ static void io_event_cb(pa_mainloop_api *m, pa_io_event *e, int fd, pa_io_event_
         unsigned fs;
         jack_nframes_t frame_idx;
         pa_memchunk chunk;
+        void *p;
 
         fs = pa_frame_size(&u->sink->sample_spec);
 
         pa_sink_render_full(u->sink, u->frames_requested * fs, &chunk);
+        p = pa_memblock_acquire(chunk.memblock);
 
         for (frame_idx = 0; frame_idx < u->frames_requested; frame_idx ++) {
             unsigned c;
 
             for (c = 0; c < u->channels; c++) {
-                float *s = ((float*) ((uint8_t*) chunk.memblock->data + chunk.index)) + (frame_idx * u->channels) + c;
+                float *s = ((float*) ((uint8_t*) p + chunk.index)) + (frame_idx * u->channels) + c;
                 float *d = ((float*) u->buffer[c]) + frame_idx;
 
                 *d = *s;
             }
         }
 
+        pa_memblock_release(chunk.memblock);
         pa_memblock_unref(chunk.memblock);
 
         u->frames_requested = 0;
diff --git a/src/modules/module-jack-source.c b/src/modules/module-jack-source.c
index 8ca2403..e19b218 100644
--- a/src/modules/module-jack-source.c
+++ b/src/modules/module-jack-source.c
@@ -136,23 +136,28 @@ static void io_event_cb(pa_mainloop_api *m, pa_io_event *e, int fd, pa_io_event_
         unsigned fs;
         jack_nframes_t frame_idx;
         pa_memchunk chunk;
+        void *p;
 
         fs = pa_frame_size(&u->source->sample_spec);
 
         chunk.memblock = pa_memblock_new(u->core->mempool, chunk.length = u->frames_posted * fs);
         chunk.index = 0;
 
+        p = pa_memblock_acquire(chunk.memblock);
+
         for (frame_idx = 0; frame_idx < u->frames_posted; frame_idx ++) {
             unsigned c;
 
             for (c = 0; c < u->channels; c++) {
                 float *s = ((float*) u->buffer[c]) + frame_idx;
-                float *d = ((float*) ((uint8_t*) chunk.memblock->data + chunk.index)) + (frame_idx * u->channels) + c;
+                float *d = ((float*) ((uint8_t*) p + chunk.index)) + (frame_idx * u->channels) + c;
 
                 *d = *s;
             }
         }
 
+        pa_memblock_release(chunk.memblock);
+
         pa_source_post(u->source, &chunk);
         pa_memblock_unref(chunk.memblock);
 
diff --git a/src/modules/module-null-sink.c b/src/modules/module-null-sink.c
index 54a8e89..8cf961b 100644
--- a/src/modules/module-null-sink.c
+++ b/src/modules/module-null-sink.c
@@ -28,7 +28,6 @@
 #include <stdlib.h>
 #include <sys/stat.h>
 #include <stdio.h>
-#include <assert.h>
 #include <errno.h>
 #include <string.h>
 #include <fcntl.h>
@@ -38,6 +37,7 @@
 #include <pulse/timeval.h>
 #include <pulse/xmalloc.h>
 
+#include <pulsecore/macro.h>
 #include <pulsecore/iochannel.h>
 #include <pulsecore/sink.h>
 #include <pulsecore/module.h>
@@ -64,11 +64,9 @@ struct userdata {
     pa_core *core;
     pa_module *module;
     pa_sink *sink;
-    pa_time_event *time_event;
+    pa_thread *thread;
     size_t block_size;
-
-    uint64_t n_bytes;
-    struct timeval start_time;
+    struct timeval timestamp;
 };
 
 static const char* const valid_modargs[] = {
@@ -81,35 +79,131 @@ static const char* const valid_modargs[] = {
     NULL
 };
 
-static void time_callback(pa_mainloop_api *m, pa_time_event*e, const struct timeval *tv, void *userdata) {
+static void thread_func(void *userdata) {
     struct userdata *u = userdata;
-    pa_memchunk chunk;
-    struct timeval ntv = *tv;
-    size_t l;
-
-    assert(u);
-
-    if (pa_sink_render(u->sink, u->block_size, &chunk) >= 0) {
-        l = chunk.length;
-        pa_memblock_unref(chunk.memblock);
-    } else
-        l = u->block_size;
-
-    pa_timeval_add(&ntv, pa_bytes_to_usec(l, &u->sink->sample_spec));
-    m->time_restart(e, &ntv);
-
-    u->n_bytes += l;
-}
-
-static pa_usec_t get_latency(pa_sink *s) {
-    struct userdata *u = s->userdata;
-    pa_usec_t a, b;
-    struct timeval now;
+    int quit = 0;
+    struct pollfd pollfd;
+    int running = 1;
+
+    pa_assert(u);
+
+    pa_log_debug("Thread starting up");
+
+    memset(&pollfd, 0, sizeof(pollfd));
+    pollfd.fd = pa_asyncmsgq_get_fd(u->sink->asyncmsgq, PA_ASYNCQ_POP);
+    pollfd.events = POLLIN;
+
+    pa_gettimeofday(u->timestamp);
+    
+    for (;;) {
+        int code;
+        void *data, *object;
+        int r, timeout;
+        struct timeval now;
+
+        /* Check whether there is a message for us to process */
+        if (pa_asyncmsgq_get(u->sink->asyncmsgq, &object, &code, &data) == 0) {
+
+
+            /* Now process these messages our own way */
+            if (!object) {
+
+                switch (code) {
+                    case PA_MESSAGE_SHUTDOWN:
+                        goto finish;
+
+                    default:
+                        pa_sink_process_msg(u->sink->asyncmsgq, object, code, data);
+
+                }
+                
+            } else if (object == u->sink) {
+
+                switch (code) {
+                    case PA_SINK_MESSAGE_STOP:
+                        pa_assert(running);
+                        running = 0;
+                        break;
+                        
+                    case PA_SINK_MESSAGE_START:
+                        pa_assert(!running);
+                        running = 1;
+                        
+                        pa_gettimeofday(u->timestamp);
+                        break;
+                        
+                    case PA_SINK_MESSAGE_GET_LATENCY:
+                        
+                        if (pa_timeval_cmp(&u->timestamp, &now) > 0)
+                            *((pa_usec_t*) data) = 0;
+                        else
+                            *((pa_usec_t*) data) = pa_timeval_diff(&u->timestamp, &now);
+                        break;
+                        
+                        /* ... */
+
+                    default:
+                        pa_sink_process_msg(u->sink->asyncmsgq, object, code, data);
+                }
+            }
+            
+            pa_asyncmsgq_done(u->sink->asyncmsgq);
+            continue;
+        }
+
+        /* Render some data and drop it immediately */
+
+        if (running) {
+            pa_gettimeofday(&now);
+            
+            if (pa_timeval_cmp(u->timestamp, &now) <= 0) {
+                pa_memchunk chunk;
+                size_t l;
+                
+                if (pa_sink_render(u->sink, u->block_size, &chunk) >= 0) {
+                    l = chunk.length;
+                    pa_memblock_unref(chunk.memblock);
+                } else
+                    l = u->block_size;
+                
+                pa_timeval_add(&u->timestamp, pa_bytes_to_usec(l, &u->sink->sample_spec));
+                continue;
+            }
+
+            timeout = pa_timeval_diff(&u->timestamp, &now)/1000;
+            
+            if (timeout < 1)
+                timeout = 1;
+        } else
+            timeout = -1;
+
+        /* Hmm, nothing to do. Let's sleep */
+        
+        if (pa_asyncmsgq_before_poll(u->sink->asyncmsgq) < 0)
+            continue;
+
+        r = poll(&pollfd, 1, timeout);
+        pa_asyncmsgq_after_poll(u->sink->asyncmsgq);
+
+        if (r < 0) {
+            if (errno == EINTR)
+                continue;
+
+            pa_log("poll() failed: %s", pa_cstrerror(errno));
+            goto fail;
+        }
+        
+        pa_assert(r == 0 || pollfd.revents == POLLIN);
+    }
 
-    a = pa_timeval_diff(pa_gettimeofday(&now), &u->start_time);
-    b = pa_bytes_to_usec(u->n_bytes, &s->sample_spec);
+fail:
+    /* We have to continue processing messages until we receive the
+     * SHUTDOWN message */
+    pa_asyncmsgq_post(u->core->asyncmsgq, u->core, PA_CORE_MESSAGE_UNLOAD_MODULE, pa_module_ref(u->module), NULL, pa_module_unref);
+    pa_asyncmsgq_wait_for(PA_MESSAGE_SHUTDOWN);
 
-    return b > a ? b - a : 0;
+finish:
+    pa_log_debug("Thread shutting down");
 }
 
 int pa__init(pa_core *c, pa_module*m) {
@@ -118,17 +212,17 @@ int pa__init(pa_core *c, pa_module*m) {
     pa_channel_map map;
     pa_modargs *ma = NULL;
 
-    assert(c);
-    assert(m);
+    pa_assert(c);
+    pa_assert(m);
 
     if (!(ma = pa_modargs_new(m->argument, valid_modargs))) {
-        pa_log("failed to parse module arguments.");
+        pa_log("Failed to parse module arguments.");
         goto fail;
     }
 
     ss = c->default_sample_spec;
     if (pa_modargs_get_sample_spec_and_channel_map(ma, &ss, &map, PA_CHANNEL_MAP_DEFAULT) < 0) {
-        pa_log("invalid sample format specification or channel map.");
+        pa_log("Invalid sample format specification or channel map");
         goto fail;
     }
 
@@ -138,22 +232,24 @@ int pa__init(pa_core *c, pa_module*m) {
     m->userdata = u;
 
     if (!(u->sink = pa_sink_new(c, __FILE__, pa_modargs_get_value(ma, "sink_name", DEFAULT_SINK_NAME), 0, &ss, &map))) {
-        pa_log("failed to create sink.");
+        pa_log("Failed to create sink.");
         goto fail;
     }
 
-    u->sink->get_latency = get_latency;
     u->sink->userdata = u;
     pa_sink_set_owner(u->sink, m);
     pa_sink_set_description(u->sink, pa_modargs_get_value(ma, "description", "NULL sink"));
 
-    u->n_bytes = 0;
-    pa_gettimeofday(&u->start_time);
-
-    u->time_event = c->mainloop->time_new(c->mainloop, &u->start_time, time_callback, u);
-
-    u->block_size = pa_bytes_per_second(&ss) / 10;
+    u->block_size = pa_bytes_per_second(&ss) / 20; /* 50 ms */
+    
+    if (u->block_size <= 0)
+        u->block_size = pa_frame_size(&ss);
 
+    if (!(u->thread = pa_thread_new(thread_func, u))) {
+        pa_log("Failed to create thread.");
+        goto fail;
+    }
+    
     pa_modargs_free(ma);
 
     return 0;
@@ -169,15 +265,21 @@ fail:
 
 void pa__done(pa_core *c, pa_module*m) {
     struct userdata *u;
-    assert(c && m);
+    
+    pa_assert(c);
+    pa_assert(m);
 
     if (!(u = m->userdata))
         return;
 
     pa_sink_disconnect(u->sink);
-    pa_sink_unref(u->sink);
 
-    u->core->mainloop->time_free(u->time_event);
+    if (u->thread) {
+        pa_asyncmsgq_send(u->sink->asyncmsgq, PA_SINK_MESSAGE_SHUTDOWN, NULL);
+        pa_thread_free(u->thread);
+    }
+    
+    pa_sink_unref(u->sink);
 
     pa_xfree(u);
 }
diff --git a/src/modules/module-oss-mmap.c b/src/modules/module-oss-mmap.c
index 16c9b31..567230e 100644
--- a/src/modules/module-oss-mmap.c
+++ b/src/modules/module-oss-mmap.c
@@ -173,7 +173,7 @@ static void out_fill_memblocks(struct userdata *u, unsigned n) {
                     u->out_fragment_size,
                     1);
         assert(chunk.memblock);
-        chunk.length = chunk.memblock->length;
+        chunk.length = pa_memblock_get_length(chunk.memblock);
         chunk.index = 0;
 
         pa_sink_render_into_full(u->sink, &chunk);
@@ -217,7 +217,7 @@ static void in_post_memblocks(struct userdata *u, unsigned n) {
 
         if (!u->in_memblocks[u->in_current]) {
             chunk.memblock = u->in_memblocks[u->in_current] = pa_memblock_new_fixed(u->core->mempool, (uint8_t*) u->in_mmap+u->in_fragment_size*u->in_current, u->in_fragment_size, 1);
-            chunk.length = chunk.memblock->length;
+            chunk.length = pa_memblock_get_length(chunk.memblock);
             chunk.index = 0;
 
             pa_source_post(u->source, &chunk);
diff --git a/src/modules/module-oss.c b/src/modules/module-oss.c
index 9d4d0ea..9061e11 100644
--- a/src/modules/module-oss.c
+++ b/src/modules/module-oss.c
@@ -158,6 +158,7 @@ static void do_write(struct userdata *u) {
     }
 
     do {
+        void *p;
         memchunk = &u->memchunk;
 
         if (!memchunk->length)
@@ -165,10 +166,11 @@ static void do_write(struct userdata *u) {
                 memchunk = &u->silence;
 
         assert(memchunk->memblock);
-        assert(memchunk->memblock->data);
         assert(memchunk->length);
 
-        if ((r = pa_iochannel_write(u->io, (uint8_t*) memchunk->memblock->data + memchunk->index, memchunk->length)) < 0) {
+        p = pa_memblock_acquire(memchunk->memblock);
+        if ((r = pa_iochannel_write(u->io, (uint8_t*) p + memchunk->index, memchunk->length)) < 0) {
+            pa_memblock_release(memchunk->memblock);
 
             if (errno != EAGAIN) {
                 pa_log("write() failed: %s", pa_cstrerror(errno));
@@ -180,6 +182,8 @@ static void do_write(struct userdata *u) {
             break;
         }
 
+        pa_memblock_release(memchunk->memblock);
+
         if (memchunk == &u->silence)
             assert(r % u->sample_size == 0);
         else {
@@ -224,9 +228,13 @@ static void do_read(struct userdata *u) {
     }
 
     do {
+        void *p;
         memchunk.memblock = pa_memblock_new(u->core->mempool, l);
-        assert(memchunk.memblock);
-        if ((r = pa_iochannel_read(u->io, memchunk.memblock->data, memchunk.memblock->length)) < 0) {
+
+        p = pa_memblock_acquire(memchunk.memblock);
+
+        if ((r = pa_iochannel_read(u->io, p, pa_memblock_get_length(memchunk.memblock))) < 0) {
+            pa_memblock_release(memchunk.memblock);
             pa_memblock_unref(memchunk.memblock);
 
             if (errno != EAGAIN) {
@@ -239,8 +247,10 @@ static void do_read(struct userdata *u) {
             break;
         }
 
-        assert(r <= (ssize_t) memchunk.memblock->length);
-        memchunk.length = memchunk.memblock->length = r;
+        pa_memblock_release(memchunk.memblock);
+
+        assert(r <= (ssize_t) pa_memblock_get_length(memchunk.memblock));
+        memchunk.length = r;
         memchunk.index = 0;
 
         pa_source_post(u->source, &memchunk);
diff --git a/src/modules/module-pipe-sink.c b/src/modules/module-pipe-sink.c
index 170b046..61672ed 100644
--- a/src/modules/module-pipe-sink.c
+++ b/src/modules/module-pipe-sink.c
@@ -58,20 +58,16 @@ PA_MODULE_USAGE(
         "rate=<sample rate>"
         "channel_map=<channel map>")
 
-#define DEFAULT_FIFO_NAME "/tmp/music.output"
+#define DEFAULT_FILE_NAME "/tmp/music.output"
 #define DEFAULT_SINK_NAME "fifo_output"
 
 struct userdata {
     pa_core *core;
-
-    char *filename;
-
-    pa_sink *sink;
-    pa_iochannel *io;
-    pa_defer_event *defer_event;
-
-    pa_memchunk memchunk;
     pa_module *module;
+    pa_sink *sink;
+    char *filename;
+    int fd;
+    pa_thread *thread;
 };
 
 static const char* const valid_modargs[] = {
@@ -84,97 +80,203 @@ static const char* const valid_modargs[] = {
     NULL
 };
 
-static void do_write(struct userdata *u) {
-    ssize_t r;
-    assert(u);
-
-    u->core->mainloop->defer_enable(u->defer_event, 0);
-
-    if (!pa_iochannel_is_writable(u->io))
-        return;
-
-    pa_module_set_used(u->module, pa_sink_used_by(u->sink));
-
-    if (!u->memchunk.length)
-        if (pa_sink_render(u->sink, PIPE_BUF, &u->memchunk) < 0)
-            return;
-
-    assert(u->memchunk.memblock && u->memchunk.length);
-
-    if ((r = pa_iochannel_write(u->io, (uint8_t*) u->memchunk.memblock->data + u->memchunk.index, u->memchunk.length)) < 0) {
-        pa_log("write(): %s", pa_cstrerror(errno));
-        return;
-    }
+enum {
+    POLLFD_ASYNCQ,
+    POLLFD_FIFO,
+    POLLFD_MAX,
+};
 
-    u->memchunk.index += r;
-    u->memchunk.length -= r;
+static void thread_func(void *userdata) {
+    struct userdata *u = userdata;
+    int quit = 0;
+    struct pollfd pollfd[POLLFD_MAX];
+    int running = 1, underrun = 0;
+    pa_memchunk memchunk;
 
-    if (u->memchunk.length <= 0) {
-        pa_memblock_unref(u->memchunk.memblock);
-        u->memchunk.memblock = NULL;
+    pa_assert(u);
+
+    pa_log_debug("Thread starting up");
+
+    memset(&pollfd, 0, sizeof(pollfd));
+    pollfd[POLLFD_ASYNCQ].fd = pa_asyncmsgq_get_fd(u->sink->asyncmsgq, PA_ASYNCQ_POP);
+    pollfd[POLLFD_ASYNCQ].events = POLLIN;
+
+    pollfd[POLLFD_FIFO].fd = u->fd;
+
+    memset(&memchunk, 0, sizeof(memchunk));
+
+    for (;;) {
+        int code;
+        void *object, *data;
+        int r;
+        struct timeval now;
+
+        /* Check whether there is a message for us to process */
+        if (pa_asyncmsgq_get(u->sink->asyncmsgq, &object, &code, &data) == 0) {
+
+
+            /* Now process these messages our own way */
+            if (!object) {
+                switch (code) {
+                    case PA_SINK_MESSAGE_SHUTDOWN:
+                        goto finish;
+
+                    default:
+                        pa_sink_process_msg(u->sink->asyncmsgq, object, code, data);
+                }
+                
+            } else if (object == u->sink) {
+                        
+                case PA_SINK_MESSAGE_STOP:
+                    pa_assert(running);
+                    running = 0;
+                    break;
+
+                case PA_SINK_MESSAGE_START:
+                    pa_assert(!running);
+                    running = 1;
+                    break;
+
+                case PA_SINK_MESSAGE_GET_LATENCY: {
+                    size_t n = 0;
+                    int l;
+
+                    if (ioctl(u->fd, TIOCINQ, &l) >= 0 && l > 0)
+                        n = (size_t) l;
+
+                    n += memchunk.length;
+
+                    *((pa_usec_t*) data) pa_bytes_to_usec(n, &u->sink->sample_spec);
+                    break;
+                }
+
+                /* ... */
+
+                default:
+                    pa_sink_process_msg(u->sink->asyncmsgq, object, code, data);
+            }
+            
+            pa_asyncmsgq_done(u->sink->asyncmsgq);
+            continue;
+        }
+
+        /* Render some data and write it to the fifo */
+
+        if (running && (pollfd[POLLFD_FIFO].revents || underrun)) {
+
+            if (chunk.length <= 0)
+                pa_sink_render(u->fd, PIPE_BUF, &chunk);
+
+            underrun = chunk.length <= 0;
+
+            if (!underrun) {
+                ssize_t l;
+                
+                p = pa_memblock_acquire(u->memchunk.memblock);
+                l = pa_write(u->fd, (uint8_t*) p + u->memchunk.index, u->memchunk.length);
+                pa_memblock_release(p);
+                    
+                if (l < 0) {
+
+                    if (errno != EINTR && errno != EAGAIN) {
+                        pa_log("Failed to write data to FIFO: %s", pa_cstrerror(errno));
+                        goto fail;
+                    }
+                    
+                } else {
+                        
+                    u->memchunk.index += l;
+                    u->memchunk.length -= l;
+
+                    if (u->memchunk.length <= 0) {
+                        pa_memblock_unref(u->memchunk.memblock);
+                        u->memchunk.memblock = NULL;
+                    }
+                }
+
+                pollfd[POLLFD_FIFO].revents = 0;
+                continue;
+            }
+        }
+
+        pollfd[POLLFD_FIFO].events = running && !underrun ? POLLOUT : 0;
+
+        /* Hmm, nothing to do. Let's sleep */
+        
+        if (pa_asyncmsgq_before_poll(u->sink->asyncmsgq) < 0)
+            continue;
+
+        r = poll(&pollfd, 1, 0);
+        pa_asyncmsgq_after_poll(u->sink->asyncmsgq);
+
+        if (r < 0) {
+            if (errno == EINTR)
+                continue;
+
+            pa_log("poll() failed: %s", pa_cstrerror(errno));
+            goto fail;
+        }
+
+        if (pollfd[POLLFD_FIFO].revents & ~POLLIN) {
+            pa_log("FIFO shutdown.");
+            goto fail;
+        }
+        
+        pa_assert(pollfd[POLLFD_ASYNCQ].revents & ~POLLIN == 0);
     }
-}
-
-static void notify_cb(pa_sink*s) {
-    struct userdata *u = s->userdata;
-    assert(s && u);
-
-    if (pa_iochannel_is_writable(u->io))
-        u->core->mainloop->defer_enable(u->defer_event, 1);
-}
-
-static pa_usec_t get_latency_cb(pa_sink *s) {
-    struct userdata *u = s->userdata;
-    assert(s && u);
-
-    return u->memchunk.memblock ? pa_bytes_to_usec(u->memchunk.length, &s->sample_spec) : 0;
-}
-
-static void defer_callback(PA_GCC_UNUSED pa_mainloop_api *m, PA_GCC_UNUSED pa_defer_event*e, void *userdata) {
-    struct userdata *u = userdata;
-    assert(u);
-    do_write(u);
-}
+    
+fail:
+    /* We have to continue processing messages until we receive the
+     * SHUTDOWN message */
+    pa_asyncmsgq_post(u->core->asyncmsgq, u->core, PA_CORE_MESSAGE_UNLOAD_MODULE, pa_module_ref(u->module), pa_module_unref);
+    pa_asyncmsgq_wait_for(PA_SINK_MESSAGE_SHUTDOWN);
 
-static void io_callback(PA_GCC_UNUSED pa_iochannel *io, void*userdata) {
-    struct userdata *u = userdata;
-    assert(u);
-    do_write(u);
+finish:
+    pa_log_debug("Thread shutting down");
 }
 
 int pa__init(pa_core *c, pa_module*m) {
     struct userdata *u = NULL;
     struct stat st;
-    const char *p;
-    int fd = -1;
     pa_sample_spec ss;
     pa_channel_map map;
     pa_modargs *ma = NULL;
     char *t;
 
-    assert(c && m);
+    pa_assert(c);
+    pa_assert(m);
 
     if (!(ma = pa_modargs_new(m->argument, valid_modargs))) {
-        pa_log("failed to parse module arguments");
+        pa_log("Failed to parse module arguments.");
         goto fail;
     }
 
     ss = c->default_sample_spec;
     if (pa_modargs_get_sample_spec_and_channel_map(ma, &ss, &map, PA_CHANNEL_MAP_DEFAULT) < 0) {
-        pa_log("invalid sample format specification");
+        pa_log("Invalid sample format specification");
         goto fail;
     }
 
-    mkfifo(p = pa_modargs_get_value(ma, "file", DEFAULT_FIFO_NAME), 0777);
-
-    if ((fd = open(p, O_RDWR)) < 0) {
+    u = pa_xnew0(struct userdata, 1);
+    u->core = c;
+    u->module = m;
+    u->filename = pa_xstrdup(pa_modargs_get_value(ma, "file", DEFAULT_FIFO_NAME));
+    u->fd = fd;
+    u->memchunk.memblock = NULL;
+    u->memchunk.length = 0;
+    m->userdata = u;
+    
+    mkfifo(u->filename, 0666);
+    
+    if ((u->fd = open(u->filename, O_RDWR)) < 0) {
         pa_log("open('%s'): %s", p, pa_cstrerror(errno));
         goto fail;
     }
 
-    pa_fd_set_cloexec(fd, 1);
+    pa_fd_set_cloexec(u->fd, 1);
+    pa_make_nonblock_fd(u->fd);
 
-    if (fstat(fd, &st) < 0) {
+    if (fstat(u->fd, &st) < 0) {
         pa_log("fstat('%s'): %s", p, pa_cstrerror(errno));
         goto fail;
     }
@@ -184,34 +286,21 @@ int pa__init(pa_core *c, pa_module*m) {
         goto fail;
     }
 
-    u = pa_xmalloc0(sizeof(struct userdata));
-    u->filename = pa_xstrdup(p);
-    u->core = c;
-    u->module = m;
-    m->userdata = u;
-
     if (!(u->sink = pa_sink_new(c, __FILE__, pa_modargs_get_value(ma, "sink_name", DEFAULT_SINK_NAME), 0, &ss, &map))) {
-        pa_log("failed to create sink.");
+        pa_log("Failed to create sink.");
         goto fail;
     }
-    u->sink->notify = notify_cb;
-    u->sink->get_latency = get_latency_cb;
+    
     u->sink->userdata = u;
     pa_sink_set_owner(u->sink, m);
     pa_sink_set_description(u->sink, t = pa_sprintf_malloc("Unix FIFO sink '%s'", p));
     pa_xfree(t);
 
-    u->io = pa_iochannel_new(c->mainloop, -1, fd);
-    assert(u->io);
-    pa_iochannel_set_callback(u->io, io_callback, u);
-
-    u->memchunk.memblock = NULL;
-    u->memchunk.length = 0;
-
-    u->defer_event = c->mainloop->defer_new(c->mainloop, defer_callback, u);
-    assert(u->defer_event);
-    c->mainloop->defer_enable(u->defer_event, 0);
-
+    if (!(u->thread = pa_thread_new(thread_func, u))) {
+        pa_log("Failed to create thread.");
+        goto fail;
+    }
+    
     pa_modargs_free(ma);
 
     return 0;
@@ -220,9 +309,6 @@ fail:
     if (ma)
         pa_modargs_free(ma);
 
-    if (fd >= 0)
-        close(fd);
-
     pa__done(c, m);
 
     return -1;
@@ -230,22 +316,31 @@ fail:
 
 void pa__done(pa_core *c, pa_module*m) {
     struct userdata *u;
-    assert(c && m);
+    pa_assert(c);
+    pa_assert(m);
 
     if (!(u = m->userdata))
         return;
 
-    if (u->memchunk.memblock)
-        pa_memblock_unref(u->memchunk.memblock);
-
     pa_sink_disconnect(u->sink);
+
+    if (u->thread) {
+        pa_asyncmsgq_send(u->sink->asyncmsgq, PA_SINK_MESSAGE_SHUTDOWN, NULL);
+        pa_thread_free(u->thread);
+    }
+    
     pa_sink_unref(u->sink);
-    pa_iochannel_free(u->io);
-    u->core->mainloop->defer_free(u->defer_event);
 
-    assert(u->filename);
-    unlink(u->filename);
-    pa_xfree(u->filename);
+    if (u->memchunk.memblock)
+       pa_memblock_unref(u->memchunk.memblock);
+
+    if (u->filename) {
+        unlink(u->filename);
+        pa_xfree(u->filename);
+    }
+
+    if (u->fd >= 0)
+        close(u->fd);
 
     pa_xfree(u);
 }
diff --git a/src/modules/module-pipe-source.c b/src/modules/module-pipe-source.c
index 56c721b..f275c5d 100644
--- a/src/modules/module-pipe-source.c
+++ b/src/modules/module-pipe-source.c
@@ -84,7 +84,9 @@ static const char* const valid_modargs[] = {
 
 static void do_read(struct userdata *u) {
     ssize_t r;
+    void *p;
     pa_memchunk chunk;
+
     assert(u);
 
     if (!pa_iochannel_is_readable(u->io))
@@ -97,17 +99,22 @@ static void do_read(struct userdata *u) {
         u->chunk.index = chunk.length = 0;
     }
 
-    assert(u->chunk.memblock && u->chunk.memblock->length > u->chunk.index);
-    if ((r = pa_iochannel_read(u->io, (uint8_t*) u->chunk.memblock->data + u->chunk.index, u->chunk.memblock->length - u->chunk.index)) <= 0) {
+    assert(u->chunk.memblock);
+    assert(pa_memblock_get_length(u->chunk.memblock) > u->chunk.index);
+
+    p = pa_memblock_acquire(u->chunk.memblock);
+    if ((r = pa_iochannel_read(u->io, (uint8_t*) p + u->chunk.index, pa_memblock_get_length(u->chunk.memblock) - u->chunk.index)) <= 0) {
+        pa_memblock_release(u->chunk.memblock);
         pa_log("read(): %s", pa_cstrerror(errno));
         return;
     }
+    pa_memblock_release(u->chunk.memblock);
 
     u->chunk.length = r;
     pa_source_post(u->source, &u->chunk);
     u->chunk.index += r;
 
-    if (u->chunk.index >= u->chunk.memblock->length) {
+    if (u->chunk.index >= pa_memblock_get_length(u->chunk.memblock)) {
         u->chunk.index = u->chunk.length = 0;
         pa_memblock_unref(u->chunk.memblock);
         u->chunk.memblock = NULL;
diff --git a/src/modules/module-sine.c b/src/modules/module-sine.c
index 661455b..baf3734 100644
--- a/src/modules/module-sine.c
+++ b/src/modules/module-sine.c
@@ -65,7 +65,7 @@ static int sink_input_peek(pa_sink_input *i, pa_memchunk *chunk) {
 
     chunk->memblock = pa_memblock_ref(u->memblock);
     chunk->index = u->peek_index;
-    chunk->length = u->memblock->length - u->peek_index;
+    chunk->length = pa_memblock_get_length(u->memblock) - u->peek_index;
     return 0;
 }
 
@@ -74,11 +74,12 @@ static void sink_input_drop(pa_sink_input *i, const pa_memchunk *chunk, size_t l
     assert(i && chunk && length && i->userdata);
     u = i->userdata;
 
-    assert(chunk->memblock == u->memblock && length <= u->memblock->length-u->peek_index);
+    assert(chunk->memblock == u->memblock);
+    assert(length <= pa_memblock_get_length(u->memblock)-u->peek_index);
 
     u->peek_index += length;
 
-    if (u->peek_index >= u->memblock->length)
+    if (u->peek_index >= pa_memblock_get_length(u->memblock))
         u->peek_index = 0;
 }
 
@@ -111,6 +112,7 @@ int pa__init(pa_core *c, pa_module*m) {
     pa_sample_spec ss;
     uint32_t frequency;
     char t[256];
+    void *p;
     pa_sink_input_new_data data;
 
     if (!(ma = pa_modargs_new(m->argument, valid_modargs))) {
@@ -142,7 +144,9 @@ int pa__init(pa_core *c, pa_module*m) {
     }
 
     u->memblock = pa_memblock_new(c->mempool, pa_bytes_per_second(&ss));
-    calc_sine(u->memblock->data, u->memblock->length, frequency);
+    p = pa_memblock_acquire(u->memblock);
+    calc_sine(p, pa_memblock_get_length(u->memblock), frequency);
+    pa_memblock_release(u->memblock);
 
     snprintf(t, sizeof(t), "Sine Generator at %u Hz", frequency);
 
diff --git a/src/modules/rtp/rtp.c b/src/modules/rtp/rtp.c
index 03a0141..f0ab7d8 100644
--- a/src/modules/rtp/rtp.c
+++ b/src/modules/rtp/rtp.c
@@ -81,7 +81,7 @@ int pa_rtp_send(pa_rtp_context *c, size_t size, pa_memblockq *q) {
             size_t k = n + chunk.length > size ? size - n : chunk.length;
 
             if (chunk.memblock) {
-                iov[iov_idx].iov_base = (void*)((uint8_t*) chunk.memblock->data + chunk.index);
+                iov[iov_idx].iov_base = (void*)((uint8_t*) pa_memblock_acquire(chunk.memblock) + chunk.index);
                 iov[iov_idx].iov_len = k;
                 mb[iov_idx] = chunk.memblock;
                 iov_idx ++;
@@ -116,8 +116,10 @@ int pa_rtp_send(pa_rtp_context *c, size_t size, pa_memblockq *q) {
 
                 k = sendmsg(c->fd, &m, MSG_DONTWAIT);
 
-                for (i = 1; i < iov_idx; i++)
+                for (i = 1; i < iov_idx; i++) {
+                    pa_memblock_release(mb[i]);
                     pa_memblock_unref(mb[i]);
+                }
 
                 c->sequence++;
             } else
@@ -174,7 +176,7 @@ int pa_rtp_recv(pa_rtp_context *c, pa_memchunk *chunk, pa_mempool *pool) {
 
     chunk->memblock = pa_memblock_new(pool, size);
 
-    iov.iov_base = chunk->memblock->data;
+    iov.iov_base = pa_memblock_acquire(chunk->memblock);
     iov.iov_len = size;
 
     m.msg_name = NULL;
@@ -195,9 +197,9 @@ int pa_rtp_recv(pa_rtp_context *c, pa_memchunk *chunk, pa_mempool *pool) {
         goto fail;
     }
 
-    memcpy(&header, chunk->memblock->data, sizeof(uint32_t));
-    memcpy(&c->timestamp, (uint8_t*) chunk->memblock->data + 4, sizeof(uint32_t));
-    memcpy(&c->ssrc, (uint8_t*) chunk->memblock->data + 8, sizeof(uint32_t));
+    memcpy(&header, iov.iov_base, sizeof(uint32_t));
+    memcpy(&c->timestamp, (uint8_t*) iov.iov_base + 4, sizeof(uint32_t));
+    memcpy(&c->ssrc, (uint8_t*) iov.iov_base + 8, sizeof(uint32_t));
 
     header = ntohl(header);
     c->timestamp = ntohl(c->timestamp);
@@ -238,8 +240,10 @@ int pa_rtp_recv(pa_rtp_context *c, pa_memchunk *chunk, pa_mempool *pool) {
     return 0;
 
 fail:
-    if (chunk->memblock)
+    if (chunk->memblock) {
+        pa_memblock_release(chunk->memblock);
         pa_memblock_unref(chunk->memblock);
+    }
 
     return -1;
 }
diff --git a/src/pulse/internal.h b/src/pulse/internal.h
index 52354fd..e5c9ef1 100644
--- a/src/pulse/internal.h
+++ b/src/pulse/internal.h
@@ -116,6 +116,7 @@ struct pa_stream {
     uint32_t requested_bytes;
 
     pa_memchunk peek_memchunk;
+    void *peek_data;
     pa_memblockq *record_memblockq;
 
     int corked;
diff --git a/src/pulse/stream.c b/src/pulse/stream.c
index f20c17a..44fce52 100644
--- a/src/pulse/stream.c
+++ b/src/pulse/stream.c
@@ -91,6 +91,7 @@ pa_stream *pa_stream_new(pa_context *c, const char *name, const pa_sample_spec *
     s->peek_memchunk.index = 0;
     s->peek_memchunk.length = 0;
     s->peek_memchunk.memblock = NULL;
+    s->peek_data = NULL;
 
     s->record_memblockq = NULL;
 
@@ -125,8 +126,11 @@ static void stream_free(pa_stream *s) {
         s->mainloop->time_free(s->auto_timing_update_event);
     }
 
-    if (s->peek_memchunk.memblock)
+    if (s->peek_memchunk.memblock) {
+        if (s->peek_data)
+            pa_memblock_release(s->peek_memchunk.memblock);
         pa_memblock_unref(s->peek_memchunk.memblock);
+    }
 
     if (s->record_memblockq)
         pa_memblockq_free(s->record_memblockq);
@@ -608,8 +612,11 @@ int pa_stream_write(
     if (free_cb)
         chunk.memblock = pa_memblock_new_user(s->context->mempool, (void*) data, length, free_cb, 1);
     else {
+        void *tdata;
         chunk.memblock = pa_memblock_new(s->context->mempool, length);
-        memcpy(chunk.memblock->data, data, length);
+        tdata = pa_memblock_acquire(chunk.memblock);
+        memcpy(tdata, data, length);
+        pa_memblock_release(chunk.memblock);
     }
 
     chunk.index = 0;
@@ -675,9 +682,12 @@ int pa_stream_peek(pa_stream *s, const void **data, size_t *length) {
             *length = 0;
             return 0;
         }
+
+        s->peek_data = pa_memblock_acquire(s->peek_memchunk.memblock);
     }
 
-    *data = (const char*) s->peek_memchunk.memblock->data + s->peek_memchunk.index;
+    assert(s->peek_data);
+    *data = (uint8_t*) s->peek_data + s->peek_memchunk.index;
     *length = s->peek_memchunk.length;
     return 0;
 }
@@ -696,6 +706,8 @@ int pa_stream_drop(pa_stream *s) {
     if (s->timing_info_valid && !s->timing_info.read_index_corrupt)
         s->timing_info.read_index += s->peek_memchunk.length;
 
+    assert(s->peek_data);
+    pa_memblock_release(s->peek_memchunk.memblock);
     pa_memblock_unref(s->peek_memchunk.memblock);
     s->peek_memchunk.length = 0;
     s->peek_memchunk.index = 0;
diff --git a/src/pulse/xmalloc.h b/src/pulse/xmalloc.h
index 2f6399c..62a450d 100644
--- a/src/pulse/xmalloc.h
+++ b/src/pulse/xmalloc.h
@@ -75,6 +75,15 @@ static inline void* pa_xnew0_internal(unsigned n, size_t k) {
 /** Same as pa_xnew() but set the memory to zero */
 #define pa_xnew0(type, n) ((type*) pa_xnew0_internal((n), sizeof(type)))
 
+/** Internal helper for pa_xnew0() */
+static inline void* pa_xnewdup_internal(const void *p, unsigned n, size_t k) {
+    assert(n < INT_MAX/k);
+    return pa_xmemdup(p, n*k);
+}
+
+/** Same as pa_xnew() but set the memory to zero */
+#define pa_xnewdup(type, p, n) ((type*) pa_xnewdup_internal((p), (n), sizeof(type)))
+
 PA_C_DECL_END
 
 #endif
diff --git a/src/pulsecore/asyncmsgq.c b/src/pulsecore/asyncmsgq.c
new file mode 100644
index 0000000..31e27e7
--- /dev/null
+++ b/src/pulsecore/asyncmsgq.c
@@ -0,0 +1,235 @@
+/* $Id$ */
+
+/***
+  This file is part of PulseAudio.
+
+  Copyright 2006 Lennart Poettering
+
+  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
+  Lesser 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.
+***/
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <unistd.h>
+#include <errno.h>
+
+#include <pulsecore/atomic.h>
+#include <pulsecore/log.h>
+#include <pulsecore/thread.h>
+#include <pulsecore/semaphore.h>
+#include <pulsecore/macro.h>
+#include <pulsecore/core-util.h>
+#include <pulsecore/flist.h>
+#include <pulse/xmalloc.h>
+
+#include "asyncmsgq.h"
+
+PA_STATIC_FLIST_DECLARE(asyncmsgq, 0);
+
+struct asyncmsgq_item {
+    int code;
+    pa_msgobject *object;
+    void *userdata;
+    pa_free_cb_t free_cb;
+    pa_memchunk memchunk;
+    pa_semaphore *semaphore;
+};
+
+struct pa_asyncmsgq {
+    pa_asyncq *asyncq;
+    pa_mutex *mutex; /* only for the writer side */
+
+    struct asyncmsgq_item *current;
+};
+
+pa_asyncmsgq *pa_asyncmsgq_new(unsigned size) {
+    pa_asyncmsgq *a;
+
+    a = pa_xnew(pa_asyncmsgq, 1);
+
+    pa_assert_se(a->asyncq = pa_asyncq_new(size));
+    pa_assert_se(a->mutex = pa_mutex_new(0));
+    a->current = NULL;
+    
+    return a;
+}
+
+void pa_asyncmsgq_free(pa_asyncmsgq *a) {
+    struct asyncmsgq_item *i;
+    pa_assert(a);
+
+    while ((i = pa_asyncq_pop(a->asyncq, 0))) {
+
+        pa_assert(!i->semaphore);
+
+        if (i->object)
+            pa_msgobject_unref(i->object);
+
+        if (i->memchunk.memblock)
+            pa_memblock_unref(i->object);
+        
+        if (i->userdata_free_cb)
+            i->userdata_free_cb(i->userdata);
+        
+        if (pa_flist_push(PA_STATIC_FLIST_GET(asyncmsgq), i) < 0)
+            pa_xfree(i);
+    }
+
+    pa_asyncq_free(a->asyncq, NULL);
+    pa_mutex_free(a->mutex);
+    pa_xfree(a);
+}
+
+void pa_asyncmsgq_post(pa_asyncmsgq *a, pa_msgobject *object, int code, const void *userdata, const pa_memchunk *chunk, pa_free_cb_t free_cb) {
+    struct asyncmsgq_item *i;
+    pa_assert(a);
+
+    if (!(i = pa_flist_pop(PA_STATIC_FLIST_GET(asyncmsgq))))
+        i = pa_xnew(struct asyncmsgq_item, 1);
+
+    i->code = code;
+    i->object = pa_msgobject_ref(object);
+    i->userdata = (void*) userdata;
+    i->free_cb = free_cb;
+    if (chunk) {
+        pa_assert(chunk->memblock);
+        i->memchunk = *chunk;
+        pa_memblock_ref(i->memchunk.memblock);
+    } else
+        pa_memchunk_reset(&i->memchunk);
+    i->semaphore = NULL;
+
+    /* Thus mutex makes the queue multiple-writer safe. This lock is only used on the writing side */
+    pa_mutex_lock(a->mutex);
+    pa_assert_se(pa_asyncq_push(a->asyncq, i, 1) == 0);
+    pa_mutex_unlock(a->mutex);
+}
+
+int pa_asyncmsgq_send(pa_asyncmsgq *a, pa_msgobject *object, int code, const void *userdata, const pa_memchunk *chunk) {
+    struct asyncmsgq_item i;
+    pa_assert(a);
+
+    i.code = code;
+    i.object = object;
+    i.userdata = (void*) userdata;
+    i.free_cb = NULL;
+    i.ret = -1;
+    if (chunk) {
+        pa_assert(chunk->memblock);
+        i->memchunk = *chunk;
+    } else
+        pa_memchunk_reset(&i->memchunk);
+    pa_assert_se(i.semaphore = pa_semaphore_new(0));
+
+    /* Thus mutex makes the queue multiple-writer safe. This lock is only used on the writing side */
+    pa_mutex_lock(a->mutex);
+    pa_assert_se(pa_asyncq_push(a->asyncq, &i, 1) == 0);
+    pa_mutex_unlock(a->mutex);
+
+    pa_semaphore_wait(i.semaphore);
+    pa_semaphore_free(i.semaphore);
+
+    return i.ret;
+}
+
+int pa_asyncmsgq_get(pa_asyncmsgq *a, pa_msgobject **object, int *code, void **userdata, pa_memchunk *chunk, int wait) {
+    pa_assert(a);
+    pa_assert(code);
+    pa_assert(!a->current);
+
+    if (!(a->current = pa_asyncq_pop(a->asyncq, wait)))
+        return -1;
+
+    *code = a->current->code;
+    if (userdata)
+        *userdata = a->current->userdata;
+    if (object)
+        *object = a->current->object;
+    if (chunk)
+        *chunk = a->chunk;
+    
+    return 0;
+}
+
+void pa_asyncmsgq_done(pa_asyncmsgq *a, int ret) {
+    pa_assert(a);
+    pa_assert(a->current);
+
+    if (a->current->semaphore) {
+        a->current->ret = ret;
+        pa_semaphore_post(a->current->semaphore);
+    } else {
+
+        if (a->current->free_cb)
+            a->current->free_cb(a->current->userdata);
+
+        if (a->current->object)
+            pa_msgobject_unref(a->current->object);
+
+        if (a->current->memchunk.memblock)
+            pa_memblock_unref(a->current->memchunk.memblock);
+        
+        if (pa_flist_push(PA_STATIC_FLIST_GET(asyncmsgq), a->current) < 0)
+            pa_xfree(a->current);
+    }
+
+    a->current = NULL;
+}
+
+int pa_asyncmsgq_wait_for(pa_asyncmsgq *a, int code) {
+    int c;
+    pa_assert(a);
+    
+    do {
+        
+        if (pa_asyncmsgq_get(a, NULL, &c, NULL, 1) < 0)
+            return -1;
+
+        pa_asyncmsgq_done(a);
+        
+    } while (c != code);
+
+    return 0;
+}
+
+int pa_asyncmsgq_get_fd(pa_asyncmsgq *a) {
+    pa_assert(a);
+
+    return pa_asyncq_get_fd(a->asyncq);
+}
+
+int pa_asyncmsgq_before_poll(pa_asyncmsgq *a) {
+    pa_assert(a);
+
+    return pa_asyncq_before_poll(a->asyncq);
+}
+
+void pa_asyncmsgq_after_poll(pa_asyncmsgq *a) {
+    pa_assert(a);
+
+    pa_asyncq_after_poll(a->asyncq);
+}
+
+int pa_asyncmsgq_dispatch(pa_msgobject *object, int code, void *userdata, pa_memchunk *memchunk) {
+    pa_assert(q);
+
+    if (object)
+        return object->msg_process(object, code, userdata, memchunk);
+
+    return 0;
+}
diff --git a/src/pulsecore/asyncmsgq.h b/src/pulsecore/asyncmsgq.h
new file mode 100644
index 0000000..17b37e4
--- /dev/null
+++ b/src/pulsecore/asyncmsgq.h
@@ -0,0 +1,73 @@
+#ifndef foopulseasyncmsgqhfoo
+#define foopulseasyncmsgqhfoo
+
+/* $Id$ */
+
+/***
+  This file is part of PulseAudio.
+
+  Copyright 2004-2006 Lennart Poettering
+
+  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
+  Lesser 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.
+***/
+
+#include <sys/types.h>
+
+#include <pulsecore/asyncq.h>
+#include <pulsecore/memchunk.h>
+#include <pulsecore/msgobject.h>
+
+/* A simple asynchronous message queue, based on pa_asyncq. In
+ * contrast to pa_asyncq this one is multiple-writer safe, though
+ * still not multiple-reader safe. This queue is intended to be used
+ * for controlling real-time threads from normal-priority
+ * threads. Multiple-writer-safety is accomplished by using a mutex on
+ * the writer side. This queue is thus not useful for communication
+ * between several real-time threads.
+ *
+ * The queue takes messages consisting of:
+ *    "Object" for which this messages is intended (may be NULL)
+ *    A numeric message code
+ *    Arbitrary userdata pointer (may be NULL)
+ *    A memchunk (may be NULL)
+ *
+ * There are two functions for submitting messages: _post and
+ * _send. The fromer just enqueues the message asynchronously, the
+ * latter waits for completion, synchronously. */
+
+enum {
+    PA_MESSAGE_SHUTDOWN /* A generic message to inform the handler of this queue to quit */
+};
+
+typedef struct pa_asyncmsgq pa_asyncmsgq;
+
+pa_asyncmsgq* pa_asyncmsgq_new(size_t size);
+void pa_asyncmsgq_free(pa_asyncmsgq* q);
+
+void pa_asyncmsgq_post(pa_asyncmsgq *q, pa_msgobject *object, int code, const void *userdata, const pa_memchunk *memchunk, pa_free_cb_t userdata_free_cb);
+int pa_asyncmsgq_send(pa_asyncmsgq *q, pa_msgobject *object, int code, const void *userdata, const pa_memchunk *memchunk);
+
+int pa_asyncmsgq_get(pa_asyncmsgq *q, pa_msgobject **object, int *code, void **userdata, pa_memchunk *memchunk, int wait);
+int pa_asyncmsgq_dispatch(pa_msgobject *object, int code, void *userdata, pa_memchunk *memchunk);
+void pa_asyncmsgq_done(pa_asyncmsgq *q, int ret);
+int pa_asyncmsgq_wait_for(pa_asyncmsgq *a, int code);
+
+/* Just for the reading side */
+int pa_asyncmsgq_get_fd(pa_asyncmsgq *q);
+int pa_asyncmsgq_before_poll(pa_asyncmsgq *a);
+void pa_asyncmsgq_after_poll(pa_asyncmsgq *a);
+
+#endif
diff --git a/src/pulsecore/asyncq.c b/src/pulsecore/asyncq.c
new file mode 100644
index 0000000..779cd47
--- /dev/null
+++ b/src/pulsecore/asyncq.c
@@ -0,0 +1,271 @@
+/* $Id$ */
+
+/***
+  This file is part of PulseAudio.
+
+  Copyright 2006 Lennart Poettering
+
+  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
+  Lesser 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.
+***/
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <unistd.h>
+#include <errno.h>
+
+#include <pulsecore/atomic.h>
+#include <pulsecore/log.h>
+#include <pulsecore/thread.h>
+#include <pulsecore/macro.h>
+#include <pulsecore/core-util.h>
+#include <pulse/xmalloc.h>
+
+#include "asyncq.h"
+
+#define ASYNCQ_SIZE 128
+
+/* For debugging purposes we can define _Y to put and extra thread
+ * yield between each operation. */
+
+#ifdef PROFILE
+#define _Y pa_thread_yield()
+#else
+#define _Y do { } while(0)
+#endif
+
+struct pa_asyncq {
+    unsigned size;
+    unsigned read_idx;
+    unsigned write_idx;
+    pa_atomic_int_t read_waiting;
+    pa_atomic_int_t write_waiting;
+    int read_fds[2], write_fds[2];
+};
+
+#define PA_ASYNCQ_CELLS(x) ((pa_atomic_ptr_t*) ((uint8_t*) (x) + PA_ALIGN(sizeof(struct pa_asyncq))))
+
+static int is_power_of_two(unsigned size) {
+    return !(size & (size - 1));
+}
+
+static int reduce(pa_asyncq *l, int value) {
+    return value & (unsigned) (l->size - 1);
+}
+
+pa_asyncq *pa_asyncq_new(unsigned size) {
+    pa_asyncq *l;
+
+    if (!size)
+        size = ASYNCQ_SIZE;
+
+    pa_assert(is_power_of_two(size));
+
+    l = pa_xmalloc0(PA_ALIGN(sizeof(pa_asyncq)) + (sizeof(pa_atomic_ptr_t) * size));
+
+    l->size = size;
+    pa_atomic_store(&l->read_waiting, 0);
+    pa_atomic_store(&l->write_waiting, 0);
+
+    if (pipe(l->read_fds) < 0) {
+        pa_xfree(l);
+        return NULL;
+    }
+    
+    if (pipe(l->write_fds) < 0) {
+        pa_close(l->read_fds[0]);
+        pa_close(l->read_fds[1]);
+        pa_xfree(l);
+        return NULL;
+    }
+
+    pa_make_nonblock_fd(l->read_fds[1]);
+    pa_make_nonblock_fd(l->write_fds[1]);
+
+    return l;
+}
+
+void pa_asyncq_free(pa_asyncq *l, pa_free_cb_t free_cb) {
+    pa_assert(l);
+
+    if (free_cb) {
+        void *p;
+        
+        while ((p = pa_asyncq_pop(l, 0)))
+            free_cb(p);
+    }
+
+    pa_close(l->read_fds[0]);
+    pa_close(l->read_fds[1]);
+    pa_close(l->write_fds[0]);
+    pa_close(l->write_fds[1]);
+    
+    pa_xfree(l);
+}
+
+int pa_asyncq_push(pa_asyncq*l, void *p, int wait) {
+    int idx;
+    pa_atomic_ptr_t *cells;
+
+    pa_assert(l);
+    pa_assert(p);
+
+    cells = PA_ASYNCQ_CELLS(l);
+    
+    _Y;
+    idx = reduce(l, l->write_idx);
+
+    if (!pa_atomic_ptr_cmpxchg(&cells[idx], NULL, p)) {
+        
+        /* First try failed. Let's wait for changes. */
+
+        if (!wait)
+            return -1;
+
+        _Y;
+
+        pa_atomic_inc(&l->write_waiting);
+
+        for (;;) {
+            char x[20];
+            
+            _Y;
+
+            if (pa_atomic_ptr_cmpxchg(&cells[idx], NULL, p))
+                break;
+
+            _Y;
+
+            if (read(l->write_fds[0], x, sizeof(x)) < 0 && errno != EINTR) {
+                pa_atomic_dec(&l->write_waiting);
+                return -1;
+            }
+        }
+        
+        _Y;
+
+        pa_atomic_dec(&l->write_waiting);
+    }
+    
+    _Y;
+    l->write_idx++;
+    
+    if (pa_atomic_load(&l->read_waiting)) {
+        char x = 'x';
+        _Y;
+        write(l->read_fds[1], &x, sizeof(x));
+    }
+    
+    return 0;
+}
+
+void* pa_asyncq_pop(pa_asyncq*l, int wait) {
+    int idx;
+    void *ret;
+    pa_atomic_ptr_t *cells;
+
+    pa_assert(l);
+
+    cells = PA_ASYNCQ_CELLS(l);
+
+    _Y;
+    idx = reduce(l, l->read_idx);
+
+    if (!(ret = pa_atomic_ptr_load(&cells[idx]))) {
+
+        /* First try failed. Let's wait for changes. */
+    
+        if (!wait)
+            return NULL;
+
+        _Y;
+
+        pa_atomic_inc(&l->read_waiting);
+
+        for (;;) {
+            char x[20];
+
+            _Y;
+
+            if ((ret = pa_atomic_ptr_load(&cells[idx])))
+                break;
+
+            _Y;
+
+            if (read(l->read_fds[0], x, sizeof(x)) < 0 && errno != EINTR) {
+                pa_atomic_dec(&l->read_waiting);
+                return NULL;
+            }
+        }
+
+        _Y;
+
+        pa_atomic_dec(&l->read_waiting);
+    }
+
+    /* Guaranteed if we only have a single reader */
+    pa_assert_se(pa_atomic_ptr_cmpxchg(&cells[idx], ret, NULL));
+
+    _Y;
+    l->read_idx++;
+
+    if (pa_atomic_load(&l->write_waiting)) {
+        char x = 'x';
+        _Y;
+        write(l->write_fds[1], &x, sizeof(x));
+    }
+            
+    return ret;
+}
+
+int pa_asyncq_get_fd(pa_asyncq *q) {
+    pa_assert(q);
+
+    return q->read_fds[0];
+}
+
+int pa_asyncq_before_poll(pa_asyncq *l) {
+    int idx;
+    pa_atomic_ptr_t *cells;
+
+    pa_assert(l);
+
+    cells = PA_ASYNCQ_CELLS(l);
+
+    _Y;
+    idx = reduce(l, l->read_idx);
+
+    if (pa_atomic_ptr_load(&cells[idx]))
+        return -1;
+
+    pa_atomic_inc(&l->read_waiting);
+    
+    if (pa_atomic_ptr_load(&cells[idx])) {
+        pa_atomic_dec(&l->read_waiting);
+        return -1;
+    }
+
+    return 0;
+}
+
+int pa_asyncq_after_poll(pa_asyncq *l) {
+    pa_assert(l);
+
+    pa_assert(pa_atomic_load(&l->read_waiting) > 0);
+
+    pa_atomic_dec(&l->read_waiting);
+}
diff --git a/src/pulsecore/asyncq.h b/src/pulsecore/asyncq.h
new file mode 100644
index 0000000..aac45b1
--- /dev/null
+++ b/src/pulsecore/asyncq.h
@@ -0,0 +1,56 @@
+#ifndef foopulseasyncqhfoo
+#define foopulseasyncqhfoo
+
+/* $Id$ */
+
+/***
+  This file is part of PulseAudio.
+
+  Copyright 2004-2006 Lennart Poettering
+
+  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
+  Lesser 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.
+***/
+
+#include <sys/types.h>
+#include <pulse/def.h>
+
+/* A simple, asynchronous, lock-free (if requested also wait-free)
+ * queue. Not multiple-reader/multiple-writer safe. If that is
+ * required both sides can be protected by a mutex each. --- Which is
+ * not a bad thing in most cases, since this queue is intended for
+ * communication between a normal thread and a single real-time
+ * thread. Only the real-time side needs to be lock-free/wait-free.
+ *
+ * If the queue is full and another entry shall be pushed, or when the
+ * queue is empty and another entry shall be popped and the "wait"
+ * argument is non-zero, the queue will block on a UNIX FIFO object --
+ * that will probably require locking on the kernel side -- which
+ * however is probably not problematic, because we do it only on
+ * starvation or overload in which case we have to block anyway.  */
+
+typedef struct pa_asyncq pa_asyncq;
+
+pa_asyncq* pa_asyncq_new(size_t size);
+void pa_asyncq_free(pa_asyncq* q, pa_free_cb_t free_cb);
+
+void* pa_asyncq_pop(pa_asyncq *q, int wait);
+int pa_asyncq_push(pa_asyncq *q, void *p, int wait);
+
+int pa_asyncq_get_fd(pa_asyncq *q);
+int pa_asyncq_before_poll(pa_asyncq *a);
+int pa_asyncq_after_poll(pa_asyncq *a);
+
+#endif
diff --git a/src/pulsecore/atomic.h b/src/pulsecore/atomic.h
index 013e8c2..9a024f9 100644
--- a/src/pulsecore/atomic.h
+++ b/src/pulsecore/atomic.h
@@ -31,9 +31,9 @@
  * It is not guaranteed however, that sizeof(AO_t) == sizeof(size_t).
  * however very likely. */
 
-typedef struct pa_atomic_int {
+typedef struct pa_atomic {
     volatile AO_t value;
-} pa_atomic_int_t;
+} pa_atomic_t;
 
 #define PA_ATOMIC_INIT(v) { .value = (v) }
 
@@ -41,31 +41,31 @@ typedef struct pa_atomic_int {
  * to support more elaborate memory barriers, in which case we will add
  * suffixes to the function names */
 
-static inline int pa_atomic_load(const pa_atomic_int_t *a) {
+static inline int pa_atomic_load(const pa_atomic_t *a) {
     return (int) AO_load_full((AO_t*) &a->value);
 }
 
-static inline void pa_atomic_store(pa_atomic_int_t *a, int i) {
+static inline void pa_atomic_store(pa_atomic_t *a, int i) {
     AO_store_full(&a->value, (AO_t) i);
 }
 
-static inline int pa_atomic_add(pa_atomic_int_t *a, int i) {
+static inline int pa_atomic_add(pa_atomic_t *a, int i) {
     return AO_fetch_and_add_full(&a->value, (AO_t) i);
 }
 
-static inline int pa_atomic_sub(pa_atomic_int_t *a, int i) {
+static inline int pa_atomic_sub(pa_atomic_t *a, int i) {
     return AO_fetch_and_add_full(&a->value, (AO_t) -i);
 }
 
-static inline int pa_atomic_inc(pa_atomic_int_t *a) {
+static inline int pa_atomic_inc(pa_atomic_t *a) {
     return AO_fetch_and_add1_full(&a->value);
 }
 
-static inline int pa_atomic_dec(pa_atomic_int_t *a) {
+static inline int pa_atomic_dec(pa_atomic_t *a) {
     return AO_fetch_and_sub1_full(&a->value);
 }
 
-static inline int pa_atomic_cmpxchg(pa_atomic_int_t *a, int old_i, int new_i) {
+static inline int pa_atomic_cmpxchg(pa_atomic_t *a, int old_i, int new_i) {
     return AO_compare_and_swap_full(&a->value, old_i, new_i);
 }
 
@@ -73,6 +73,8 @@ typedef struct pa_atomic_ptr {
     volatile AO_t value;
 } pa_atomic_ptr_t;
 
+#define PA_ATOMIC_PTR_INIT(v) { .value = (AO_t) (v) }
+
 static inline void* pa_atomic_ptr_load(const pa_atomic_ptr_t *a) {
     return (void*) AO_load_full((AO_t*) &a->value);
 }
diff --git a/src/pulsecore/cli-command.c b/src/pulsecore/cli-command.c
index 6989069..36c85d6 100644
--- a/src/pulsecore/cli-command.c
+++ b/src/pulsecore/cli-command.c
@@ -95,6 +95,7 @@ static int pa_cli_command_sink_input_volume(pa_core *c, pa_tokenizer *t, pa_strb
 static int pa_cli_command_source_volume(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, int *fail);
 static int pa_cli_command_sink_mute(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, int *fail);
 static int pa_cli_command_source_mute(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, int *fail);
+static int pa_cli_command_sink_input_mute(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, int *fail);
 static int pa_cli_command_sink_default(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, int *fail);
 static int pa_cli_command_source_default(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, int *fail);
 static int pa_cli_command_kill_client(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, int *fail);
@@ -130,12 +131,13 @@ static const struct command commands[] = {
     { "info",                    pa_cli_command_info,               "Show comprehensive status",    1 },
     { "ls",                      pa_cli_command_info,               NULL,                           1 },
     { "list",                    pa_cli_command_info,               NULL,                           1 },
-    { "load-module",             pa_cli_command_load,               "Load a module (args: name, arguments)",                     3},
-    { "unload-module",           pa_cli_command_unload,             "Unload a module (args: index)",                             2},
-    { "set-sink-volume",         pa_cli_command_sink_volume,        "Set the volume of a sink (args: index|name, volume)",             3},
+    { "load-module",             pa_cli_command_load,               "Load a module (args: name, arguments)", 3},
+    { "unload-module",           pa_cli_command_unload,             "Unload a module (args: index)", 2},
+    { "set-sink-volume",         pa_cli_command_sink_volume,        "Set the volume of a sink (args: index|name, volume)", 3},
     { "set-sink-input-volume",   pa_cli_command_sink_input_volume,  "Set the volume of a sink input (args: index|name, volume)", 3},
     { "set-source-volume",       pa_cli_command_source_volume,      "Set the volume of a source (args: index|name, volume)", 3},
     { "set-sink-mute",           pa_cli_command_sink_mute,          "Set the mute switch of a sink (args: index|name, mute)", 3},
+    { "set-sink-input-mute",     pa_cli_command_sink_input_mute,    "Set the mute switch of a sink input (args: index|name, mute)", 3},
     { "set-source-mute",         pa_cli_command_source_mute,        "Set the mute switch of a source (args: index|name, mute)", 3},
     { "set-default-sink",        pa_cli_command_sink_default,       "Set the default sink (args: index|name)", 2},
     { "set-default-source",      pa_cli_command_source_default,     "Set the default source (args: index|name)", 2},
@@ -392,7 +394,7 @@ static int pa_cli_command_sink_volume(pa_core *c, pa_tokenizer *t, pa_strbuf *bu
     }
 
     pa_cvolume_set(&cvolume, sink->sample_spec.channels, volume);
-    pa_sink_set_volume(sink, PA_MIXER_HARDWARE, &cvolume);
+    pa_sink_set_volume(sink, &cvolume);
     return 0;
 }
 
@@ -460,7 +462,7 @@ static int pa_cli_command_source_volume(pa_core *c, pa_tokenizer *t, pa_strbuf *
     }
 
     pa_cvolume_set(&cvolume, source->sample_spec.channels, volume);
-    pa_source_set_volume(source, PA_MIXER_HARDWARE, &cvolume);
+    pa_source_set_volume(source, &cvolume);
     return 0;
 }
 
@@ -489,7 +491,7 @@ static int pa_cli_command_sink_mute(pa_core *c, pa_tokenizer *t, pa_strbuf *buf,
         return -1;
     }
 
-    pa_sink_set_mute(sink, PA_MIXER_HARDWARE, mute);
+    pa_sink_set_mute(sink, mute);
     return 0;
 }
 
@@ -518,7 +520,42 @@ static int pa_cli_command_source_mute(pa_core *c, pa_tokenizer *t, pa_strbuf *bu
         return -1;
     }
 
-    pa_source_set_mute(source, PA_MIXER_HARDWARE, mute);
+    pa_source_set_mute(source, mute);
+    return 0;
+}
+
+static int pa_cli_command_sink_input_mute(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, PA_GCC_UNUSED int *fail) {
+    const char *n, *v;
+    pa_sink_input *si;
+    uint32_t idx;
+    int mute;
+
+    if (!(n = pa_tokenizer_get(t, 1))) {
+        pa_strbuf_puts(buf, "You need to specify a sink input by its index.\n");
+        return -1;
+    }
+
+    if ((idx = parse_index(n)) == PA_IDXSET_INVALID) {
+        pa_strbuf_puts(buf, "Failed to parse index.\n");
+        return -1;
+    }
+
+    if (!(v = pa_tokenizer_get(t, 2))) {
+        pa_strbuf_puts(buf, "You need to specify a volume >= 0. (0 is muted, 0x100 is normal volume)\n");
+        return -1;
+    }
+
+    if (pa_atoi(v, &mute) < 0) {
+        pa_strbuf_puts(buf, "Failed to parse mute switch.\n");
+        return -1;
+    }
+
+    if (!(si = pa_idxset_get_by_index(c->sink_inputs, (uint32_t) idx))) {
+        pa_strbuf_puts(buf, "No sink input found with this index.\n");
+        return -1;
+    }
+
+    pa_sink_input_set_mute(si, mute);
     return 0;
 }
 
@@ -900,7 +937,7 @@ static int pa_cli_command_dump(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, PA_G
     nl = 0;
 
     for (sink = pa_idxset_first(c->sinks, &idx); sink; sink = pa_idxset_next(c->sinks, &idx)) {
-        if (sink->owner && sink->owner->auto_unload)
+        if (sink->module && sink->module->auto_unload)
             continue;
 
         if (!nl) {
@@ -908,12 +945,12 @@ static int pa_cli_command_dump(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, PA_G
             nl = 1;
         }
 
-        pa_strbuf_printf(buf, "set-sink-volume %s 0x%03x\n", sink->name, pa_cvolume_avg(pa_sink_get_volume(sink, PA_MIXER_HARDWARE)));
-        pa_strbuf_printf(buf, "set-sink-mute %s %d\n", sink->name, pa_sink_get_mute(sink, PA_MIXER_HARDWARE));
+        pa_strbuf_printf(buf, "set-sink-volume %s 0x%03x\n", sink->name, pa_cvolume_avg(pa_sink_get_volume(sink)));
+        pa_strbuf_printf(buf, "set-sink-mute %s %d\n", sink->name, pa_sink_get_mute(sink));
     }
 
     for (source = pa_idxset_first(c->sources, &idx); source; source = pa_idxset_next(c->sources, &idx)) {
-        if (source->owner && source->owner->auto_unload)
+        if (source->module && source->module->auto_unload)
             continue;
 
         if (!nl) {
@@ -921,8 +958,8 @@ static int pa_cli_command_dump(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, PA_G
             nl = 1;
         }
 
-        pa_strbuf_printf(buf, "set-source-volume %s 0x%03x\n", source->name, pa_cvolume_avg(pa_source_get_volume(source, PA_MIXER_HARDWARE)));
-        pa_strbuf_printf(buf, "set-source-mute %s %d\n", source->name, pa_source_get_mute(source, PA_MIXER_HARDWARE));
+        pa_strbuf_printf(buf, "set-source-volume %s 0x%03x\n", source->name, pa_cvolume_avg(pa_source_get_volume(source)));
+        pa_strbuf_printf(buf, "set-source-mute %s %d\n", source->name, pa_source_get_mute(source));
     }
 
 
diff --git a/src/pulsecore/cli-text.c b/src/pulsecore/cli-text.c
index 413f933..05d681e 100644
--- a/src/pulsecore/cli-text.c
+++ b/src/pulsecore/cli-text.c
@@ -93,6 +93,12 @@ char *pa_sink_list_to_string(pa_core *c) {
     pa_strbuf *s;
     pa_sink *sink;
     uint32_t idx = PA_IDXSET_INVALID;
+    static const char* const state_table[] = {
+        [PA_SINK_RUNNING] = "RUNNING",
+        [PA_SINK_SUSPENDED] = "SUSPENDED",
+        [PA_SINK_IDLE] = "IDLE",
+        [PA_SINK_DISCONNECTED] = "DISCONNECTED"
+    };
     assert(c);
 
     s = pa_strbuf_new();
@@ -108,22 +114,29 @@ char *pa_sink_list_to_string(pa_core *c) {
             "  %c index: %u\n"
             "\tname: <%s>\n"
             "\tdriver: <%s>\n"
+            "\tis_hardware: <%i>\n"
+            "\tstate: %s\n"
             "\tvolume: <%s>\n"
+            "\tmute: <%i>\n"
             "\tlatency: <%0.0f usec>\n"
             "\tmonitor_source: <%u>\n"
             "\tsample spec: <%s>\n"
             "\tchannel map: <%s>\n",
             c->default_sink_name && !strcmp(sink->name, c->default_sink_name) ? '*' : ' ',
-            sink->index, sink->name,
+            sink->index,
+            sink->name,
             sink->driver,
-            pa_cvolume_snprint(cv, sizeof(cv), pa_sink_get_volume(sink, PA_MIXER_HARDWARE)),
+            !!sink->is_hardware,
+            state_table[pa_sink_get_state(sink)],
+            pa_cvolume_snprint(cv, sizeof(cv), pa_sink_get_volume(sink)),
+            !!pa_sink_get_mute(sink),
             (double) pa_sink_get_latency(sink),
             sink->monitor_source ? sink->monitor_source->index : PA_INVALID_INDEX,
             pa_sample_spec_snprint(ss, sizeof(ss), &sink->sample_spec),
             pa_channel_map_snprint(cm, sizeof(cm), &sink->channel_map));
 
-        if (sink->owner)
-            pa_strbuf_printf(s, "\towner module: <%u>\n", sink->owner->index);
+        if (sink->module)
+            pa_strbuf_printf(s, "\tmodule: <%u>\n", sink->module->index);
         if (sink->description)
             pa_strbuf_printf(s, "\tdescription: <%s>\n", sink->description);
     }
@@ -135,6 +148,12 @@ char *pa_source_list_to_string(pa_core *c) {
     pa_strbuf *s;
     pa_source *source;
     uint32_t idx = PA_IDXSET_INVALID;
+    static const char* const state_table[] = {
+        [PA_SOURCE_RUNNING] = "RUNNING",
+        [PA_SOURCE_SUSPENDED] = "SUSPENDED",
+        [PA_SOURCE_IDLE] = "IDLE",
+        [PA_SOURCE_DISCONNECTED] = "DISCONNECTED"
+    };
     assert(c);
 
     s = pa_strbuf_new();
@@ -143,7 +162,7 @@ char *pa_source_list_to_string(pa_core *c) {
     pa_strbuf_printf(s, "%u source(s) available.\n", pa_idxset_size(c->sources));
 
     for (source = pa_idxset_first(c->sources, &idx); source; source = pa_idxset_next(c->sources, &idx)) {
-        char ss[PA_SAMPLE_SPEC_SNPRINT_MAX], cm[PA_CHANNEL_MAP_SNPRINT_MAX];
+        char ss[PA_SAMPLE_SPEC_SNPRINT_MAX], cm[PA_CHANNEL_MAP_SNPRINT_MAX], cv[PA_CVOLUME_SNPRINT_MAX];
 
 
         pa_strbuf_printf(
@@ -151,6 +170,10 @@ char *pa_source_list_to_string(pa_core *c) {
             "  %c index: %u\n"
             "\tname: <%s>\n"
             "\tdriver: <%s>\n"
+            "\tis_hardware: <%i>\n"
+            "\tstate: %s\n"
+            "\tvolume: <%s>\n"
+            "\tmute: <%u>\n"
             "\tlatency: <%0.0f usec>\n"
             "\tsample spec: <%s>\n"
             "\tchannel map: <%s>\n",
@@ -158,14 +181,18 @@ char *pa_source_list_to_string(pa_core *c) {
             source->index,
             source->name,
             source->driver,
+            !!source->is_hardware,
+            state_table[pa_source_get_state(source)],
+            pa_cvolume_snprint(cv, sizeof(cv), pa_source_get_volume(source)),
+            !!pa_source_get_mute(source),
             (double) pa_source_get_latency(source),
             pa_sample_spec_snprint(ss, sizeof(ss), &source->sample_spec),
             pa_channel_map_snprint(cm, sizeof(cm), &source->channel_map));
 
         if (source->monitor_of)
             pa_strbuf_printf(s, "\tmonitor_of: <%u>\n", source->monitor_of->index);
-        if (source->owner)
-            pa_strbuf_printf(s, "\towner module: <%u>\n", source->owner->index);
+        if (source->module)
+            pa_strbuf_printf(s, "\tmodule: <%u>\n", source->module->index);
         if (source->description)
             pa_strbuf_printf(s, "\tdescription: <%s>\n", source->description);
     }
@@ -179,9 +206,9 @@ char *pa_source_output_list_to_string(pa_core *c) {
     pa_source_output *o;
     uint32_t idx = PA_IDXSET_INVALID;
     static const char* const state_table[] = {
-        "RUNNING",
-        "CORKED",
-        "DISCONNECTED"
+        [PA_SOURCE_OUTPUT_RUNNING] = "RUNNING",
+        [PA_SOURCE_OUTPUT_CORKED] = "CORKED",
+        [PA_SOURCE_OUTPUT_DISCONNECTED] = "DISCONNECTED"
     };
     assert(c);
 
@@ -202,14 +229,16 @@ char *pa_source_output_list_to_string(pa_core *c) {
             "\tdriver: <%s>\n"
             "\tstate: %s\n"
             "\tsource: <%u> '%s'\n"
+            "\tlatency: <%0.0f usec>\n"
             "\tsample spec: <%s>\n"
             "\tchannel map: <%s>\n"
             "\tresample method: %s\n",
             o->index,
             o->name,
             o->driver,
-            state_table[o->state],
+            state_table[pa_source_output_get_state(o)],
             o->source->index, o->source->name,
+            (double) pa_source_output_get_latency(o),
             pa_sample_spec_snprint(ss, sizeof(ss), &o->sample_spec),
             pa_channel_map_snprint(cm, sizeof(cm), &o->channel_map),
             pa_resample_method_to_string(pa_source_output_get_resample_method(o)));
@@ -227,9 +256,10 @@ char *pa_sink_input_list_to_string(pa_core *c) {
     pa_sink_input *i;
     uint32_t idx = PA_IDXSET_INVALID;
     static const char* const state_table[] = {
-        "RUNNING",
-        "CORKED",
-        "DISCONNECTED"
+        [PA_SINK_INPUT_RUNNING] = "RUNNING",
+        [PA_SINK_INPUT_DRAINED] = "DRAINED",
+        [PA_SINK_INPUT_CORKED] = "CORKED",
+        [PA_SINK_INPUT_DISCONNECTED] = "DISCONNECTED"
     };
 
     assert(c);
@@ -251,6 +281,7 @@ char *pa_sink_input_list_to_string(pa_core *c) {
             "\tstate: %s\n"
             "\tsink: <%u> '%s'\n"
             "\tvolume: <%s>\n"
+            "\tmute: <%i>\n"
             "\tlatency: <%0.0f usec>\n"
             "\tsample spec: <%s>\n"
             "\tchannel map: <%s>\n"
@@ -258,16 +289,17 @@ char *pa_sink_input_list_to_string(pa_core *c) {
             i->index,
             i->name,
             i->driver,
-            state_table[i->state],
+            state_table[pa_sink_input_get_state(i)],
             i->sink->index, i->sink->name,
             pa_cvolume_snprint(cv, sizeof(cv), pa_sink_input_get_volume(i)),
+            !!pa_sink_input_get_mute(i),
             (double) pa_sink_input_get_latency(i),
             pa_sample_spec_snprint(ss, sizeof(ss), &i->sample_spec),
             pa_channel_map_snprint(cm, sizeof(cm), &i->channel_map),
             pa_resample_method_to_string(pa_sink_input_get_resample_method(i)));
 
         if (i->module)
-            pa_strbuf_printf(s, "\towner module: <%u>\n", i->module->index);
+            pa_strbuf_printf(s, "\tmodule: <%u>\n", i->module->index);
         if (i->client)
             pa_strbuf_printf(s, "\tclient: <%u> '%s'\n", i->client->index, i->client->name);
     }
diff --git a/src/pulsecore/core-def.h b/src/pulsecore/core-def.h
index 10a3be4..4bc0513 100644
--- a/src/pulsecore/core-def.h
+++ b/src/pulsecore/core-def.h
@@ -24,9 +24,6 @@
   USA.
 ***/
 
-typedef enum pa_mixer {
-    PA_MIXER_SOFTWARE,
-    PA_MIXER_HARDWARE
-} pa_mixer_t;
+/* FIXME: Remove this shit */
 
 #endif
diff --git a/src/pulsecore/core.c b/src/pulsecore/core.c
index 31b6c18..c80caf1 100644
--- a/src/pulsecore/core.c
+++ b/src/pulsecore/core.c
@@ -45,13 +45,59 @@
 #include <pulsecore/props.h>
 #include <pulsecore/random.h>
 #include <pulsecore/log.h>
+#include <pulsecore/macro.h>
 
 #include "core.h"
 
+static int core_process_msg(pa_msgobject *o, int code, void *userdata, pa_memchunk *chunk) {
+    pa_core *c = PA_CORE(o);
+
+    pa_core_assert_ref(c);
+    
+    switch (code) {
+        
+        case PA_CORE_MESSAGE_UNLOAD_MODULE:
+            pa_module_unload(c, userdata);
+            return 0;
+
+        default:
+            return -1;
+    }
+}
+
+static void asyncmsgq_cb(pa_mainloop_api*api, pa_io_event* e, int fd, pa_io_event_flags_t events, void *userdata) {
+    pa_core *c = userdata;
+    
+    pa_assert(pa_asyncmsgq_get_fd(c->asyncmsgq) == fd);
+    pa_assert(events == PA_IO_EVENT_INPUT);
+
+    pa_asyncmsgq_after_poll(c->asyncmsgq);
+
+    for (;;) {
+        pa_msgobject *object;
+        int code;
+        void *data;
+        pa_memchunk chunk;
+
+        /* Check whether there is a message for us to process */
+        while (pa_asyncmsgq_get(c->asyncmsgq, &object, &code, &data, &chunk, 0) == 0) {
+            pa_asyncmsgq_dispatch(object, code, data, &chunk);
+            pa_asyncmsgq_done(c->asyncmsgq, 0);
+        }
+        
+        if (pa_asyncmsgq_before_poll(c->asyncmsgq) == 0)
+            break;
+    }
+}
+
+static void core_free(pa_object *o);
+
 pa_core* pa_core_new(pa_mainloop_api *m, int shared) {
     pa_core* c;
     pa_mempool *pool;
 
+    pa_assert(m);
+    
     if (shared) {
         if (!(pool = pa_mempool_new(shared))) {
             pa_log_warn("failed to allocate shared memory pool. Falling back to a normal memory pool.");
@@ -66,7 +112,9 @@ pa_core* pa_core_new(pa_mainloop_api *m, int shared) {
         }
     }
 
-    c = pa_xnew(pa_core, 1);
+    c = pa_msgobject_new(pa_core);
+    c->parent.parent.free = core_free;
+    c->parent.process_msg = core_process_msg;
 
     c->mainloop = m;
     c->clients = pa_idxset_new(NULL, NULL);
@@ -123,11 +171,17 @@ pa_core* pa_core_new(pa_mainloop_api *m, int shared) {
 #ifdef SIGPIPE
     pa_check_signal_is_blocked(SIGPIPE);
 #endif
+
+    pa_assert_se(c->asyncmsgq = pa_asyncmsgq_new(0));
+    pa_assert_se(pa_asyncmsgq_before_poll(c->asyncmsgq) == 0);
+    pa_assert_se(c->asyncmsgq_event = c->mainloop->io_new(c->mainloop, pa_asyncmsgq_get_fd(c->asyncmsgq), PA_IO_EVENT_INPUT, asyncmsgq_cb, c));
+            
     return c;
 }
 
-void pa_core_free(pa_core *c) {
-    assert(c);
+static void core_free(pa_object *o) {
+    pa_core *c = PA_CORE(o);
+    pa_core_assert_ref(c);
 
     pa_module_unload_all(c);
     assert(!c->modules);
@@ -162,6 +216,10 @@ void pa_core_free(pa_core *c) {
 
     pa_property_cleanup(c);
 
+    c->mainloop->io_free(c->asyncmsgq_event);
+    pa_asyncmsgq_after_poll(c->asyncmsgq);
+    pa_asyncmsgq_free(c->asyncmsgq);
+
     pa_hook_free(&c->hook_sink_input_new);
     pa_hook_free(&c->hook_sink_disconnect);
     pa_hook_free(&c->hook_source_output_new);
diff --git a/src/pulsecore/core.h b/src/pulsecore/core.h
index 51a18b6..dc2ebb4 100644
--- a/src/pulsecore/core.h
+++ b/src/pulsecore/core.h
@@ -34,17 +34,21 @@
 #include <pulsecore/queue.h>
 #include <pulsecore/llist.h>
 #include <pulsecore/hook-list.h>
+#include <pulsecore/asyncmsgq.h>
 
 typedef struct pa_core pa_core;
 
 #include <pulsecore/core-subscribe.h>
 #include <pulsecore/sink-input.h>
+#include <pulsecore/msgobject.h>
 
 /* The core structure of PulseAudio. Every PulseAudio daemon contains
  * exactly one of these. It is used for storing kind of global
  * variables for the daemon. */
 
 struct pa_core {
+    pa_msgobject parent;
+    
     /* A random value which may be used to identify this instance of
      * PulseAudio. Not cryptographically secure in any way. */
     uint32_t cookie;
@@ -88,10 +92,20 @@ struct pa_core {
         hook_sink_disconnect,
         hook_source_output_new,
         hook_source_disconnect;
+
+    pa_asyncmsgq *asyncmsgq;
+    pa_io_event *asyncmsgq_event;
+};
+
+PA_DECLARE_CLASS(pa_core);
+#define PA_CORE(o) ((pa_core*) o)
+
+enum {
+    PA_CORE_MESSAGE_UNLOAD_MODULE,
+    PA_CORE_MESSAGE_MAX
 };
 
 pa_core* pa_core_new(pa_mainloop_api *m, int shared);
-void pa_core_free(pa_core*c);
 
 /* Check whether noone is connected to this core */
 void pa_core_check_quit(pa_core *c);
diff --git a/src/pulsecore/flist.c b/src/pulsecore/flist.c
index 00567ab..3805e1d 100644
--- a/src/pulsecore/flist.c
+++ b/src/pulsecore/flist.c
@@ -30,6 +30,7 @@
 #include <pulsecore/atomic.h>
 #include <pulsecore/log.h>
 #include <pulsecore/thread.h>
+#include <pulsecore/macro.h>
 #include <pulse/xmalloc.h>
 
 #include "flist.h"
@@ -90,18 +91,19 @@ enum {
 };
 
 struct cell {
-    pa_atomic_int_t state;
+    pa_atomic_t state;
     void *data;
 };
 
 struct pa_flist {
-    struct cell *cells;
     unsigned size;
-    pa_atomic_int_t length;
-    pa_atomic_int_t read_idx;
-    pa_atomic_int_t write_idx;
+    pa_atomic_t length;
+    pa_atomic_t read_idx;
+    pa_atomic_t write_idx;
 };
 
+#define PA_FLIST_CELLS(x) ((struct cell*) ((uint8_t*) (x) + PA_ALIGN(sizeof(struct pa_flist))))
+
 static int is_power_of_two(unsigned size) {
     return !(size & (size - 1));
 }
@@ -114,10 +116,9 @@ pa_flist *pa_flist_new(unsigned size) {
 
     assert(is_power_of_two(size));
 
-    l = pa_xnew(pa_flist, 1);
+    l = pa_xmalloc0(PA_ALIGN(sizeof(pa_flist)) + (sizeof(struct cell) * size));
 
     l->size = size;
-    l->cells = pa_xnew0(struct cell, size);
 
     pa_atomic_store(&l->read_idx, 0);
     pa_atomic_store(&l->write_idx, 0);
@@ -134,30 +135,35 @@ void pa_flist_free(pa_flist *l, pa_free_cb_t free_cb) {
     assert(l);
 
     if (free_cb) {
+        struct cell *cells;
         int len, idx;
 
+        cells = PA_FLIST_CELLS(l);
+
         idx = reduce(l, pa_atomic_load(&l->read_idx));
         len = pa_atomic_load(&l->length);
 
         for (; len > 0; len--) {
 
-            if (pa_atomic_load(&l->cells[idx].state) == STATE_USED)
-                free_cb(l->cells[idx].data);
+            if (pa_atomic_load(&cells[idx].state) == STATE_USED)
+                free_cb(cells[idx].data);
 
             idx = reduce(l, idx + 1);
         }
     }
 
-    pa_xfree(l->cells);
     pa_xfree(l);
 }
 
 int pa_flist_push(pa_flist*l, void *p) {
     int idx, len, n;
+    struct cell *cells;
 
     assert(l);
     assert(p);
 
+    cells = PA_FLIST_CELLS(l);
+    
     n = len = (int) l->size - pa_atomic_load(&l->length) + N_EXTRA_SCAN;
     _Y;
     idx = reduce(l, pa_atomic_load(&l->write_idx));
@@ -165,13 +171,13 @@ int pa_flist_push(pa_flist*l, void *p) {
     for (; n > 0 ; n--) {
         _Y;
 
-        if (pa_atomic_cmpxchg(&l->cells[idx].state, STATE_UNUSED, STATE_BUSY)) {
+        if (pa_atomic_cmpxchg(&cells[idx].state, STATE_UNUSED, STATE_BUSY)) {
             _Y;
             pa_atomic_inc(&l->write_idx);
             _Y;
-            l->cells[idx].data = p;
+            cells[idx].data = p;
             _Y;
-            pa_atomic_store(&l->cells[idx].state, STATE_USED);
+            pa_atomic_store(&cells[idx].state, STATE_USED);
             _Y;
             pa_atomic_inc(&l->length);
             return 0;
@@ -191,9 +197,12 @@ int pa_flist_push(pa_flist*l, void *p) {
 
 void* pa_flist_pop(pa_flist*l) {
     int idx, len, n;
+    struct cell *cells;
 
     assert(l);
 
+    cells = PA_FLIST_CELLS(l);
+
     n = len = pa_atomic_load(&l->length) + N_EXTRA_SCAN;
     _Y;
     idx = reduce(l, pa_atomic_load(&l->read_idx));
@@ -201,14 +210,14 @@ void* pa_flist_pop(pa_flist*l) {
     for (; n > 0 ; n--) {
         _Y;
 
-        if (pa_atomic_cmpxchg(&l->cells[idx].state, STATE_USED, STATE_BUSY)) {
+        if (pa_atomic_cmpxchg(&cells[idx].state, STATE_USED, STATE_BUSY)) {
             void *p;
             _Y;
             pa_atomic_inc(&l->read_idx);
             _Y;
-            p = l->cells[idx].data;
+            p = cells[idx].data;
             _Y;
-            pa_atomic_store(&l->cells[idx].state, STATE_UNUSED);
+            pa_atomic_store(&cells[idx].state, STATE_UNUSED);
             _Y;
 
             pa_atomic_dec(&l->length);
diff --git a/src/pulsecore/flist.h b/src/pulsecore/flist.h
index bf702bf..80fd86c 100644
--- a/src/pulsecore/flist.h
+++ b/src/pulsecore/flist.h
@@ -26,6 +26,8 @@
 
 #include <pulse/def.h>
 
+#include <pulsecore/once.h>
+
 /* A multiple-reader multipler-write lock-free free list implementation */
 
 typedef struct pa_flist pa_flist;
@@ -38,4 +40,22 @@ void pa_flist_free(pa_flist *l, pa_free_cb_t free_cb);
 int pa_flist_push(pa_flist*l, void *p);
 void* pa_flist_pop(pa_flist*l);
 
+#define PA_STATIC_FLIST_DECLARE(name, size)                     \
+    struct {                                                    \
+        pa_flist *flist;                                        \
+        pa_once_t once;                                         \
+    } name##_static_flist = { NULL, PA_ONCE_INIT };             \
+                                                                \
+    static void name##_init(void) {                             \
+        name##_static_flist.flist = pa_flist_new(size);         \
+    }                                                           \
+                                                                \
+    static inline pa_flist* name##_get(void) {                  \
+        pa_once(&name##_static_flist.once, name##_init);        \
+        return name##_static_flist.flist;                       \
+    } \
+    struct __stupid_useless_struct_to_allow_trailing_semicolon
+
+#define PA_STATIC_FLIST_GET(name) (name##_get())
+
 #endif
diff --git a/src/pulsecore/hashmap.h b/src/pulsecore/hashmap.h
index 3ca2a47..98df450 100644
--- a/src/pulsecore/hashmap.h
+++ b/src/pulsecore/hashmap.h
@@ -32,11 +32,13 @@
 
 typedef struct pa_hashmap pa_hashmap;
 
+typedef void (*pa_free2_cb_t)(void *p, void *userdata);
+
 /* Create a new hashmap. Use the specified functions for hashing and comparing objects in the map */
 pa_hashmap *pa_hashmap_new(pa_hash_func_t hash_func, pa_compare_func_t compare_func);
 
 /* Free the hash table. Calls the specified function for every value in the table. The function may be NULL */
-void pa_hashmap_free(pa_hashmap*, void (*free_func)(void *p, void *userdata), void *userdata);
+void pa_hashmap_free(pa_hashmap*, pa_free2_cb_t free_cb, void *userdata);
 
 /* Returns non-zero when the entry already exists */
 int pa_hashmap_put(pa_hashmap *h, const void *key, void *value);
diff --git a/src/pulsecore/idxset.c b/src/pulsecore/idxset.c
index 70ef7ba..e683ead 100644
--- a/src/pulsecore/idxset.c
+++ b/src/pulsecore/idxset.c
@@ -32,6 +32,7 @@
 #include <string.h>
 
 #include <pulse/xmalloc.h>
+#include <pulsecore/macro.h>
 
 #include "idxset.h"
 
diff --git a/src/pulsecore/idxset.h b/src/pulsecore/idxset.h
index 17a70f4..5b55cec 100644
--- a/src/pulsecore/idxset.h
+++ b/src/pulsecore/idxset.h
@@ -44,11 +44,6 @@ int pa_idxset_trivial_compare_func(const void *a, const void *b);
 unsigned pa_idxset_string_hash_func(const void *p);
 int pa_idxset_string_compare_func(const void *a, const void *b);
 
-#define PA_PTR_TO_UINT(p) ((unsigned int) (unsigned long) (p))
-#define PA_UINT_TO_PTR(u) ((void*) (unsigned long) (u))
-#define PA_PTR_TO_UINT32(p) ((uint32_t) PA_PTR_TO_UINT(p))
-#define PA_UINT32_TO_PTR(u) PA_UINT_TO_PTR(u)
-
 typedef unsigned (*pa_hash_func_t)(const void *p);
 typedef int (*pa_compare_func_t)(const void *a, const void *b);
 
diff --git a/src/pulsecore/macro.h b/src/pulsecore/macro.h
new file mode 100644
index 0000000..215c5c0
--- /dev/null
+++ b/src/pulsecore/macro.h
@@ -0,0 +1,80 @@
+#ifndef foopulsemacrohfoo
+#define foopulsemacrohfoo
+
+/* $Id$ */
+
+/***
+  This file is part of PulseAudio.
+
+  Copyright 2004-2006 Lennart Poettering
+
+  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 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.
+***/
+
+#include <sys/types.h>
+#include <pulsecore/log.h>
+
+static inline size_t pa_align(size_t l) {
+    return (((l + sizeof(void*) - 1) / sizeof(void*)) * sizeof(void*));
+}
+
+#define PA_ALIGN(x) (pa_align(x))
+
+#define PA_ELEMENTSOF(x) (sizeof(x)/sizeof((x)[0]))
+
+#define SA_MAX(a, b) ((a) > (b) ? (a) : (b))
+#define SA_MIN(a, b) ((a) < (b) ? (a) : (b))
+
+#ifdef __GNUC__
+#define PA_PRETTY_FUNCTION __PRETTY_FUNCTION__
+#else
+#define PA_PRETTY_FUNCTION ""
+#endif
+
+#define pa_return_if_fail(expr) \
+    do { \
+        if (!(expr)) { \
+            pa_log_debug("%s: Assertion <%s> failed.\n", PA_PRETTY_FUNCTION, #expr ); \
+            return; \
+        } \
+    } while(0)
+
+#define pa_return_val_if_fail(expr, val) \
+    do { \
+        if (!(expr)) { \
+            pa_log_debug("%s: Assertion <%s> failed.\n", PA_PRETTY_FUNCTION, #expr ); \
+            return (val); \
+        } \
+    } while(0)
+
+#define pa_return_null_if_fail(expr) pa_return_val_if_fail(expr, NULL)
+
+#define pa_assert assert
+
+#define pa_assert_not_reached() pa_assert(!"Should not be reached.")
+
+/* An assert which guarantees side effects of x */
+#define pa_assert_se(x) do {                  \
+        int _r = !!(x);                       \
+        pa_assert(_r);                        \
+    } while(0)
+
+#define PA_PTR_TO_UINT(p) ((unsigned int) (unsigned long) (p))
+#define PA_UINT_TO_PTR(u) ((void*) (unsigned long) (u))
+#define PA_PTR_TO_UINT32(p) ((uint32_t) PA_PTR_TO_UINT(p))
+#define PA_UINT32_TO_PTR(u) PA_UINT_TO_PTR(u)
+
+#endif
diff --git a/src/pulsecore/mcalign.c b/src/pulsecore/mcalign.c
index dd1d71f..9761643 100644
--- a/src/pulsecore/mcalign.c
+++ b/src/pulsecore/mcalign.c
@@ -91,6 +91,7 @@ void pa_mcalign_push(pa_mcalign *m, const pa_memchunk *c) {
 
         } else {
             size_t l;
+            void *lo_data, *m_data;
 
             /* We have to copy */
             assert(m->leftover.length < m->base);
@@ -102,10 +103,15 @@ void pa_mcalign_push(pa_mcalign *m, const pa_memchunk *c) {
             /* Can we use the current block? */
             pa_memchunk_make_writable(&m->leftover, m->base);
 
-            memcpy((uint8_t*) m->leftover.memblock->data + m->leftover.index + m->leftover.length, (uint8_t*) c->memblock->data + c->index, l);
+            lo_data = pa_memblock_acquire(m->leftover.memblock);
+            m_data = pa_memblock_acquire(c->memblock);
+            memcpy((uint8_t*) lo_data + m->leftover.index + m->leftover.length, (uint8_t*) m_data + c->index, l);
+            pa_memblock_release(m->leftover.memblock);
+            pa_memblock_release(c->memblock);
             m->leftover.length += l;
 
-            assert(m->leftover.length <= m->base && m->leftover.length <= m->leftover.memblock->length);
+            assert(m->leftover.length <= m->base);
+            assert(m->leftover.length <= pa_memblock_get_length(m->leftover.memblock));
 
             if (c->length > l) {
                 /* Save the remainder of the memory block */
diff --git a/src/pulsecore/memblock.c b/src/pulsecore/memblock.c
index 6f09a90..71b576a 100644
--- a/src/pulsecore/memblock.c
+++ b/src/pulsecore/memblock.c
@@ -33,10 +33,14 @@
 #include <unistd.h>
 
 #include <pulse/xmalloc.h>
+#include <pulse/def.h>
 
 #include <pulsecore/shm.h>
 #include <pulsecore/log.h>
 #include <pulsecore/hashmap.h>
+#include <pulsecore/semaphore.h>
+#include <pulsecore/macro.h>
+#include <pulsecore/flist.h>
 
 #include "memblock.h"
 
@@ -48,6 +52,32 @@
 #define PA_MEMIMPORT_SLOTS_MAX 128
 #define PA_MEMIMPORT_SEGMENTS_MAX 16
 
+struct pa_memblock {
+    PA_REFCNT_DECLARE; /* the reference counter */
+    pa_mempool *pool;
+
+    pa_memblock_type_t type;
+    int read_only; /* boolean */
+
+    pa_atomic_ptr_t data;
+    size_t length;
+
+    pa_atomic_t n_acquired;
+    pa_atomic_t please_signal;
+
+    union {
+        struct {
+            /* If type == PA_MEMBLOCK_USER this points to a function for freeing this memory block */
+            pa_free_cb_t free_cb;
+        } user;
+
+        struct  {
+            uint32_t id;
+            pa_memimport_segment *segment;
+        } imported;
+    } per_type;
+};
+
 struct pa_memimport_segment {
     pa_memimport *import;
     pa_shm memory;
@@ -55,6 +85,8 @@ struct pa_memimport_segment {
 };
 
 struct pa_memimport {
+    pa_mutex *mutex;
+
     pa_mempool *pool;
     pa_hashmap *segments;
     pa_hashmap *blocks;
@@ -73,9 +105,11 @@ struct memexport_slot {
 };
 
 struct pa_memexport {
+    pa_mutex *mutex;
     pa_mempool *pool;
 
     struct memexport_slot slots[PA_MEMEXPORT_SLOTS_MAX];
+
     PA_LLIST_HEAD(struct memexport_slot, free_slots);
     PA_LLIST_HEAD(struct memexport_slot, used_slots);
     unsigned n_init;
@@ -95,21 +129,27 @@ struct mempool_slot {
 };
 
 struct pa_mempool {
+    pa_semaphore *semaphore;
+    pa_mutex *mutex;
+
     pa_shm memory;
     size_t block_size;
-    unsigned n_blocks, n_init;
+    unsigned n_blocks;
+
+    pa_atomic_t n_init;
 
     PA_LLIST_HEAD(pa_memimport, imports);
     PA_LLIST_HEAD(pa_memexport, exports);
 
     /* A list of free slots that may be reused */
-    PA_LLIST_HEAD(struct mempool_slot, free_slots);
+    pa_flist *free_slots;
 
     pa_mempool_stat stat;
 };
 
 static void segment_detach(pa_memimport_segment *seg);
 
+/* No lock necessary */
 static void stat_add(pa_memblock*b) {
     assert(b);
     assert(b->pool);
@@ -129,6 +169,7 @@ static void stat_add(pa_memblock*b) {
     pa_atomic_inc(&b->pool->stat.n_accumulated_by_type[b->type]);
 }
 
+/* No lock necessary */
 static void stat_remove(pa_memblock *b) {
     assert(b);
     assert(b->pool);
@@ -152,6 +193,7 @@ static void stat_remove(pa_memblock *b) {
 
 static pa_memblock *memblock_new_appended(pa_mempool *p, size_t length);
 
+/* No lock necessary */
 pa_memblock *pa_memblock_new(pa_mempool *p, size_t length) {
     pa_memblock *b;
 
@@ -164,56 +206,70 @@ pa_memblock *pa_memblock_new(pa_mempool *p, size_t length) {
     return b;
 }
 
+/* No lock necessary */
 static pa_memblock *memblock_new_appended(pa_mempool *p, size_t length) {
     pa_memblock *b;
 
     assert(p);
     assert(length > 0);
 
-    b = pa_xmalloc(sizeof(pa_memblock) + length);
+    b = pa_xmalloc(PA_ALIGN(sizeof(pa_memblock)) + length);
+    PA_REFCNT_INIT(b);
+    b->pool = p;
     b->type = PA_MEMBLOCK_APPENDED;
     b->read_only = 0;
-    PA_REFCNT_INIT(b);
+    pa_atomic_ptr_store(&b->data, (uint8_t*) b + PA_ALIGN(sizeof(pa_memblock)));
     b->length = length;
-    b->data = (uint8_t*) b + sizeof(pa_memblock);
-    b->pool = p;
+    pa_atomic_store(&b->n_acquired, 0);
+    pa_atomic_store(&b->please_signal, 0);
 
     stat_add(b);
     return b;
 }
 
+/* No lock necessary */
 static struct mempool_slot* mempool_allocate_slot(pa_mempool *p) {
     struct mempool_slot *slot;
     assert(p);
 
-    if (p->free_slots) {
-        slot = p->free_slots;
-        PA_LLIST_REMOVE(struct mempool_slot, p->free_slots, slot);
-    } else if (p->n_init < p->n_blocks)
-        slot = (struct mempool_slot*) ((uint8_t*) p->memory.ptr + (p->block_size * p->n_init++));
-    else {
-        pa_log_debug("Pool full");
-        pa_atomic_inc(&p->stat.n_pool_full);
-        return NULL;
+    if (!(slot = pa_flist_pop(p->free_slots))) {
+        int idx;
+
+        /* The free list was empty, we have to allocate a new entry */
+
+        if ((unsigned) (idx = pa_atomic_inc(&p->n_init)) >= p->n_blocks)
+            pa_atomic_dec(&p->n_init);
+        else
+            slot = (struct mempool_slot*) ((uint8_t*) p->memory.ptr + (p->block_size * idx));
+
+        if (!slot) {
+            pa_log_debug("Pool full");
+            pa_atomic_inc(&p->stat.n_pool_full);
+            return NULL;
+        }
     }
 
     return slot;
 }
 
+/* No lock necessary */
 static void* mempool_slot_data(struct mempool_slot *slot) {
     assert(slot);
 
     return (uint8_t*) slot + sizeof(struct mempool_slot);
 }
 
+/* No lock necessary */
 static unsigned mempool_slot_idx(pa_mempool *p, void *ptr) {
     assert(p);
+
     assert((uint8_t*) ptr >= (uint8_t*) p->memory.ptr);
     assert((uint8_t*) ptr < (uint8_t*) p->memory.ptr + p->memory.size);
 
     return ((uint8_t*) ptr - (uint8_t*) p->memory.ptr) / p->block_size;
 }
 
+/* No lock necessary */
 static struct mempool_slot* mempool_slot_by_ptr(pa_mempool *p, void *ptr) {
     unsigned idx;
 
@@ -223,6 +279,7 @@ static struct mempool_slot* mempool_slot_by_ptr(pa_mempool *p, void *ptr) {
     return (struct mempool_slot*) ((uint8_t*) p->memory.ptr + (idx * p->block_size));
 }
 
+/* No lock necessary */
 pa_memblock *pa_memblock_new_pool(pa_mempool *p, size_t length) {
     pa_memblock *b = NULL;
     struct mempool_slot *slot;
@@ -237,7 +294,7 @@ pa_memblock *pa_memblock_new_pool(pa_mempool *p, size_t length) {
 
         b = mempool_slot_data(slot);
         b->type = PA_MEMBLOCK_POOL;
-        b->data = (uint8_t*) b + sizeof(pa_memblock);
+        pa_atomic_ptr_store(&b->data, (uint8_t*) b + sizeof(pa_memblock));
 
     } else if (p->block_size - sizeof(struct mempool_slot) >= length) {
 
@@ -246,22 +303,26 @@ pa_memblock *pa_memblock_new_pool(pa_mempool *p, size_t length) {
 
         b = pa_xnew(pa_memblock, 1);
         b->type = PA_MEMBLOCK_POOL_EXTERNAL;
-        b->data = mempool_slot_data(slot);
+        pa_atomic_ptr_store(&b->data, mempool_slot_data(slot));
+
     } else {
         pa_log_debug("Memory block too large for pool: %u > %u", length, p->block_size - sizeof(struct mempool_slot));
         pa_atomic_inc(&p->stat.n_too_large_for_pool);
         return NULL;
     }
 
-    b->length = length;
-    b->read_only = 0;
     PA_REFCNT_INIT(b);
     b->pool = p;
+    b->read_only = 0;
+    b->length = length;
+    pa_atomic_store(&b->n_acquired, 0);
+    pa_atomic_store(&b->please_signal, 0);
 
     stat_add(b);
     return b;
 }
 
+/* No lock necessary */
 pa_memblock *pa_memblock_new_fixed(pa_mempool *p, void *d, size_t length, int read_only) {
     pa_memblock *b;
 
@@ -270,17 +331,20 @@ pa_memblock *pa_memblock_new_fixed(pa_mempool *p, void *d, size_t length, int re
     assert(length > 0);
 
     b = pa_xnew(pa_memblock, 1);
+    PA_REFCNT_INIT(b);
+    b->pool = p;
     b->type = PA_MEMBLOCK_FIXED;
     b->read_only = read_only;
-    PA_REFCNT_INIT(b);
+    pa_atomic_ptr_store(&b->data, d);
     b->length = length;
-    b->data = d;
-    b->pool = p;
+    pa_atomic_store(&b->n_acquired, 0);
+    pa_atomic_store(&b->please_signal, 0);
 
     stat_add(b);
     return b;
 }
 
+/* No lock necessary */
 pa_memblock *pa_memblock_new_user(pa_mempool *p, void *d, size_t length, void (*free_cb)(void *p), int read_only) {
     pa_memblock *b;
 
@@ -290,18 +354,68 @@ pa_memblock *pa_memblock_new_user(pa_mempool *p, void *d, size_t length, void (*
     assert(free_cb);
 
     b = pa_xnew(pa_memblock, 1);
+    PA_REFCNT_INIT(b);
+    b->pool = p;
     b->type = PA_MEMBLOCK_USER;
     b->read_only = read_only;
-    PA_REFCNT_INIT(b);
+    pa_atomic_ptr_store(&b->data, d);
     b->length = length;
-    b->data = d;
+    pa_atomic_store(&b->n_acquired, 0);
+    pa_atomic_store(&b->please_signal, 0);
+
     b->per_type.user.free_cb = free_cb;
-    b->pool = p;
 
     stat_add(b);
     return b;
 }
 
+/* No lock necessary */
+int pa_memblock_is_read_only(pa_memblock *b) {
+    assert(b);
+    assert(PA_REFCNT_VALUE(b) > 0);
+
+    return b->read_only && PA_REFCNT_VALUE(b) == 1;
+}
+
+/* No lock necessary */
+void* pa_memblock_acquire(pa_memblock *b) {
+    assert(b);
+    assert(PA_REFCNT_VALUE(b) > 0);
+
+    pa_atomic_inc(&b->n_acquired);
+
+    return pa_atomic_ptr_load(&b->data);
+}
+
+/* No lock necessary, in corner cases locks by its own */
+void pa_memblock_release(pa_memblock *b) {
+    int r;
+    assert(b);
+    assert(PA_REFCNT_VALUE(b) > 0);
+
+    r = pa_atomic_dec(&b->n_acquired);
+    assert(r >= 1);
+
+    /* Signal a waiting thread that this memblock is no longer used */
+    if (r == 1 && pa_atomic_load(&b->please_signal))
+        pa_semaphore_post(b->pool->semaphore);
+}
+
+size_t pa_memblock_get_length(pa_memblock *b) {
+    assert(b);
+    assert(PA_REFCNT_VALUE(b) > 0);
+
+    return b->length;
+}
+
+pa_mempool* pa_memblock_get_pool(pa_memblock *b) {
+    assert(b);
+    assert(PA_REFCNT_VALUE(b) > 0);
+
+    return b->pool;
+}
+
+/* No lock necessary */
 pa_memblock* pa_memblock_ref(pa_memblock*b) {
     assert(b);
     assert(PA_REFCNT_VALUE(b) > 0);
@@ -310,19 +424,17 @@ pa_memblock* pa_memblock_ref(pa_memblock*b) {
     return b;
 }
 
-void pa_memblock_unref(pa_memblock*b) {
+static void memblock_free(pa_memblock *b) {
     assert(b);
-    assert(PA_REFCNT_VALUE(b) > 0);
 
-    if (PA_REFCNT_DEC(b) > 0)
-        return;
+    assert(pa_atomic_load(&b->n_acquired) == 0);
 
     stat_remove(b);
 
     switch (b->type) {
         case PA_MEMBLOCK_USER :
             assert(b->per_type.user.free_cb);
-            b->per_type.user.free_cb(b->data);
+            b->per_type.user.free_cb(pa_atomic_ptr_load(&b->data));
 
             /* Fall through */
 
@@ -333,17 +445,24 @@ void pa_memblock_unref(pa_memblock*b) {
 
         case PA_MEMBLOCK_IMPORTED : {
             pa_memimport_segment *segment;
+            pa_memimport *import;
+
+            /* FIXME! This should be implemented lock-free */
 
             segment = b->per_type.imported.segment;
             assert(segment);
-            assert(segment->import);
-
-            pa_hashmap_remove(segment->import->blocks, PA_UINT32_TO_PTR(b->per_type.imported.id));
-            segment->import->release_cb(segment->import, b->per_type.imported.id, segment->import->userdata);
+            import = segment->import;
+            assert(import);
 
+            pa_mutex_lock(import->mutex);
+            pa_hashmap_remove(import->blocks, PA_UINT32_TO_PTR(b->per_type.imported.id));
             if (-- segment->n_blocks <= 0)
                 segment_detach(segment);
 
+            pa_mutex_unlock(import->mutex);
+
+            import->release_cb(import, b->per_type.imported.id, import->userdata);
+
             pa_xfree(b);
             break;
         }
@@ -351,13 +470,20 @@ void pa_memblock_unref(pa_memblock*b) {
         case PA_MEMBLOCK_POOL_EXTERNAL:
         case PA_MEMBLOCK_POOL: {
             struct mempool_slot *slot;
+            int call_free;
 
-            slot = mempool_slot_by_ptr(b->pool, b->data);
+            slot = mempool_slot_by_ptr(b->pool, pa_atomic_ptr_load(&b->data));
             assert(slot);
 
-            PA_LLIST_PREPEND(struct mempool_slot, b->pool->free_slots, slot);
+            call_free = b->type == PA_MEMBLOCK_POOL_EXTERNAL;
 
-            if (b->type == PA_MEMBLOCK_POOL_EXTERNAL)
+            /* The free list dimensions should easily allow all slots
+             * to fit in, hence try harder if pushing this slot into
+             * the free list fails */
+            while (pa_flist_push(b->pool->free_slots, slot) < 0)
+                ;
+
+            if (call_free)
                 pa_xfree(b);
 
             break;
@@ -369,6 +495,36 @@ void pa_memblock_unref(pa_memblock*b) {
     }
 }
 
+/* No lock necessary */
+void pa_memblock_unref(pa_memblock*b) {
+    assert(b);
+    assert(PA_REFCNT_VALUE(b) > 0);
+
+    if (PA_REFCNT_DEC(b) > 0)
+        return;
+
+    memblock_free(b);
+}
+
+/* Self locked */
+static void memblock_wait(pa_memblock *b) {
+    assert(b);
+
+    if (pa_atomic_load(&b->n_acquired) > 0) {
+        /* We need to wait until all threads gave up access to the
+         * memory block before we can go on. Unfortunately this means
+         * that we have to lock and wait here. Sniff! */
+
+        pa_atomic_inc(&b->please_signal);
+
+        while (pa_atomic_load(&b->n_acquired) > 0)
+            pa_semaphore_wait(b->pool->semaphore);
+
+        pa_atomic_dec(&b->please_signal);
+    }
+}
+
+/* No lock necessary. This function is not multiple caller safe! */
 static void memblock_make_local(pa_memblock *b) {
     assert(b);
 
@@ -381,38 +537,43 @@ static void memblock_make_local(pa_memblock *b) {
             void *new_data;
             /* We can move it into a local pool, perfect! */
 
+            new_data = mempool_slot_data(slot);
+            memcpy(new_data, pa_atomic_ptr_load(&b->data), b->length);
+            pa_atomic_ptr_store(&b->data, new_data);
+
             b->type = PA_MEMBLOCK_POOL_EXTERNAL;
             b->read_only = 0;
 
-            new_data = mempool_slot_data(slot);
-            memcpy(new_data, b->data, b->length);
-            b->data = new_data;
             goto finish;
         }
     }
 
     /* Humm, not enough space in the pool, so lets allocate the memory with malloc() */
-    b->type = PA_MEMBLOCK_USER;
     b->per_type.user.free_cb = pa_xfree;
+    pa_atomic_ptr_store(&b->data, pa_xmemdup(pa_atomic_ptr_load(&b->data), b->length));
+
+    b->type = PA_MEMBLOCK_USER;
     b->read_only = 0;
-    b->data = pa_xmemdup(b->data, b->length);
 
 finish:
     pa_atomic_inc(&b->pool->stat.n_allocated_by_type[b->type]);
     pa_atomic_inc(&b->pool->stat.n_accumulated_by_type[b->type]);
+    memblock_wait(b);
 }
 
+/* No lock necessary. This function is not multiple caller safe*/
 void pa_memblock_unref_fixed(pa_memblock *b) {
     assert(b);
     assert(PA_REFCNT_VALUE(b) > 0);
     assert(b->type == PA_MEMBLOCK_FIXED);
 
-    if (PA_REFCNT_VALUE(b) > 1)
+    if (PA_REFCNT_DEC(b) > 0)
         memblock_make_local(b);
-
-    pa_memblock_unref(b);
+    else
+        memblock_free(b);
 }
 
+/* Self-locked. This function is not multiple-caller safe */
 static void memblock_replace_import(pa_memblock *b) {
     pa_memimport_segment *seg;
 
@@ -428,6 +589,8 @@ static void memblock_replace_import(pa_memblock *b) {
     assert(seg);
     assert(seg->import);
 
+    pa_mutex_lock(seg->import->mutex);
+
     pa_hashmap_remove(
             seg->import->blocks,
             PA_UINT32_TO_PTR(b->per_type.imported.id));
@@ -436,6 +599,8 @@ static void memblock_replace_import(pa_memblock *b) {
 
     if (-- seg->n_blocks <= 0)
         segment_detach(seg);
+
+    pa_mutex_unlock(seg->import->mutex);
 }
 
 pa_mempool* pa_mempool_new(int shared) {
@@ -444,12 +609,15 @@ pa_mempool* pa_mempool_new(int shared) {
 
     p = pa_xnew(pa_mempool, 1);
 
+    p->mutex = pa_mutex_new(1);
+    p->semaphore = pa_semaphore_new(0);
+
 #ifdef HAVE_SYSCONF
     ps = (size_t) sysconf(_SC_PAGESIZE);
 #elif defined(PAGE_SIZE)
-	ps = (size_t) PAGE_SIZE;
+    ps = (size_t) PAGE_SIZE;
 #else
-	ps = 4096; /* Let's hope it's like x86. */
+    ps = 4096; /* Let's hope it's like x86. */
 #endif
 
     p->block_size = (PA_MEMPOOL_SLOT_SIZE/ps)*ps;
@@ -466,13 +634,13 @@ pa_mempool* pa_mempool_new(int shared) {
         return NULL;
     }
 
-    p->n_init = 0;
+    memset(&p->stat, 0, sizeof(p->stat));
+    pa_atomic_store(&p->n_init, 0);
 
     PA_LLIST_HEAD_INIT(pa_memimport, p->imports);
     PA_LLIST_HEAD_INIT(pa_memexport, p->exports);
-    PA_LLIST_HEAD_INIT(struct mempool_slot, p->free_slots);
 
-    memset(&p->stat, 0, sizeof(p->stat));
+    p->free_slots = pa_flist_new(p->n_blocks*2);
 
     return p;
 }
@@ -480,34 +648,61 @@ pa_mempool* pa_mempool_new(int shared) {
 void pa_mempool_free(pa_mempool *p) {
     assert(p);
 
+    pa_mutex_lock(p->mutex);
+
     while (p->imports)
         pa_memimport_free(p->imports);
 
     while (p->exports)
         pa_memexport_free(p->exports);
 
+    pa_mutex_unlock(p->mutex);
+
     if (pa_atomic_load(&p->stat.n_allocated) > 0)
         pa_log_warn("WARNING! Memory pool destroyed but not all memory blocks freed!");
 
+    pa_flist_free(p->free_slots, NULL);
     pa_shm_free(&p->memory);
+
+    pa_mutex_free(p->mutex);
+    pa_semaphore_free(p->semaphore);
+
     pa_xfree(p);
 }
 
+/* No lock necessary */
 const pa_mempool_stat* pa_mempool_get_stat(pa_mempool *p) {
     assert(p);
 
     return &p->stat;
 }
 
+/* No lock necessary */
 void pa_mempool_vacuum(pa_mempool *p) {
     struct mempool_slot *slot;
+    pa_flist *list;
 
     assert(p);
 
-    for (slot = p->free_slots; slot; slot = slot->next)
-        pa_shm_punch(&p->memory, (uint8_t*) slot + sizeof(struct mempool_slot) - (uint8_t*) p->memory.ptr, p->block_size - sizeof(struct mempool_slot));
+    list = pa_flist_new(p->n_blocks*2);
+
+    while ((slot = pa_flist_pop(p->free_slots)))
+        while (pa_flist_push(list, slot) < 0)
+            ;
+
+    while ((slot = pa_flist_pop(list))) {
+        pa_shm_punch(&p->memory,
+                     (uint8_t*) slot - (uint8_t*) p->memory.ptr + sizeof(struct mempool_slot),
+                     p->block_size - sizeof(struct mempool_slot));
+
+        while (pa_flist_push(p->free_slots, slot))
+            ;
+    }
+
+    pa_flist_free(list, NULL);
 }
 
+/* No lock necessary */
 int pa_mempool_get_shm_id(pa_mempool *p, uint32_t *id) {
     assert(p);
 
@@ -519,6 +714,7 @@ int pa_mempool_get_shm_id(pa_mempool *p, uint32_t *id) {
     return 0;
 }
 
+/* No lock necessary */
 int pa_mempool_is_shared(pa_mempool *p) {
     assert(p);
 
@@ -533,18 +729,23 @@ pa_memimport* pa_memimport_new(pa_mempool *p, pa_memimport_release_cb_t cb, void
     assert(cb);
 
     i = pa_xnew(pa_memimport, 1);
+    i->mutex = pa_mutex_new(0);
     i->pool = p;
     i->segments = pa_hashmap_new(NULL, NULL);
     i->blocks = pa_hashmap_new(NULL, NULL);
     i->release_cb = cb;
     i->userdata = userdata;
 
+    pa_mutex_lock(p->mutex);
     PA_LLIST_PREPEND(pa_memimport, p->imports, i);
+    pa_mutex_unlock(p->mutex);
+
     return i;
 }
 
 static void memexport_revoke_blocks(pa_memexport *e, pa_memimport *i);
 
+/* Should be called locked */
 static pa_memimport_segment* segment_attach(pa_memimport *i, uint32_t shm_id) {
     pa_memimport_segment* seg;
 
@@ -565,6 +766,7 @@ static pa_memimport_segment* segment_attach(pa_memimport *i, uint32_t shm_id) {
     return seg;
 }
 
+/* Should be called locked */
 static void segment_detach(pa_memimport_segment *seg) {
     assert(seg);
 
@@ -573,51 +775,68 @@ static void segment_detach(pa_memimport_segment *seg) {
     pa_xfree(seg);
 }
 
+/* Self-locked. Not multiple-caller safe */
 void pa_memimport_free(pa_memimport *i) {
     pa_memexport *e;
     pa_memblock *b;
 
     assert(i);
 
-    /* If we've exported this block further we need to revoke that export */
-    for (e = i->pool->exports; e; e = e->next)
-        memexport_revoke_blocks(e, i);
+    pa_mutex_lock(i->mutex);
 
     while ((b = pa_hashmap_get_first(i->blocks)))
         memblock_replace_import(b);
 
     assert(pa_hashmap_size(i->segments) == 0);
 
+    pa_mutex_unlock(i->mutex);
+
+    pa_mutex_lock(i->pool->mutex);
+
+    /* If we've exported this block further we need to revoke that export */
+    for (e = i->pool->exports; e; e = e->next)
+        memexport_revoke_blocks(e, i);
+
+    PA_LLIST_REMOVE(pa_memimport, i->pool->imports, i);
+
+    pa_mutex_unlock(i->pool->mutex);
+
     pa_hashmap_free(i->blocks, NULL, NULL);
     pa_hashmap_free(i->segments, NULL, NULL);
 
-    PA_LLIST_REMOVE(pa_memimport, i->pool->imports, i);
+    pa_mutex_free(i->mutex);
+
     pa_xfree(i);
 }
 
+/* Self-locked */
 pa_memblock* pa_memimport_get(pa_memimport *i, uint32_t block_id, uint32_t shm_id, size_t offset, size_t size) {
-    pa_memblock *b;
+    pa_memblock *b = NULL;
     pa_memimport_segment *seg;
 
     assert(i);
 
+    pa_mutex_lock(i->mutex);
+
     if (pa_hashmap_size(i->blocks) >= PA_MEMIMPORT_SLOTS_MAX)
-        return NULL;
+        goto finish;
 
     if (!(seg = pa_hashmap_get(i->segments, PA_UINT32_TO_PTR(shm_id))))
         if (!(seg = segment_attach(i, shm_id)))
-            return NULL;
+            goto finish;
 
     if (offset+size > seg->memory.size)
-        return NULL;
+        goto finish;
 
     b = pa_xnew(pa_memblock, 1);
+    PA_REFCNT_INIT(b);
+    b->pool = i->pool;
     b->type = PA_MEMBLOCK_IMPORTED;
     b->read_only = 1;
-    PA_REFCNT_INIT(b);
+    pa_atomic_ptr_store(&b->data, (uint8_t*) seg->memory.ptr + offset);
     b->length = size;
-    b->data = (uint8_t*) seg->memory.ptr + offset;
-    b->pool = i->pool;
+    pa_atomic_store(&b->n_acquired, 0);
+    pa_atomic_store(&b->please_signal, 0);
     b->per_type.imported.id = block_id;
     b->per_type.imported.segment = seg;
 
@@ -625,6 +844,10 @@ pa_memblock* pa_memimport_get(pa_memimport *i, uint32_t block_id, uint32_t shm_i
 
     seg->n_blocks++;
 
+finish:
+    pa_mutex_unlock(i->mutex);
+
+    if (b)
     stat_add(b);
 
     return b;
@@ -634,10 +857,15 @@ int pa_memimport_process_revoke(pa_memimport *i, uint32_t id) {
     pa_memblock *b;
     assert(i);
 
+    pa_mutex_lock(i->mutex);
+
     if (!(b = pa_hashmap_get(i->blocks, PA_UINT32_TO_PTR(id))))
         return -1;
 
     memblock_replace_import(b);
+
+    pa_mutex_unlock(i->mutex);
+
     return 0;
 }
 
@@ -652,6 +880,7 @@ pa_memexport* pa_memexport_new(pa_mempool *p, pa_memexport_revoke_cb_t cb, void
         return NULL;
 
     e = pa_xnew(pa_memexport, 1);
+    e->mutex = pa_mutex_new(1);
     e->pool = p;
     PA_LLIST_HEAD_INIT(struct memexport_slot, e->free_slots);
     PA_LLIST_HEAD_INIT(struct memexport_slot, e->used_slots);
@@ -659,51 +888,75 @@ pa_memexport* pa_memexport_new(pa_mempool *p, pa_memexport_revoke_cb_t cb, void
     e->revoke_cb = cb;
     e->userdata = userdata;
 
+    pa_mutex_lock(p->mutex);
     PA_LLIST_PREPEND(pa_memexport, p->exports, e);
+    pa_mutex_unlock(p->mutex);
     return e;
 }
 
 void pa_memexport_free(pa_memexport *e) {
     assert(e);
 
+    pa_mutex_lock(e->mutex);
     while (e->used_slots)
         pa_memexport_process_release(e, e->used_slots - e->slots);
+    pa_mutex_unlock(e->mutex);
 
+    pa_mutex_lock(e->pool->mutex);
     PA_LLIST_REMOVE(pa_memexport, e->pool->exports, e);
+    pa_mutex_unlock(e->pool->mutex);
+
     pa_xfree(e);
 }
 
+/* Self-locked */
 int pa_memexport_process_release(pa_memexport *e, uint32_t id) {
+    pa_memblock *b;
+
     assert(e);
 
+    pa_mutex_lock(e->mutex);
+
     if (id >= e->n_init)
-        return -1;
+        goto fail;
 
     if (!e->slots[id].block)
-        return -1;
+        goto fail;
+
+    b = e->slots[id].block;
+    e->slots[id].block = NULL;
+
+    PA_LLIST_REMOVE(struct memexport_slot, e->used_slots, &e->slots[id]);
+    PA_LLIST_PREPEND(struct memexport_slot, e->free_slots, &e->slots[id]);
+
+    pa_mutex_unlock(e->mutex);
 
 /*     pa_log("Processing release for %u", id); */
 
     assert(pa_atomic_load(&e->pool->stat.n_exported) > 0);
-    assert(pa_atomic_load(&e->pool->stat.exported_size) >= (int) e->slots[id].block->length);
+    assert(pa_atomic_load(&e->pool->stat.exported_size) >= (int) b->length);
 
     pa_atomic_dec(&e->pool->stat.n_exported);
-    pa_atomic_sub(&e->pool->stat.exported_size, e->slots[id].block->length);
-
-    pa_memblock_unref(e->slots[id].block);
-    e->slots[id].block = NULL;
+    pa_atomic_sub(&e->pool->stat.exported_size, b->length);
 
-    PA_LLIST_REMOVE(struct memexport_slot, e->used_slots, &e->slots[id]);
-    PA_LLIST_PREPEND(struct memexport_slot, e->free_slots, &e->slots[id]);
+    pa_memblock_unref(b);
 
     return 0;
+
+fail:
+    pa_mutex_unlock(e->mutex);
+
+    return -1;
 }
 
+/* Self-locked */
 static void memexport_revoke_blocks(pa_memexport *e, pa_memimport *i) {
     struct memexport_slot *slot, *next;
     assert(e);
     assert(i);
 
+    pa_mutex_lock(e->mutex);
+
     for (slot = e->used_slots; slot; slot = next) {
         uint32_t idx;
         next = slot->next;
@@ -716,8 +969,11 @@ static void memexport_revoke_blocks(pa_memexport *e, pa_memimport *i) {
         e->revoke_cb(e, idx, e->userdata);
         pa_memexport_process_release(e, idx);
     }
+
+    pa_mutex_unlock(e->mutex);
 }
 
+/* No lock necessary */
 static pa_memblock *memblock_shared_copy(pa_mempool *p, pa_memblock *b) {
     pa_memblock *n;
 
@@ -734,13 +990,16 @@ static pa_memblock *memblock_shared_copy(pa_mempool *p, pa_memblock *b) {
     if (!(n = pa_memblock_new_pool(p, b->length)))
         return NULL;
 
-    memcpy(n->data, b->data, b->length);
+    memcpy(pa_atomic_ptr_load(&n->data), pa_atomic_ptr_load(&b->data), b->length);
     return n;
 }
 
+/* Self-locked */
 int pa_memexport_put(pa_memexport *e, pa_memblock *b, uint32_t *block_id, uint32_t *shm_id, size_t *offset, size_t * size) {
     pa_shm *memory;
     struct memexport_slot *slot;
+    void *data;
+    size_t length;
 
     assert(e);
     assert(b);
@@ -753,12 +1012,15 @@ int pa_memexport_put(pa_memexport *e, pa_memblock *b, uint32_t *block_id, uint32
     if (!(b = memblock_shared_copy(e->pool, b)))
         return -1;
 
+    pa_mutex_lock(e->mutex);
+
     if (e->free_slots) {
         slot = e->free_slots;
         PA_LLIST_REMOVE(struct memexport_slot, e->free_slots, slot);
-    } else if (e->n_init < PA_MEMEXPORT_SLOTS_MAX) {
+    } else if (e->n_init < PA_MEMEXPORT_SLOTS_MAX)
         slot = &e->slots[e->n_init++];
-    } else {
+    else {
+        pa_mutex_unlock(e->mutex);
         pa_memblock_unref(b);
         return -1;
     }
@@ -767,8 +1029,11 @@ int pa_memexport_put(pa_memexport *e, pa_memblock *b, uint32_t *block_id, uint32
     slot->block = b;
     *block_id = slot - e->slots;
 
+    pa_mutex_unlock(e->mutex);
 /*     pa_log("Got block id %u", *block_id); */
 
+    data = pa_memblock_acquire(b);
+
     if (b->type == PA_MEMBLOCK_IMPORTED) {
         assert(b->per_type.imported.segment);
         memory = &b->per_type.imported.segment->memory;
@@ -778,15 +1043,17 @@ int pa_memexport_put(pa_memexport *e, pa_memblock *b, uint32_t *block_id, uint32
         memory = &b->pool->memory;
     }
 
-    assert(b->data >= memory->ptr);
-    assert((uint8_t*) b->data + b->length <= (uint8_t*) memory->ptr + memory->size);
+    assert(data >= memory->ptr);
+    assert((uint8_t*) data + length <= (uint8_t*) memory->ptr + memory->size);
 
     *shm_id = memory->id;
-    *offset = (uint8_t*) b->data - (uint8_t*) memory->ptr;
-    *size = b->length;
+    *offset = (uint8_t*) data - (uint8_t*) memory->ptr;
+    *size = length;
+
+    pa_memblock_release(b);
 
     pa_atomic_inc(&e->pool->stat.n_exported);
-    pa_atomic_add(&e->pool->stat.exported_size, b->length);
+    pa_atomic_add(&e->pool->stat.exported_size, length);
 
     return 0;
 }
diff --git a/src/pulsecore/memblock.h b/src/pulsecore/memblock.h
index fe4773d..6f8bbef 100644
--- a/src/pulsecore/memblock.h
+++ b/src/pulsecore/memblock.h
@@ -28,6 +28,7 @@
 #include <sys/types.h>
 #include <inttypes.h>
 
+#include <pulse/def.h>
 #include <pulsecore/llist.h>
 #include <pulsecore/refcnt.h>
 #include <pulsecore/atomic.h>
@@ -58,45 +59,25 @@ typedef struct pa_memexport pa_memexport;
 typedef void (*pa_memimport_release_cb_t)(pa_memimport *i, uint32_t block_id, void *userdata);
 typedef void (*pa_memexport_revoke_cb_t)(pa_memexport *e, uint32_t block_id, void *userdata);
 
-struct pa_memblock {
-    pa_memblock_type_t type;
-    int read_only; /* boolean */
-    PA_REFCNT_DECLARE; /* the reference counter */
-    size_t length;
-    void *data;
-    pa_mempool *pool;
-
-    union {
-        struct {
-            void (*free_cb)(void *p);  /* If type == PA_MEMBLOCK_USER this points to a function for freeing this memory block */
-        } user;
-
-        struct  {
-            uint32_t id;
-            pa_memimport_segment *segment;
-        } imported;
-    } per_type;
-};
-
 /* Please note that updates to this structure are not locked,
  * i.e. n_allocated might be updated at a point in time where
  * n_accumulated is not yet. Take these values with a grain of salt,
- * threy are here for purely statistical reasons.*/
+ * they are here for purely statistical reasons.*/
 struct pa_mempool_stat {
-    pa_atomic_int_t n_allocated;
-    pa_atomic_int_t n_accumulated;
-    pa_atomic_int_t n_imported;
-    pa_atomic_int_t n_exported;
-    pa_atomic_int_t allocated_size;
-    pa_atomic_int_t accumulated_size;
-    pa_atomic_int_t imported_size;
-    pa_atomic_int_t exported_size;
-
-    pa_atomic_int_t n_too_large_for_pool;
-    pa_atomic_int_t n_pool_full;
-
-    pa_atomic_int_t n_allocated_by_type[PA_MEMBLOCK_TYPE_MAX];
-    pa_atomic_int_t n_accumulated_by_type[PA_MEMBLOCK_TYPE_MAX];
+    pa_atomic_t n_allocated;
+    pa_atomic_t n_accumulated;
+    pa_atomic_t n_imported;
+    pa_atomic_t n_exported;
+    pa_atomic_t allocated_size;
+    pa_atomic_t accumulated_size;
+    pa_atomic_t imported_size;
+    pa_atomic_t exported_size;
+
+    pa_atomic_t n_too_large_for_pool;
+    pa_atomic_t n_pool_full;
+
+    pa_atomic_t n_allocated_by_type[PA_MEMBLOCK_TYPE_MAX];
+    pa_atomic_t n_accumulated_by_type[PA_MEMBLOCK_TYPE_MAX];
 };
 
 /* Allocate a new memory block of type PA_MEMBLOCK_MEMPOOL or PA_MEMBLOCK_APPENDED, depending on the size */
@@ -120,9 +101,17 @@ pa_memblock* pa_memblock_ref(pa_memblock*b);
 /* This special unref function has to be called by the owner of the
 memory of a static memory block when he wants to release all
 references to the memory. This causes the memory to be copied and
-converted into a PA_MEMBLOCK_DYNAMIC type memory block */
+converted into a pool or malloc'ed memory block. Please note that this
+function is not multiple caller safe, i.e. needs to be locked
+manually if called from more than one thread at the same time.  */
 void pa_memblock_unref_fixed(pa_memblock*b);
 
+int pa_memblock_is_read_only(pa_memblock *b);
+void* pa_memblock_acquire(pa_memblock *b);
+void pa_memblock_release(pa_memblock *b);
+size_t pa_memblock_get_length(pa_memblock *b);
+pa_mempool * pa_memblock_get_pool(pa_memblock *b);
+
 /* The memory block manager */
 pa_mempool* pa_mempool_new(int shared);
 void pa_mempool_free(pa_mempool *p);
diff --git a/src/pulsecore/memblockq.c b/src/pulsecore/memblockq.c
index e31fb6d..a80df33 100644
--- a/src/pulsecore/memblockq.c
+++ b/src/pulsecore/memblockq.c
@@ -178,7 +178,7 @@ int pa_memblockq_push(pa_memblockq* bq, const pa_memchunk *uchunk) {
     assert(uchunk);
     assert(uchunk->memblock);
     assert(uchunk->length > 0);
-    assert(uchunk->index + uchunk->length <= uchunk->memblock->length);
+    assert(uchunk->index + uchunk->length <= pa_memblock_get_length(uchunk->memblock));
 
     if (uchunk->length % bq->base)
         return -1;
@@ -362,8 +362,8 @@ int pa_memblockq_peek(pa_memblockq* bq, pa_memchunk *chunk) {
         if (bq->silence) {
             chunk->memblock = pa_memblock_ref(bq->silence);
 
-            if (!length || length > chunk->memblock->length)
-                length = chunk->memblock->length;
+            if (!length || length > pa_memblock_get_length(chunk->memblock))
+                length = pa_memblock_get_length(chunk->memblock);
 
             chunk->length = length;
         } else {
@@ -415,8 +415,8 @@ void pa_memblockq_drop(pa_memblockq *bq, const pa_memchunk *chunk, size_t length
 
             if (bq->silence) {
 
-                if (!l || l > bq->silence->length)
-                    l = bq->silence->length;
+                if (!l || l > pa_memblock_get_length(bq->silence))
+                    l = pa_memblock_get_length(bq->silence);
 
             }
 
diff --git a/src/pulsecore/memchunk.c b/src/pulsecore/memchunk.c
index 7111e1e..f00cc9e 100644
--- a/src/pulsecore/memchunk.c
+++ b/src/pulsecore/memchunk.c
@@ -37,22 +37,25 @@
 void pa_memchunk_make_writable(pa_memchunk *c, size_t min) {
     pa_memblock *n;
     size_t l;
+    void *tdata, *sdata;
 
     assert(c);
     assert(c->memblock);
-    assert(PA_REFCNT_VALUE(c->memblock) > 0);
 
-    if (PA_REFCNT_VALUE(c->memblock) == 1 &&
-        !c->memblock->read_only &&
-        c->memblock->length >= c->index+min)
+    if (pa_memblock_is_read_only(c->memblock) &&
+        pa_memblock_get_length(c->memblock) >= c->index+min)
         return;
 
     l = c->length;
     if (l < min)
         l = min;
 
-    n = pa_memblock_new(c->memblock->pool, l);
-    memcpy(n->data, (uint8_t*) c->memblock->data + c->index, c->length);
+    n = pa_memblock_new(pa_memblock_get_pool(c->memblock), l);
+    tdata = pa_memblock_acquire(n);
+    sdata = pa_memblock_acquire(c->memblock);
+    memcpy(tdata, (uint8_t*) sdata + c->index, c->length);
+    pa_memblock_release(n);
+    pa_memblock_release(c->memblock);
     pa_memblock_unref(c->memblock);
     c->memblock = n;
     c->index = 0;
diff --git a/src/pulsecore/msgobject.c b/src/pulsecore/msgobject.c
new file mode 100644
index 0000000..ea404cc
--- /dev/null
+++ b/src/pulsecore/msgobject.c
@@ -0,0 +1,40 @@
+/* $Id$ */
+
+/***
+  This file is part of PulseAudio.
+
+  Copyright 2004-2006 Lennart Poettering
+  Copyright 2006 Pierre Ossman <ossman at cendio.se> for Cendio AB
+
+  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 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.
+***/
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "msgobject.h"
+
+pa_msgobject *pa_msgobject_new_internal(size_t size, const char *type_name) {
+    pa_msgobject *o;
+    
+    pa_assert(size > sizeof(pa_msgobject));
+    pa_assert(type_name);
+
+    o = PA_MSGOBJECT(pa_object_new_internal(size, type_name));
+    o->process_msg = NULL;
+    return o;
+}
diff --git a/src/pulsecore/msgobject.h b/src/pulsecore/msgobject.h
new file mode 100644
index 0000000..317ebd2
--- /dev/null
+++ b/src/pulsecore/msgobject.h
@@ -0,0 +1,52 @@
+#ifndef foopulsemsgobjecthfoo
+#define foopulsemsgobjecthfoo
+
+/* $Id$ */
+
+/***
+  This file is part of PulseAudio.
+
+  Copyright 2004-2006 Lennart Poettering
+  Copyright 2006 Pierre Ossman <ossman at cendio.se> for Cendio AB
+
+  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 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.
+***/
+
+#include <sys/types.h>
+
+#include <pulse/xmalloc.h>
+#include <pulsecore/refcnt.h>
+#include <pulsecore/macro.h>
+#include <pulsecore/object.h>
+#include <pulsecore/memchunk.h>
+
+typedef struct pa_msgobject pa_msgobject;
+
+struct pa_msgobject {
+    pa_object parent;
+    int (*process_msg)(pa_msgobject *o, int code, void *userdata, pa_memchunk *chunk);
+};
+
+pa_msgobject *pa_msgobject_new_internal(size_t size, const char *type_name);
+
+#define pa_msgobject_new(type) ((type*) pa_msgobject_new_internal(sizeof(type), #type))
+#define pa_msgobject_free ((void (*) (pa_msgobject* o)) pa_object_free)
+
+#define PA_MSGOBJECT(o) ((pa_msgobject*) (o))
+
+PA_DECLARE_CLASS(pa_msgobject);
+
+#endif
diff --git a/src/pulsecore/mutex-posix.c b/src/pulsecore/mutex-posix.c
index 52e731b..a66950e 100644
--- a/src/pulsecore/mutex-posix.c
+++ b/src/pulsecore/mutex-posix.c
@@ -28,8 +28,6 @@
 #include <assert.h>
 #include <pthread.h>
 
-#include <atomic_ops.h>
-
 #include <pulse/xmalloc.h>
 
 #include "mutex.h"
diff --git a/src/pulsecore/object.c b/src/pulsecore/object.c
new file mode 100644
index 0000000..de7d5ad
--- /dev/null
+++ b/src/pulsecore/object.c
@@ -0,0 +1,61 @@
+/* $Id$ */
+
+/***
+  This file is part of PulseAudio.
+
+  Copyright 2004-2006 Lennart Poettering
+  Copyright 2006 Pierre Ossman <ossman at cendio.se> for Cendio AB
+
+  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 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.
+***/
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "object.h"
+
+pa_object *pa_object_new_internal(size_t size, const char *type_name) {
+    pa_object *o;
+    
+    pa_assert(size > sizeof(pa_object));
+    pa_assert(type_name);
+
+    o = pa_xmalloc(size);
+    PA_REFCNT_INIT(o);
+    o->type_name = type_name;
+    o->free = pa_object_free;
+
+    return o;
+}
+
+pa_object *pa_object_ref(pa_object *o) {
+    pa_assert(o);
+    pa_assert(PA_REFCNT_VALUE(o) >= 1);
+
+    PA_REFCNT_INC(o);
+    return o;
+}
+
+void pa_object_unref(pa_object *o) {
+    pa_assert(o);
+    pa_assert(PA_REFCNT_VALUE(o) >= 1);
+
+    if (PA_REFCNT_DEC(o) <= 0) {
+        pa_assert(o->free);
+        o->free(o);
+    }
+}
diff --git a/src/pulsecore/object.h b/src/pulsecore/object.h
new file mode 100644
index 0000000..8fccf19
--- /dev/null
+++ b/src/pulsecore/object.h
@@ -0,0 +1,72 @@
+#ifndef foopulseobjecthfoo
+#define foopulseobjecthfoo
+
+/* $Id$ */
+
+/***
+  This file is part of PulseAudio.
+
+  Copyright 2004-2006 Lennart Poettering
+  Copyright 2006 Pierre Ossman <ossman at cendio.se> for Cendio AB
+
+  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 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.
+***/
+
+#include <sys/types.h>
+#include <pulse/xmalloc.h>
+#include <pulsecore/refcnt.h>
+#include <pulsecore/macro.h>
+
+typedef struct pa_object pa_object;
+
+struct pa_object {
+    PA_REFCNT_DECLARE;
+    const char *type_name;
+    void (*free)(pa_object *o);
+};
+
+pa_object *pa_object_new_internal(size_t size, const char *type_name);
+#define pa_object_new(type) ((type*) pa_object_new_internal(sizeof(type), #type))
+
+#define pa_object_free ((void (*) (pa_object* o)) pa_xfree)
+
+pa_object *pa_object_ref(pa_object *o);
+void pa_object_unref(pa_object *o);
+
+static inline int pa_object_refcnt(pa_object *o) {
+    return o ? PA_REFCNT_VALUE(o) : 0;
+}
+
+#define pa_object_assert_ref(o) pa_assert(pa_object_refcnt(o))
+
+#define PA_OBJECT(o) ((pa_object*) (o))
+
+#define PA_DECLARE_CLASS(c) \
+    static inline c* c##_ref(c *o) {                            \
+        return (c*) pa_object_ref(PA_OBJECT(o));                \
+    }                                                           \
+    static inline void c##_unref(c* o) {                        \
+        pa_object_unref(PA_OBJECT(o));                          \
+    }                                                           \
+    static inline int c##_refcnt(c* o) {                        \
+        return pa_object_refcnt(PA_OBJECT(o));                  \
+    }                                                           \
+    static inline void c##_assert_ref(c *o) {                   \
+        pa_object_assert_ref(PA_OBJECT(o));                     \
+    }                                                           \
+    struct __stupid_useless_struct_to_allow_trailing_semicolon
+        
+#endif
diff --git a/src/pulsecore/once-posix.c b/src/pulsecore/once-posix.c
index 4af7b36..7ccd08e 100644
--- a/src/pulsecore/once-posix.c
+++ b/src/pulsecore/once-posix.c
@@ -26,44 +26,56 @@
 #endif
 
 #include <pthread.h>
-#include <assert.h>
 
+#include <pulsecore/macro.h>
 #include <pulsecore/mutex.h>
 
 #include "once.h"
 
-#define ASSERT_SUCCESS(x) do { \
-    int _r = (x); \
-    assert(_r == 0); \
-} while(0)
-
-static pa_mutex *global_mutex;
-static pthread_once_t global_mutex_once = PTHREAD_ONCE_INIT;
-
-static void global_mutex_once_func(void) {
-    global_mutex = pa_mutex_new(0);
-}
-
+/* Not reentrant -- how could it be? */
 void pa_once(pa_once_t *control, pa_once_func_t func) {
-    assert(control);
-    assert(func);
-
-    /* Create the global mutex */
-    ASSERT_SUCCESS(pthread_once(&global_mutex_once, global_mutex_once_func));
-
-    /* Create the local mutex */
-    pa_mutex_lock(global_mutex);
-    if (!control->mutex)
-        control->mutex = pa_mutex_new(1);
-    pa_mutex_unlock(global_mutex);
-
-    /* Execute function */
-    pa_mutex_lock(control->mutex);
-    if (!control->once_value) {
-        control->once_value = 1;
-        func();
+    pa_mutex *m;
+    
+    pa_assert(control);
+    pa_assert(func);
+
+    if (pa_atomic_load(&control->done))
+        return;
+    
+    pa_atomic_inc(&control->ref);
+        
+    for (;;) {
+        
+        if ((m = pa_atomic_ptr_load(&control->mutex))) {
+
+            /* The mutex is stored in locked state, hence let's just
+             * wait until it is unlocked */
+            pa_mutex_lock(m);
+            pa_mutex_unlock(m);
+            break;
+        }
+
+        pa_assert_se(m = pa_mutex_new(0));
+        pa_mutex_lock(m);
+        
+        if (pa_atomic_ptr_cmpxchg(&control->mutex, NULL, m)) {
+            func();
+            pa_atomic_store(&control->done, 1);
+            pa_mutex_unlock(m);
+
+            break;
+        }
+
+        pa_mutex_unlock(m);
+        pa_mutex_free(m);
+    }
+
+    pa_assert(pa_atomic_load(&control->done));
+    
+    if (pa_atomic_dec(&control->ref) <= 1) {
+        pa_assert(pa_atomic_ptr_cmpxchg(&control->mutex, m, NULL));
+        pa_mutex_free(m);
     }
-    pa_mutex_unlock(control->mutex);
 
     /* Caveat: We have to make sure that the once func has completed
      * before returning, even if the once func is not actually
diff --git a/src/pulsecore/once.h b/src/pulsecore/once.h
index c20fc0b..b260212 100644
--- a/src/pulsecore/once.h
+++ b/src/pulsecore/once.h
@@ -25,13 +25,19 @@
 ***/
 
 #include <pulsecore/mutex.h>
+#include <pulsecore/atomic.h>
 
 typedef struct pa_once {
-    unsigned int once_value;
-    pa_mutex *mutex;
+    pa_atomic_ptr_t mutex;
+    pa_atomic_t ref, done;
 } pa_once_t;
 
-#define PA_ONCE_INIT { .once_value = 0, .mutex = NULL }
+#define PA_ONCE_INIT                                                    \
+    {                                                                   \
+        .mutex = PA_ATOMIC_PTR_INIT(NULL),                              \
+        .ref = PA_ATOMIC_INIT(0),                                   \
+        .done = PA_ATOMIC_INIT(0)                                   \
+    }
 
 typedef void (*pa_once_func_t) (void);
 
diff --git a/src/pulsecore/play-memblockq.c b/src/pulsecore/play-memblockq.c
index 76edd27..9c5945a 100644
--- a/src/pulsecore/play-memblockq.c
+++ b/src/pulsecore/play-memblockq.c
@@ -122,7 +122,5 @@ int pa_play_memblockq(
 
     si->userdata = q;
 
-    pa_sink_notify(si->sink);
-
     return 0;
 }
diff --git a/src/pulsecore/play-memchunk.c b/src/pulsecore/play-memchunk.c
index 9132e29..65b6e82 100644
--- a/src/pulsecore/play-memchunk.c
+++ b/src/pulsecore/play-memchunk.c
@@ -57,7 +57,7 @@ static int sink_input_peek(pa_sink_input *i, pa_memchunk *chunk) {
     if (c->length <= 0)
         return -1;
 
-    assert(c->memblock && c->memblock->length);
+    assert(c->memblock);
     *chunk = *c;
     pa_memblock_ref(c->memblock);
 
@@ -122,7 +122,5 @@ int pa_play_memchunk(
 
     pa_memblock_ref(chunk->memblock);
 
-    pa_sink_notify(si->sink);
-
     return 0;
 }
diff --git a/src/pulsecore/protocol-esound.c b/src/pulsecore/protocol-esound.c
index 49a78d4..6a5c612 100644
--- a/src/pulsecore/protocol-esound.c
+++ b/src/pulsecore/protocol-esound.c
@@ -894,14 +894,22 @@ static int do_read(struct connection *c) {
         }
     } else if (c->state == ESD_CACHING_SAMPLE) {
         ssize_t r;
+        void *p;
 
-        assert(c->scache.memchunk.memblock && c->scache.name && c->scache.memchunk.index < c->scache.memchunk.length);
+        assert(c->scache.memchunk.memblock);
+        assert(c->scache.name);
+        assert(c->scache.memchunk.index < c->scache.memchunk.length);
 
-        if ((r = pa_iochannel_read(c->io, (uint8_t*) c->scache.memchunk.memblock->data+c->scache.memchunk.index, c->scache.memchunk.length-c->scache.memchunk.index)) <= 0) {
+        p = pa_memblock_acquire(c->scache.memchunk.memblock);
+
+        if ((r = pa_iochannel_read(c->io, (uint8_t*) p+c->scache.memchunk.index, c->scache.memchunk.length-c->scache.memchunk.index)) <= 0) {
+            pa_memblock_release(c->scache.memchunk.memblock);
             pa_log_debug("read(): %s", r < 0 ? pa_cstrerror(errno) : "EOF");
             return -1;
         }
 
+        pa_memblock_release(c->scache.memchunk.memblock);
+
         c->scache.memchunk.index += r;
         assert(c->scache.memchunk.index <= c->scache.memchunk.length);
 
@@ -928,6 +936,7 @@ static int do_read(struct connection *c) {
         pa_memchunk chunk;
         ssize_t r;
         size_t l;
+        void *p;
 
         assert(c->input_memblockq);
 
@@ -940,7 +949,7 @@ static int do_read(struct connection *c) {
             l = c->playback.fragment_size;
 
         if (c->playback.current_memblock)
-            if (c->playback.current_memblock->length - c->playback.memblock_index < l) {
+            if (pa_memblock_get_length(c->playback.current_memblock) - c->playback.memblock_index < l) {
                 pa_memblock_unref(c->playback.current_memblock);
                 c->playback.current_memblock = NULL;
                 c->playback.memblock_index = 0;
@@ -948,14 +957,19 @@ static int do_read(struct connection *c) {
 
         if (!c->playback.current_memblock) {
             c->playback.current_memblock = pa_memblock_new(c->protocol->core->mempool, c->playback.fragment_size*2);
-            assert(c->playback.current_memblock && c->playback.current_memblock->length >= l);
+            assert(c->playback.current_memblock);
+            assert(pa_memblock_get_length(c->playback.current_memblock) >= l);
             c->playback.memblock_index = 0;
         }
 
-        if ((r = pa_iochannel_read(c->io, (uint8_t*) c->playback.current_memblock->data+c->playback.memblock_index, l)) <= 0) {
+        p = pa_memblock_acquire(c->playback.current_memblock);
+
+        if ((r = pa_iochannel_read(c->io, (uint8_t*) p+c->playback.memblock_index, l)) <= 0) {
+            pa_memblock_release(c->playback.current_memblock);
             pa_log_debug("read(): %s", r < 0 ? pa_cstrerror(errno) : "EOF");
             return -1;
         }
+        pa_memblock_release(c->playback.current_memblock);
 
         chunk.memblock = c->playback.current_memblock;
         chunk.index = c->playback.memblock_index;
@@ -993,19 +1007,26 @@ static int do_write(struct connection *c) {
     } else if (c->state == ESD_STREAMING_DATA && c->source_output) {
         pa_memchunk chunk;
         ssize_t r;
+        void *p;
 
         assert(c->output_memblockq);
         if (pa_memblockq_peek(c->output_memblockq, &chunk) < 0)
             return 0;
 
-        assert(chunk.memblock && chunk.length);
+        assert(chunk.memblock);
+        assert(chunk.length);
+
+        p = pa_memblock_acquire(chunk.memblock);
 
-        if ((r = pa_iochannel_write(c->io, (uint8_t*) chunk.memblock->data+chunk.index, chunk.length)) < 0) {
+        if ((r = pa_iochannel_write(c->io, (uint8_t*) p+chunk.index, chunk.length)) < 0) {
+            pa_memblock_release(chunk.memblock);
             pa_memblock_unref(chunk.memblock);
             pa_log("write(): %s", pa_cstrerror(errno));
             return -1;
         }
 
+        pa_memblock_release(chunk.memblock);
+
         pa_memblockq_drop(c->output_memblockq, &chunk, r);
         pa_memblock_unref(chunk.memblock);
 
diff --git a/src/pulsecore/protocol-native.c b/src/pulsecore/protocol-native.c
index dd41b3d..8645569 100644
--- a/src/pulsecore/protocol-native.c
+++ b/src/pulsecore/protocol-native.c
@@ -2278,6 +2278,7 @@ static void pstream_memblock_callback(pa_pstream *p, uint32_t channel, int64_t o
     } else {
         struct upload_stream *u = (struct upload_stream*) stream;
         size_t l;
+
         assert(u->type == UPLOAD_STREAM);
 
         if (!u->memchunk.memblock) {
@@ -2297,9 +2298,18 @@ static void pstream_memblock_callback(pa_pstream *p, uint32_t channel, int64_t o
         if (l > chunk->length)
             l = chunk->length;
 
+
         if (l > 0) {
-            memcpy((uint8_t*) u->memchunk.memblock->data + u->memchunk.index + u->memchunk.length,
-                   (uint8_t*) chunk->memblock->data+chunk->index, l);
+            void *src, *dst;
+            dst = pa_memblock_acquire(u->memchunk.memblock);
+            src = pa_memblock_acquire(chunk->memblock);
+
+            memcpy((uint8_t*) dst + u->memchunk.index + u->memchunk.length,
+                   (uint8_t*) src+chunk->index, l);
+
+            pa_memblock_release(u->memchunk.memblock);
+            pa_memblock_release(chunk->memblock);
+
             u->memchunk.length += l;
             u->length -= l;
         }
diff --git a/src/pulsecore/protocol-simple.c b/src/pulsecore/protocol-simple.c
index 31ad6dd..288cf87 100644
--- a/src/pulsecore/protocol-simple.c
+++ b/src/pulsecore/protocol-simple.c
@@ -25,7 +25,6 @@
 #include <config.h>
 #endif
 
-#include <assert.h>
 #include <stdlib.h>
 #include <limits.h>
 #include <stdio.h>
@@ -54,13 +53,13 @@ struct connection {
     pa_source_output *source_output;
     pa_client *client;
     pa_memblockq *input_memblockq, *output_memblockq;
-    pa_defer_event *defer_event;
 
     int dead;
 
     struct {
         pa_memblock *current_memblock;
         size_t memblock_index, fragment_size;
+        pa_atomic_int missing;
     } playback;
 };
 
@@ -69,35 +68,52 @@ struct pa_protocol_simple {
     pa_core *core;
     pa_socket_server*server;
     pa_idxset *connections;
+
+    pa_asyncmsgq *asyncmsgq;
+
     enum {
         RECORD = 1,
         PLAYBACK = 2,
         DUPLEX = 3
     } mode;
+
     pa_sample_spec sample_spec;
     char *source_name, *sink_name;
 };
 
+enum {
+    SINK_INPUT_MESSAGE_POST_DATA = PA_SINK_INPUT_MESSAGE_MAX, /* data from main loop to sink input */
+};
+
+enum {
+    MESSAGE_REQUEST_DATA,   /* data from source output to main loop */ 
+    MESSAGE_POST_DATA       /* data from source output to main loop */
+};
+
+    
 #define PLAYBACK_BUFFER_SECONDS (.5)
 #define PLAYBACK_BUFFER_FRAGMENTS (10)
 #define RECORD_BUFFER_SECONDS (5)
 #define RECORD_BUFFER_FRAGMENTS (100)
 
 static void connection_free(struct connection *c) {
-    assert(c);
+    pa_assert(c);
 
     pa_idxset_remove_by_data(c->protocol->connections, c, NULL);
 
-    if (c->playback.current_memblock)
-        pa_memblock_unref(c->playback.current_memblock);
     if (c->sink_input) {
         pa_sink_input_disconnect(c->sink_input);
         pa_sink_input_unref(c->sink_input);
     }
+    
     if (c->source_output) {
         pa_source_output_disconnect(c->source_output);
         pa_source_output_unref(c->source_output);
     }
+    
+    if (c->playback.current_memblock)
+        pa_memblock_unref(c->playback.current_memblock);
+    
     if (c->client)
         pa_client_free(c->client);
     if (c->io)
@@ -106,8 +122,7 @@ static void connection_free(struct connection *c) {
         pa_memblockq_free(c->input_memblockq);
     if (c->output_memblockq)
         pa_memblockq_free(c->output_memblockq);
-    if (c->defer_event)
-        c->protocol->core->mainloop->defer_free(c->defer_event);
+    
     pa_xfree(c);
 }
 
@@ -115,27 +130,37 @@ static int do_read(struct connection *c) {
     pa_memchunk chunk;
     ssize_t r;
     size_t l;
+    void *p;
 
-    if (!c->sink_input || !(l = pa_memblockq_missing(c->input_memblockq)))
+    pa_assert(c);
+    
+    if (!c->sink_input || !(l = pa_atomic_load(&c->playback.missing)))
         return 0;
 
     if (l > c->playback.fragment_size)
         l = c->playback.fragment_size;
 
     if (c->playback.current_memblock)
-        if (c->playback.current_memblock->length - c->playback.memblock_index < l) {
+        if (pa_memblock_get_length(c->playback.current_memblock) - c->playback.memblock_index < l) {
             pa_memblock_unref(c->playback.current_memblock);
             c->playback.current_memblock = NULL;
             c->playback.memblock_index = 0;
         }
 
     if (!c->playback.current_memblock) {
-        c->playback.current_memblock = pa_memblock_new(c->protocol->core->mempool, c->playback.fragment_size*2);
-        assert(c->playback.current_memblock && c->playback.current_memblock->length >= l);
+        pa_assert_se(c->playback.current_memblock = pa_memblock_new(c->protocol->core->mempool, l));
         c->playback.memblock_index = 0;
     }
 
-    if ((r = pa_iochannel_read(c->io, (uint8_t*) c->playback.current_memblock->data+c->playback.memblock_index, l)) <= 0) {
+    p = pa_memblock_acquire(c->playback.current_memblock);
+    r = pa_iochannel_read(c->io, (uint8_t*) p + c->playback.memblock_index, l);
+    pa_memblock_release(c->playback.current_memblock);
+    
+    if (r <= 0) {
+
+        if (errno == EINTR || errno == EAGAIN)
+            return 0;
+        
         pa_log_debug("read(): %s", r == 0 ? "EOF" : pa_cstrerror(errno));
         return -1;
     }
@@ -143,14 +168,10 @@ static int do_read(struct connection *c) {
     chunk.memblock = c->playback.current_memblock;
     chunk.index = c->playback.memblock_index;
     chunk.length = r;
-    assert(chunk.memblock);
 
     c->playback.memblock_index += r;
 
-    assert(c->input_memblockq);
-    pa_memblockq_push_align(c->input_memblockq, &chunk);
-    assert(c->sink_input);
-    pa_sink_notify(c->sink_input->sink);
+    pa_asyncmsgq_post(c->protocol->asyncmsgq, c, MESSAGE_POST_DATA, NULL, &chunk, NULL, NULL);
 
     return 0;
 }
@@ -158,35 +179,41 @@ static int do_read(struct connection *c) {
 static int do_write(struct connection *c) {
     pa_memchunk chunk;
     ssize_t r;
+    void *p;
+
+    p_assert(c);
 
     if (!c->source_output)
         return 0;
 
-    assert(c->output_memblockq);
     if (pa_memblockq_peek(c->output_memblockq, &chunk) < 0)
         return 0;
 
-    assert(chunk.memblock && chunk.length);
+    pa_assert(chunk.memblock);
+    pa_assert(chunk.length);
+
+    p = pa_memblock_acquire(chunk.memblock);
+    r = pa_iochannel_write(c->io, (uint8_t*) p+chunk.index, chunk.length);
+    pa_memblock_release(chunk.memblock);
+    
+    pa_memblock_unref(chunk.memblock);
+
+    if (r < 0) {
+
+        if (errno == EINTR || errno == EAGAIN)
+            return 0;
 
-    if ((r = pa_iochannel_write(c->io, (uint8_t*) chunk.memblock->data+chunk.index, chunk.length)) < 0) {
-        pa_memblock_unref(chunk.memblock);
         pa_log("write(): %s", pa_cstrerror(errno));
         return -1;
     }
 
     pa_memblockq_drop(c->output_memblockq, &chunk, r);
-    pa_memblock_unref(chunk.memblock);
-
-    pa_source_notify(c->source_output->source);
-
+    
     return 0;
 }
 
 static void do_work(struct connection *c) {
-    assert(c);
-
-    assert(c->protocol && c->protocol->core && c->protocol->core->mainloop && c->protocol->core->mainloop->defer_enable);
-    c->protocol->core->mainloop->defer_enable(c->defer_event, 0);
+    pa_assert(c);
 
     if (c->dead)
         return;
@@ -207,103 +234,148 @@ static void do_work(struct connection *c) {
 fail:
 
     if (c->sink_input) {
+
+        /* If there is a sink input, we first drain what we already have read before shutting down the connection */
         c->dead = 1;
 
         pa_iochannel_free(c->io);
         c->io = NULL;
 
         pa_memblockq_prebuf_disable(c->input_memblockq);
-        pa_sink_notify(c->sink_input->sink);
     } else
         connection_free(c);
 }
 
 /*** sink_input callbacks ***/
 
-static int sink_input_peek_cb(pa_sink_input *i, pa_memchunk *chunk) {
+/* Called from thread context */
+static int sink_input_process_msg(pa_sink_input *i, int code, void *userdata, const pa_memchunk *chunk) {
     struct connection*c;
-    assert(i && i->userdata && chunk);
+    
+    pa_assert(i);
     c = i->userdata;
+    pa_assert(c);
 
-    if (pa_memblockq_peek(c->input_memblockq, chunk) < 0) {
+    switch (code) {
 
-        if (c->dead)
-            connection_free(c);
+        case SINK_INPUT_MESSAGE_POST_DATA: {
+            pa_assert(chunk);
 
-        return -1;
+            /* New data from the main loop */
+            pa_memblockq_push_align(c->input_memblockq, chunk);
+            return 0;
+        }
+        
+        case PA_SINK_INPUT_MESSAGE_GET_LATENCY: {
+            pa_usec_t *r = userdata;
+            
+            *r = pa_bytes_to_usec(pa_memblockq_get_length(c->input_memblockq), &c->sink_input->sample_spec);
+
+            /* Fall through, the default handler will add in the extra
+             * latency added by the resampler */
+        }
+
+        default:
+            return pa_sink_input_process_msg(i, code, userdata);
     }
+}
 
-    return 0;
+/* Called from thread context */
+static int sink_input_peek_cb(pa_sink_input *i, pa_memchunk *chunk) {
+    struct connection*c;
+    
+    pa_assert(i);
+    c = i->userdata;
+    pa_assert(c);
+    pa_assert(chunk);
+
+    r = pa_memblockq_peek(c->input_memblockq, chunk);
+
+    if (c->dead && r < 0)
+        connection_free(c);
+
+    return r;
 }
 
+/* Called from thread context */
 static void sink_input_drop_cb(pa_sink_input *i, const pa_memchunk *chunk, size_t length) {
     struct connection*c = i->userdata;
-    assert(i && c && length);
+    size_t old, new;
+    
+    pa_assert(i);
+    pa_assert(c);
+    pa_assert(length);
 
+    old = pa_memblockq_missing(c->input_memblockq);
     pa_memblockq_drop(c->input_memblockq, chunk, length);
+    new = pa_memblockq_missing(c->input_memblockq);
 
-    /* do something */
-    assert(c->protocol && c->protocol->core && c->protocol->core->mainloop && c->protocol->core->mainloop->defer_enable);
-    c->protocol->core->mainloop->defer_enable(c->defer_event, 1);
+    pa_atomic_store(&c->playback.missing, &new);
+
+    if (new > old)
+        pa_asyncmsgq_post(c->protocol->asyncmsgq, c, MESSAGE_REQUEST_DATA, NULL, NULL, NULL, NULL);
 }
 
+/* Called from main context */
 static void sink_input_kill_cb(pa_sink_input *i) {
-    assert(i && i->userdata);
+    pa_assert(i);
+    pa_assert(i->userdata);
+    
     connection_free((struct connection *) i->userdata);
 }
 
-
-static pa_usec_t sink_input_get_latency_cb(pa_sink_input *i) {
-    struct connection*c = i->userdata;
-    assert(i && c);
-    return pa_bytes_to_usec(pa_memblockq_get_length(c->input_memblockq), &c->sink_input->sample_spec);
-}
-
 /*** source_output callbacks ***/
 
 static void source_output_push_cb(pa_source_output *o, const pa_memchunk *chunk) {
-    struct connection *c = o->userdata;
-    assert(o && c && chunk);
-
-    pa_memblockq_push(c->output_memblockq, chunk);
+    struct connection *c;
+    
+    pa_assert(o);
+    c = o->userdata;
+    pa_assert(c);
+    pa_assert(chunk);
 
-    /* do something */
-    assert(c->protocol && c->protocol->core && c->protocol->core->mainloop && c->protocol->core->mainloop->defer_enable);
-    c->protocol->core->mainloop->defer_enable(c->defer_event, 1);
+    pa_asyncmsgq_post(c->protocol->asyncmsgq, c, MESSAGE_REQUEST_DATA, NULL, chunk, NULL, NULL);
 }
 
 static void source_output_kill_cb(pa_source_output *o) {
-    assert(o && o->userdata);
-    connection_free((struct connection *) o->userdata);
+    struct connection*c;
+
+    pa_assert(o);
+    c = o->userdata;
+    pa_assert(c);
+    
+    connection_free(c);
 }
 
 static pa_usec_t source_output_get_latency_cb(pa_source_output *o) {
-    struct connection*c = o->userdata;
-    assert(o && c);
+    struct connection*c;
+    
+    pa_assert(o);
+    c = o->userdata;
+    pa_assert(c);
+    
     return pa_bytes_to_usec(pa_memblockq_get_length(c->output_memblockq), &c->source_output->sample_spec);
 }
 
 /*** client callbacks ***/
 
-static void client_kill_cb(pa_client *c) {
-    assert(c && c->userdata);
-    connection_free((struct connection *) c->userdata);
+static void client_kill_cb(pa_client *client) {
+    struct connection*c;
+    
+    pa_assert(client);
+    c = client->userdata;
+    pa_assert(c);
+
+    connection_free(client);
 }
 
 /*** pa_iochannel callbacks ***/
 
 static void io_callback(pa_iochannel*io, void *userdata) {
     struct connection *c = userdata;
-    assert(io && c && c->io == io);
-
-    do_work(c);
-}
 
-/*** fixed callback ***/
-
-static void defer_callback(pa_mainloop_api*a, pa_defer_event *e, void *userdata) {
-    struct connection *c = userdata;
-    assert(a && c && c->defer_event == e);
+    pa_assert(io);
+    pa_assert(c);
 
     do_work(c);
 }
@@ -314,7 +386,10 @@ static void on_connection(pa_socket_server*s, pa_iochannel *io, void *userdata)
     pa_protocol_simple *p = userdata;
     struct connection *c = NULL;
     char cname[256];
-    assert(s && io && p);
+    
+    pa_assert(s);
+    pa_assert(io);
+    pa_assert(p);
 
     if (pa_idxset_size(p->connections)+1 > MAX_CONNECTIONS) {
         pa_log("Warning! Too many connections (%u), dropping incoming connection.", MAX_CONNECTIONS);
@@ -322,25 +397,25 @@ static void on_connection(pa_socket_server*s, pa_iochannel *io, void *userdata)
         return;
     }
 
-    c = pa_xmalloc(sizeof(struct connection));
+    c = pa_xnew(struct connection, 1);
     c->io = io;
     c->sink_input = NULL;
     c->source_output = NULL;
-    c->defer_event = NULL;
     c->input_memblockq = c->output_memblockq = NULL;
     c->protocol = p;
     c->playback.current_memblock = NULL;
     c->playback.memblock_index = 0;
     c->playback.fragment_size = 0;
     c->dead = 0;
+    pa_atomic_store(&c->playback.missing, 0);
 
     pa_iochannel_socket_peer_to_string(io, cname, sizeof(cname));
-    c->client = pa_client_new(p->core, __FILE__, cname);
-    assert(c->client);
+    pa_assert_se(c->client = pa_client_new(p->core, __FILE__, cname));
     c->client->owner = p->module;
     c->client->kill = client_kill_cb;
     c->client->userdata = c;
 
+    
     if (p->mode & PLAYBACK) {
         pa_sink_input_new_data data;
         size_t l;
@@ -372,11 +447,13 @@ static void on_connection(pa_socket_server*s, pa_iochannel *io, void *userdata)
                 (size_t) -1,
                 l/PLAYBACK_BUFFER_FRAGMENTS,
                 NULL);
-        assert(c->input_memblockq);
+        pa_assert(c->input_memblockq);
         pa_iochannel_socket_set_rcvbuf(io, l/PLAYBACK_BUFFER_FRAGMENTS*5);
         c->playback.fragment_size = l/10;
 
-        pa_sink_notify(c->sink_input->sink);
+        pa_atomic_store(&c->playback.missing, pa_memblockq_missing(c->input_memblockq));
+
+        pa_sink_input_put(c->sink_input);
     }
 
     if (p->mode & RECORD) {
@@ -409,16 +486,14 @@ static void on_connection(pa_socket_server*s, pa_iochannel *io, void *userdata)
                 0,
                 NULL);
         pa_iochannel_socket_set_sndbuf(io, l/RECORD_BUFFER_FRAGMENTS*2);
-        pa_source_notify(c->source_output->source);
+
+        pa_source_output_put(c->source_output);
     }
 
+
     pa_iochannel_set_callback(c->io, io_callback, c);
     pa_idxset_put(p->connections, c, NULL);
-
-    c->defer_event = p->core->mainloop->defer_new(p->core->mainloop, defer_callback, c);
-    assert(c->defer_event);
-    p->core->mainloop->defer_enable(c->defer_event, 0);
-
+    
     return;
 
 fail:
@@ -426,16 +501,60 @@ fail:
         connection_free(c);
 }
 
+static void asyncmsgq_cb(pa_mainloop_api*api, pa_io_event* e, int fd, pa_io_event_flags_t events, void *userdata) {
+    pa_protocol_simple *p = userdata;
+    int do_some_work = 0;
+    
+    pa_assert(pa_asyncmsgq_get_fd(p->asyncmsgq) == fd);
+    pa_assert(events == PA_IO_EVENT_INPUT);
+
+    pa_asyncmsgq_after_poll(p->asyncmsgq);
+
+    for (;;) {
+        int code;
+        void *object, *data;
+
+        /* Check whether there is a message for us to process */
+        while (pa_asyncmsgq_get(p->asyncmsgq, &object, &code, &data) == 0) {
+
+            connection *c = object;
+
+            pa_assert(c);
+            
+            switch (code) {
+
+                case MESSAGE_REQUEST_DATA:
+                    do_work(c);
+                    break;
+
+                case MESSAGE_POST_DATA:
+                    pa_memblockq_push(c->output_memblockq, chunk);
+                    do_work(c);
+                    break;
+            }
+
+            pa_asyncmsgq_done(p->asyncmsgq);
+        }
+        
+        if (pa_asyncmsgq_before_poll(p->asyncmsgq) == 0)
+            break;
+    }
+}
+
 pa_protocol_simple* pa_protocol_simple_new(pa_core *core, pa_socket_server *server, pa_module *m, pa_modargs *ma) {
     pa_protocol_simple* p = NULL;
     int enable;
-    assert(core && server && ma);
+    
+    pa_assert(core);
+    pa_assert(server);
+    pa_assert(ma);
 
-    p = pa_xmalloc0(sizeof(pa_protocol_simple));
+    p = pa_xnew0(pa_protocol_simple, 1);
     p->module = m;
     p->core = core;
     p->server = server;
     p->connections = pa_idxset_new(NULL, NULL);
+    pa_assert_se(p->asyncmsgq = pa_asyncmsgq_new(0));
 
     p->sample_spec = core->default_sample_spec;
     if (pa_modargs_get_sample_spec(ma, &p->sample_spec) < 0) {
@@ -467,18 +586,22 @@ pa_protocol_simple* pa_protocol_simple_new(pa_core *core, pa_socket_server *serv
 
     pa_socket_server_set_callback(p->server, on_connection, p);
 
+    pa_assert_se(pa_asyncmsgq_before_poll(p->asyncmsgq) == 0);
+    pa_assert_se(p->asyncmsgq_event = core->mainloop->io_event_new(core->mainloop, pa_asyncmsgq_get_fd(p->asyncmsgq), PA_IO_EVENT_INPUT, p));
+    
     return p;
 
 fail:
     if (p)
         pa_protocol_simple_free(p);
+    
     return NULL;
 }
 
 
 void pa_protocol_simple_free(pa_protocol_simple *p) {
     struct connection *c;
-    assert(p);
+    pa_assert(p);
 
     if (p->connections) {
         while((c = pa_idxset_first(p->connections, NULL)))
@@ -489,6 +612,13 @@ void pa_protocol_simple_free(pa_protocol_simple *p) {
 
     if (p->server)
         pa_socket_server_unref(p->server);
+
+    if (p->asyncmsgq) {
+        c->mainloop->io_event_free(c->asyncmsgq_event);
+        pa_asyncmsgq_after_poll(c->asyncmsgq);
+        pa_asyncmsgq_free(p->asyncmsgq);
+    }
+    
     pa_xfree(p);
 }
 
diff --git a/src/pulsecore/pstream.c b/src/pulsecore/pstream.c
index fdb1a66..f4aab1c 100644
--- a/src/pulsecore/pstream.c
+++ b/src/pulsecore/pstream.c
@@ -49,7 +49,6 @@
 #include <pulsecore/log.h>
 #include <pulsecore/core-scache.h>
 #include <pulsecore/creds.h>
-#include <pulsecore/mutex.h>
 #include <pulsecore/refcnt.h>
 
 #include "pstream.h"
@@ -118,8 +117,8 @@ struct pa_pstream {
     pa_mainloop_api *mainloop;
     pa_defer_event *defer_event;
     pa_iochannel *io;
+
     pa_queue *send_queue;
-    pa_mutex *mutex;
 
     int dead;
 
@@ -129,6 +128,7 @@ struct pa_pstream {
         uint32_t shm_info[PA_PSTREAM_SHM_MAX];
         void *data;
         size_t index;
+        pa_memchunk memchunk;
     } write;
 
     struct {
@@ -173,8 +173,6 @@ static void do_something(pa_pstream *p) {
 
     pa_pstream_ref(p);
 
-    pa_mutex_lock(p->mutex);
-
     p->mainloop->defer_enable(p->defer_event, 0);
 
     if (!p->dead && pa_iochannel_is_readable(p->io)) {
@@ -188,8 +186,6 @@ static void do_something(pa_pstream *p) {
             goto fail;
     }
 
-    pa_mutex_unlock(p->mutex);
-
     pa_pstream_unref(p);
     return;
 
@@ -200,8 +196,6 @@ fail:
     if (p->die_callback)
         p->die_callback(p, p->die_callback_userdata);
 
-    pa_mutex_unlock(p->mutex);
-
     pa_pstream_unref(p);
 }
 
@@ -214,16 +208,6 @@ static void io_callback(pa_iochannel*io, void *userdata) {
     do_something(p);
 }
 
-static void defer_callback(pa_mainloop_api *m, pa_defer_event *e, void*userdata) {
-    pa_pstream *p = userdata;
-
-    assert(p);
-    assert(p->defer_event == e);
-    assert(p->mainloop == m);
-
-    do_something(p);
-}
-
 static void memimport_release_cb(pa_memimport *i, uint32_t block_id, void *userdata);
 
 pa_pstream *pa_pstream_new(pa_mainloop_api *m, pa_iochannel *io, pa_mempool *pool) {
@@ -239,17 +223,14 @@ pa_pstream *pa_pstream_new(pa_mainloop_api *m, pa_iochannel *io, pa_mempool *poo
     pa_iochannel_set_callback(io, io_callback, p);
     p->dead = 0;
 
-    p->mutex = pa_mutex_new(1);
-
     p->mainloop = m;
-    p->defer_event = m->defer_new(m, defer_callback, p);
-    m->defer_enable(p->defer_event, 0);
 
     p->send_queue = pa_queue_new();
     assert(p->send_queue);
 
     p->write.current = NULL;
     p->write.index = 0;
+    pa_memchunk_reset(&p->write.memchunk);
     p->read.memblock = NULL;
     p->read.packet = NULL;
     p->read.index = 0;
@@ -312,8 +293,8 @@ static void pstream_free(pa_pstream *p) {
     if (p->read.packet)
         pa_packet_unref(p->read.packet);
 
-    if (p->mutex)
-        pa_mutex_free(p->mutex);
+    if (p->write.memchunk.memblock)
+        pa_memblock_unref(p->write.memchunk.memblock);
 
     pa_xfree(p);
 }
@@ -325,10 +306,8 @@ void pa_pstream_send_packet(pa_pstream*p, pa_packet *packet, const pa_creds *cre
     assert(PA_REFCNT_VALUE(p) > 0);
     assert(packet);
 
-    pa_mutex_lock(p->mutex);
-
     if (p->dead)
-        goto finish;
+        return;
 
     i = pa_xnew(struct item_info, 1);
     i->type = PA_PSTREAM_ITEM_PACKET;
@@ -340,11 +319,6 @@ void pa_pstream_send_packet(pa_pstream*p, pa_packet *packet, const pa_creds *cre
 #endif
 
     pa_queue_push(p->send_queue, i);
-    p->mainloop->defer_enable(p->defer_event, 1);
-
-finish:
-
-    pa_mutex_unlock(p->mutex);
 }
 
 void pa_pstream_send_memblock(pa_pstream*p, uint32_t channel, int64_t offset, pa_seek_mode_t seek_mode, const pa_memchunk *chunk) {
@@ -355,12 +329,9 @@ void pa_pstream_send_memblock(pa_pstream*p, uint32_t channel, int64_t offset, pa
     assert(channel != (uint32_t) -1);
     assert(chunk);
 
-    pa_mutex_lock(p->mutex);
-
     if (p->dead)
-        goto finish;
+        return;
 
-    length = chunk->length;
     idx = 0;
 
     while (length > 0) {
@@ -389,10 +360,6 @@ void pa_pstream_send_memblock(pa_pstream*p, uint32_t channel, int64_t offset, pa
     }
 
     p->mainloop->defer_enable(p->defer_event, 1);
-
-finish:
-
-    pa_mutex_unlock(p->mutex);
 }
 
 static void memimport_release_cb(pa_memimport *i, uint32_t block_id, void *userdata) {
@@ -402,10 +369,8 @@ static void memimport_release_cb(pa_memimport *i, uint32_t block_id, void *userd
     assert(p);
     assert(PA_REFCNT_VALUE(p) > 0);
 
-    pa_mutex_lock(p->mutex);
-
     if (p->dead)
-        goto finish;
+        return;
 
 /*     pa_log("Releasing block %u", block_id); */
 
@@ -417,11 +382,6 @@ static void memimport_release_cb(pa_memimport *i, uint32_t block_id, void *userd
 #endif
 
     pa_queue_push(p->send_queue, item);
-    p->mainloop->defer_enable(p->defer_event, 1);
-
-finish:
-
-    pa_mutex_unlock(p->mutex);
 }
 
 static void memexport_revoke_cb(pa_memexport *e, uint32_t block_id, void *userdata) {
@@ -431,11 +391,8 @@ static void memexport_revoke_cb(pa_memexport *e, uint32_t block_id, void *userda
     assert(p);
     assert(PA_REFCNT_VALUE(p) > 0);
 
-    pa_mutex_lock(p->mutex);
-
     if (p->dead)
-        goto finish;
-
+        return;
 /*     pa_log("Revoking block %u", block_id); */
 
     item = pa_xnew(struct item_info, 1);
@@ -446,22 +403,20 @@ static void memexport_revoke_cb(pa_memexport *e, uint32_t block_id, void *userda
 #endif
 
     pa_queue_push(p->send_queue, item);
-    p->mainloop->defer_enable(p->defer_event, 1);
-
-finish:
-
-    pa_mutex_unlock(p->mutex);
 }
 
 static void prepare_next_write_item(pa_pstream *p) {
     assert(p);
     assert(PA_REFCNT_VALUE(p) > 0);
 
-    if (!(p->write.current = pa_queue_pop(p->send_queue)))
+    p->write.current = pa_queue_pop(p->send_queue);
+
+    if (!p->write.current)
         return;
 
     p->write.index = 0;
     p->write.data = NULL;
+    pa_memchunk_reset(&p->write.memchunk);
 
     p->write.descriptor[PA_PSTREAM_DESCRIPTOR_LENGTH] = 0;
     p->write.descriptor[PA_PSTREAM_DESCRIPTOR_CHANNEL] = htonl((uint32_t) -1);
@@ -528,7 +483,9 @@ static void prepare_next_write_item(pa_pstream *p) {
 
         if (send_payload) {
             p->write.descriptor[PA_PSTREAM_DESCRIPTOR_LENGTH] = htonl(p->write.current->chunk.length);
-            p->write.data = (uint8_t*) p->write.current->chunk.memblock->data + p->write.current->chunk.index;
+            p->write.memchunk = p->write.current->chunk;
+            pa_memblock_ref(p->write.memchunk.memblock);
+            p->write.data = NULL;
         }
 
         p->write.descriptor[PA_PSTREAM_DESCRIPTOR_FLAGS] = htonl(flags);
@@ -544,6 +501,7 @@ static int do_write(pa_pstream *p) {
     void *d;
     size_t l;
     ssize_t r;
+    pa_memblock *release_memblock = NULL;
 
     assert(p);
     assert(PA_REFCNT_VALUE(p) > 0);
@@ -558,9 +516,16 @@ static int do_write(pa_pstream *p) {
         d = (uint8_t*) p->write.descriptor + p->write.index;
         l = PA_PSTREAM_DESCRIPTOR_SIZE - p->write.index;
     } else {
-        assert(p->write.data);
+        assert(p->write.data || p->write.memchunk.memblock);
+
+        if (p->write.data)
+            d = p->write.data;
+        else {
+            d = (uint8_t*) pa_memblock_acquire(p->write.memchunk.memblock) + p->write.memchunk.index;
+            release_memblock = p->write.memchunk.memblock;
+        }
 
-        d = (uint8_t*) p->write.data + p->write.index - PA_PSTREAM_DESCRIPTOR_SIZE;
+        d = (uint8_t*) d + p->write.index - PA_PSTREAM_DESCRIPTOR_SIZE;
         l = ntohl(p->write.descriptor[PA_PSTREAM_DESCRIPTOR_LENGTH]) - (p->write.index - PA_PSTREAM_DESCRIPTOR_SIZE);
     }
 
@@ -570,14 +535,17 @@ static int do_write(pa_pstream *p) {
     if (p->send_creds_now) {
 
         if ((r = pa_iochannel_write_with_creds(p->io, d, l, &p->write_creds)) < 0)
-            return -1;
+            goto fail;
 
         p->send_creds_now = 0;
     } else
 #endif
 
     if ((r = pa_iochannel_write(p->io, d, l)) < 0)
-        return -1;
+        goto fail;
+
+    if (release_memblock)
+        pa_memblock_release(release_memblock);
 
     p->write.index += r;
 
@@ -591,13 +559,20 @@ static int do_write(pa_pstream *p) {
     }
 
     return 0;
+
+fail:
+
+    if (release_memblock)
+        pa_memblock_release(release_memblock);
+
+    return -1;
 }
 
 static int do_read(pa_pstream *p) {
     void *d;
     size_t l;
     ssize_t r;
-
+    pa_memblock *release_memblock = NULL;
     assert(p);
     assert(PA_REFCNT_VALUE(p) > 0);
 
@@ -605,8 +580,16 @@ static int do_read(pa_pstream *p) {
         d = (uint8_t*) p->read.descriptor + p->read.index;
         l = PA_PSTREAM_DESCRIPTOR_SIZE - p->read.index;
     } else {
-        assert(p->read.data);
-        d = (uint8_t*) p->read.data + p->read.index - PA_PSTREAM_DESCRIPTOR_SIZE;
+        assert(p->read.data || p->read.memblock);
+
+        if (p->read.data)
+            d = p->read.data;
+        else {
+            d = pa_memblock_acquire(p->read.memblock);
+            release_memblock = p->read.memblock;
+        }
+
+        d = (uint8_t*) d + p->read.index - PA_PSTREAM_DESCRIPTOR_SIZE;
         l = ntohl(p->read.descriptor[PA_PSTREAM_DESCRIPTOR_LENGTH]) - (p->read.index - PA_PSTREAM_DESCRIPTOR_SIZE);
     }
 
@@ -615,15 +598,18 @@ static int do_read(pa_pstream *p) {
         int b = 0;
 
         if ((r = pa_iochannel_read_with_creds(p->io, d, l, &p->read_creds, &b)) <= 0)
-            return -1;
+            goto fail;
 
         p->read_creds_valid = p->read_creds_valid || b;
     }
 #else
     if ((r = pa_iochannel_read(p->io, d, l)) <= 0)
-        return -1;
+        goto fail;
 #endif
 
+    if (release_memblock)
+        pa_memblock_release(release_memblock);
+
     p->read.index += r;
 
     if (p->read.index == PA_PSTREAM_DESCRIPTOR_SIZE) {
@@ -704,7 +690,7 @@ static int do_read(pa_pstream *p) {
                 /* Frame is a memblock frame */
 
                 p->read.memblock = pa_memblock_new(p->mempool, length);
-                p->read.data = p->read.memblock->data;
+                p->read.data = NULL;
             } else {
 
                 pa_log_warn("Recieved memblock frame with invalid flags value.");
@@ -791,7 +777,7 @@ static int do_read(pa_pstream *p) {
 
                     chunk.memblock = b;
                     chunk.index = 0;
-                    chunk.length = b->length;
+                    chunk.length = pa_memblock_get_length(b);
 
                     offset = (int64_t) (
                             (((uint64_t) ntohl(p->read.descriptor[PA_PSTREAM_DESCRIPTOR_OFFSET_HI])) << 32) |
@@ -819,52 +805,51 @@ frame_done:
     p->read.memblock = NULL;
     p->read.packet = NULL;
     p->read.index = 0;
+    p->read.data = NULL;
 
 #ifdef HAVE_CREDS
     p->read_creds_valid = 0;
 #endif
 
     return 0;
+
+fail:
+    if (release_memblock)
+        pa_memblock_release(release_memblock);
+
+    return -1;
 }
 
 void pa_pstream_set_die_callback(pa_pstream *p, pa_pstream_notify_cb_t cb, void *userdata) {
     assert(p);
     assert(PA_REFCNT_VALUE(p) > 0);
 
-    pa_mutex_lock(p->mutex);
     p->die_callback = cb;
     p->die_callback_userdata = userdata;
-    pa_mutex_unlock(p->mutex);
 }
 
 void pa_pstream_set_drain_callback(pa_pstream *p, pa_pstream_notify_cb_t cb, void *userdata) {
     assert(p);
     assert(PA_REFCNT_VALUE(p) > 0);
 
-    pa_mutex_lock(p->mutex);
     p->drain_callback = cb;
     p->drain_callback_userdata = userdata;
-    pa_mutex_unlock(p->mutex);
 }
 
 void pa_pstream_set_recieve_packet_callback(pa_pstream *p, pa_pstream_packet_cb_t cb, void *userdata) {
     assert(p);
     assert(PA_REFCNT_VALUE(p) > 0);
 
-    pa_mutex_lock(p->mutex);
     p->recieve_packet_callback = cb;
     p->recieve_packet_callback_userdata = userdata;
-    pa_mutex_unlock(p->mutex);
 }
 
 void pa_pstream_set_recieve_memblock_callback(pa_pstream *p, pa_pstream_memblock_cb_t cb, void *userdata) {
     assert(p);
     assert(PA_REFCNT_VALUE(p) > 0);
 
-    pa_mutex_lock(p->mutex);
     p->recieve_memblock_callback = cb;
     p->recieve_memblock_callback_userdata = userdata;
-    pa_mutex_unlock(p->mutex);
 }
 
 int pa_pstream_is_pending(pa_pstream *p) {
@@ -873,15 +858,11 @@ int pa_pstream_is_pending(pa_pstream *p) {
     assert(p);
     assert(PA_REFCNT_VALUE(p) > 0);
 
-    pa_mutex_lock(p->mutex);
-
     if (p->dead)
         b = 0;
     else
         b = p->write.current || !pa_queue_is_empty(p->send_queue);
 
-    pa_mutex_unlock(p->mutex);
-
     return b;
 }
 
@@ -904,8 +885,6 @@ pa_pstream* pa_pstream_ref(pa_pstream*p) {
 void pa_pstream_close(pa_pstream *p) {
     assert(p);
 
-    pa_mutex_lock(p->mutex);
-
     p->dead = 1;
 
     if (p->import) {
@@ -923,25 +902,16 @@ void pa_pstream_close(pa_pstream *p) {
         p->io = NULL;
     }
 
-    if (p->defer_event) {
-        p->mainloop->defer_free(p->defer_event);
-        p->defer_event = NULL;
-    }
-
     p->die_callback = NULL;
     p->drain_callback = NULL;
     p->recieve_packet_callback = NULL;
     p->recieve_memblock_callback = NULL;
-
-    pa_mutex_unlock(p->mutex);
 }
 
 void pa_pstream_use_shm(pa_pstream *p, int enable) {
     assert(p);
     assert(PA_REFCNT_VALUE(p) > 0);
 
-    pa_mutex_lock(p->mutex);
-
     p->use_shm = enable;
 
     if (enable) {
@@ -956,6 +926,4 @@ void pa_pstream_use_shm(pa_pstream *p, int enable) {
             p->export = NULL;
         }
     }
-
-    pa_mutex_unlock(p->mutex);
 }
diff --git a/src/pulsecore/refcnt.h b/src/pulsecore/refcnt.h
index 43433ff..64271ab 100644
--- a/src/pulsecore/refcnt.h
+++ b/src/pulsecore/refcnt.h
@@ -27,18 +27,18 @@
 #include <pulsecore/atomic.h>
 
 #define PA_REFCNT_DECLARE \
-  pa_atomic_int_t _ref
+    pa_atomic_t _ref
 
 #define PA_REFCNT_INIT(p) \
-  pa_atomic_store(&p->_ref, 1)
+    pa_atomic_store(&(p)->_ref, 1)
 
 #define PA_REFCNT_INC(p) \
-  pa_atomic_inc(&p->_ref)
+    pa_atomic_inc(&(p)->_ref)
 
 #define PA_REFCNT_DEC(p) \
-  (pa_atomic_dec(&p->_ref)-1)
+    (pa_atomic_dec(&(p)->_ref)-1)
 
 #define PA_REFCNT_VALUE(p) \
-  pa_atomic_load(&p->_ref)
+    pa_atomic_load(&(p)->_ref)
 
 #endif
diff --git a/src/pulsecore/resampler.c b/src/pulsecore/resampler.c
index 3827ff9..248d733 100644
--- a/src/pulsecore/resampler.c
+++ b/src/pulsecore/resampler.c
@@ -53,8 +53,7 @@ struct pa_resampler {
 };
 
 struct impl_libsamplerate {
-    pa_memblock *buf1_block, *buf2_block, *buf3_block, *buf4_block;
-    float* buf1, *buf2, *buf3, *buf4;
+    pa_memchunk buf1, buf2, buf3, buf4;
     unsigned buf1_samples, buf2_samples, buf3_samples, buf4_samples;
 
     pa_convert_to_float32ne_func_t to_float32ne_func;
@@ -226,14 +225,14 @@ static void libsamplerate_free(pa_resampler *r) {
     if (u->src_state)
         src_delete(u->src_state);
 
-    if (u->buf1_block)
-        pa_memblock_unref(u->buf1_block);
-    if (u->buf2_block)
-        pa_memblock_unref(u->buf2_block);
-    if (u->buf3_block)
-        pa_memblock_unref(u->buf3_block);
-    if (u->buf4_block)
-        pa_memblock_unref(u->buf4_block);
+    if (u->buf1.memblock)
+        pa_memblock_unref(u->buf1.memblock);
+    if (u->buf2.memblock)
+        pa_memblock_unref(u->buf2.memblock);
+    if (u->buf3.memblock)
+        pa_memblock_unref(u->buf3.memblock);
+    if (u->buf4.memblock)
+        pa_memblock_unref(u->buf4.memblock);
     pa_xfree(u);
 }
 
@@ -272,64 +271,80 @@ static void calc_map_table(pa_resampler *r) {
     }
 }
 
-static float * convert_to_float(pa_resampler *r, void *input, unsigned n_frames) {
+static pa_memchunk* convert_to_float(pa_resampler *r, pa_memchunk *input) {
     struct impl_libsamplerate *u;
     unsigned n_samples;
+    void *src, *dst;
 
     assert(r);
     assert(input);
+    assert(input->memblock);
+
     assert(r->impl_data);
     u = r->impl_data;
 
     /* Convert the incoming sample into floats and place them in buf1 */
 
-    if (!u->to_float32ne_func)
+    if (!u->to_float32ne_func || !input->length)
         return input;
 
-    n_samples = n_frames * r->i_ss.channels;
+    n_samples = (input->length / r->i_fz) * r->i_ss.channels;
 
-    if (u->buf1_samples < n_samples) {
-        if (u->buf1_block)
-            pa_memblock_unref(u->buf1_block);
+    if (!u->buf1.memblock || u->buf1_samples < n_samples) {
+        if (u->buf1.memblock)
+            pa_memblock_unref(u->buf1.memblock);
 
         u->buf1_samples = n_samples;
-        u->buf1_block = pa_memblock_new(r->mempool, sizeof(float) * n_samples);
-        u->buf1 = u->buf1_block->data;
+        u->buf1.memblock = pa_memblock_new(r->mempool, u->buf1.length = sizeof(float) * n_samples);
+        u->buf1.index = 0;
     }
 
-    u->to_float32ne_func(n_samples, input, u->buf1);
+    src = (uint8_t*) pa_memblock_acquire(input->memblock) + input->index;
+    dst = (uint8_t*) pa_memblock_acquire(u->buf1.memblock);
+    u->to_float32ne_func(n_samples, src, dst);
+    pa_memblock_release(input->memblock);
+    pa_memblock_release(u->buf1.memblock);
+
+    u->buf1.length = sizeof(float) * n_samples;
 
-    return u->buf1;
+    return &u->buf1;
 }
 
-static float *remap_channels(pa_resampler *r, float *input, unsigned n_frames) {
+static pa_memchunk *remap_channels(pa_resampler *r, pa_memchunk *input) {
     struct impl_libsamplerate *u;
-    unsigned n_samples;
+    unsigned n_samples, n_frames;
     int i_skip, o_skip;
     unsigned oc;
+    float *src, *dst;
 
     assert(r);
     assert(input);
+    assert(input->memblock);
+
     assert(r->impl_data);
     u = r->impl_data;
 
     /* Remap channels and place the result int buf2 */
 
-    if (!u->map_required)
+    if (!u->map_required || !input->length)
         return input;
 
-    n_samples = n_frames * r->o_ss.channels;
+    n_samples = input->length / sizeof(float);
+    n_frames = n_samples / r->o_ss.channels;
 
-    if (u->buf2_samples < n_samples) {
-        if (u->buf2_block)
-            pa_memblock_unref(u->buf2_block);
+    if (!u->buf2.memblock || u->buf2_samples < n_samples) {
+        if (u->buf2.memblock)
+            pa_memblock_unref(u->buf2.memblock);
 
         u->buf2_samples = n_samples;
-        u->buf2_block = pa_memblock_new(r->mempool, sizeof(float) * n_samples);
-        u->buf2 = u->buf2_block->data;
+        u->buf2.memblock = pa_memblock_new(r->mempool, u->buf2.length = sizeof(float) * n_samples);
+        u->buf2.index = 0;
     }
 
-    memset(u->buf2, 0, n_samples * sizeof(float));
+    src = (float*) ((uint8_t*) pa_memblock_acquire(input->memblock) + input->index);
+    dst = (float*) pa_memblock_acquire(u->buf2.memblock);
+
+    memset(dst, 0, n_samples * sizeof(float));
 
     o_skip = sizeof(float) * r->o_ss.channels;
     i_skip = sizeof(float) * r->i_ss.channels;
@@ -340,49 +355,57 @@ static float *remap_channels(pa_resampler *r, float *input, unsigned n_frames) {
 
         for (i = 0; i < PA_CHANNELS_MAX && u->map_table[oc][i] >= 0; i++)
             oil_vectoradd_f32(
-                u->buf2 + oc, o_skip,
-                u->buf2 + oc, o_skip,
-                input + u->map_table[oc][i], i_skip,
+                dst + oc, o_skip,
+                dst + oc, o_skip,
+                src + u->map_table[oc][i], i_skip,
                 n_frames,
                 &one, &one);
     }
 
-    return u->buf2;
+    pa_memblock_release(input->memblock);
+    pa_memblock_release(u->buf2.memblock);
+
+    u->buf2.length = n_frames * sizeof(float) * r->o_ss.channels;
+
+    return &u->buf2;
 }
 
-static float *resample(pa_resampler *r, float *input, unsigned *n_frames) {
+static pa_memchunk *resample(pa_resampler *r, pa_memchunk *input) {
     struct impl_libsamplerate *u;
     SRC_DATA data;
+    unsigned in_n_frames, in_n_samples;
     unsigned out_n_frames, out_n_samples;
     int ret;
 
     assert(r);
     assert(input);
-    assert(n_frames);
     assert(r->impl_data);
     u = r->impl_data;
 
     /* Resample the data and place the result in buf3 */
 
-    if (!u->src_state)
+    if (!u->src_state || !input->length)
         return input;
 
-    out_n_frames = (*n_frames*r->o_ss.rate/r->i_ss.rate)+1024;
+    in_n_samples = input->length / sizeof(float);
+    in_n_frames = in_n_samples * r->o_ss.channels;
+
+    out_n_frames = (in_n_frames*r->o_ss.rate/r->i_ss.rate)+1024;
     out_n_samples = out_n_frames * r->o_ss.channels;
 
-    if (u->buf3_samples < out_n_samples) {
-        if (u->buf3_block)
-            pa_memblock_unref(u->buf3_block);
+    if (!u->buf3.memblock || u->buf3_samples < out_n_samples) {
+        if (u->buf3.memblock)
+            pa_memblock_unref(u->buf3.memblock);
 
         u->buf3_samples = out_n_samples;
-        u->buf3_block = pa_memblock_new(r->mempool, sizeof(float) * out_n_samples);
-        u->buf3 = u->buf3_block->data;
+        u->buf3.memblock = pa_memblock_new(r->mempool, u->buf3.length = sizeof(float) * out_n_samples);
+        u->buf3.index = 0;
     }
 
-    data.data_in = input;
-    data.input_frames = *n_frames;
+    data.data_in = (float*) ((uint8_t*) pa_memblock_acquire(input->memblock) + input->index);
+    data.input_frames = in_n_frames;
 
-    data.data_out = u->buf3;
+    data.data_out = (float*) pa_memblock_acquire(u->buf3.memblock);
     data.output_frames = out_n_frames;
 
     data.src_ratio = (double) r->o_ss.rate / r->i_ss.rate;
@@ -390,16 +413,20 @@ static float *resample(pa_resampler *r, float *input, unsigned *n_frames) {
 
     ret = src_process(u->src_state, &data);
     assert(ret == 0);
-    assert((unsigned) data.input_frames_used == *n_frames);
+    assert((unsigned) data.input_frames_used == in_n_frames);
 
-    *n_frames = data.output_frames_gen;
+    pa_memblock_release(input->memblock);
+    pa_memblock_release(u->buf3.memblock);
 
-    return u->buf3;
+    u->buf3.length = data.output_frames_gen * sizeof(float) * r->o_ss.channels;
+
+    return &u->buf3;
 }
 
-static void *convert_from_float(pa_resampler *r, float *input, unsigned n_frames) {
+static pa_memchunk *convert_from_float(pa_resampler *r, pa_memchunk *input) {
     struct impl_libsamplerate *u;
-    unsigned n_samples;
+    unsigned n_samples, n_frames;
+    void *src, *dst;
 
     assert(r);
     assert(input);
@@ -408,30 +435,35 @@ static void *convert_from_float(pa_resampler *r, float *input, unsigned n_frames
 
     /* Convert the data into the correct sample type and place the result in buf4 */
 
-    if (!u->from_float32ne_func)
+    if (!u->from_float32ne_func || !input->length)
         return input;
 
+    n_frames = input->length / sizeof(float) / r->o_ss.channels;
     n_samples = n_frames * r->o_ss.channels;
 
     if (u->buf4_samples < n_samples) {
-        if (u->buf4_block)
-            pa_memblock_unref(u->buf4_block);
+        if (u->buf4.memblock)
+            pa_memblock_unref(u->buf4.memblock);
 
         u->buf4_samples = n_samples;
-        u->buf4_block = pa_memblock_new(r->mempool, sizeof(float) * n_samples);
-        u->buf4 = u->buf4_block->data;
+        u->buf4.memblock = pa_memblock_new(r->mempool, u->buf4.length = r->o_fz * n_frames);
+        u->buf4.index = 0;
     }
 
-    u->from_float32ne_func(n_samples, input, u->buf4);
+    src = (uint8_t*) pa_memblock_acquire(input->memblock) + input->length;
+    dst = pa_memblock_acquire(u->buf4.memblock);
+    u->from_float32ne_func(n_samples, src, dst);
+    pa_memblock_release(input->memblock);
+    pa_memblock_release(u->buf4.memblock);
 
-    return u->buf4;
+    u->buf4.length = r->o_fz * n_frames;
+
+    return &u->buf4;
 }
 
 static void libsamplerate_run(pa_resampler *r, const pa_memchunk *in, pa_memchunk *out) {
     struct impl_libsamplerate *u;
-    float *buf;
-    void *input, *output;
-    unsigned n_frames;
+    pa_memchunk *buf;
 
     assert(r);
     assert(in);
@@ -443,55 +475,23 @@ static void libsamplerate_run(pa_resampler *r, const pa_memchunk *in, pa_memchun
 
     u = r->impl_data;
 
-    input = ((uint8_t*) in->memblock->data + in->index);
-    n_frames = in->length / r->i_fz;
-    assert(n_frames > 0);
-
-    buf = convert_to_float(r, input, n_frames);
-    buf = remap_channels(r, buf, n_frames);
-    buf = resample(r, buf, &n_frames);
-
-    if (n_frames) {
-        output = convert_from_float(r, buf, n_frames);
-
-        if (output == input) {
-            /* Mm, no adjustment has been necessary, so let's return the original block */
-            out->memblock = pa_memblock_ref(in->memblock);
-            out->index = in->index;
-            out->length = in->length;
-        } else {
-            out->length = n_frames * r->o_fz;
-            out->index = 0;
-            out->memblock = NULL;
-
-            if (output == u->buf1) {
-                u->buf1 = NULL;
-                u->buf1_samples = 0;
-                out->memblock = u->buf1_block;
-                u->buf1_block = NULL;
-            } else if (output == u->buf2) {
-                u->buf2 = NULL;
-                u->buf2_samples = 0;
-                out->memblock = u->buf2_block;
-                u->buf2_block = NULL;
-            } else if (output == u->buf3) {
-                u->buf3 = NULL;
-                u->buf3_samples = 0;
-                out->memblock = u->buf3_block;
-                u->buf3_block = NULL;
-            } else if (output == u->buf4) {
-                u->buf4 = NULL;
-                u->buf4_samples = 0;
-                out->memblock = u->buf4_block;
-                u->buf4_block = NULL;
-            }
-
-            assert(out->memblock);
-        }
-    } else {
-        out->memblock = NULL;
-        out->index = out->length = 0;
-    }
+    buf = convert_to_float(r, (pa_memchunk*) in);
+    buf = remap_channels(r, buf);
+    buf = resample(r, buf);
+
+    if (buf->length) {
+        buf = convert_from_float(r, buf);
+        *out = *buf;
+
+        if (buf == in)
+            pa_memblock_ref(buf->memblock);
+        else
+            pa_memchunk_reset(buf);
+    } else
+        pa_memchunk_reset(out);
+
+    pa_memblock_release(in->memblock);
+
 }
 
 static void libsamplerate_update_input_rate(pa_resampler *r, uint32_t rate) {
@@ -518,8 +518,10 @@ static int libsamplerate_init(pa_resampler *r) {
 
     r->impl_data = u = pa_xnew(struct impl_libsamplerate, 1);
 
-    u->buf1 = u->buf2 = u->buf3 = u->buf4 = NULL;
-    u->buf1_block = u->buf2_block = u->buf3_block = u->buf4_block = NULL;
+    pa_memchunk_reset(&u->buf1);
+    pa_memchunk_reset(&u->buf2);
+    pa_memchunk_reset(&u->buf3);
+    pa_memchunk_reset(&u->buf4);
     u->buf1_samples = u->buf2_samples = u->buf3_samples = u->buf4_samples = 0;
 
     if (r->i_ss.format == PA_SAMPLE_FLOAT32NE)
@@ -580,6 +582,7 @@ static void trivial_run(pa_resampler *r, const pa_memchunk *in, pa_memchunk *out
         /* Do real resampling */
         size_t l;
         unsigned o_index;
+        void *src, *dst;
 
         /* The length of the new memory block rounded up */
         l = ((((n_frames+1) * r->o_ss.rate) / r->i_ss.rate) + 1) * fz;
@@ -587,6 +590,9 @@ static void trivial_run(pa_resampler *r, const pa_memchunk *in, pa_memchunk *out
         out->index = 0;
         out->memblock = pa_memblock_new(r->mempool, l);
 
+        src = (uint8_t*) pa_memblock_acquire(in->memblock) + in->index;
+        dst = pa_memblock_acquire(out->memblock);
+
         for (o_index = 0;; o_index++, u->o_counter++) {
             unsigned j;
 
@@ -596,13 +602,16 @@ static void trivial_run(pa_resampler *r, const pa_memchunk *in, pa_memchunk *out
             if (j >= n_frames)
                 break;
 
-            assert(o_index*fz < out->memblock->length);
+            assert(o_index*fz < pa_memblock_get_length(out->memblock));
 
-            memcpy((uint8_t*) out->memblock->data + fz*o_index,
-                   (uint8_t*) in->memblock->data + in->index + fz*j, fz);
+            memcpy((uint8_t*) dst + fz*o_index,
+                   (uint8_t*) src + fz*j, fz);
 
         }
 
+        pa_memblock_release(in->memblock);
+        pa_memblock_release(out->memblock);
+
         out->length = o_index*fz;
     }
 
diff --git a/src/pulsecore/sample-util.c b/src/pulsecore/sample-util.c
index a997140..2e51427 100644
--- a/src/pulsecore/sample-util.c
+++ b/src/pulsecore/sample-util.c
@@ -61,15 +61,27 @@ pa_memblock *pa_silence_memblock_new(pa_mempool *pool, const pa_sample_spec *spe
 }
 
 pa_memblock *pa_silence_memblock(pa_memblock* b, const pa_sample_spec *spec) {
-    assert(b && b->data && spec);
-    pa_silence_memory(b->data, b->length, spec);
+    void *data;
+
+    assert(b);
+    assert(spec);
+
+    data = pa_memblock_acquire(b);
+    pa_silence_memory(data, pa_memblock_get_length(b), spec);
+    pa_memblock_release(b);
     return b;
 }
 
 void pa_silence_memchunk(pa_memchunk *c, const pa_sample_spec *spec) {
-    assert(c && c->memblock && c->memblock->data && spec && c->length);
+    void *data;
 
-    pa_silence_memory((uint8_t*) c->memblock->data+c->index, c->length, spec);
+    assert(c);
+    assert(c->memblock);
+    assert(spec);
+
+    data = pa_memblock_acquire(c->memblock);
+    pa_silence_memory((uint8_t*) data+c->index, c->length, spec);
+    pa_memblock_release(c->memblock);
 }
 
 void pa_silence_memory(void *p, size_t length, const pa_sample_spec *spec) {
@@ -98,26 +110,38 @@ void pa_silence_memory(void *p, size_t length, const pa_sample_spec *spec) {
 }
 
 size_t pa_mix(
-    const pa_mix_info streams[],
-    unsigned nstreams,
-    void *data,
-    size_t length,
-    const pa_sample_spec *spec,
-    const pa_cvolume *volume,
-    int mute) {
+        pa_mix_info streams[],
+        unsigned nstreams,
+        void *data,
+        size_t length,
+        const pa_sample_spec *spec,
+        const pa_cvolume *volume,
+        int mute) {
+
+    pa_cvolume full_volume;
+    size_t d = 0;
+    unsigned k;
+
+    assert(streams);
+    assert(data);
+    assert(length);
+    assert(spec);
 
-    assert(streams && data && length && spec);
+    if (!volume)
+        volume = pa_cvolume_reset(&full_volume, spec->channels);
+
+    for (k = 0; k < nstreams; k++)
+        streams[k].internal = pa_memblock_acquire(streams[k].chunk.memblock);
 
     switch (spec->format) {
         case PA_SAMPLE_S16NE:{
-            size_t d;
             unsigned channel = 0;
 
             for (d = 0;; d += sizeof(int16_t)) {
                 int32_t sum = 0;
 
                 if (d >= length)
-                    return d;
+                    goto finish;
 
                 if (!mute && volume->values[channel] != PA_VOLUME_MUTED) {
                     unsigned i;
@@ -127,12 +151,12 @@ size_t pa_mix(
                         pa_volume_t cvolume = streams[i].volume.values[channel];
 
                         if (d >= streams[i].chunk.length)
-                            return d;
+                            goto finish;
 
                         if (cvolume == PA_VOLUME_MUTED)
                             v = 0;
                         else {
-                            v = *((int16_t*) ((uint8_t*) streams[i].chunk.memblock->data + streams[i].chunk.index + d));
+                            v = *((int16_t*) ((uint8_t*) streams[i].internal + streams[i].chunk.index + d));
 
                             if (cvolume != PA_VOLUME_NORM)
                                 v = (int32_t) (v * pa_sw_volume_to_linear(cvolume));
@@ -155,17 +179,18 @@ size_t pa_mix(
                 if (++channel >= spec->channels)
                     channel = 0;
             }
+
+            break;
         }
 
         case PA_SAMPLE_S16RE:{
-            size_t d;
             unsigned channel = 0;
 
             for (d = 0;; d += sizeof(int16_t)) {
                 int32_t sum = 0;
 
                 if (d >= length)
-                    return d;
+                    goto finish;
 
                 if (!mute && volume->values[channel] != PA_VOLUME_MUTED) {
                     unsigned i;
@@ -175,12 +200,12 @@ size_t pa_mix(
                         pa_volume_t cvolume = streams[i].volume.values[channel];
 
                         if (d >= streams[i].chunk.length)
-                            return d;
+                            goto finish;
 
                         if (cvolume == PA_VOLUME_MUTED)
                             v = 0;
                         else {
-                            v = INT16_SWAP(*((int16_t*) ((uint8_t*) streams[i].chunk.memblock->data + streams[i].chunk.index + d)));
+                            v = INT16_SWAP(*((int16_t*) ((uint8_t*) streams[i].internal + streams[i].chunk.index + d)));
 
                             if (cvolume != PA_VOLUME_NORM)
                                 v = (int32_t) (v * pa_sw_volume_to_linear(cvolume));
@@ -203,17 +228,18 @@ size_t pa_mix(
                 if (++channel >= spec->channels)
                     channel = 0;
             }
+
+            break;
         }
 
         case PA_SAMPLE_U8: {
-            size_t d;
             unsigned channel = 0;
 
             for (d = 0;; d ++) {
                 int32_t sum = 0;
 
                 if (d >= length)
-                    return d;
+                    goto finish;
 
                 if (!mute && volume->values[channel] != PA_VOLUME_MUTED) {
                     unsigned i;
@@ -223,12 +249,12 @@ size_t pa_mix(
                         pa_volume_t cvolume = streams[i].volume.values[channel];
 
                         if (d >= streams[i].chunk.length)
-                            return d;
+                            goto finish;
 
                         if (cvolume == PA_VOLUME_MUTED)
                             v = 0;
                         else {
-                            v = (int32_t) *((uint8_t*) streams[i].chunk.memblock->data + streams[i].chunk.index + d) - 0x80;
+                            v = (int32_t) *((uint8_t*) streams[i].internal + streams[i].chunk.index + d) - 0x80;
 
                             if (cvolume != PA_VOLUME_NORM)
                                 v = (int32_t) (v * pa_sw_volume_to_linear(cvolume));
@@ -251,17 +277,18 @@ size_t pa_mix(
                 if (++channel >= spec->channels)
                     channel = 0;
             }
+
+            break;
         }
 
         case PA_SAMPLE_FLOAT32NE: {
-            size_t d;
             unsigned channel = 0;
 
             for (d = 0;; d += sizeof(float)) {
                 float sum = 0;
 
                 if (d >= length)
-                    return d;
+                    goto finish;
 
                 if (!mute && volume->values[channel] != PA_VOLUME_MUTED) {
                     unsigned i;
@@ -271,12 +298,12 @@ size_t pa_mix(
                         pa_volume_t cvolume = streams[i].volume.values[channel];
 
                         if (d >= streams[i].chunk.length)
-                            return d;
+                            goto finish;
 
                         if (cvolume == PA_VOLUME_MUTED)
                             v = 0;
                         else {
-                            v = *((float*) ((uint8_t*) streams[i].chunk.memblock->data + streams[i].chunk.index + d));
+                            v = *((float*) ((uint8_t*) streams[i].internal + streams[i].chunk.index + d));
 
                             if (cvolume != PA_VOLUME_NORM)
                                 v *= pa_sw_volume_to_linear(cvolume);
@@ -295,17 +322,34 @@ size_t pa_mix(
                 if (++channel >= spec->channels)
                     channel = 0;
             }
+
+            break;
         }
 
         default:
             pa_log_error("ERROR: Unable to mix audio data of format %s.", pa_sample_format_to_string(spec->format));
             abort();
     }
+
+finish:
+
+    for (k = 0; k < nstreams; k++)
+        pa_memblock_release(streams[k].chunk.memblock);
+
+    return d;
 }
 
 
-void pa_volume_memchunk(pa_memchunk*c, const pa_sample_spec *spec, const pa_cvolume *volume) {
-    assert(c && spec && (c->length % pa_frame_size(spec) == 0));
+void pa_volume_memchunk(
+        pa_memchunk*c,
+        const pa_sample_spec *spec,
+        const pa_cvolume *volume) {
+
+    void *ptr;
+
+    assert(c);
+    assert(spec);
+    assert(c->length % pa_frame_size(spec) == 0);
     assert(volume);
 
     if (pa_cvolume_channels_equal_to(volume, PA_VOLUME_NORM))
@@ -316,6 +360,8 @@ void pa_volume_memchunk(pa_memchunk*c, const pa_sample_spec *spec, const pa_cvol
         return;
     }
 
+    ptr = pa_memblock_acquire(c->memblock);
+
     switch (spec->format) {
         case PA_SAMPLE_S16NE: {
             int16_t *d;
@@ -326,7 +372,7 @@ void pa_volume_memchunk(pa_memchunk*c, const pa_sample_spec *spec, const pa_cvol
             for (channel = 0; channel < spec->channels; channel++)
                 linear[channel] = pa_sw_volume_to_linear(volume->values[channel]);
 
-            for (channel = 0, d = (int16_t*) ((uint8_t*) c->memblock->data+c->index), n = c->length/sizeof(int16_t); n > 0; d++, n--) {
+            for (channel = 0, d = (int16_t*) ((uint8_t*) ptr + c->index), n = c->length/sizeof(int16_t); n > 0; d++, n--) {
                 int32_t t = (int32_t)(*d);
 
                 t = (int32_t) (t * linear[channel]);
@@ -351,7 +397,7 @@ void pa_volume_memchunk(pa_memchunk*c, const pa_sample_spec *spec, const pa_cvol
             for (channel = 0; channel < spec->channels; channel++)
                 linear[channel] = pa_sw_volume_to_linear(volume->values[channel]);
 
-            for (channel = 0, d = (int16_t*) ((uint8_t*) c->memblock->data+c->index), n = c->length/sizeof(int16_t); n > 0; d++, n--) {
+            for (channel = 0, d = (int16_t*) ((uint8_t*) ptr + c->index), n = c->length/sizeof(int16_t); n > 0; d++, n--) {
                 int32_t t = (int32_t)(INT16_SWAP(*d));
 
                 t = (int32_t) (t * linear[channel]);
@@ -373,7 +419,7 @@ void pa_volume_memchunk(pa_memchunk*c, const pa_sample_spec *spec, const pa_cvol
             size_t n;
             unsigned channel = 0;
 
-            for (d = (uint8_t*) c->memblock->data + c->index, n = c->length; n > 0; d++, n--) {
+            for (d = (uint8_t*) ptr + c->index, n = c->length; n > 0; d++, n--) {
                 int32_t t = (int32_t) *d - 0x80;
 
                 t = (int32_t) (t * pa_sw_volume_to_linear(volume->values[channel]));
@@ -395,7 +441,7 @@ void pa_volume_memchunk(pa_memchunk*c, const pa_sample_spec *spec, const pa_cvol
             unsigned n;
             unsigned channel;
 
-            d = (float*) ((uint8_t*) c->memblock->data + c->index);
+            d = (float*) ((uint8_t*) ptr + c->index);
             skip = spec->channels * sizeof(float);
             n = c->length/sizeof(float)/spec->channels;
 
@@ -418,5 +464,7 @@ void pa_volume_memchunk(pa_memchunk*c, const pa_sample_spec *spec, const pa_cvol
                 pa_sample_format_to_string(spec->format));
             abort();
     }
+
+    pa_memblock_release(c->memblock);
 }
 
diff --git a/src/pulsecore/sample-util.h b/src/pulsecore/sample-util.h
index 3ff065a..2b11ad3 100644
--- a/src/pulsecore/sample-util.h
+++ b/src/pulsecore/sample-util.h
@@ -39,10 +39,11 @@ typedef struct pa_mix_info {
     pa_memchunk chunk;
     pa_cvolume volume;
     void *userdata;
+    void *internal; /* Used internally by pa_mix(), should not be initialised when calling pa_mix() */
 } pa_mix_info;
 
 size_t pa_mix(
-    const pa_mix_info channels[],
+    pa_mix_info channels[],
     unsigned nchannels,
     void *data,
     size_t length,
diff --git a/src/pulsecore/semaphore-posix.c b/src/pulsecore/semaphore-posix.c
new file mode 100644
index 0000000..71ec57a
--- /dev/null
+++ b/src/pulsecore/semaphore-posix.c
@@ -0,0 +1,69 @@
+/* $Id$ */
+
+/***
+  This file is part of PulseAudio.
+
+  Copyright 2006 Lennart Poettering
+
+  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 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.
+***/
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <errno.h>
+#include <pthread.h>
+#include <semaphore.h>
+
+#include <pulse/xmalloc.h>
+#include <pulsecore/macro.h>
+
+#include "semaphore.h"
+
+struct pa_semaphore {
+    sem_t sem;
+};
+
+pa_semaphore* pa_semaphore_new(unsigned value) {
+    pa_semaphore *s;
+
+    s = pa_xnew(pa_semaphore, 1);
+    pa_assert_se(sem_init(&s->sem, 0, value) == 0);
+    return s;
+}
+
+void pa_semaphore_free(pa_semaphore *s) {
+    pa_assert(s);
+    pa_assert_se(sem_destroy(&s->sem) == 0);
+    pa_xfree(s);
+}
+
+void pa_semaphore_post(pa_semaphore *s) {
+    pa_assert(s);
+    pa_assert_se(sem_post(&s->sem) == 0);
+}
+
+void pa_semaphore_wait(pa_semaphore *s) {
+    int ret;
+    pa_assert(s);
+    
+    do {
+        ret = sem_wait(&s->sem);
+    } while (ret < 0 && errno == EINTR);
+
+    pa_assert(ret == 0);
+}
diff --git a/src/pulsecore/semaphore.h b/src/pulsecore/semaphore.h
new file mode 100644
index 0000000..c394e0f
--- /dev/null
+++ b/src/pulsecore/semaphore.h
@@ -0,0 +1,35 @@
+#ifndef foopulsesemaphorehfoo
+#define foopulsesemaphorehfoo
+
+/* $Id$ */
+
+/***
+  This file is part of PulseAudio.
+
+  Copyright 2006 Lennart Poettering
+
+  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 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.
+***/
+
+typedef struct pa_semaphore pa_semaphore;
+
+pa_semaphore* pa_semaphore_new(unsigned value);
+void pa_semaphore_free(pa_semaphore *m);
+
+void pa_semaphore_post(pa_semaphore *m);
+void pa_semaphore_wait(pa_semaphore *m);
+
+#endif
diff --git a/src/pulsecore/sink-input.c b/src/pulsecore/sink-input.c
index 3ddd743..da7b58b 100644
--- a/src/pulsecore/sink-input.c
+++ b/src/pulsecore/sink-input.c
@@ -27,7 +27,6 @@
 #endif
 
 #include <stdio.h>
-#include <assert.h>
 #include <stdlib.h>
 #include <string.h>
 
@@ -46,41 +45,45 @@
 #define MOVE_BUFFER_LENGTH (1024*1024)
 #define SILENCE_BUFFER_LENGTH (64*1024)
 
-#define CHECK_VALIDITY_RETURN_NULL(condition) \
-do {\
-if (!(condition)) \
-    return NULL; \
-} while (0)
+static void sink_input_free(pa_msgobject *o);
 
 pa_sink_input_new_data* pa_sink_input_new_data_init(pa_sink_input_new_data *data) {
-    assert(data);
+    pa_assert(data);
 
     memset(data, 0, sizeof(*data));
     data->resample_method = PA_RESAMPLER_INVALID;
+    
     return data;
 }
 
 void pa_sink_input_new_data_set_channel_map(pa_sink_input_new_data *data, const pa_channel_map *map) {
-    assert(data);
+    pa_assert(data);
 
     if ((data->channel_map_is_set = !!map))
         data->channel_map = *map;
 }
 
 void pa_sink_input_new_data_set_volume(pa_sink_input_new_data *data, const pa_cvolume *volume) {
-    assert(data);
+    pa_assert(data);
 
     if ((data->volume_is_set = !!volume))
         data->volume = *volume;
 }
 
 void pa_sink_input_new_data_set_sample_spec(pa_sink_input_new_data *data, const pa_sample_spec *spec) {
-    assert(data);
+    pa_assert(data);
 
     if ((data->sample_spec_is_set = !!spec))
         data->sample_spec = *spec;
 }
 
+void pa_sink_input_new_data_set_muted(pa_sink_input_new_data *data, int mute) {
+    pa_assert(data);
+
+    data->muted_is_set = 1;
+    data->muted = !!mute;
+}
+
 pa_sink_input* pa_sink_input_new(
         pa_core *core,
         pa_sink_input_new_data *data,
@@ -88,46 +91,52 @@ pa_sink_input* pa_sink_input_new(
 
     pa_sink_input *i;
     pa_resampler *resampler = NULL;
-    int r;
     char st[PA_SAMPLE_SPEC_SNPRINT_MAX];
 
-    assert(core);
-    assert(data);
+    pa_assert(core);
+    pa_assert(data);
 
     if (!(flags & PA_SINK_INPUT_NO_HOOKS))
         if (pa_hook_fire(&core->hook_sink_input_new, data) < 0)
             return NULL;
 
-    CHECK_VALIDITY_RETURN_NULL(!data->driver || pa_utf8_valid(data->driver));
-    CHECK_VALIDITY_RETURN_NULL(!data->name || pa_utf8_valid(data->name));
+    pa_return_null_if_fail(!data->driver || pa_utf8_valid(data->driver));
+    pa_return_null_if_fail(!data->name || pa_utf8_valid(data->name));
 
     if (!data->sink)
         data->sink = pa_namereg_get(core, NULL, PA_NAMEREG_SINK, 1);
 
-    CHECK_VALIDITY_RETURN_NULL(data->sink);
-    CHECK_VALIDITY_RETURN_NULL(data->sink->state == PA_SINK_RUNNING);
+    pa_return_null_if_fail(data->sink);
+    pa_return_null_if_fail(pa_sink_get_state(data->sink) != PA_SINK_DISCONNECTED);
 
     if (!data->sample_spec_is_set)
         data->sample_spec = data->sink->sample_spec;
 
-    CHECK_VALIDITY_RETURN_NULL(pa_sample_spec_valid(&data->sample_spec));
+    pa_return_null_if_fail(pa_sample_spec_valid(&data->sample_spec));
 
-    if (!data->channel_map_is_set)
-        pa_channel_map_init_auto(&data->channel_map, data->sample_spec.channels, PA_CHANNEL_MAP_DEFAULT);
+    if (!data->channel_map_is_set) {
+        if (data->sink->channel_map.channels == data->sample_spec.channels)
+            data->channel_map = data->sink->channel_map;
+        else 
+            pa_channel_map_init_auto(&data->channel_map, data->sample_spec.channels, PA_CHANNEL_MAP_DEFAULT);
+    }
 
-    CHECK_VALIDITY_RETURN_NULL(pa_channel_map_valid(&data->channel_map));
-    CHECK_VALIDITY_RETURN_NULL(data->channel_map.channels == data->sample_spec.channels);
+    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)
         pa_cvolume_reset(&data->volume, data->sample_spec.channels);
 
-    CHECK_VALIDITY_RETURN_NULL(pa_cvolume_valid(&data->volume));
-    CHECK_VALIDITY_RETURN_NULL(data->volume.channels == data->sample_spec.channels);
+    pa_return_null_if_fail(pa_cvolume_valid(&data->volume));
+    pa_return_null_if_fail(data->volume.channels == data->sample_spec.channels);
 
+    if (!data->muted_is_set)
+        data->muted = 0;
+    
     if (data->resample_method == PA_RESAMPLER_INVALID)
         data->resample_method = core->resample_method;
 
-    CHECK_VALIDITY_RETURN_NULL(data->resample_method < PA_RESAMPLER_MAX);
+    pa_return_null_if_fail(data->resample_method < PA_RESAMPLER_MAX);
 
     if (pa_idxset_size(data->sink->inputs) >= PA_MAX_INPUTS_PER_SINK) {
         pa_log_warn("Failed to create sink input: too many inputs per sink.");
@@ -136,7 +145,7 @@ pa_sink_input* pa_sink_input_new(
 
     if ((flags & PA_SINK_INPUT_VARIABLE_RATE) ||
         !pa_sample_spec_equal(&data->sample_spec, &data->sink->sample_spec) ||
-        !pa_channel_map_equal(&data->channel_map, &data->sink->channel_map))
+        !pa_channel_map_equal(&data->channel_map, &data->sink->channel_map)) {
 
         if (!(resampler = pa_resampler_new(
                       core->mempool,
@@ -147,20 +156,31 @@ pa_sink_input* pa_sink_input_new(
             return NULL;
         }
 
-    i = pa_xnew(pa_sink_input, 1);
-    i->ref = 1;
-    i->state = PA_SINK_INPUT_DRAINED;
+        data->resample_method = pa_resampler_get_method(resampler);
+    }
+
+    i = pa_msgobject_new(pa_sink_input);
+
+    i->parent.parent.free = sink_input_free;
+    i->parent.process_msg = pa_sink_input_process_msg;
+    
+    i->core = core;
+    pa_atomic_load(&i->state, PA_SINK_INPUT_DRAINED);
     i->flags = flags;
     i->name = pa_xstrdup(data->name);
     i->driver = pa_xstrdup(data->driver);
     i->module = data->module;
     i->sink = data->sink;
     i->client = data->client;
-
+    
+    i->resample_method = data->resample_method;
     i->sample_spec = data->sample_spec;
     i->channel_map = data->channel_map;
-    i->volume = data->volume;
 
+    i->volume = data->volume;
+    i->muted = data->muted;
+    
+    i->process_msg = NULL;
     i->peek = NULL;
     i->drop = NULL;
     i->kill = NULL;
@@ -168,94 +188,87 @@ pa_sink_input* pa_sink_input_new(
     i->underrun = NULL;
     i->userdata = NULL;
 
-    i->move_silence = 0;
+    i->thread_info.silence_memblock = NULL;
+    i->thread_info.move_silence = 0;
+    pa_memchunk_reset(&i->thread_info.resampled_chunk);
+    i->thread_info.resampler = resampler;
+    i->thread_info.soft_volume = i->volume;
+    i->thread_info.soft_muted = i->muted;
 
-    pa_memchunk_reset(&i->resampled_chunk);
-    i->resampler = resampler;
-    i->resample_method = data->resample_method;
-    i->silence_memblock = NULL;
+    pa_assert_se(pa_idxset_put(core->sink_inputs, i, &i->index) == 0);
+    pa_assert_se(pa_idxset_put(i->sink->inputs, i, NULL) == 0);
 
-    r = pa_idxset_put(core->sink_inputs, i, &i->index);
-    assert(r == 0);
-    r = pa_idxset_put(i->sink->inputs, i, NULL);
-    assert(r == 0);
-
-    pa_log_info("created %u \"%s\" on %s with sample spec %s",
+    pa_log_info("Created input %u \"%s\" on %s with sample spec %s",
                 i->index,
                 i->name,
                 i->sink->name,
                 pa_sample_spec_snprint(st, sizeof(st), &i->sample_spec));
 
-    pa_subscription_post(core, PA_SUBSCRIPTION_EVENT_SINK_INPUT|PA_SUBSCRIPTION_EVENT_NEW, i->index);
-
-    /* We do not call pa_sink_notify() here, because the virtual
-     * functions have not yet been initialized */
+    /* Don't forget to call pa_sink_input_put! */
 
     return i;
 }
 
 void pa_sink_input_disconnect(pa_sink_input *i) {
-    assert(i);
-    assert(i->state != PA_SINK_INPUT_DISCONNECTED);
-    assert(i->sink);
-    assert(i->sink->core);
+    pa_assert(i);
+    pa_return_if_fail(pa_sink_input_get_state(i) != PA_SINK_INPUT_DISCONNECTED);
 
+    pa_asyncmsgq_send(i->sink->asyncmsgq, i->sink, PA_SINK_MESSAGE_REMOVE_INPUT, i, NULL);
+    
     pa_idxset_remove_by_data(i->sink->core->sink_inputs, i, NULL);
     pa_idxset_remove_by_data(i->sink->inputs, i, NULL);
 
     pa_subscription_post(i->sink->core, PA_SUBSCRIPTION_EVENT_SINK_INPUT|PA_SUBSCRIPTION_EVENT_REMOVE, i->index);
     i->sink = NULL;
 
+    i->process_msg = NULL;
     i->peek = NULL;
     i->drop = NULL;
     i->kill = NULL;
     i->get_latency = NULL;
     i->underrun = NULL;
 
-    i->state = PA_SINK_INPUT_DISCONNECTED;
+    pa_atomic_load(&i->state, PA_SINK_INPUT_DISCONNECTED);
 }
 
-static void sink_input_free(pa_sink_input* i) {
-    assert(i);
+static void sink_input_free(pa_msgobject *o) {
+    pa_sink_input* i = PA_SINK_INPUT(o);
 
-    if (i->state != PA_SINK_INPUT_DISCONNECTED)
-        pa_sink_input_disconnect(i);
+    pa_assert(i);
+    pa_assert(pa_sink_input_refcnt(i) == 0);
+    
+    pa_sink_input_disconnect(i);
 
-    pa_log_info("freed %u \"%s\"", i->index, i->name);
+    pa_log_info("Freeing output %u \"%s\"", i->index, i->name);
 
     if (i->resampled_chunk.memblock)
         pa_memblock_unref(i->resampled_chunk.memblock);
 
-    if (i->resampler)
-        pa_resampler_free(i->resampler);
+    if (i->thread_info.resampler)
+        pa_resampler_free(i->thread_info.resampler);
 
-    if (i->silence_memblock)
-        pa_memblock_unref(i->silence_memblock);
+    if (i->thread_info.silence_memblock)
+        pa_memblock_unref(i->thread_info.silence_memblock);
 
     pa_xfree(i->name);
     pa_xfree(i->driver);
     pa_xfree(i);
 }
 
-void pa_sink_input_unref(pa_sink_input *i) {
-    assert(i);
-    assert(i->ref >= 1);
+void pa_sink_input_put(pa_sink_input *i) {
+    pa_sink_input_assert_ref(i);
 
-    if (!(--i->ref))
-        sink_input_free(i);
-}
+    i->thread_info.volume = i->volume;
+    i->thread_info.muted = i->muted;
 
-pa_sink_input* pa_sink_input_ref(pa_sink_input *i) {
-    assert(i);
-    assert(i->ref >= 1);
+    pa_asyncmsgq_post(i->sink->asyncmsgq, i->sink, PA_SINK_MESSAGE_ADD_INPUT, i, NULL, pa_sink_unref, pa_sink_input_unref);
+    pa_sink_update_status(i->sink);
 
-    i->ref++;
-    return i;
+    pa_subscription_post(core, PA_SUBSCRIPTION_EVENT_SINK_INPUT|PA_SUBSCRIPTION_EVENT_NEW, i->index);
 }
 
 void pa_sink_input_kill(pa_sink_input*i) {
-    assert(i);
-    assert(i->ref >= 1);
+    pa_sink_input_assert_ref(i);
 
     if (i->kill)
         i->kill(i);
@@ -264,18 +277,14 @@ void pa_sink_input_kill(pa_sink_input*i) {
 pa_usec_t pa_sink_input_get_latency(pa_sink_input *i) {
     pa_usec_t r = 0;
 
-    assert(i);
-    assert(i->ref >= 1);
+    pa_sink_input_assert_ref(i);
 
+    if (pa_asyncmsgq_send(i->sink->asyncmsgq, i->sink, PA_SINK_INPUT_MESSAGE_GET_LATENCY, &r, NULL) < 0)
+        r = 0;
+    
     if (i->get_latency)
         r += i->get_latency(i);
 
-    if (i->resampled_chunk.memblock)
-        r += pa_bytes_to_usec(i->resampled_chunk.length, &i->sink->sample_spec);
-
-    if (i->move_silence)
-        r += pa_bytes_to_usec(i->move_silence, &i->sink->sample_spec);
-
     return r;
 }
 
@@ -283,35 +292,40 @@ int pa_sink_input_peek(pa_sink_input *i, pa_memchunk *chunk, pa_cvolume *volume)
     int ret = -1;
     int do_volume_adj_here;
     int volume_is_norm;
+    pa_sink_input_state_t state;
+    
+    pa_sink_input_assert_ref(i);
+    pa_assert(chunk);
+    pa_assert(volume);
 
-    assert(i);
-    assert(i->ref >= 1);
-    assert(chunk);
-    assert(volume);
+    state = pa_sink_input_get_state(i);
 
-    pa_sink_input_ref(i);
+    if (state == PA_SINK_INPUT_DISCONNECTED)
+        return -1;
 
-    if (!i->peek || !i->drop || i->state == PA_SINK_INPUT_CORKED)
+    if (!i->peek || !i->drop || state == PA_SINK_INPUT_CORKED)
         goto finish;
 
-    assert(i->state == PA_SINK_INPUT_RUNNING || i->state == PA_SINK_INPUT_DRAINED);
+    pa_assert(state == PA_SINK_INPUT_RUNNING || state == PA_SINK_INPUT_DRAINED);
 
-    if (i->move_silence > 0) {
+/*     if (i->thread_info.move_silence > 0) { */
+/*         size_t l; */
 
-        /* We have just been moved and shall play some silence for a
-         * while until the old sink has drained its playback buffer */
+/*         /\* We have just been moved and shall play some silence for a */
+/*          * while until the old sink has drained its playback buffer *\/ */
 
-        if (!i->silence_memblock)
-            i->silence_memblock = pa_silence_memblock_new(i->sink->core->mempool, &i->sink->sample_spec, SILENCE_BUFFER_LENGTH);
+/*         if (!i->thread_info.silence_memblock) */
+/*             i->thread_info.silence_memblock = pa_silence_memblock_new(i->sink->core->mempool, &i->sink->sample_spec, SILENCE_BUFFER_LENGTH); */
 
-        chunk->memblock = pa_memblock_ref(i->silence_memblock);
-        chunk->index = 0;
-        chunk->length = i->move_silence < chunk->memblock->length ? i->move_silence : chunk->memblock->length;
+/*         chunk->memblock = pa_memblock_ref(i->thread_info.silence_memblock); */
+/*         chunk->index = 0; */
+/*         l = pa_memblock_get_length(chunk->memblock); */
+/*         chunk->length = i->move_silence < l ? i->move_silence : l; */
 
-        ret = 0;
-        do_volume_adj_here = 1;
-        goto finish;
-    }
+/*         ret = 0; */
+/*         do_volume_adj_here = 1; */
+/*         goto finish; */
+/*     } */
 
     if (!i->resampler) {
         do_volume_adj_here = 0;
@@ -320,16 +334,16 @@ int pa_sink_input_peek(pa_sink_input *i, pa_memchunk *chunk, pa_cvolume *volume)
     }
 
     do_volume_adj_here = !pa_channel_map_equal(&i->channel_map, &i->sink->channel_map);
-    volume_is_norm = pa_cvolume_is_norm(&i->volume);
+    volume_is_norm = pa_cvolume_is_norm(&i->thread_info.soft_volume) && !i->thread_info.soft_muted;
 
-    while (!i->resampled_chunk.memblock) {
+    while (!i->thread_info.resampled_chunk.memblock) {
         pa_memchunk tchunk;
         size_t l;
 
         if ((ret = i->peek(i, &tchunk)) < 0)
             goto finish;
 
-        assert(tchunk.length);
+        pa_assert(tchunk.length);
 
         l = pa_resampler_request(i->resampler, CONVERT_BUFFER_LENGTH);
 
@@ -342,30 +356,30 @@ int pa_sink_input_peek(pa_sink_input *i, pa_memchunk *chunk, pa_cvolume *volume)
         /* It might be necessary to adjust the volume here */
         if (do_volume_adj_here && !volume_is_norm) {
             pa_memchunk_make_writable(&tchunk, 0);
-            pa_volume_memchunk(&tchunk, &i->sample_spec, &i->volume);
+            pa_volume_memchunk(&tchunk, &i->sample_spec, &i->thread_info.soft_volume);
         }
 
-        pa_resampler_run(i->resampler, &tchunk, &i->resampled_chunk);
+        pa_resampler_run(i->resampler, &tchunk, &i->thread_info.resampled_chunk);
         pa_memblock_unref(tchunk.memblock);
     }
 
-    assert(i->resampled_chunk.memblock);
-    assert(i->resampled_chunk.length);
+    pa_assert(i->thread_info.resampled_chunk.memblock);
+    pa_assert(i->thread_info.resampled_chunk.length);
 
-    *chunk = i->resampled_chunk;
-    pa_memblock_ref(i->resampled_chunk.memblock);
+    *chunk = i->thread_info.resampled_chunk;
+    pa_memblock_ref(i->thread_info.resampled_chunk.memblock);
 
     ret = 0;
 
 finish:
 
-    if (ret < 0 && i->state == PA_SINK_INPUT_RUNNING && i->underrun)
+    if (ret < 0 && state == PA_SINK_INPUT_RUNNING && i->underrun)
         i->underrun(i);
 
     if (ret >= 0)
-        i->state = PA_SINK_INPUT_RUNNING;
+        pa_atomic_cmpxchg(&i->state, state, PA_SINK_INPUT_RUNNING);
     else if (ret < 0 && i->state == PA_SINK_INPUT_RUNNING)
-        i->state = PA_SINK_INPUT_DRAINED;
+        pa_atomic_cmpxchg(&i->state, state, PA_SINK_INPUT_DRAINED);
 
     if (ret >= 0) {
         /* Let's see if we had to apply the volume adjustment
@@ -376,42 +390,42 @@ finish:
             pa_cvolume_reset(volume, i->sink->sample_spec.channels);
         else
             /* We've both the same channel map, so let's have the sink do the adjustment for us*/
-            *volume = i->volume;
+            *volume = i->thread_info.volume;
     }
 
-    pa_sink_input_unref(i);
-
     return ret;
 }
 
 void pa_sink_input_drop(pa_sink_input *i, const pa_memchunk *chunk, size_t length) {
-    assert(i);
-    assert(i->ref >= 1);
-    assert(length > 0);
+    pa_sink_input_assert_ref(i);
+    pa_assert(length > 0);
 
-    if (i->move_silence > 0) {
+/*     if (i->move_silence > 0) { */
 
-        if (chunk) {
+/*         if (chunk) { */
+/*             size_t l; */
 
-            if (chunk->memblock != i->silence_memblock ||
-                chunk->index != 0 ||
-                (chunk->memblock && (chunk->length != (i->silence_memblock->length < i->move_silence ? i->silence_memblock->length : i->move_silence))))
-                return;
+/*             l = pa_memblock_get_length(i->silence_memblock); */
 
-        }
+/*             if (chunk->memblock != i->silence_memblock || */
+/*                 chunk->index != 0 || */
+/*                 (chunk->memblock && (chunk->length != (l < i->move_silence ? l : i->move_silence)))) */
+/*                 return; */
 
-        assert(i->move_silence >= length);
+/*         } */
 
-        i->move_silence -= length;
+/*         pa_assert(i->move_silence >= length); */
 
-        if (i->move_silence <= 0) {
-            assert(i->silence_memblock);
-            pa_memblock_unref(i->silence_memblock);
-            i->silence_memblock = NULL;
-        }
+/*         i->move_silence -= length; */
 
-        return;
-    }
+/*         if (i->move_silence <= 0) { */
+/*             pa_assert(i->silence_memblock); */
+/*             pa_memblock_unref(i->silence_memblock); */
+/*             i->silence_memblock = NULL; */
+/*         } */
+
+/*         return; */
+/*     } */
 
     if (!i->resampler) {
         if (i->drop)
@@ -419,75 +433,88 @@ void pa_sink_input_drop(pa_sink_input *i, const pa_memchunk *chunk, size_t lengt
         return;
     }
 
-    assert(i->resampled_chunk.memblock);
-    assert(i->resampled_chunk.length >= length);
+    pa_assert(i->thread_info.resampled_chunk.memblock);
+    pa_assert(i->thread_info.resampled_chunk.length >= length);
 
-    i->resampled_chunk.index += length;
-    i->resampled_chunk.length -= length;
+    i->thread_info.resampled_chunk.index += length;
+    i->thread_info.resampled_chunk.length -= length;
 
-    if (i->resampled_chunk.length <= 0) {
-        pa_memblock_unref(i->resampled_chunk.memblock);
-        i->resampled_chunk.memblock = NULL;
-        i->resampled_chunk.index = i->resampled_chunk.length = 0;
+    if (i->thread_info.resampled_chunk.length <= 0) {
+        pa_memblock_unref(i->thread_info.resampled_chunk.memblock);
+        i->thread_info.resampled_chunk.memblock = NULL;
+        i->thread_info.resampled_chunk.index = i->thread_info.resampled_chunk.length = 0;
     }
 }
 
 void pa_sink_input_set_volume(pa_sink_input *i, const pa_cvolume *volume) {
-    assert(i);
-    assert(i->ref >= 1);
-    assert(i->sink);
-    assert(i->sink->core);
+    pa_sink_input_assert_ref(i);
 
     if (pa_cvolume_equal(&i->volume, volume))
         return;
 
     i->volume = *volume;
+
+    pa_asyncmsgq_post(s->asyncmsgq, pa_sink_input_ref(i), PA_SINK_INPUT_MESSAGE_SET_VOLUME, pa_xnewdup(struct pa_cvolume, volume, 1), pa_sink_input_unref, pa_xfree);
     pa_subscription_post(i->sink->core, PA_SUBSCRIPTION_EVENT_SINK_INPUT|PA_SUBSCRIPTION_EVENT_CHANGE, i->index);
 }
 
-const pa_cvolume * pa_sink_input_get_volume(pa_sink_input *i) {
-    assert(i);
-    assert(i->ref >= 1);
+const pa_cvolume *pa_sink_input_get_volume(pa_sink_input *i) {
+    pa_sink_input_assert_ref(i);
 
     return &i->volume;
 }
 
-void pa_sink_input_cork(pa_sink_input *i, int b) {
-    int n;
+void pa_sink_input_set_mute(pa_sink_input *i, int mute) {
+    pa_assert(i);
+    pa_sink_input_assert_ref(i);
+
+    if (!i->muted == !mute)
+        return;
+
+    i->muted = mute;
+
+    pa_asyncmsgq_post(s->asyncmsgq, pa_sink_input_ref(i), PA_SINK_INPUT_MESSAGE_SET_MUTE, PA_UINT_TO_PTR(mute), pa_sink_input_unref, NULL);
+    pa_subscription_post(i->sink->core, PA_SUBSCRIPTION_EVENT_SINK_INPUT|PA_SUBSCRIPTION_EVENT_CHANGE, i->index);
+}
 
-    assert(i);
-    assert(i->ref >= 1);
+int pa_sink_input_get_mute(pa_sink_input *i) {
+    pa_sink_input_assert_ref(i);
 
-    assert(i->state != PA_SINK_INPUT_DISCONNECTED);
+    return !!i->mute;
+}
+
+void pa_sink_input_cork(pa_sink_input *i, int b) {
+    int n;
+    pa_sink_input_state_t state;
 
-    n = i->state == PA_SINK_INPUT_CORKED && !b;
+    pa_sink_input_assert_ref(i);
 
-    if (b)
-        i->state = PA_SINK_INPUT_CORKED;
-    else if (i->state == PA_SINK_INPUT_CORKED)
-        i->state = PA_SINK_INPUT_DRAINED;
+    state = pa_sink_input_get_state(i);
+    pa_assert(state != PA_SINK_INPUT_DISCONNECTED);
 
-    if (n)
-        pa_sink_notify(i->sink);
+    if (b && state != PA_SINK_INPUT_CORKED)
+        pa_atomic_store(i->state, PA_SINK_INPUT_CORKED);
+    else if (!b && state == PA_SINK_INPUT_CORKED)
+        pa_atomic_cmpxchg(i->state, state, PA_SINK_INPUT_DRAINED);
 }
 
-void pa_sink_input_set_rate(pa_sink_input *i, uint32_t rate) {
-    assert(i);
-    assert(i->resampler);
-    assert(i->ref >= 1);
+int pa_sink_input_set_rate(pa_sink_input *i, uint32_t rate) {
+    pa_sink_input_assert_ref(i);
+    pa_return_val_if_fail(u->thread_info.resampler, -1);
 
     if (i->sample_spec.rate == rate)
-        return;
+        return 0;
 
     i->sample_spec.rate = rate;
-    pa_resampler_set_input_rate(i->resampler, rate);
 
+    pa_asyncmsgq_post(s->asyncmsgq, pa_sink_input_ref(i), PA_SINK_INPUT_MESSAGE_SET_RATE, PA_UINT_TO_PTR(rate), NULL, pa_sink_input_unref, NULL);
+    
     pa_subscription_post(i->sink->core, PA_SUBSCRIPTION_EVENT_SINK_INPUT|PA_SUBSCRIPTION_EVENT_CHANGE, i->index);
+    return 0
 }
 
 void pa_sink_input_set_name(pa_sink_input *i, const char *name) {
-    assert(i);
-    assert(i->ref >= 1);
+    pa_sink_input_assert_ref(i);
 
     if (!i->name && !name)
         return;
@@ -502,13 +529,9 @@ void pa_sink_input_set_name(pa_sink_input *i, const char *name) {
 }
 
 pa_resample_method_t pa_sink_input_get_resample_method(pa_sink_input *i) {
-    assert(i);
-    assert(i->ref >= 1);
-
-    if (!i->resampler)
-        return i->resample_method;
+    pa_sink_input_assert_ref(i);
 
-    return pa_resampler_get_method(i->resampler);
+    return i->resample_method;
 }
 
 int pa_sink_input_move_to(pa_sink_input *i, pa_sink *dest, int immediately) {
@@ -516,156 +539,196 @@ int pa_sink_input_move_to(pa_sink_input *i, pa_sink *dest, int immediately) {
     pa_memblockq *buffer = NULL;
     pa_sink *origin;
 
-    assert(i);
-    assert(dest);
+    pa_sink_input_assert_ref(i);
+    pa_sink_assert_ref(dest);
 
-    origin = i->sink;
+    return -1;
+    
+/*     origin = i->sink; */
 
-    if (dest == origin)
-        return 0;
+/*     if (dest == origin) */
+/*         return 0; */
 
-    if (pa_idxset_size(dest->inputs) >= PA_MAX_INPUTS_PER_SINK) {
-        pa_log_warn("Failed to move sink input: too many inputs per sink.");
-        return -1;
-    }
+/*     if (pa_idxset_size(dest->inputs) >= PA_MAX_INPUTS_PER_SINK) { */
+/*         pa_log_warn("Failed to move sink input: too many inputs per sink."); */
+/*         return -1; */
+/*     } */
 
-    if (i->resampler &&
-        pa_sample_spec_equal(&origin->sample_spec, &dest->sample_spec) &&
-        pa_channel_map_equal(&origin->channel_map, &dest->channel_map))
+/*     if (i->resampler && */
+/*         pa_sample_spec_equal(&origin->sample_spec, &dest->sample_spec) && */
+/*         pa_channel_map_equal(&origin->channel_map, &dest->channel_map)) */
 
-        /* Try to reuse the old resampler if possible */
-        new_resampler = i->resampler;
+/*         /\* Try to reuse the old resampler if possible *\/ */
+/*         new_resampler = i->resampler; */
 
-    else if ((i->flags & PA_SINK_INPUT_VARIABLE_RATE) ||
-        !pa_sample_spec_equal(&i->sample_spec, &dest->sample_spec) ||
-        !pa_channel_map_equal(&i->channel_map, &dest->channel_map)) {
+/*     else if ((i->flags & PA_SINK_INPUT_VARIABLE_RATE) || */
+/*         !pa_sample_spec_equal(&i->sample_spec, &dest->sample_spec) || */
+/*         !pa_channel_map_equal(&i->channel_map, &dest->channel_map)) { */
 
-        /* Okey, we need a new resampler for the new sink */
+/*         /\* Okey, we need a new resampler for the new sink *\/ */
 
-        if (!(new_resampler = pa_resampler_new(
-                      dest->core->mempool,
-                      &i->sample_spec, &i->channel_map,
-                      &dest->sample_spec, &dest->channel_map,
-                      i->resample_method))) {
-            pa_log_warn("Unsupported resampling operation.");
-            return -1;
-        }
-    }
+/*         if (!(new_resampler = pa_resampler_new( */
+/*                       dest->core->mempool, */
+/*                       &i->sample_spec, &i->channel_map, */
+/*                       &dest->sample_spec, &dest->channel_map, */
+/*                       i->resample_method))) { */
+/*             pa_log_warn("Unsupported resampling operation."); */
+/*             return -1; */
+/*         } */
+/*     } */
 
-    if (!immediately) {
-        pa_usec_t old_latency, new_latency;
-        pa_usec_t silence_usec = 0;
+/*     if (!immediately) { */
+/*         pa_usec_t old_latency, new_latency; */
+/*         pa_usec_t silence_usec = 0; */
 
-        buffer = pa_memblockq_new(0, MOVE_BUFFER_LENGTH, 0, pa_frame_size(&origin->sample_spec), 0, 0, NULL);
+/*         buffer = pa_memblockq_new(0, MOVE_BUFFER_LENGTH, 0, pa_frame_size(&origin->sample_spec), 0, 0, NULL); */
 
-        /* Let's do a little bit of Voodoo for compensating latency
-         * differences */
+/*         /\* Let's do a little bit of Voodoo for compensating latency */
+/*          * differences *\/ */
 
-        old_latency = pa_sink_get_latency(origin);
-        new_latency = pa_sink_get_latency(dest);
+/*         old_latency = pa_sink_get_latency(origin); */
+/*         new_latency = pa_sink_get_latency(dest); */
 
-        /* The already resampled data should go to the old sink */
+/*         /\* The already resampled data should go to the old sink *\/ */
 
-        if (old_latency >= new_latency) {
+/*         if (old_latency >= new_latency) { */
 
-            /* The latency of the old sink is larger than the latency
-             * of the new sink. Therefore to compensate for the
-             * difference we to play silence on the new one for a
-             * while */
+/*             /\* The latency of the old sink is larger than the latency */
+/*              * of the new sink. Therefore to compensate for the */
+/*              * difference we to play silence on the new one for a */
+/*              * while *\/ */
 
-            silence_usec = old_latency - new_latency;
+/*             silence_usec = old_latency - new_latency; */
 
-        } else {
-            size_t l;
-            int volume_is_norm;
+/*         } else { */
+/*             size_t l; */
+/*             int volume_is_norm; */
 
-            /* The latency of new sink is larger than the latency of
-             * the old sink. Therefore we have to precompute a little
-             * and make sure that this is still played on the old
-             * sink, until we can play the first sample on the new
-             * sink.*/
+/*             /\* The latency of new sink is larger than the latency of */
+/*              * the old sink. Therefore we have to precompute a little */
+/*              * and make sure that this is still played on the old */
+/*              * sink, until we can play the first sample on the new */
+/*              * sink.*\/ */
 
-            l = pa_usec_to_bytes(new_latency - old_latency, &origin->sample_spec);
+/*             l = pa_usec_to_bytes(new_latency - old_latency, &origin->sample_spec); */
 
-            volume_is_norm = pa_cvolume_is_norm(&i->volume);
+/*             volume_is_norm = pa_cvolume_is_norm(&i->volume); */
 
-            while (l > 0) {
-                pa_memchunk chunk;
-                pa_cvolume volume;
-                size_t n;
+/*             while (l > 0) { */
+/*                 pa_memchunk chunk; */
+/*                 pa_cvolume volume; */
+/*                 size_t n; */
 
-                if (pa_sink_input_peek(i, &chunk, &volume) < 0)
-                    break;
+/*                 if (pa_sink_input_peek(i, &chunk, &volume) < 0) */
+/*                     break; */
 
-                n = chunk.length > l ? l : chunk.length;
-                pa_sink_input_drop(i, &chunk, n);
-                chunk.length = n;
+/*                 n = chunk.length > l ? l : chunk.length; */
+/*                 pa_sink_input_drop(i, &chunk, n); */
+/*                 chunk.length = n; */
 
-                if (!volume_is_norm) {
-                    pa_memchunk_make_writable(&chunk, 0);
-                    pa_volume_memchunk(&chunk, &origin->sample_spec, &volume);
-                }
+/*                 if (!volume_is_norm) { */
+/*                     pa_memchunk_make_writable(&chunk, 0); */
+/*                     pa_volume_memchunk(&chunk, &origin->sample_spec, &volume); */
+/*                 } */
 
-                if (pa_memblockq_push(buffer, &chunk) < 0) {
-                    pa_memblock_unref(chunk.memblock);
-                    break;
-                }
+/*                 if (pa_memblockq_push(buffer, &chunk) < 0) { */
+/*                     pa_memblock_unref(chunk.memblock); */
+/*                     break; */
+/*                 } */
 
-                pa_memblock_unref(chunk.memblock);
-                l -= n;
-            }
-        }
+/*                 pa_memblock_unref(chunk.memblock); */
+/*                 l -= n; */
+/*             } */
+/*         } */
 
-        if (i->resampled_chunk.memblock) {
+/*         if (i->resampled_chunk.memblock) { */
 
-            /* There is still some data left in the already resampled
-             * memory block. Hence, let's output it on the old sink
-             * and sleep so long on the new sink */
+/*             /\* There is still some data left in the already resampled */
+/*              * memory block. Hence, let's output it on the old sink */
+/*              * and sleep so long on the new sink *\/ */
 
-            pa_memblockq_push(buffer, &i->resampled_chunk);
-            silence_usec += pa_bytes_to_usec(i->resampled_chunk.length, &origin->sample_spec);
-        }
+/*             pa_memblockq_push(buffer, &i->resampled_chunk); */
+/*             silence_usec += pa_bytes_to_usec(i->resampled_chunk.length, &origin->sample_spec); */
+/*         } */
 
-        /* Calculate the new sleeping time */
-        i->move_silence = pa_usec_to_bytes(
-                pa_bytes_to_usec(i->move_silence, &i->sample_spec) +
-                silence_usec,
-                &i->sample_spec);
-    }
+/*         /\* Calculate the new sleeping time *\/ */
+/*         i->move_silence = pa_usec_to_bytes( */
+/*                 pa_bytes_to_usec(i->move_silence, &i->sample_spec) + */
+/*                 silence_usec, */
+/*                 &i->sample_spec); */
+/*     } */
 
-    /* Okey, let's move it */
-    pa_idxset_remove_by_data(origin->inputs, i, NULL);
-    pa_idxset_put(dest->inputs, i, NULL);
-    i->sink = dest;
-
-    /* Replace resampler */
-    if (new_resampler != i->resampler) {
-        if (i->resampler)
-            pa_resampler_free(i->resampler);
-        i->resampler = new_resampler;
-
-        /* if the resampler changed, the silence memblock is
-         * probably invalid now, too */
-        if (i->silence_memblock) {
-            pa_memblock_unref(i->silence_memblock);
-            i->silence_memblock = NULL;
-        }
-    }
+/*     /\* Okey, let's move it *\/ */
+/*     pa_idxset_remove_by_data(origin->inputs, i, NULL); */
+/*     pa_idxset_put(dest->inputs, i, NULL); */
+/*     i->sink = dest; */
 
-    /* Dump already resampled data */
-    if (i->resampled_chunk.memblock) {
-        pa_memblock_unref(i->resampled_chunk.memblock);
-        i->resampled_chunk.memblock = NULL;
-        i->resampled_chunk.index = i->resampled_chunk.length = 0;
-    }
+/*     /\* Replace resampler *\/ */
+/*     if (new_resampler != i->resampler) { */
+/*         if (i->resampler) */
+/*             pa_resampler_free(i->resampler); */
+/*         i->resampler = new_resampler; */
 
-    /* Notify everyone */
-    pa_subscription_post(i->sink->core, PA_SUBSCRIPTION_EVENT_SINK_INPUT|PA_SUBSCRIPTION_EVENT_CHANGE, i->index);
-    pa_sink_notify(i->sink);
+/*         /\* if the resampler changed, the silence memblock is */
+/*          * probably invalid now, too *\/ */
+/*         if (i->silence_memblock) { */
+/*             pa_memblock_unref(i->silence_memblock); */
+/*             i->silence_memblock = NULL; */
+/*         } */
+/*     } */
+
+/*     /\* Dump already resampled data *\/ */
+/*     if (i->resampled_chunk.memblock) { */
+/*         pa_memblock_unref(i->resampled_chunk.memblock); */
+/*         i->resampled_chunk.memblock = NULL; */
+/*         i->resampled_chunk.index = i->resampled_chunk.length = 0; */
+/*     } */
 
-    /* Ok, no let's feed the precomputed buffer to the old sink */
-    if (buffer)
-        pa_play_memblockq(origin, "Ghost Stream", &origin->sample_spec, &origin->channel_map, buffer, NULL);
+/*     /\* Notify everyone *\/ */
+/*     pa_subscription_post(i->sink->core, PA_SUBSCRIPTION_EVENT_SINK_INPUT|PA_SUBSCRIPTION_EVENT_CHANGE, i->index); */
+/*     pa_sink_notify(i->sink); */
+
+/*     /\* Ok, now let's feed the precomputed buffer to the old sink *\/ */
+/*     if (buffer) */
+/*         pa_play_memblockq(origin, "Ghost Stream", &origin->sample_spec, &origin->channel_map, buffer, NULL); */
+
+/*     return 0; */
+}
+
+int pa_sink_input_process_msg(pa_msgobject *o, int code, void *userdata, pa_memchunk *chunk) {
+    pa_sink_input *i = PA_SINK_INPUT(o);
+    
+    pa_sink_input_assert_ref(i);
+
+    switch (code) {
+        case PA_SINK_INPUT_MESSAGE_SET_VOLUME:
+            s->thread_info.soft_volume = *((pa_cvolume*) userdata);
+            return 0;
+            
+        case PA_SINK_INPUT_MESSAGE_SET_MUTE:
+            s->thread_info.soft_muted = PA_PTR_TO_UINT(userdata);
+            return 0;
+            
+        case PA_SINK_INPUT_MESSAGE_GET_LATENCY: {
+            pa_usec_t *r = userdata;
+            
+            if (i->thread_info.resampled_chunk.memblock)
+                *r += pa_bytes_to_usec(i->resampled_chunk.length, &i->sink->sample_spec);
+
+/*             if (i->move_silence) */
+/*                 r += pa_bytes_to_usec(i->move_silence, &i->sink->sample_spec); */
+            
+            return 0;
+        }
+            
+        case PA_SINK_INPUT_MESSAGE_SET_RATE: {
+            
+            i->thread_info.sample_spec.rate = PA_PTR_TO_UINT(userdata);
+            pa_resampler_set_input_rate(i->resampler, PA_PTR_TO_UINT(userdata));
+
+            return 0;
+        }
+    }
 
-    return 0;
+    return -1;
 }
diff --git a/src/pulsecore/sink-input.h b/src/pulsecore/sink-input.h
index 51d9ec7..64a7a73 100644
--- a/src/pulsecore/sink-input.h
+++ b/src/pulsecore/sink-input.h
@@ -1,5 +1,5 @@
-#ifndef foosinkinputhfoo
-#define foosinkinputhfoo
+#ifndef foopulsesinkinputhfoo
+#define foopulsesinkinputhfoo
 
 /* $Id$ */
 
@@ -51,9 +51,11 @@ typedef enum pa_sink_input_flags {
 } pa_sink_input_flags_t;
 
 struct pa_sink_input {
-    int ref;
+    pa_msgobject parent;
+    
     uint32_t index;
-    pa_sink_input_state_t state;
+    pa_core *core;
+    pa_atomic_t state;
     pa_sink_input_flags_t flags;
 
     char *name, *driver;                /* may be NULL */
@@ -64,27 +66,47 @@ struct pa_sink_input {
 
     pa_sample_spec sample_spec;
     pa_channel_map channel_map;
+    
     pa_cvolume volume;
+    int muted;
 
-    /* Some silence to play before the actual data. This is used to
-     * compensate for latency differences when moving a sink input
-     * "hot" between sinks. */
-    size_t move_silence;
-
+    int (*process_msg)(pa_sink_input *i, int code, void *userdata); 
     int (*peek) (pa_sink_input *i, pa_memchunk *chunk);
     void (*drop) (pa_sink_input *i, const pa_memchunk *chunk, size_t length);
     void (*kill) (pa_sink_input *i);             /* may be NULL */
     pa_usec_t (*get_latency) (pa_sink_input *i); /* may be NULL */
     void (*underrun) (pa_sink_input *i);         /* may be NULL */
 
-    void *userdata;
+    pa_resample_method_t resample_method;
 
-    pa_memchunk resampled_chunk;
-    pa_resampler *resampler;                     /* may be NULL */
+    struct {
+        pa_sample_spec sample_spec;
+        
+        pa_memchunk resampled_chunk;
+        pa_resampler *resampler;                     /* may be NULL */
+        
+        /* Some silence to play before the actual data. This is used to
+         * compensate for latency differences when moving a sink input
+         * "hot" between sinks. */
+        /*         size_t move_silence; */
+        pa_memblock *silence_memblock;               /* may be NULL */
+
+        pa_cvolume volume;
+        int muted;
+    } thread_info;
+    
+    void *userdata;
+};
 
-    pa_resample_method_t resample_method;
+PA_DECLARE_CLASS(pa_sink_input);
+#define PA_SINK_INPUT(o) ((pa_sink_input*) (o))
 
-    pa_memblock *silence_memblock;               /* may be NULL */
+enum {
+    PA_SINK_INPUT_MESSAGE_SET_VOLUME,
+    PA_SINK_INPUT_MESSAGE_SET_MUTE,
+    PA_SINK_INPUT_MESSAGE_GET_LATENCY,
+    PA_SINK_INPUT_MESSAGE_SET_RATE,
+    PA_SINK_INPUT_MESSAGE_MAX
 };
 
 typedef struct pa_sink_input_new_data {
@@ -100,6 +122,8 @@ typedef struct pa_sink_input_new_data {
     int channel_map_is_set;
     pa_cvolume volume;
     int volume_is_set;
+    int muted;
+    int muted_is_set;
 
     pa_resample_method_t resample_method;
 } pa_sink_input_new_data;
@@ -108,37 +132,46 @@ pa_sink_input_new_data* pa_sink_input_new_data_init(pa_sink_input_new_data *data
 void pa_sink_input_new_data_set_sample_spec(pa_sink_input_new_data *data, const pa_sample_spec *spec);
 void pa_sink_input_new_data_set_channel_map(pa_sink_input_new_data *data, const pa_channel_map *map);
 void pa_sink_input_new_data_set_volume(pa_sink_input_new_data *data, const pa_cvolume *volume);
+void pa_sink_input_new_data_set_muted(pa_sink_input_new_data *data, int mute);
+
+/* To be called by the implementing module only */
 
 pa_sink_input* pa_sink_input_new(
         pa_core *core,
         pa_sink_input_new_data *data,
         pa_sink_input_flags_t flags);
 
-void pa_sink_input_unref(pa_sink_input* i);
-pa_sink_input* pa_sink_input_ref(pa_sink_input* i);
-
-/* To be called by the implementing module only */
+void pa_sink_input_put(pa_sink_input *i);
 void pa_sink_input_disconnect(pa_sink_input* i);
 
-/* External code may request disconnection with this funcion */
+void pa_sink_input_set_name(pa_sink_input *i, const char *name);
+
+/* Callable by everyone */
+
+/* External code may request disconnection with this function */
 void pa_sink_input_kill(pa_sink_input*i);
 
 pa_usec_t pa_sink_input_get_latency(pa_sink_input *i);
 
-int pa_sink_input_peek(pa_sink_input *i, pa_memchunk *chunk, pa_cvolume *volume);
-void pa_sink_input_drop(pa_sink_input *i, const pa_memchunk *chunk, size_t length);
-
 void pa_sink_input_set_volume(pa_sink_input *i, const pa_cvolume *volume);
-const pa_cvolume * pa_sink_input_get_volume(pa_sink_input *i);
+const pa_cvolume *pa_sink_input_get_volume(pa_sink_input *i);
+void pa_sink_input_set_mute(pa_sink_input *i, int mute);
+int pa_sink_input_get_mute(pa_sink_input *i);
 
 void pa_sink_input_cork(pa_sink_input *i, int b);
 
 void pa_sink_input_set_rate(pa_sink_input *i, uint32_t rate);
 
-void pa_sink_input_set_name(pa_sink_input *i, const char *name);
-
 pa_resample_method_t pa_sink_input_get_resample_method(pa_sink_input *i);
 
 int pa_sink_input_move_to(pa_sink_input *i, pa_sink *dest, int immediately);
 
+#define pa_sink_input_get_state(i) ((pa_sink_input_state_t) pa_atomic_load(&i->state))
+
+/* To be used exclusively by the sink driver thread */
+
+int pa_sink_input_peek(pa_sink_input *i, pa_memchunk *chunk, pa_cvolume *volume);
+void pa_sink_input_drop(pa_sink_input *i, const pa_memchunk *chunk, size_t length);
+int pa_sink_input_process_msg(pa_msgobject *o, int code, void *userdata, pa_memchunk *chunk);
+
 #endif
diff --git a/src/pulsecore/sink.c b/src/pulsecore/sink.c
index 9588c2c..3620559 100644
--- a/src/pulsecore/sink.c
+++ b/src/pulsecore/sink.c
@@ -41,16 +41,13 @@
 #include <pulsecore/sample-util.h>
 #include <pulsecore/core-subscribe.h>
 #include <pulsecore/log.h>
+#include <pulsecore/macro.h>
 
 #include "sink.h"
 
 #define MAX_MIX_CHANNELS 32
 
-#define CHECK_VALIDITY_RETURN_NULL(condition) \
-do {\
-if (!(condition)) \
-    return NULL; \
-} while (0)
+static void sink_free(pa_object *s);
 
 pa_sink* pa_sink_new(
         pa_core *core,
@@ -66,60 +63,64 @@ pa_sink* pa_sink_new(
     int r;
     pa_channel_map tmap;
 
-    assert(core);
-    assert(name);
-    assert(spec);
+    pa_assert(core);
+    pa_assert(name);
+    pa_assert(spec);
 
-    CHECK_VALIDITY_RETURN_NULL(pa_sample_spec_valid(spec));
+    pa_return_null_if_fail(pa_sample_spec_valid(spec));
 
     if (!map)
         map = pa_channel_map_init_auto(&tmap, spec->channels, PA_CHANNEL_MAP_DEFAULT);
 
-    CHECK_VALIDITY_RETURN_NULL(map && pa_channel_map_valid(map));
-    CHECK_VALIDITY_RETURN_NULL(map->channels == spec->channels);
-    CHECK_VALIDITY_RETURN_NULL(!driver || pa_utf8_valid(driver));
-    CHECK_VALIDITY_RETURN_NULL(pa_utf8_valid(name) && *name);
+    pa_return_null_if_fail(map && pa_channel_map_valid(map));
+    pa_return_null_if_fail(map->channels == spec->channels);
+    pa_return_null_if_fail(!driver || pa_utf8_valid(driver));
+    pa_return_null_if_fail(name && pa_utf8_valid(name) && *name);
 
-    s = pa_xnew(pa_sink, 1);
+    s = pa_msgobject_new(pa_sink);
 
     if (!(name = pa_namereg_register(core, name, PA_NAMEREG_SINK, s, fail))) {
         pa_xfree(s);
         return NULL;
     }
 
-    s->ref = 1;
+    s->parent.parent.free = sink_free;
+    s->parent.process_msg = pa_sink_process_msg;
+    
     s->core = core;
-    s->state = PA_SINK_RUNNING;
+    pa_atomic_store(&s->state, PA_SINK_IDLE);
     s->name = pa_xstrdup(name);
     s->description = NULL;
     s->driver = pa_xstrdup(driver);
-    s->owner = NULL;
+    s->module = NULL;
 
     s->sample_spec = *spec;
     s->channel_map = *map;
 
     s->inputs = pa_idxset_new(NULL, NULL);
 
-    pa_cvolume_reset(&s->sw_volume, spec->channels);
-    pa_cvolume_reset(&s->hw_volume, spec->channels);
-    s->sw_muted = 0;
-    s->hw_muted = 0;
+    pa_cvolume_reset(&s->volume, spec->channels);
+    s->muted = 0;
+    s->refresh_volume = s->refresh_mute = 0;
 
     s->is_hardware = 0;
 
     s->get_latency = NULL;
-    s->notify = NULL;
-    s->set_hw_volume = NULL;
-    s->get_hw_volume = NULL;
-    s->set_hw_mute = NULL;
-    s->get_hw_mute = NULL;
+    s->set_volume = NULL;
+    s->get_volume = NULL;
+    s->set_mute = NULL;
+    s->get_mute = NULL;
+    s->start = NULL;
+    s->stop = NULL;
     s->userdata = NULL;
 
+    pa_assert_se(s->asyncmsgq = pa_asyncmsgq_new(0));
+    
     r = pa_idxset_put(core->sinks, s, &s->index);
-    assert(s->index != PA_IDXSET_INVALID && r >= 0);
+    pa_assert(s->index != PA_IDXSET_INVALID && r >= 0);
 
     pa_sample_spec_snprint(st, sizeof(st), spec);
-    pa_log_info("created %u \"%s\" with sample spec \"%s\"", s->index, s->name, st);
+    pa_log_info("Created sink %u \"%s\" with sample spec \"%s\"", s->index, s->name, st);
 
     n = pa_sprintf_malloc("%s.monitor", name);
 
@@ -135,24 +136,64 @@ pa_sink* pa_sink_new(
 
     pa_xfree(n);
 
+    s->thread_info.inputs = pa_hashmap_new(pa_idxset_trivial_hash_func, pa_idxset_trivial_compare_func);
+    s->thread_info.soft_volume = s->volume;
+    s->thread_info.soft_muted = s->muted;
+    
     pa_subscription_post(core, PA_SUBSCRIPTION_EVENT_SINK | PA_SUBSCRIPTION_EVENT_NEW, s->index);
 
     return s;
 }
 
+static void sink_start(pa_sink *s) {
+    pa_sink_state_t state;
+    pa_assert(s);
+
+    state = pa_sink_get_state(s);
+    pa_return_if_fail(state == PA_SINK_IDLE || state == PA_SINK_SUSPENDED);
+
+    pa_atomic_store(&s->state, PA_SINK_RUNNING);
+
+    if (s->start)
+        s->start(s);
+    else
+        pa_asyncmsgq_post(s->asyncmsgq, PA_MSGOBJECT(s), PA_SINK_MESSAGE_START, NULL, NULL, NULL);
+}
+
+static void sink_stop(pa_sink *s) {
+    pa_sink_state_t state;
+    int stop;
+    
+    pa_assert(s);
+    state = pa_sink_get_state(s);
+    pa_return_if_fail(state == PA_SINK_RUNNING || state == PA_SINK_SUSPENDED);
+
+    stop = state == PA_SINK_RUNNING;
+    pa_atomic_store(&s->state, PA_SINK_IDLE);
+
+    if (stop) {
+        if (s->stop)
+            s->stop(s);
+        else
+            pa_asyncmsgq_post(s->asyncmsgq, PA_MSGOBJECT(s), PA_SINK_MESSAGE_STOP, NULL, NULL, NULL);
+    }
+}
+
 void pa_sink_disconnect(pa_sink* s) {
     pa_sink_input *i, *j = NULL;
 
-    assert(s);
-    assert(s->state == PA_SINK_RUNNING);
+    pa_assert(s);
+    pa_return_if_fail(pa_sink_get_state(s) != PA_SINK_DISCONNECTED);
 
-    s->state = PA_SINK_DISCONNECTED;
+    sink_stop(s);
+
+    pa_atomic_store(&s->state, PA_SINK_DISCONNECTED);
     pa_namereg_unregister(s->core, s->name);
 
     pa_hook_fire(&s->core->hook_sink_disconnect, s);
 
     while ((i = pa_idxset_first(s->inputs, NULL))) {
-        assert(i != j);
+        pa_assert(i != j);
         pa_sink_input_kill(i);
         j = i;
     }
@@ -163,23 +204,25 @@ void pa_sink_disconnect(pa_sink* s) {
     pa_idxset_remove_by_data(s->core->sinks, s, NULL);
 
     s->get_latency = NULL;
-    s->notify = NULL;
-    s->get_hw_volume = NULL;
-    s->set_hw_volume = NULL;
-    s->set_hw_mute = NULL;
-    s->get_hw_mute = NULL;
+    s->get_volume = NULL;
+    s->set_volume = NULL;
+    s->set_mute = NULL;
+    s->get_mute = NULL;
+    s->start = NULL;
+    s->stop = NULL;
 
     pa_subscription_post(s->core, PA_SUBSCRIPTION_EVENT_SINK | PA_SUBSCRIPTION_EVENT_REMOVE, s->index);
 }
 
-static void sink_free(pa_sink *s) {
-    assert(s);
-    assert(!s->ref);
+static void sink_free(pa_object *o) {
+    pa_sink *s = PA_SINK(o);
+            
+    pa_assert(s);
+    pa_assert(pa_sink_refcnt(s) == 0);
 
-    if (s->state != PA_SINK_DISCONNECTED)
-        pa_sink_disconnect(s);
+    pa_sink_disconnect(s);
 
-    pa_log_info("freed %u \"%s\"", s->index, s->name);
+    pa_log_info("Freeing sink %u \"%s\"", s->index, s->name);
 
     if (s->monitor_source) {
         pa_source_unref(s->monitor_source);
@@ -187,47 +230,66 @@ static void sink_free(pa_sink *s) {
     }
 
     pa_idxset_free(s->inputs, NULL, NULL);
+    
+    pa_hashmap_free(s->thread_info.inputs, (pa_free2_cb_t) pa_sink_input_unref, NULL);
 
+    pa_asyncmsgq_free(s->asyncmsgq);
+    
     pa_xfree(s->name);
     pa_xfree(s->description);
     pa_xfree(s->driver);
     pa_xfree(s);
 }
 
-void pa_sink_unref(pa_sink*s) {
-    assert(s);
-    assert(s->ref >= 1);
+void pa_sink_update_status(pa_sink*s) {
+    pa_sink_assert_ref(s);
 
-    if (!(--s->ref))
-        sink_free(s);
+    if (pa_sink_get_state(s) == PA_SINK_SUSPENDED)
+        return;
+    
+    if (pa_sink_used_by(s) > 0)
+        sink_start(s);
+    else
+        sink_stop(s);
 }
 
-pa_sink* pa_sink_ref(pa_sink *s) {
-    assert(s);
-    assert(s->ref >= 1);
+void pa_sink_suspend(pa_sink *s, int suspend) {
+    pa_sink_state_t state;
 
-    s->ref++;
-    return s;
-}
+    pa_sink_assert_ref(s);
 
-void pa_sink_notify(pa_sink*s) {
-    assert(s);
-    assert(s->ref >= 1);
+    state = pa_sink_get_state(s);
+    pa_return_if_fail(suspend && (state == PA_SINK_RUNNING || state == PA_SINK_IDLE));
+    pa_return_if_fail(!suspend && (state == PA_SINK_SUSPENDED));
 
-    if (s->notify)
-        s->notify(s);
+
+    if (suspend) {
+        pa_atomic_store(&s->state, PA_SINK_SUSPENDED);
+
+        if (s->stop)
+            s->stop(s);
+        else
+            pa_asyncmsgq_post(s->asyncmsgq, PA_MSGOBJECT(s), PA_SINK_MESSAGE_STOP, NULL, NULL, NULL);
+        
+    } else {
+        pa_atomic_store(&s->state, PA_SINK_RUNNING);
+
+        if (s->start)
+            s->start(s);
+        else
+            pa_asyncmsgq_post(s->asyncmsgq, PA_MSGOBJECT(s), PA_SINK_MESSAGE_START, NULL, NULL, NULL);
+    }
 }
 
 static unsigned fill_mix_info(pa_sink *s, pa_mix_info *info, unsigned maxinfo) {
-    uint32_t idx = PA_IDXSET_INVALID;
     pa_sink_input *i;
     unsigned n = 0;
+    void *state = NULL;
 
-    assert(s);
-    assert(s->ref >= 1);
-    assert(info);
+    pa_sink_assert_ref(s);
+    pa_assert(info);
 
-    for (i = pa_idxset_first(s->inputs, &idx); maxinfo > 0 && i; i = pa_idxset_next(s->inputs, &idx)) {
+    while ((i = pa_hashmap_iterate(s->thread_info.inputs, &state, NULL))) {
         /* Increase ref counter, to make sure that this input doesn't
          * vanish while we still need it */
         pa_sink_input_ref(i);
@@ -239,9 +301,8 @@ static unsigned fill_mix_info(pa_sink *s, pa_mix_info *info, unsigned maxinfo) {
 
         info->userdata = i;
 
-        assert(info->chunk.memblock);
-        assert(info->chunk.memblock->data);
-        assert(info->chunk.length);
+        pa_assert(info->chunk.memblock);
+        pa_assert(info->chunk.length);
 
         info++;
         maxinfo--;
@@ -252,15 +313,14 @@ static unsigned fill_mix_info(pa_sink *s, pa_mix_info *info, unsigned maxinfo) {
 }
 
 static void inputs_drop(pa_sink *s, pa_mix_info *info, unsigned maxinfo, size_t length) {
-    assert(s);
-    assert(s->ref >= 1);
-    assert(info);
+    pa_sink_assert_ref(s);
+    pa_assert(info);
 
     for (; maxinfo > 0; maxinfo--, info++) {
         pa_sink_input *i = info->userdata;
 
-        assert(i);
-        assert(info->chunk.memblock);
+        pa_assert(i);
+        pa_assert(info->chunk.memblock);
 
         /* Drop read data */
         pa_sink_input_drop(i, &info->chunk, length);
@@ -277,10 +337,9 @@ int pa_sink_render(pa_sink*s, size_t length, pa_memchunk *result) {
     unsigned n;
     int r = -1;
 
-    assert(s);
-    assert(s->ref >= 1);
-    assert(length);
-    assert(result);
+    pa_sink_assert_ref(s);
+    pa_assert(length);
+    pa_assert(result);
 
     pa_sink_ref(s);
 
@@ -298,23 +357,23 @@ int pa_sink_render(pa_sink*s, size_t length, pa_memchunk *result) {
         if (result->length > length)
             result->length = length;
 
-        pa_sw_cvolume_multiply(&volume, &s->sw_volume, &info[0].volume);
+        pa_sw_cvolume_multiply(&volume, &s->thread_info.soft_volume, &info[0].volume);
 
-        if (s->sw_muted || !pa_cvolume_is_norm(&volume)) {
+        if (s->thread_info.soft_muted || !pa_cvolume_is_norm(&volume)) {
             pa_memchunk_make_writable(result, 0);
-            if (s->sw_muted)
+            if (s->thread_info.soft_muted || pa_cvolume_is_muted(&volume))
                 pa_silence_memchunk(result, &s->sample_spec);
             else
                 pa_volume_memchunk(result, &s->sample_spec, &volume);
         }
     } else {
+        void *ptr;
         result->memblock = pa_memblock_new(s->core->mempool, length);
-        assert(result->memblock);
 
-/*          pa_log("mixing %i", n);  */
+        ptr = pa_memblock_acquire(result->memblock);
+        result->length = pa_mix(info, n, ptr, length, &s->sample_spec, &s->thread_info.soft_volume, s->thread_info.soft_muted);
+        pa_memblock_release(result->memblock);
 
-        result->length = pa_mix(info, n, result->memblock->data, length,
-            &s->sample_spec, &s->sw_volume, s->sw_muted);
         result->index = 0;
     }
 
@@ -336,12 +395,10 @@ int pa_sink_render_into(pa_sink*s, pa_memchunk *target) {
     unsigned n;
     int r = -1;
 
-    assert(s);
-    assert(s->ref >= 1);
-    assert(target);
-    assert(target->memblock);
-    assert(target->length);
-    assert(target->memblock->data);
+    pa_sink_assert_ref(s);
+    pa_assert(target);
+    pa_assert(target->memblock);
+    pa_assert(target->length);
 
     pa_sink_ref(s);
 
@@ -350,30 +407,48 @@ int pa_sink_render_into(pa_sink*s, pa_memchunk *target) {
     if (n <= 0)
         goto finish;
 
-    if (n == 1) {
-        pa_cvolume volume;
 
+    if (n == 1) {
         if (target->length > info[0].chunk.length)
             target->length = info[0].chunk.length;
 
-        memcpy((uint8_t*) target->memblock->data + target->index,
-               (uint8_t*) info[0].chunk.memblock->data + info[0].chunk.index,
-               target->length);
-
-        pa_sw_cvolume_multiply(&volume, &s->sw_volume, &info[0].volume);
-
-        if (s->sw_muted)
+        if (s->thread_info.soft_muted)
             pa_silence_memchunk(target, &s->sample_spec);
-        else if (!pa_cvolume_is_norm(&volume))
-            pa_volume_memchunk(target, &s->sample_spec, &volume);
-    } else
+        else {
+            void *src, *ptr;
+            pa_cvolume volume;
+            
+            ptr = pa_memblock_acquire(target->memblock);
+            src = pa_memblock_acquire(info[0].chunk.memblock);
+            
+            memcpy((uint8_t*) ptr + target->index,
+                   (uint8_t*) src + info[0].chunk.index,
+                   target->length);
+            
+            pa_memblock_release(target->memblock);
+            pa_memblock_release(info[0].chunk.memblock);
+            
+            pa_sw_cvolume_multiply(&volume, &s->thread_info.soft_volume, &info[0].volume);
+
+            if (!pa_cvolume_is_norm(&volume))
+                pa_volume_memchunk(target, &s->sample_spec, &volume);
+        }
+            
+    } else {
+        void *ptr;
+
+        ptr = pa_memblock_acquire(target->memblock);
+        
         target->length = pa_mix(info, n,
-                                (uint8_t*) target->memblock->data + target->index,
+                                (uint8_t*) ptr + target->index,
                                 target->length,
                                 &s->sample_spec,
-                                &s->sw_volume,
-                                s->sw_muted);
-
+                                &s->thread_info.soft_volume,
+                                s->thread_info.soft_muted);
+    
+        pa_memblock_release(target->memblock);
+    }
+    
     inputs_drop(s, info, n, target->length);
 
     if (s->monitor_source)
@@ -391,12 +466,10 @@ void pa_sink_render_into_full(pa_sink *s, pa_memchunk *target) {
     pa_memchunk chunk;
     size_t l, d;
 
-    assert(s);
-    assert(s->ref >= 1);
-    assert(target);
-    assert(target->memblock);
-    assert(target->length);
-    assert(target->memblock->data);
+    pa_sink_assert_ref(s);
+    pa_assert(target);
+    pa_assert(target->memblock);
+    pa_assert(target->length);
 
     pa_sink_ref(s);
 
@@ -425,10 +498,9 @@ void pa_sink_render_into_full(pa_sink *s, pa_memchunk *target) {
 }
 
 void pa_sink_render_full(pa_sink *s, size_t length, pa_memchunk *result) {
-    assert(s);
-    assert(s->ref >= 1);
-    assert(length);
-    assert(result);
+    pa_sink_assert_ref(s);
+    pa_assert(length);
+    pa_assert(result);
 
     /*** This needs optimization ***/
 
@@ -439,108 +511,109 @@ void pa_sink_render_full(pa_sink *s, size_t length, pa_memchunk *result) {
 }
 
 pa_usec_t pa_sink_get_latency(pa_sink *s) {
-    assert(s);
-    assert(s->ref >= 1);
-
-    if (!s->get_latency)
+    pa_usec_t usec = 0;
+    
+    pa_sink_assert_ref(s);
+
+    if (s->get_latency)
+        return s->get_latency(s);
+    
+    if (pa_asyncmsgq_send(s->asyncmsgq, PA_MSGOBJECT(s), PA_SINK_MESSAGE_GET_LATENCY, &usec, NULL) < 0)
         return 0;
 
-    return s->get_latency(s);
+    return usec;
 }
 
-void pa_sink_set_owner(pa_sink *s, pa_module *m) {
-    assert(s);
-    assert(s->ref >= 1);
+void pa_sink_set_volume(pa_sink *s, const pa_cvolume *volume) {
+    int changed;
 
-    if (s->owner == m)
-        return;
+    pa_sink_assert_ref(s);
+    pa_assert(volume);
 
-    s->owner = m;
+    changed = !pa_cvolume_equal(volume, &s->volume);
+    s->volume = *volume;
+    
+    if (s->set_volume && s->set_volume(s) < 0)
+        s->set_volume = NULL;
 
-    if (s->monitor_source)
-        pa_source_set_owner(s->monitor_source, m);
+    if (!s->set_volume)
+        pa_asyncmsgq_post(s->asyncmsgq, PA_MSGOBJECT(s), PA_SINK_MESSAGE_SET_VOLUME, pa_xnewdup(struct pa_cvolume, volume, 1), NULL, pa_xfree);
 
-    pa_subscription_post(s->core, PA_SUBSCRIPTION_EVENT_SINK|PA_SUBSCRIPTION_EVENT_CHANGE, s->index);
+    if (changed)
+        pa_subscription_post(s->core, PA_SUBSCRIPTION_EVENT_SINK|PA_SUBSCRIPTION_EVENT_CHANGE, s->index);
 }
 
-void pa_sink_set_volume(pa_sink *s, pa_mixer_t m, const pa_cvolume *volume) {
-    pa_cvolume *v;
-
-    assert(s);
-    assert(s->ref >= 1);
-    assert(volume);
-
-    if (m == PA_MIXER_HARDWARE && s->set_hw_volume)
-        v = &s->hw_volume;
-    else
-        v = &s->sw_volume;
+const pa_cvolume *pa_sink_get_volume(pa_sink *s) {
+    struct pa_cvolume old_volume;
 
-    if (pa_cvolume_equal(v, volume))
-        return;
+    pa_sink_assert_ref(s);
 
-    *v = *volume;
+    old_volume = s->volume;
+    
+    if (s->get_volume && s->get_volume(s) < 0)
+        s->get_volume = NULL;
 
-    if (v == &s->hw_volume)
-        if (s->set_hw_volume(s) < 0)
-            s->sw_volume =  *volume;
+    if (!s->get_volume && s->refresh_volume)
+        pa_asyncmsgq_send(s->asyncmsgq, PA_MSGOBJECT(s), PA_SINK_MESSAGE_GET_VOLUME, &s->volume, NULL);
 
-    pa_subscription_post(s->core, PA_SUBSCRIPTION_EVENT_SINK|PA_SUBSCRIPTION_EVENT_CHANGE, s->index);
+    if (!pa_cvolume_equal(&old_volume, &s->volume))
+        pa_subscription_post(s->core, PA_SUBSCRIPTION_EVENT_SINK|PA_SUBSCRIPTION_EVENT_CHANGE, s->index);
+    
+    return &s->volume;
 }
 
-const pa_cvolume *pa_sink_get_volume(pa_sink *s, pa_mixer_t m) {
-    assert(s);
-    assert(s->ref >= 1);
+void pa_sink_set_mute(pa_sink *s, int mute) {
+    int changed;
+    
+    pa_sink_assert_ref(s);
 
-    if (m == PA_MIXER_HARDWARE && s->set_hw_volume) {
+    changed = s->muted != mute;
 
-        if (s->get_hw_volume)
-            s->get_hw_volume(s);
+    if (s->set_mute && s->set_mute(s) < 0)
+        s->set_mute = NULL;
 
-        return &s->hw_volume;
-    } else
-        return &s->sw_volume;
-}
+    if (!s->set_mute)
+        pa_asyncmsgq_post(s->asyncmsgq, PA_MSGOBJECT(s), PA_SINK_MESSAGE_SET_MUTE, PA_UINT_TO_PTR(mute), NULL, NULL);
 
-void pa_sink_set_mute(pa_sink *s, pa_mixer_t m, int mute) {
-    int *t;
-
-    assert(s);
-    assert(s->ref >= 1);
-
-    if (m == PA_MIXER_HARDWARE && s->set_hw_mute)
-        t = &s->hw_muted;
-    else
-        t = &s->sw_muted;
+    if (changed)
+        pa_subscription_post(s->core, PA_SUBSCRIPTION_EVENT_SINK|PA_SUBSCRIPTION_EVENT_CHANGE, s->index);
+}
 
-    if (!!*t == !!mute)
-        return;
+int pa_sink_get_mute(pa_sink *s) {
+    int old_muted;
+    
+    pa_sink_assert_ref(s);
 
-    *t = !!mute;
+    old_muted = s->muted;
+    
+    if (s->get_mute && s->get_mute(s) < 0)
+        s->get_mute = NULL;
 
-    if (t == &s->hw_muted)
-        if (s->set_hw_mute(s) < 0)
-            s->sw_muted = !!mute;
+    if (!s->get_mute && s->refresh_mute)
+        pa_asyncmsgq_send(s->asyncmsgq, PA_MSGOBJECT(s), PA_SINK_MESSAGE_GET_MUTE, &s->muted, NULL);
 
-    pa_subscription_post(s->core, PA_SUBSCRIPTION_EVENT_SINK|PA_SUBSCRIPTION_EVENT_CHANGE, s->index);
+    if (old_muted != s->muted)
+        pa_subscription_post(s->core, PA_SUBSCRIPTION_EVENT_SINK|PA_SUBSCRIPTION_EVENT_CHANGE, s->index);
+    
+    return s->muted;
 }
 
-int pa_sink_get_mute(pa_sink *s, pa_mixer_t m) {
-    assert(s);
-    assert(s->ref >= 1);
+void pa_sink_set_module(pa_sink *s, pa_module *m) {
+    pa_sink_assert_ref(s);
 
-    if (m == PA_MIXER_HARDWARE && s->set_hw_mute) {
+    if (s->module == m)
+        return;
 
-        if (s->get_hw_mute)
-            s->get_hw_mute(s);
+    s->module = m;
 
-        return s->hw_muted;
-    } else
-        return s->sw_muted;
+    if (s->monitor_source)
+        pa_source_set_module(s->monitor_source, m);
+
+    pa_subscription_post(s->core, PA_SUBSCRIPTION_EVENT_SINK|PA_SUBSCRIPTION_EVENT_CHANGE, s->index);
 }
 
 void pa_sink_set_description(pa_sink *s, const char *description) {
-    assert(s);
-    assert(s->ref >= 1);
+    pa_sink_assert_ref(s);
 
     if (!description && !s->description)
         return;
@@ -565,8 +638,7 @@ void pa_sink_set_description(pa_sink *s, const char *description) {
 unsigned pa_sink_used_by(pa_sink *s) {
     unsigned ret;
 
-    assert(s);
-    assert(s->ref >= 1);
+    pa_sink_assert_ref(s);
 
     ret = pa_idxset_size(s->inputs);
 
@@ -575,3 +647,41 @@ unsigned pa_sink_used_by(pa_sink *s) {
 
     return ret;
 }
+
+int pa_sink_process_msg(pa_msgobject *o, int code, void *userdata, pa_memchunk *chunk) {
+    pa_sink *s = PA_SINK(o);
+    pa_sink_assert_ref(s);
+
+    switch (code) {
+        case PA_SINK_MESSAGE_ADD_INPUT: {
+            pa_sink_input *i = userdata;
+            pa_hashmap_put(s->thread_info.inputs, PA_UINT32_TO_PTR(i->index), pa_sink_input_ref(i));
+            return 0;
+        }
+            
+        case PA_SINK_MESSAGE_REMOVE_INPUT: {
+            pa_sink_input *i = userdata;
+            pa_hashmap_remove(s->thread_info.inputs, PA_UINT32_TO_PTR(i->index));
+            return 0;
+        }
+            
+        case PA_SINK_MESSAGE_SET_VOLUME:
+            s->thread_info.soft_volume = *((pa_cvolume*) userdata);
+            return 0;
+            
+        case PA_SINK_MESSAGE_SET_MUTE:
+            s->thread_info.soft_muted = PA_PTR_TO_UINT(userdata);
+            return 0;
+            
+        case PA_SINK_MESSAGE_GET_VOLUME:
+            *((pa_cvolume*) userdata) = s->thread_info.soft_volume;
+            return 0;
+            
+        case PA_SINK_MESSAGE_GET_MUTE:
+            *((int*) userdata) = s->thread_info.soft_muted;
+            return 0;
+            
+        default:
+            return -1;
+    }
+}
diff --git a/src/pulsecore/sink.h b/src/pulsecore/sink.h
index ef73f67..2939cc4 100644
--- a/src/pulsecore/sink.h
+++ b/src/pulsecore/sink.h
@@ -1,5 +1,5 @@
-#ifndef foosinkhfoo
-#define foosinkhfoo
+#ifndef foopulsesinkhfoo
+#define foopulsesinkhfoo
 
 /* $Id$ */
 
@@ -25,37 +25,43 @@
   USA.
 ***/
 
-#include <inttypes.h>
-
 typedef struct pa_sink pa_sink;
 
+#include <inttypes.h>
+
 #include <pulse/sample.h>
 #include <pulse/channelmap.h>
 #include <pulse/volume.h>
+
 #include <pulsecore/core-def.h>
 #include <pulsecore/core.h>
 #include <pulsecore/idxset.h>
 #include <pulsecore/source.h>
 #include <pulsecore/module.h>
+#include <pulsecore/refcnt.h>
+#include <pulsecore/msgobject.h>
 
 #define PA_MAX_INPUTS_PER_SINK 32
 
 typedef enum pa_sink_state {
     PA_SINK_RUNNING,
+    PA_SINK_SUSPENDED,
+    PA_SINK_IDLE,
     PA_SINK_DISCONNECTED
 } pa_sink_state_t;
 
 struct pa_sink {
-    int ref;
+    pa_msgobject parent;
+
     uint32_t index;
     pa_core *core;
-    pa_sink_state_t state;
+    pa_atomic_t state;
 
     char *name;
     char *description, *driver;            /* may be NULL */
     int is_hardware;
 
-    pa_module *owner;                      /* may be NULL */
+    pa_module *module;                      /* may be NULL */
 
     pa_sample_spec sample_spec;
     pa_channel_map channel_map;
@@ -63,49 +69,85 @@ struct pa_sink {
     pa_idxset *inputs;
     pa_source *monitor_source;             /* may be NULL */
 
-    pa_cvolume hw_volume, sw_volume;
-    int hw_muted, sw_muted;
-
-    void (*notify)(pa_sink*sink);          /* may be NULL */
-    pa_usec_t (*get_latency)(pa_sink *s);  /* dito */
-    int (*set_hw_volume)(pa_sink *s);      /* dito */
-    int (*get_hw_volume)(pa_sink *s);      /* dito */
-    int (*set_hw_mute)(pa_sink *s);        /* dito */
-    int (*get_hw_mute)(pa_sink *s);        /* dito */
+    pa_cvolume volume;
+    int muted;
+    int refresh_volume;
+    int refresh_mute;
+
+    int (*start)(pa_sink *s);
+    int (*stop)(pa_sink *s);
+    int (*set_volume)(pa_sink *s);      /* dito */
+    int (*get_volume)(pa_sink *s);      /* dito */
+    int (*get_mute)(pa_sink *s);        /* dito */
+    int (*set_mute)(pa_sink *s);        /* dito */
+    pa_usec_t (*get_latency)(pa_sink *s);    /* dito */
+
+    pa_asyncmsgq *asyncmsgq;
+
+    /* Contains copies of the above data so that the real-time worker
+     * thread can work without access locking */
+    struct {
+        pa_hashmap *inputs;
+        pa_cvolume soft_volume;
+        int soft_muted;
+    } thread_info;
 
     void *userdata;
 };
 
+PA_DECLARE_CLASS(pa_sink);
+#define PA_SINK(s) ((pa_sink*) (s))
+
+typedef enum pa_sink_message {
+    PA_SINK_MESSAGE_ADD_INPUT,
+    PA_SINK_MESSAGE_REMOVE_INPUT,
+    PA_SINK_MESSAGE_GET_VOLUME,
+    PA_SINK_MESSAGE_SET_VOLUME,
+    PA_SINK_MESSAGE_GET_MUTE,
+    PA_SINK_MESSAGE_SET_MUTE,
+    PA_SINK_MESSAGE_GET_LATENCY,
+    PA_SINK_MESSAGE_START,
+    PA_SINK_MESSAGE_STOP,
+    PA_SINK_MESSAGE_MAX
+} pa_sink_message_t;
+
+/* To be used exclusively by the sink driver */
+
 pa_sink* pa_sink_new(
-    pa_core *core,
-    const char *driver,
-    const char *name,
-    int namereg_fail,
-    const pa_sample_spec *spec,
-    const pa_channel_map *map);
+        pa_core *core,
+        const char *driver,
+        const char *name,
+        int namereg_fail,
+        const pa_sample_spec *spec,
+        const pa_channel_map *map);
 
 void pa_sink_disconnect(pa_sink* s);
-void pa_sink_unref(pa_sink*s);
-pa_sink* pa_sink_ref(pa_sink *s);
 
-int pa_sink_render(pa_sink*s, size_t length, pa_memchunk *result);
-void pa_sink_render_full(pa_sink *s, size_t length, pa_memchunk *result);
-int pa_sink_render_into(pa_sink*s, pa_memchunk *target);
-void pa_sink_render_into_full(pa_sink *s, pa_memchunk *target);
+void pa_sink_set_module(pa_sink *sink, pa_module *m);
+void pa_sink_set_description(pa_sink *s, const char *description);
+
+/* Usable by everyone */
 
 pa_usec_t pa_sink_get_latency(pa_sink *s);
 
-void pa_sink_notify(pa_sink*s);
+void pa_sink_update_status(pa_sink*s);
+void pa_sink_suspend(pa_sink *s, int suspend);
 
-void pa_sink_set_owner(pa_sink *sink, pa_module *m);
+void pa_sink_set_volume(pa_sink *sink, const pa_cvolume *volume);
+const pa_cvolume *pa_sink_get_volume(pa_sink *sink);
+void pa_sink_set_mute(pa_sink *sink, int mute);
+int pa_sink_get_mute(pa_sink *sink);
 
-void pa_sink_set_volume(pa_sink *sink, pa_mixer_t m, const pa_cvolume *volume);
-const pa_cvolume *pa_sink_get_volume(pa_sink *sink, pa_mixer_t m);
-void pa_sink_set_mute(pa_sink *sink, pa_mixer_t m, int mute);
-int pa_sink_get_mute(pa_sink *sink, pa_mixer_t m);
+unsigned pa_sink_used_by(pa_sink *s);
+#define pa_sink_get_state(s) ((pa_sink_state_t) pa_atomic_load(&(s)->state))
 
-void pa_sink_set_description(pa_sink *s, const char *description);
+/* To be used exclusively by the sink driver thread */
 
-unsigned pa_sink_used_by(pa_sink *s);
+int pa_sink_render(pa_sink*s, size_t length, pa_memchunk *result);
+void pa_sink_render_full(pa_sink *s, size_t length, pa_memchunk *result);
+int pa_sink_render_into(pa_sink*s, pa_memchunk *target);
+void pa_sink_render_into_full(pa_sink *s, pa_memchunk *target);
+
+int pa_sink_process_msg(pa_msgobject *o, int code, void *userdata, pa_memchunk *chunk);
 
 #endif
diff --git a/src/pulsecore/sound-file-stream.c b/src/pulsecore/sound-file-stream.c
index 7a43c74..a682ee6 100644
--- a/src/pulsecore/sound-file-stream.c
+++ b/src/pulsecore/sound-file-stream.c
@@ -76,21 +76,25 @@ static int sink_input_peek(pa_sink_input *i, pa_memchunk *chunk) {
     if (!u->memchunk.memblock) {
         uint32_t fs = pa_frame_size(&i->sample_spec);
         sf_count_t n;
+        void *p;
 
         u->memchunk.memblock = pa_memblock_new(i->sink->core->mempool, BUF_SIZE);
         u->memchunk.index = 0;
 
+        p = pa_memblock_acquire(u->memchunk.memblock);
+
         if (u->readf_function) {
-            if ((n = u->readf_function(u->sndfile, u->memchunk.memblock->data, BUF_SIZE/fs)) <= 0)
+            if ((n = u->readf_function(u->sndfile, p, BUF_SIZE/fs)) <= 0)
                 n = 0;
 
             u->memchunk.length = n * fs;
         } else {
-            if ((n = sf_read_raw(u->sndfile, u->memchunk.memblock->data, BUF_SIZE)) <= 0)
+            if ((n = sf_read_raw(u->sndfile, p, BUF_SIZE)) <= 0)
                 n = 0;
 
             u->memchunk.length = n;
         }
+        pa_memblock_release(u->memchunk.memblock);
 
         if (!u->memchunk.length) {
             free_userdata(u);
diff --git a/src/pulsecore/sound-file.c b/src/pulsecore/sound-file.c
index 69b543a..6e93f8a 100644
--- a/src/pulsecore/sound-file.c
+++ b/src/pulsecore/sound-file.c
@@ -42,7 +42,11 @@ int pa_sound_file_load(pa_mempool *pool, const char *fname, pa_sample_spec *ss,
     int ret = -1;
     size_t l;
     sf_count_t (*readf_function)(SNDFILE *sndfile, void *ptr, sf_count_t frames) = NULL;
-    assert(fname && ss && chunk);
+    void *ptr = NULL;
+
+    assert(fname);
+    assert(ss);
+    assert(chunk);
 
     chunk->memblock = NULL;
     chunk->index = chunk->length = 0;
@@ -99,8 +103,10 @@ int pa_sound_file_load(pa_mempool *pool, const char *fname, pa_sample_spec *ss,
     chunk->index = 0;
     chunk->length = l;
 
-    if ((readf_function && readf_function(sf, chunk->memblock->data, sfinfo.frames) != sfinfo.frames) ||
-        (!readf_function && sf_read_raw(sf, chunk->memblock->data, l) != l)) {
+    ptr = pa_memblock_acquire(chunk->memblock);
+
+    if ((readf_function && readf_function(sf, ptr, sfinfo.frames) != sfinfo.frames) ||
+        (!readf_function && sf_read_raw(sf, ptr, l) != l)) {
         pa_log("Premature file end");
         goto finish;
     }
@@ -112,6 +118,9 @@ finish:
     if (sf)
         sf_close(sf);
 
+    if (ptr)
+        pa_memblock_release(chunk->memblock);
+
     if (ret != 0 && chunk->memblock)
         pa_memblock_unref(chunk->memblock);
 
diff --git a/src/pulsecore/source-output.c b/src/pulsecore/source-output.c
index c7a9858..c1aa339 100644
--- a/src/pulsecore/source-output.c
+++ b/src/pulsecore/source-output.c
@@ -26,7 +26,6 @@
 #endif
 
 #include <stdio.h>
-#include <assert.h>
 #include <stdlib.h>
 #include <string.h>
 
@@ -39,14 +38,8 @@
 
 #include "source-output.h"
 
-#define CHECK_VALIDITY_RETURN_NULL(condition) \
-do {\
-if (!(condition)) \
-    return NULL; \
-} while (0)
-
 pa_source_output_new_data* pa_source_output_new_data_init(pa_source_output_new_data *data) {
-    assert(data);
+    pa_assert(data);
 
     memset(data, 0, sizeof(*data));
     data->resample_method = PA_RESAMPLER_INVALID;
@@ -54,14 +47,14 @@ pa_source_output_new_data* pa_source_output_new_data_init(pa_source_output_new_d
 }
 
 void pa_source_output_new_data_set_channel_map(pa_source_output_new_data *data, const pa_channel_map *map) {
-    assert(data);
+    pa_assert(data);
 
     if ((data->channel_map_is_set = !!map))
         data->channel_map = *map;
 }
 
 void pa_source_output_new_data_set_sample_spec(pa_source_output_new_data *data, const pa_sample_spec *spec) {
-    assert(data);
+    pa_assert(data);
 
     if ((data->sample_spec_is_set = !!spec))
         data->sample_spec = *spec;
@@ -74,48 +67,53 @@ pa_source_output* pa_source_output_new(
 
     pa_source_output *o;
     pa_resampler *resampler = NULL;
-    int r;
     char st[PA_SAMPLE_SPEC_SNPRINT_MAX];
 
-    assert(core);
-    assert(data);
+    pa_assert(core);
+    pa_assert(data);
 
     if (!(flags & PA_SOURCE_OUTPUT_NO_HOOKS))
         if (pa_hook_fire(&core->hook_source_output_new, data) < 0)
             return NULL;
 
-    CHECK_VALIDITY_RETURN_NULL(!data->driver || pa_utf8_valid(data->driver));
-    CHECK_VALIDITY_RETURN_NULL(!data->name || pa_utf8_valid(data->name));
+    pa_return_null_if_fail(!data->driver || pa_utf8_valid(data->driver));
+    pa_return_null_if_fail(!data->name || pa_utf8_valid(data->name));
 
     if (!data->source)
         data->source = pa_namereg_get(core, NULL, PA_NAMEREG_SOURCE, 1);
 
-    CHECK_VALIDITY_RETURN_NULL(data->source);
-    CHECK_VALIDITY_RETURN_NULL(data->source->state == PA_SOURCE_RUNNING);
+    pa_return_null_if_fail(data->source);
+    pa_return_null_if_fail(pa_source_get_state(data->source) != PA_SOURCE_DISCONNECTED);
 
     if (!data->sample_spec_is_set)
         data->sample_spec = data->source->sample_spec;
 
-    CHECK_VALIDITY_RETURN_NULL(pa_sample_spec_valid(&data->sample_spec));
+    pa_return_null_if_fail(pa_sample_spec_valid(&data->sample_spec));
 
-    if (!data->channel_map_is_set)
-        pa_channel_map_init_auto(&data->channel_map, data->sample_spec.channels, PA_CHANNEL_MAP_DEFAULT);
+    if (!data->channel_map_is_set) {
+        if (data->source->channel_map.channels == data->sample_spec.channels)
+            data->channel_map = data->source->channel_map;
+        else
+            pa_channel_map_init_auto(&data->channel_map, data->sample_spec.channels, PA_CHANNEL_MAP_DEFAULT);
+    }
 
-    CHECK_VALIDITY_RETURN_NULL(pa_channel_map_valid(&data->channel_map));
-    CHECK_VALIDITY_RETURN_NULL(data->channel_map.channels == data->sample_spec.channels);
+    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->resample_method == PA_RESAMPLER_INVALID)
         data->resample_method = core->resample_method;
 
-    CHECK_VALIDITY_RETURN_NULL(data->resample_method < PA_RESAMPLER_MAX);
+    pa_return_null_if_fail(data->resample_method < PA_RESAMPLER_MAX);
 
     if (pa_idxset_size(data->source->outputs) >= PA_MAX_OUTPUTS_PER_SOURCE) {
         pa_log("Failed to create source output: too many outputs per source.");
         return NULL;
     }
 
-    if (!pa_sample_spec_equal(&data->sample_spec, &data->source->sample_spec) ||
-        !pa_channel_map_equal(&data->channel_map, &data->source->channel_map))
+    if ((flags & PA_SOURCE_OUTPUT_VARIABLE_RATE) ||
+        !pa_sample_spec_equal(&data->sample_spec, &data->source->sample_spec) ||
+        !pa_channel_map_equal(&data->channel_map, &data->source->channel_map)) {
+        
         if (!(resampler = pa_resampler_new(
                       core->mempool,
                       &data->source->sample_spec, &data->source->channel_map,
@@ -125,115 +123,133 @@ pa_source_output* pa_source_output_new(
             return NULL;
         }
 
-    o = pa_xnew(pa_source_output, 1);
-    o->ref = 1;
-    o->state = PA_SOURCE_OUTPUT_RUNNING;
+        data->resample_method = pa_resampler_get_method(resampler);
+    }
+
+    o = pa_source_output_new(pa_source_output);
+    
+    o->parent.parent.free = source_output_free;
+    o->parent.process_msg = pa_source_output_process_msg;
+    
+    o->core = core;
+    pa_atomic_load(&o->state, PA_SOURCE_OUTPUT_RUNNING);
+    o->flags = flags;
     o->name = pa_xstrdup(data->name);
     o->driver = pa_xstrdup(data->driver);
     o->module = data->module;
     o->source = data->source;
     o->client = data->client;
 
+    o->resample_method = data->resample_method;
     o->sample_spec = data->sample_spec;
     o->channel_map = data->channel_map;
 
+    o->process_msg = NULL;
     o->push = NULL;
     o->kill = NULL;
     o->get_latency = NULL;
     o->userdata = NULL;
 
-    o->resampler = resampler;
-    o->resample_method = data->resample_method;
+    o->thread_info.resampler = resampler;
 
-    r = pa_idxset_put(core->source_outputs, o, &o->index);
-    assert(r == 0);
-    r = pa_idxset_put(o->source->outputs, o, NULL);
-    assert(r == 0);
+    pa_assert_se(pa_idxset_put(core->source_outputs, o, &o->index) == 0);
+    pa_assert_se( pa_idxset_put(o->source->outputs, o, NULL) == 0);
 
-    pa_log_info("created %u \"%s\" on %s with sample spec %s",
+    pa_log_info("Created output %u \"%s\" on %s with sample spec %s",
                 o->index,
                 o->name,
                 o->source->name,
                 pa_sample_spec_snprint(st, sizeof(st), &o->sample_spec));
 
-    pa_subscription_post(core, PA_SUBSCRIPTION_EVENT_SOURCE_OUTPUT|PA_SUBSCRIPTION_EVENT_NEW, o->index);
-
-    /* We do not call pa_source_notify() here, because the virtual
-     * functions have not yet been initialized */
+    /* Don't forget to call pa_source_output_put! */
 
     return o;
 }
 
 void pa_source_output_disconnect(pa_source_output*o) {
-    assert(o);
-    assert(o->state != PA_SOURCE_OUTPUT_DISCONNECTED);
-    assert(o->source);
-    assert(o->source->core);
+    pa_assert(o);
+    pa_return_if_fail(pa_source_output_get_state(i) != PA_SOURCE_OUTPUT_DISCONNECTED);
+    pa_assert(o->source);
+    pa_assert(o->source->core);
 
+    pa_asyncmsgq_send(i->sink->asyncmsgq, i->sink, PA_SOURCE_MESSAGE_REMOVE_OUTPUT, o, NULL);
+    
     pa_idxset_remove_by_data(o->source->core->source_outputs, o, NULL);
     pa_idxset_remove_by_data(o->source->outputs, o, NULL);
 
     pa_subscription_post(o->source->core, PA_SUBSCRIPTION_EVENT_SOURCE_OUTPUT|PA_SUBSCRIPTION_EVENT_REMOVE, o->index);
     o->source = NULL;
 
+    o->process_msg = NULL;
     o->push = NULL;
     o->kill = NULL;
     o->get_latency = NULL;
 
-    o->state = PA_SOURCE_OUTPUT_DISCONNECTED;
+    pa_atomic_load(&i->state, PA_SOURCE_OUTPUT_DISCONNECTED);
 }
 
-static void source_output_free(pa_source_output* o) {
-    assert(o);
+static void source_output_free(pa_msgobject* mo) {
+    pa_source_output *o = PA_SOURCE_OUTPUT(mo);
+    
+    pa_assert(pa_source_output_refcnt(o) == 0);
 
-    if (o->state != PA_SOURCE_OUTPUT_DISCONNECTED)
-        pa_source_output_disconnect(o);
+    pa_source_output_disconnect(o);
 
-    pa_log_info("freed %u \"%s\"", o->index, o->name);
+    pa_log_info("Freeing output %u \"%s\"", o->index, o->name);
 
-    if (o->resampler)
-        pa_resampler_free(o->resampler);
+    if (o->thread_info.resampler)
+        pa_resampler_free(o->thread_info.resampler);
 
     pa_xfree(o->name);
     pa_xfree(o->driver);
     pa_xfree(o);
 }
 
-void pa_source_output_unref(pa_source_output* o) {
-    assert(o);
-    assert(o->ref >= 1);
+void pa_source_output_put(pa_source_output *o) {
+    pa_source_output_assert_ref(o);
+    
+    pa_asyncmsgq_post(o->source->asyncmsgq, o->source, PA_SOURCE_MESSAGE_ADD_OUTPUT, o, NULL, pa_source_unref, pa_source_output_unref);
+    pa_source_update_status(o->source);
 
-    if (!(--o->ref))
-        source_output_free(o);
-}
-
-pa_source_output* pa_source_output_ref(pa_source_output *o) {
-    assert(o);
-    assert(o->ref >= 1);
-
-    o->ref++;
-    return o;
+    pa_subscription_post(core, PA_SUBSCRIPTION_EVENT_SOURCE_OUTPUT|PA_SUBSCRIPTION_EVENT_NEW, o->index);
 }
 
 void pa_source_output_kill(pa_source_output*o) {
-    assert(o);
-    assert(o->ref >= 1);
+    pa_source_output_assert_ref(o);
 
     if (o->kill)
         o->kill(o);
 }
 
+pa_usec_t pa_source_output_get_latency(pa_source_output *o) {
+    pa_usec_t r = 0;
+
+    pa_source_output_assert_ref(o);
+
+    if (pa_asyncmsgq_send(o->source->asyncmsgq, i->source, PA_SOURCE_OUTPUT_MESSAGE_GET_LATENCY, &r, NULL) < 0)
+        r = 0;
+    
+    if (o->get_latency)
+        r += o->get_latency(o);
+
+    return r;
+}
+
 void pa_source_output_push(pa_source_output *o, const pa_memchunk *chunk) {
     pa_memchunk rchunk;
+    pa_source_output_state_t state;
 
-    assert(o);
-    assert(chunk);
-    assert(chunk->length);
-    assert(o->push);
+    pa_source_output_assert_ref(o);
+    pa_assert(chunk);
+    pa_assert(chunk->length);
 
-    if (o->state == PA_SOURCE_OUTPUT_CORKED)
+    state = pa_source_output_get_state(o);
+    
+    if (!o->push || state == PA_SOURCE_OUTPUT_DISCONNECTED || state == PA_SOURCE_OUTPUT_CORKED)
         return;
 
+    pa_assert(state = PA_SOURCE_OUTPUT_RUNNING);
+    
     if (!o->resampler) {
         o->push(o, chunk);
         return;
@@ -243,119 +259,137 @@ void pa_source_output_push(pa_source_output *o, const pa_memchunk *chunk) {
     if (!rchunk.length)
         return;
 
-    assert(rchunk.memblock);
+    pa_assert(rchunk.memblock);
     o->push(o, &rchunk);
     pa_memblock_unref(rchunk.memblock);
 }
 
-void pa_source_output_set_name(pa_source_output *o, const char *name) {
-    assert(o);
-    assert(o->ref >= 1);
-
-    if (!o->name && !name)
-        return;
+void pa_source_output_cork(pa_source_output *o, int b) {
+    int n;
+    pa_source_output_state_t state;
 
-    if (o->name && name && !strcmp(o->name, name))
-        return;
+    pa_source_output_assert_ref(o);
 
-    pa_xfree(o->name);
-    o->name = pa_xstrdup(name);
+    state = pa_source_output_get_state(o);
+    pa_assert(state != PA_SOURCE_OUTPUT_DISCONNECTED);
 
-    pa_subscription_post(o->source->core, PA_SUBSCRIPTION_EVENT_SOURCE_OUTPUT|PA_SUBSCRIPTION_EVENT_CHANGE, o->index);
+    if (b && state != PA_SOURCE_OUTPUT_CORKED)
+        pa_atomic_store(o->state, PA_SOURCE_OUTPUT_CORKED);
+    else if (!b && state == PA_SOURCE_OUTPUT_CORKED)
+        pa_atomic_cmpxchg(o->state, state, PA_SOURCE_OUTPUT_RUNNING);
 }
 
-pa_usec_t pa_source_output_get_latency(pa_source_output *o) {
-    assert(o);
-    assert(o->ref >= 1);
+int pa_source_output_set_rate(pa_source_output *o, uint32_t rate) {
+    pa_source_output_assert_ref(o);
+    pa_return_val_if_fail(o->thread_info.resampler, -1);
 
-    if (o->get_latency)
-        return o->get_latency(o);
+    if (i->sample_spec.rate == rate)
+        return 0;
+
+    i->sample_spec.rate = rate;
 
+    pa_asyncmsgq_post(s->asyncmsgq, pa_source_output_ref(i), PA_SOURCE_OUTPUT_MESSAGE_SET_RATE, PA_UINT_TO_PTR(rate), NULL, pa_source_output_unref, NULL);
+    
+    pa_subscription_post(o->source->core, PA_SUBSCRIPTION_EVENT_SOURCE_OUTPUT!|PA_SUBSCRIPTION_EVENT_CHANGE, i->index);
     return 0;
 }
 
-void pa_source_output_cork(pa_source_output *o, int b) {
-    int n;
-
-    assert(o);
-    assert(o->ref >= 1);
+void pa_source_output_set_name(pa_source_output *o, const char *name) {
+    pa_source_output_assert_ref(o);
 
-    if (o->state == PA_SOURCE_OUTPUT_DISCONNECTED)
+    if (!o->name && !name)
         return;
 
-    n = o->state == PA_SOURCE_OUTPUT_CORKED && !b;
+    if (o->name && name && !strcmp(o->name, name))
+        return;
 
-    o->state = b ? PA_SOURCE_OUTPUT_CORKED : PA_SOURCE_OUTPUT_RUNNING;
+    pa_xfree(o->name);
+    o->name = pa_xstrdup(name);
 
-    if (n)
-        pa_source_notify(o->source);
+    pa_subscription_post(o->source->core, PA_SUBSCRIPTION_EVENT_SOURCE_OUTPUT|PA_SUBSCRIPTION_EVENT_CHANGE, o->index);
 }
 
 pa_resample_method_t pa_source_output_get_resample_method(pa_source_output *o) {
-    assert(o);
-    assert(o->ref >= 1);
+    pa_source_output_assert_ref(o);
 
-    if (!o->resampler)
-        return o->resample_method;
-
-    return pa_resampler_get_method(o->resampler);
+    return o->resample_method; 
 }
 
 int pa_source_output_move_to(pa_source_output *o, pa_source *dest) {
     pa_source *origin;
     pa_resampler *new_resampler = NULL;
 
-    assert(o);
-    assert(o->ref >= 1);
-    assert(dest);
+    pa_source_output_assert_ref(o);
+    pa_source_assert_ref(dest);
 
-    origin = o->source;
+    return -1;
+    
+/*     origin = o->source; */
 
-    if (dest == origin)
-        return 0;
+/*     if (dest == origin) */
+/*         return 0; */
 
-    if (pa_idxset_size(dest->outputs) >= PA_MAX_OUTPUTS_PER_SOURCE) {
-        pa_log_warn("Failed to move source output: too many outputs per source.");
-        return -1;
-    }
+/*     if (pa_idxset_size(dest->outputs) >= PA_MAX_OUTPUTS_PER_SOURCE) { */
+/*         pa_log_warn("Failed to move source output: too many outputs per source."); */
+/*         return -1; */
+/*     } */
 
-    if (o->resampler &&
-        pa_sample_spec_equal(&origin->sample_spec, &dest->sample_spec) &&
-        pa_channel_map_equal(&origin->channel_map, &dest->channel_map))
+/*     if (o->resampler && */
+/*         pa_sample_spec_equal(&origin->sample_spec, &dest->sample_spec) && */
+/*         pa_channel_map_equal(&origin->channel_map, &dest->channel_map)) */
 
-        /* Try to reuse the old resampler if possible */
-        new_resampler = o->resampler;
+/*         /\* Try to reuse the old resampler if possible *\/ */
+/*         new_resampler = o->resampler; */
 
-    else if (!pa_sample_spec_equal(&o->sample_spec, &dest->sample_spec) ||
-        !pa_channel_map_equal(&o->channel_map, &dest->channel_map)) {
+/*     else if (!pa_sample_spec_equal(&o->sample_spec, &dest->sample_spec) || */
+/*         !pa_channel_map_equal(&o->channel_map, &dest->channel_map)) { */
 
-        /* Okey, we need a new resampler for the new sink */
+/*         /\* Okey, we need a new resampler for the new sink *\/ */
 
-        if (!(new_resampler = pa_resampler_new(
-                      dest->core->mempool,
-                      &dest->sample_spec, &dest->channel_map,
-                      &o->sample_spec, &o->channel_map,
-                      o->resample_method))) {
-            pa_log_warn("Unsupported resampling operation.");
-            return -1;
-        }
-    }
+/*         if (!(new_resampler = pa_resampler_new( */
+/*                       dest->core->mempool, */
+/*                       &dest->sample_spec, &dest->channel_map, */
+/*                       &o->sample_spec, &o->channel_map, */
+/*                       o->resample_method))) { */
+/*             pa_log_warn("Unsupported resampling operation."); */
+/*             return -1; */
+/*         } */
+/*     } */
 
-    /* Okey, let's move it */
-    pa_idxset_remove_by_data(origin->outputs, o, NULL);
-    pa_idxset_put(dest->outputs, o, NULL);
-    o->source = dest;
+/*     /\* Okey, let's move it *\/ */
+/*     pa_idxset_remove_by_data(origin->outputs, o, NULL); */
+/*     pa_idxset_put(dest->outputs, o, NULL); */
+/*     o->source = dest; */
 
-    /* Replace resampler */
-    if (new_resampler != o->resampler) {
-        if (o->resampler)
-            pa_resampler_free(o->resampler);
-        o->resampler = new_resampler;
-    }
+/*     /\* Replace resampler *\/ */
+/*     if (new_resampler != o->resampler) { */
+/*         if (o->resampler) */
+/*             pa_resampler_free(o->resampler); */
+/*         o->resampler = new_resampler; */
+/*     } */
 
-    /* Notify everyone */
-    pa_subscription_post(o->source->core, PA_SUBSCRIPTION_EVENT_SOURCE_OUTPUT|PA_SUBSCRIPTION_EVENT_CHANGE, o->index);
-    pa_source_notify(o->source);
+/*     /\* Notify everyone *\/ */
+/*     pa_subscription_post(o->source->core, PA_SUBSCRIPTION_EVENT_SOURCE_OUTPUT|PA_SUBSCRIPTION_EVENT_CHANGE, o->index); */
+/*     pa_source_notify(o->source); */
 
-    return 0;
+/*     return 0; */
+}
+
+int pa_source_output_process_msg(pa_msgobject *mo, int code, void *userdata, pa_memchunk* chunk) {
+    pa_source_output *o = PA_SOURCE_OUTPUT(o);
+    
+    pa_source_output_assert_ref(i);
+
+    switch (code) {
+
+        case PA_SOURCE_OUTPUT_MESSAGE_SET_RATE: {
+            
+            i->thread_info.sample_spec.rate = PA_PTR_TO_UINT(userdata);
+            pa_resampler_set_output_rate(i->resampler, PA_PTR_TO_UINT(userdata));
+
+            return 0;
+        }
+    }
+
+    return -1;
 }
diff --git a/src/pulsecore/source-output.h b/src/pulsecore/source-output.h
index 3da6caa..0f9c3ba 100644
--- a/src/pulsecore/source-output.h
+++ b/src/pulsecore/source-output.h
@@ -1,5 +1,5 @@
-#ifndef foosourceoutputhfoo
-#define foosourceoutputhfoo
+#ifndef foopulsesourceoutputhfoo
+#define foopulsesourceoutputhfoo
 
 /* $Id$ */
 
@@ -35,40 +35,59 @@ typedef struct pa_source_output pa_source_output;
 #include <pulsecore/module.h>
 #include <pulsecore/client.h>
 
-typedef enum {
+typedef enum pa_source_output_state {
     PA_SOURCE_OUTPUT_RUNNING,
     PA_SOURCE_OUTPUT_CORKED,
     PA_SOURCE_OUTPUT_DISCONNECTED
 } pa_source_output_state_t;
 
 typedef enum pa_source_output_flags {
-    PA_SOURCE_OUTPUT_NO_HOOKS = 1
+    PA_SOURCE_OUTPUT_NO_HOOKS = 1,
+    PA_SOURCE_OUTPUT_VARIABLE_RATE = 2
 } pa_source_output_flags_t;
 
 struct pa_source_output {
-    int ref;
+    pa_msgobject parent;
+    
     uint32_t index;
-    pa_source_output_state_t state;
+    pa_core *core;
+    pa_atomic_t state;
+    pa_source_output_flags_t flags;
 
     char *name, *driver;                  /* may be NULL */
     pa_module *module;                    /* may be NULL */
+    pa_client *client;                    /* may be NULL */
 
     pa_source *source;
-    pa_client *client;                    /* may be NULL */
 
     pa_sample_spec sample_spec;
     pa_channel_map channel_map;
 
+    int (*process_msg)(pa_sink_input *i, int code, void *userdata);
     void (*push)(pa_source_output *o, const pa_memchunk *chunk);
     void (*kill)(pa_source_output* o);              /* may be NULL */
     pa_usec_t (*get_latency) (pa_source_output *o); /* may be NULL */
 
-    pa_resampler* resampler;              /* may be NULL */
     pa_resample_method_t resample_method;
 
+    struct {
+        pa_sample_spec sample_spec;
+        
+        pa_resampler* resampler;              /* may be NULL */
+    } thread_info;
+        
     void *userdata;
 };
 
+PA_DECLARE_CLASS(pa_source_output);
+#define PA_SOURCE_OUTPUT(o) ((pa_source_output*) (o))
+
+enum {
+    PA_SOURCE_OUTPUT_MESSAGE_GET_LATENCY,
+    PA_SOURCE_OUTPUT_MESSAGE_SET_RATE,
+    PA_SOURCE_OUTPUT_MESSAGE_MAX
+};
+
 typedef struct pa_source_output_new_data {
     const char *name, *driver;
     pa_module *module;
@@ -89,30 +108,38 @@ void pa_source_output_new_data_set_sample_spec(pa_source_output_new_data *data,
 void pa_source_output_new_data_set_channel_map(pa_source_output_new_data *data, const pa_channel_map *map);
 void pa_source_output_new_data_set_volume(pa_source_output_new_data *data, const pa_cvolume *volume);
 
+/* To be called by the implementing module only */
+
 pa_source_output* pa_source_output_new(
         pa_core *core,
         pa_source_output_new_data *data,
         pa_source_output_flags_t flags);
 
-void pa_source_output_unref(pa_source_output* o);
-pa_source_output* pa_source_output_ref(pa_source_output *o);
-
-/* To be called by the implementing module only */
+void pa_source_output_put(pa_source_output *o);
 void pa_source_output_disconnect(pa_source_output*o);
 
-/* External code may request disconnection with this funcion */
-void pa_source_output_kill(pa_source_output*o);
+void pa_source_output_set_name(pa_source_output *i, const char *name);
 
-void pa_source_output_push(pa_source_output *o, const pa_memchunk *chunk);
+/* Callable by everyone */
 
-void pa_source_output_set_name(pa_source_output *i, const char *name);
+/* External code may request disconnection with this funcion */
+void pa_source_output_kill(pa_source_output*o);
 
 pa_usec_t pa_source_output_get_latency(pa_source_output *i);
 
 void pa_source_output_cork(pa_source_output *i, int b);
 
+void pa_source_output_set_rate(pa_source_output *o, uint32_t rate);
+
 pa_resample_method_t pa_source_output_get_resample_method(pa_source_output *o);
 
 int pa_source_output_move_to(pa_source_output *o, pa_source *dest);
 
+#define pa_source_output_get_state(o) ((pa_source_output_state_t) pa_atomic_load(&o->state))
+
+/* To be used exclusively by the source driver thread */
+
+void pa_source_output_push(pa_source_output *o, const pa_memchunk *chunk);
+int pa_source_output_process_msg(pa_msgobject *mo, int code, void *userdata, pa_memchunk *chunk);
+
 #endif
diff --git a/src/pulsecore/source.c b/src/pulsecore/source.c
index 9bb2d34..fd3c85d 100644
--- a/src/pulsecore/source.c
+++ b/src/pulsecore/source.c
@@ -42,12 +42,6 @@
 
 #include "source.h"
 
-#define CHECK_VALIDITY_RETURN_NULL(condition) \
-do {\
-if (!(condition)) \
-    return NULL; \
-} while (0)
-
 pa_source* pa_source_new(
         pa_core *core,
         const char *driver,
@@ -65,30 +59,32 @@ pa_source* pa_source_new(
     assert(name);
     assert(spec);
 
-    CHECK_VALIDITY_RETURN_NULL(pa_sample_spec_valid(spec));
+    pa_return_null_if_fail(pa_sample_spec_valid(spec));
 
     if (!map)
         map = pa_channel_map_init_auto(&tmap, spec->channels, PA_CHANNEL_MAP_DEFAULT);
 
-    CHECK_VALIDITY_RETURN_NULL(map && pa_channel_map_valid(map));
-    CHECK_VALIDITY_RETURN_NULL(map->channels == spec->channels);
-    CHECK_VALIDITY_RETURN_NULL(!driver || pa_utf8_valid(driver));
-    CHECK_VALIDITY_RETURN_NULL(pa_utf8_valid(name) && *name);
+    pa_return_null_if_fail(map && pa_channel_map_valid(map));
+    pa_return_null_if_fail(map->channels == spec->channels);
+    pa_return_null_if_fail(!driver || pa_utf8_valid(driver));
+    pa_return_null_if_fail(pa_utf8_valid(name) && *name);
 
-    s = pa_xnew(pa_source, 1);
+    s = pa_msgobject_new(pa_source);
 
     if (!(name = pa_namereg_register(core, name, PA_NAMEREG_SOURCE, s, fail))) {
         pa_xfree(s);
         return NULL;
     }
 
-    s->ref = 1;
+    s->parent.parent.free = source_free;
+    s->parent.process_msg = pa_source_process_msg;
+    
     s->core = core;
-    s->state = PA_SOURCE_RUNNING;
+    pa_atomic_store(&s->state, PA_SOURCE_IDLE);
     s->name = pa_xstrdup(name);
     s->description = NULL;
     s->driver = pa_xstrdup(driver);
-    s->owner = NULL;
+    s->module = NULL;
 
     s->sample_spec = *spec;
     s->channel_map = *map;
@@ -96,45 +92,87 @@ pa_source* pa_source_new(
     s->outputs = pa_idxset_new(NULL, NULL);
     s->monitor_of = NULL;
 
-    pa_cvolume_reset(&s->sw_volume, spec->channels);
-    pa_cvolume_reset(&s->hw_volume, spec->channels);
-    s->sw_muted = 0;
-    s->hw_muted = 0;
+    pa_cvolume_reset(&s->volume, spec->channels);
+    s->muted = 0;
+    s->refresh_volume = s->refresh_mute = 0;
 
     s->is_hardware = 0;
 
     s->get_latency = NULL;
-    s->notify = NULL;
-    s->set_hw_volume = NULL;
-    s->get_hw_volume = NULL;
-    s->set_hw_mute = NULL;
-    s->get_hw_mute = NULL;
+    s->set_volume = NULL;
+    s->get_volume = NULL;
+    s->set_mute = NULL;
+    s->get_mute = NULL;
+    s->start = NULL;
+    s->stop = NULL;
     s->userdata = NULL;
 
+    pa_assert_se(s->asyncmsgq = pa_asyncmsgq_new(0));
+    
     r = pa_idxset_put(core->sources, s, &s->index);
     assert(s->index != PA_IDXSET_INVALID && r >= 0);
 
     pa_sample_spec_snprint(st, sizeof(st), spec);
-    pa_log_info("created %u \"%s\" with sample spec \"%s\"", s->index, s->name, st);
+    pa_log_info("Created source %u \"%s\" with sample spec \"%s\"", s->index, s->name, st);
 
+    s->thread_info.outputs = pa_hashmap_new(pa_idxset_trivial_hash_func, pa_idxset_trivial_compare_func);
+    s->thread_info.soft_volume = s->volume;
+    s->thread_info.soft_muted = s->muted;
+    
     pa_subscription_post(core, PA_SUBSCRIPTION_EVENT_SOURCE | PA_SUBSCRIPTION_EVENT_NEW, s->index);
 
     return s;
 }
 
+static void source_start(pa_source *s) {
+    pa_source_state_t state;
+    pa_assert(s);
+
+    state = pa_source_get_state(s);
+    pa_return_if_fail(state == PA_SOURCE_IDLE || state == PA_SOURCE_SUSPENDED);
+
+    pa_atomic_store(&s->state, PA_SOURCE_RUNNING);
+
+    if (s->start)
+        s->start(s);
+    else
+        pa_asyncmsgq_post(s->asyncmsgq, s, PA_SOURCE_MESSAGE_START, NULL, NULL, pa_source_unref, NULL);
+}
+
+static void source_stop(pa_source *s) {
+    pa_source_state_t state;
+    int stop;
+    
+    pa_assert(s);
+    state = pa_source_get_state(s);
+    pa_return_if_fail(state == PA_SOURCE_RUNNING || state == PA_SOURCE_SUSPENDED);
+
+    stop = state == PA_SOURCE_RUNNING;
+    pa_atomic_store(&s->state, PA_SOURCE_IDLE);
+
+    if (stop) {
+        if (s->stop)
+            s->stop(s);
+        else
+            pa_asyncmsgq_post(s->asyncmsgq, s, PA_SOURCE_MESSAGE_STOP, NULL, NULL, pa_source_unref, NULL);
+    }
+}
+
 void pa_source_disconnect(pa_source *s) {
     pa_source_output *o, *j = NULL;
 
-    assert(s);
-    assert(s->state == PA_SOURCE_RUNNING);
+    pa_assert(s);
+    pa_return_if_fail(pa_sink_get_state(s) != PA_SINK_DISCONNECT);
 
-    s->state = PA_SOURCE_DISCONNECTED;
+    source_stop(s);
+    
+    pa_atomic_store(&s->state, PA_SOURCE_DISCONNECTED);
     pa_namereg_unregister(s->core, s->name);
 
     pa_hook_fire(&s->core->hook_source_disconnect, s);
 
     while ((o = pa_idxset_first(s->outputs, NULL))) {
-        assert(o != j);
+        pa_assert(o != j);
         pa_source_output_kill(o);
         j = o;
     }
@@ -142,190 +180,206 @@ void pa_source_disconnect(pa_source *s) {
     pa_idxset_remove_by_data(s->core->sources, s, NULL);
 
     s->get_latency = NULL;
-    s->notify = NULL;
-    s->get_hw_volume = NULL;
-    s->set_hw_volume = NULL;
-    s->set_hw_mute = NULL;
-    s->get_hw_mute = NULL;
+    s->get_volume = NULL;
+    s->set_volume = NULL;
+    s->set_mute = NULL;
+    s->get_mute = NULL;
+    s->start = NULL;
+    s->stop = NULL;
 
     pa_subscription_post(s->core, PA_SUBSCRIPTION_EVENT_SOURCE | PA_SUBSCRIPTION_EVENT_REMOVE, s->index);
 }
 
-static void source_free(pa_source *s) {
-    assert(s);
-    assert(!s->ref);
+static void source_free(pa_msgobject *o) {
+    pa_source *s = PA_SOURCE(o);
+    
+    pa_assert(s);
+    pa_assert(pa_source_refcnt(s) == 0);
 
-    if (s->state != PA_SOURCE_DISCONNECTED)
-        pa_source_disconnect(s);
+    pa_source_disconnect(s);
 
-    pa_log_info("freed %u \"%s\"", s->index, s->name);
+    pa_log_info("Freeing source %u \"%s\"", s->index, s->name);
 
     pa_idxset_free(s->outputs, NULL, NULL);
+    pa_hashmap_free(s->thread_info.outputs, pa_sink_output_unref, NULL);
 
+    pa_asyncmsgq_free(s->asyncmsgq);
+    
     pa_xfree(s->name);
     pa_xfree(s->description);
     pa_xfree(s->driver);
     pa_xfree(s);
 }
 
-void pa_source_unref(pa_source *s) {
-    assert(s);
-    assert(s->ref >= 1);
+void pa_source_update_status(pa_source*s) {
+    pa_source_assert_ref(s);
 
-    if (!(--s->ref))
-        source_free(s);
+    if (pa_source_get_state(s) == PA_SOURCE_STATE_SUSPENDED)
+        return;
+    
+    if (pa_source_used_by(s) > 0)
+        source_start(s);
+    else
+        source_stop(s);
 }
 
-pa_source* pa_source_ref(pa_source *s) {
-    assert(s);
-    assert(s->ref >= 1);
+void pa_source_suspend(pa_source *s, int suspend) {
+    pa_source_state_t state;
 
-    s->ref++;
-    return s;
-}
+    pa_source_assert_ref(s);
 
-void pa_source_notify(pa_source*s) {
-    assert(s);
-    assert(s->ref >= 1);
+    state = pa_source_get_state(s);
+    pa_return_if_fail(suspend && (s->state == PA_SOURCE_RUNNING || s->state == PA_SOURCE_IDLE));
+    pa_return_if_fail(!suspend && (s->state == PA_SOURCE_SUSPENDED));
 
-    if (s->notify)
-        s->notify(s);
-}
 
-static int do_post(void *p, PA_GCC_UNUSED uint32_t idx, PA_GCC_UNUSED int *del, void*userdata) {
-    pa_source_output *o = p;
-    const pa_memchunk *chunk = userdata;
+    if (suspend) {
+        pa_atomic_store(&s->state, PA_SOURCE_SUSPENDED);
 
-    assert(o);
-    assert(chunk);
+        if (s->stop)
+            s->stop(s);
+        else
+            pa_asyncmsgq_post(s->asyncmsgq, s, PA_SOURCE_MESSAGE_STOP, NULL, NULL, pa_source_unref, NULL);
+        
+    } else {
+        pa_atomic_store(&s->state, PA_SOURCE_RUNNING);
 
-    pa_source_output_push(o, chunk);
-    return 0;
+        if (s->start)
+            s->start(s);
+        else
+            pa_asyncmsgq_post(s->asyncmsgq, s, PA_SOURCE_MESSAGE_START, NULL, NULL, pa_source_unref, NULL);
+    }
 }
 
 void pa_source_post(pa_source*s, const pa_memchunk *chunk) {
-    assert(s);
-    assert(s->ref >= 1);
-    assert(chunk);
-
-    pa_source_ref(s);
+    pa_source_output *o;
+    void *state = NULL;
+    
+    pa_source_assert_ref(s);
+    pa_assert(chunk);
 
     if (s->sw_muted || !pa_cvolume_is_norm(&s->sw_volume)) {
         pa_memchunk vchunk = *chunk;
 
         pa_memblock_ref(vchunk.memblock);
         pa_memchunk_make_writable(&vchunk, 0);
-        if (s->sw_muted)
+        
+        if (s->thread_info.muted || pa_cvolume_is_muted(s->thread_info.volume))
             pa_silence_memchunk(&vchunk, &s->sample_spec);
         else
-            pa_volume_memchunk(&vchunk, &s->sample_spec, &s->sw_volume);
-        pa_idxset_foreach(s->outputs, do_post, &vchunk);
+            pa_volume_memchunk(&vchunk, &s->sample_spec, &s->thread_info.volume);
+
+        while ((o = pa_hashmap_iterate(s->thread_info.outputs, &state, NULL)))
+            pa_source_output_push(o, &vchunk);
+            
         pa_memblock_unref(vchunk.memblock);
-    } else
-        pa_idxset_foreach(s->outputs, do_post, (void*) chunk);
+    } else {
+        
+        while ((o = pa_hashmap_iterate(s->thread_info.outputs, &state, NULL)))
+            pa_source_output_push(o, chunk);
 
-    pa_source_unref(s);
+    }
 }
 
-void pa_source_set_owner(pa_source *s, pa_module *m) {
-    assert(s);
-    assert(s->ref >= 1);
-
-    if (m == s->owner)
-        return;
+pa_usec_t pa_source_get_latency(pa_source *s) {
+    pa_usec_t usec;
 
-    s->owner = m;
-    pa_subscription_post(s->core, PA_SUBSCRIPTION_EVENT_SOURCE|PA_SUBSCRIPTION_EVENT_CHANGE, s->index);
-}
+    pa_source_assert_ref(s);
 
-pa_usec_t pa_source_get_latency(pa_source *s) {
-    assert(s);
-    assert(s->ref >= 1);
+    if (s->get_latency)
+        return s->get_latency(s);
 
-    if (!s->get_latency)
+    if (pa_asyncmsgq_send(s->asyncmsgq, s, PA_SOURCE_MESSAGE_GET_LATENCY, &usec, NULL) < 0)
         return 0;
 
-    return s->get_latency(s);
+    return usec;
 }
 
-void pa_source_set_volume(pa_source *s, pa_mixer_t m, const pa_cvolume *volume) {
+void pa_source_set_volume(pa_source *s, const pa_cvolume *volume) {
     pa_cvolume *v;
 
-    assert(s);
-    assert(s->ref >= 1);
-    assert(volume);
-
-    if (m == PA_MIXER_HARDWARE && s->set_hw_volume)
-        v = &s->hw_volume;
-    else
-        v = &s->sw_volume;
-
-    if (pa_cvolume_equal(v, volume))
-        return;
+    pa_source_assert_ref(s);
+    pa_assert(volume);
 
-    *v = *volume;
+    changed = !pa_cvolume_equal(volume, s->volume);
+    s->volume = *volume;
+    
+    if (s->set_volume && s->set_volume(s) < 0)
+        s->set_volume = NULL;
 
-    if (v == &s->hw_volume)
-        if (s->set_hw_volume(s) < 0)
-            s->sw_volume =  *volume;
+    if (!s->set_volume)
+        pa_asyncmsgq_post(s->asyncmsgq, pa_source_ref(s), PA_SOURCE_MESSAGE_SET_VOLUME, pa_xnewdup(struct pa_cvolume, volume, 1), pa_source_unref, pa_xfree);
 
-    pa_subscription_post(s->core, PA_SUBSCRIPTION_EVENT_SOURCE|PA_SUBSCRIPTION_EVENT_CHANGE, s->index);
+    if (changed)
+        pa_subscription_post(s->core, PA_SUBSCRIPTION_EVENT_SOURCE|PA_SUBSCRIPTION_EVENT_CHANGE, s->index);
 }
 
-const pa_cvolume *pa_source_get_volume(pa_source *s, pa_mixer_t m) {
-    assert(s);
-    assert(s->ref >= 1);
+const pa_cvolume *pa_source_get_volume(pa_source *s) {
+    pa_source_assert_ref(s);
 
-    if (m == PA_MIXER_HARDWARE && s->set_hw_volume) {
+    old_volume = s->volume;
+    
+    if (s->get_volume && s->get_volume(s) < 0)
+        s->get_volume = NULL;
 
-        if (s->get_hw_volume)
-            s->get_hw_volume(s);
+    if (!s->get_volume && s->refresh_volume)
+        pa_asyncmsgq_send(s->asyncmsgq, s, PA_SOURCE_MESSAGE_GET_VOLUME, &s->volume);
 
-        return &s->hw_volume;
-    } else
-        return &s->sw_volume;
+    if (!pa_cvolume_equal(&old_volume, &s->volume))
+        pa_subscription_post(s->core, PA_SUBSCRIPTION_EVENT_SOURCE|PA_SUBSCRIPTION_EVENT_CHANGE, s->index);
+    
+    return &s->volume;
 }
 
 void pa_source_set_mute(pa_source *s, pa_mixer_t m, int mute) {
-    int *t;
+    int changed;
+    
+    pa_source_assert_ref(s);
 
-    assert(s);
-    assert(s->ref >= 1);
+    changed = s->muted != mute;
 
-    if (m == PA_MIXER_HARDWARE && s->set_hw_mute)
-        t = &s->hw_muted;
-    else
-        t = &s->sw_muted;
-
-    if (!!*t == !!mute)
-        return;
+    if (s->set_mute && s->set_mute(s) < 0)
+        s->set_mute = NULL;
 
-    *t = !!mute;
+    if (!s->set_mute)
+        pa_asyncmsgq_post(s->asyncmsgq, pa_source_ref(s), PA_SOURCE_MESSAGE_SET_MUTE, PA_UINT_TO_PTR(mute), pa_source_unref, NULL);
 
-    if (t == &s->hw_muted)
-        if (s->set_hw_mute(s) < 0)
-            s->sw_muted = !!mute;
-
-    pa_subscription_post(s->core, PA_SUBSCRIPTION_EVENT_SOURCE|PA_SUBSCRIPTION_EVENT_CHANGE, s->index);
+    if (changed)
+        pa_subscription_post(s->core, PA_SUBSCRIPTION_EVENT_SOURCE|PA_SUBSCRIPTION_EVENT_CHANGE, s->index);
 }
 
 int pa_source_get_mute(pa_source *s, pa_mixer_t m) {
-    assert(s);
-    assert(s->ref >= 1);
+    int old_muted;
+    
+    pa_source_assert_ref(s);
+
+    old_muted = s->muted;
+    
+    if (s->get_mute && s->get_mute(s) < 0)
+        s->get_mute = NULL;
+
+    if (!s->get_mute && s->refresh_mute)
+        pa_asyncmsgq_send(s->asyncmsgq, s, PA_SOURCE_MESSAGE_GET_MUTE, &s->muted);
+
+    if (old_muted != s->muted)
+        pa_subscription_post(s->core, PA_SUBSCRIPTION_EVENT_SOURCE|PA_SUBSCRIPTION_EVENT_CHANGE, s->index);
+    
+    return s->muted;
+}
 
-    if (m == PA_MIXER_HARDWARE && s->set_hw_mute) {
+void pa_source_set_module(pa_source *s, pa_module *m) {
+    pa_source_assert_ref(s);
 
-        if (s->get_hw_mute)
-            s->get_hw_mute(s);
+    if (m == s->module)
+        return;
 
-        return s->hw_muted;
-    } else
-        return s->sw_muted;
+    s->module = m;
+    
+    pa_subscription_post(s->core, PA_SUBSCRIPTION_EVENT_SOURCE|PA_SUBSCRIPTION_EVENT_CHANGE, s->index);
 }
 
 void pa_source_set_description(pa_source *s, const char *description) {
-    assert(s);
-    assert(s->ref >= 1);
+    pa_source_assert_ref(s);
 
     if (!description && !s->description)
         return;
@@ -340,8 +394,45 @@ void pa_source_set_description(pa_source *s, const char *description) {
 }
 
 unsigned pa_source_used_by(pa_source *s) {
-    assert(s);
-    assert(s->ref >= 1);
+    pa_source_assert_ref(s);
 
     return pa_idxset_size(s->outputs);
 }
+
+int pa_source_process_msg(pa_msgobject *o, void *object, int code, pa_memchunk *chunk, void *userdata) {
+    pa_source *s = PA_SOURCE(o);
+    pa_source_assert_ref(s);
+
+    switch (code) {
+        case PA_SOURCE_MESSAGE_ADD_OUTPUT: {
+            pa_source_output *i = userdata;
+            pa_hashmap_put(s->thread_info.outputs, PA_UINT32_TO_PTR(i->index), pa_source_output_ref(i));
+            return 0;
+        }
+            
+        case PA_SOURCE_MESSAGE_REMOVE_INPUT: {
+            pa_source_input *i = userdata;
+            pa_hashmap_remove(s->thread_info.outputs, PA_UINT32_TO_PTR(i->index), pa_source_output_ref(i));
+            return 0;
+        }
+            
+        case PA_SOURCE_MESSAGE_SET_VOLUME:
+            s->thread_info.soft_volume = *((pa_cvolume*) userdata);
+            return 0;
+            
+        case PA_SOURCE_MESSAGE_SET_MUTE:
+            s->thread_info.soft_muted = PA_PTR_TO_UINT(userdata);
+            return 0;
+            
+        case PA_SOURCE_MESSAGE_GET_VOLUME:
+            *((pa_cvolume*) userdata) = s->thread_info.soft_volume;
+            return 0;
+            
+        case PA_SOURCE_MESSAGE_GET_MUTE:
+            *((int*) userdata) = s->thread_info.soft_muted;
+            return 0;
+            
+        default:
+            return -1;
+    }
+}
diff --git a/src/pulsecore/source.h b/src/pulsecore/source.h
index 5a28cf4..1e20c6e 100644
--- a/src/pulsecore/source.h
+++ b/src/pulsecore/source.h
@@ -1,5 +1,5 @@
-#ifndef foosourcehfoo
-#define foosourcehfoo
+#ifndef foopulsesourcehfoo
+#define foopulsesourcehfoo
 
 /* $Id$ */
 
@@ -32,6 +32,7 @@ typedef struct pa_source pa_source;
 #include <pulse/sample.h>
 #include <pulse/channelmap.h>
 #include <pulse/volume.h>
+
 #include <pulsecore/core-def.h>
 #include <pulsecore/core.h>
 #include <pulsecore/idxset.h>
@@ -39,24 +40,30 @@ typedef struct pa_source pa_source;
 #include <pulsecore/memchunk.h>
 #include <pulsecore/sink.h>
 #include <pulsecore/module.h>
+#include <pulsecore/asyncmsgq.h>
+#include <pulsecore/msgobject.h>
 
-#define PA_MAX_OUTPUTS_PER_SOURCE 16
+#define PA_MAX_OUTPUTS_PER_SOURCE 32
 
 typedef enum pa_source_state {
     PA_SOURCE_RUNNING,
+    PA_SOURCE_SUSPENDED,
+    PA_SOURCE_IDLE,
     PA_SOURCE_DISCONNECTED
 } pa_source_state_t;
 
 struct pa_source {
-    int ref;
+    pa_msgobject parent;
+    
     uint32_t index;
     pa_core *core;
-    pa_source_state_t state;
+    pa_atomic_t state;
 
     char *name;
     char *description, *driver;              /* may be NULL */
+    int is_hardware;
 
-    pa_module *owner;                        /* may be NULL */
+    pa_module *module;                        /* may be NULL */
 
     pa_sample_spec sample_spec;
     pa_channel_map channel_map;
@@ -64,48 +71,79 @@ struct pa_source {
     pa_idxset *outputs;
     pa_sink *monitor_of;                     /* may be NULL */
 
-    pa_cvolume hw_volume, sw_volume;
-    int hw_muted, sw_muted;
-
-    int is_hardware;
-
-    void (*notify)(pa_source*source);        /* may be NULL */
+    pa_cvolume volume;
+    int muted;
+    int refresh_volume;
+    int referesh_mute;
+
+    void (*start)(pa_source*source);         /* may be NULL */
+    void (*stop)(pa_source*source);          /* may be NULL */
+    int (*set_volume)(pa_source *s);         /* dito */
+    int (*get_volume)(pa_source *s);         /* dito */
+    int (*set_mute)(pa_source *s);           /* dito */
+    int (*get_mute)(pa_source *s);           /* dito */
     pa_usec_t (*get_latency)(pa_source *s);  /* dito */
-    int (*set_hw_volume)(pa_source *s);      /* dito */
-    int (*get_hw_volume)(pa_source *s);      /* dito */
-    int (*set_hw_mute)(pa_source *s);        /* dito */
-    int (*get_hw_mute)(pa_source *s);        /* dito */
 
+    pa_asyncmsgq *asyncmsgq;
+
+    struct {
+        pa_hashmap *outputs;
+        pa_cvolume soft_volume;
+        int soft_muted;
+    } thread_info;
+    
     void *userdata;
 };
 
+PA_DECLARE_CLASS(pa_source);
+#define PA_SOURCE(s) ((pa_source*) (s))
+
+typedef enum pa_source_message {
+    PA_SOURCE_MESSAGE_ADD_OUTPUT,
+    PA_SOURCE_MESSAGE_REMOVE_OUTPUT,
+    PA_SOURCE_MESSAGE_GET_VOLUME,
+    PA_SOURCE_MESSAGE_SET_VOLUME,
+    PA_SOURCE_MESSAGE_GET_MUTE,
+    PA_SOURCE_MESSAGE_SET_MUTE,
+    PA_SOURCE_MESSAGE_GET_LATENCY,
+    PA_SOURCE_MESSAGE_START,
+    PA_SOURCE_MESSAGE_STOP,
+    PA_SOURCE_MESSAGE_MAX
+} pa_source_message_t;
+
+/* To be used exclusively by the source driver */
+
 pa_source* pa_source_new(
-    pa_core *core,
-    const char *driver,
-    const char *name,
-    int namereg_fail,
-    const pa_sample_spec *spec,
-    const pa_channel_map *map);
+        pa_core *core,
+        const char *driver,
+        const char *name,
+        int namereg_fail,
+        const pa_sample_spec *spec,
+        const pa_channel_map *map);
 
 void pa_source_disconnect(pa_source *s);
-void pa_source_unref(pa_source *s);
-pa_source* pa_source_ref(pa_source *c);
 
-/* Pass a new memory block to all output streams */
-void pa_source_post(pa_source*s, const pa_memchunk *b);
-
-void pa_source_notify(pa_source *s);
+void pa_source_set_module(pa_source *s, pa_module *m);
+void pa_source_set_description(pa_source *s, const char *description);
 
-void pa_source_set_owner(pa_source *s, pa_module *m);
+/* Callable by everyone */
 
 pa_usec_t pa_source_get_latency(pa_source *s);
 
-void pa_source_set_volume(pa_source *source, pa_mixer_t m, const pa_cvolume *volume);
-const pa_cvolume *pa_source_get_volume(pa_source *source, pa_mixer_t m);
-void pa_source_set_mute(pa_source *source, pa_mixer_t m, int mute);
-int pa_source_get_mute(pa_source *source, pa_mixer_t m);
+void pa_source_update_status(pa_source*s);
+void pa_source_suspend(pa_source *s);
 
-void pa_source_set_description(pa_source *s, const char *description);
+void pa_source_set_volume(pa_source *source, const pa_cvolume *volume);
+const pa_cvolume *pa_source_get_volume(pa_source *source);
+void pa_source_set_mute(pa_source *source, int mute);
+int pa_source_get_mute(pa_source *source);
 
 unsigned pa_source_used_by(pa_source *s);
+#define pa_source_get_state(s) ((pa_source_state_t) pa_atomic_load(&(s)->state))
+
+/* To be used exclusively by the source driver thread */
+
+void pa_source_post(pa_source*s, const pa_memchunk *b);
+void pa_source_process_msg(pa_msgobject *o, int code, void *userdata, pa_memchunk *chunk);
+
 #endif
diff --git a/src/pulsecore/thread-posix.c b/src/pulsecore/thread-posix.c
index 4271fa4..6ad5ac4 100644
--- a/src/pulsecore/thread-posix.c
+++ b/src/pulsecore/thread-posix.c
@@ -26,7 +26,6 @@
 #include <config.h>
 #endif
 
-#include <assert.h>
 #include <pthread.h>
 #include <sched.h>
 #include <errno.h>
@@ -35,56 +34,50 @@
 #include <pulsecore/mutex.h>
 #include <pulsecore/once.h>
 #include <pulsecore/atomic.h>
+#include <pulsecore/macro.h>
 
 #include "thread.h"
 
-#define ASSERT_SUCCESS(x) do { \
-    int _r = (x); \
-    assert(_r == 0); \
-} while(0)
-
 struct pa_thread {
     pthread_t id;
     pa_thread_func_t thread_func;
     void *userdata;
-    pa_atomic_int_t running;
+    pa_atomic_t running;
 };
 
 struct pa_tls {
     pthread_key_t key;
 };
 
-static pa_tls *thread_tls;
-static pa_once_t thread_tls_once = PA_ONCE_INIT;
+static pthread_key_t thread_key;
+static pthread_once_t thread_once = PTHREAD_ONCE_INIT;
 
-static void tls_free_cb(void *p) {
+static void thread_free_cb(void *p) {
     pa_thread *t = p;
 
-    assert(t);
+    pa_assert(t);
 
     if (!t->thread_func)
         /* This is a foreign thread, we need to free the struct */
         pa_xfree(t);
 }
 
-static void thread_tls_once_func(void) {
-    thread_tls = pa_tls_new(tls_free_cb);
-    assert(thread_tls);
+static void thread_once_func(void) {
+    pa_assert_se(pthread_key_create(&thread_key, thread_free_cb) == 0);
 }
 
 static void* internal_thread_func(void *userdata) {
     pa_thread *t = userdata;
-    assert(t);
+    pa_assert(t);
 
     t->id = pthread_self();
 
-    pa_once(&thread_tls_once, thread_tls_once_func);
-
-    pa_tls_set(thread_tls, t);
+    pthread_once(&thread_once, thread_once_func);
+    pthread_setspecific(thread_key, t);
 
     pa_atomic_inc(&t->running);
     t->thread_func(t->userdata);
-    pa_atomic_add(&t->running, -2);
+    pa_atomic_sub(&t->running, 2);
 
     return NULL;
 }
@@ -92,7 +85,7 @@ static void* internal_thread_func(void *userdata) {
 pa_thread* pa_thread_new(pa_thread_func_t thread_func, void *userdata) {
     pa_thread *t;
 
-    assert(thread_func);
+    pa_assert(thread_func);
 
     t = pa_xnew(pa_thread, 1);
     t->thread_func = thread_func;
@@ -110,26 +103,26 @@ pa_thread* pa_thread_new(pa_thread_func_t thread_func, void *userdata) {
 }
 
 int pa_thread_is_running(pa_thread *t) {
-    assert(t);
+    pa_assert(t);
 
     /* Unfortunately there is no way to tell whether a "foreign"
      * thread is still running. See
      * http://udrepper.livejournal.com/16844.html for more
      * information */
-    assert(t->thread_func);
+    pa_assert(t->thread_func);
 
     return pa_atomic_load(&t->running) > 0;
 }
 
 void pa_thread_free(pa_thread *t) {
-    assert(t);
+    pa_assert(t);
 
     pa_thread_join(t);
     pa_xfree(t);
 }
 
 int pa_thread_join(pa_thread *t) {
-    assert(t);
+    pa_assert(t);
 
     return pthread_join(t->id, NULL);
 }
@@ -137,9 +130,9 @@ int pa_thread_join(pa_thread *t) {
 pa_thread* pa_thread_self(void) {
     pa_thread *t;
 
-    pa_once(&thread_tls_once, thread_tls_once_func);
+    pthread_once(&thread_once, thread_once_func);
 
-    if ((t = pa_tls_get(thread_tls)))
+    if ((t = pthread_getspecific(thread_key)))
         return t;
 
     /* This is a foreign thread, let's create a pthread structure to
@@ -151,19 +144,19 @@ pa_thread* pa_thread_self(void) {
     t->userdata = NULL;
     pa_atomic_store(&t->running, 2);
 
-    pa_tls_set(thread_tls, t);
+    pthread_setspecific(thread_key, t);
 
     return t;
 }
 
 void* pa_thread_get_data(pa_thread *t) {
-    assert(t);
+    pa_assert(t);
 
     return t->userdata;
 }
 
 void pa_thread_set_data(pa_thread *t, void *userdata) {
-    assert(t);
+    pa_assert(t);
 
     t->userdata = userdata;
 }
@@ -172,7 +165,7 @@ void pa_thread_yield(void) {
 #ifdef HAVE_PTHREAD_YIELD
     pthread_yield();
 #else
-    ASSERT_SUCCESS(sched_yield());
+    pa_assert_se(sched_yield() == 0);
 #endif
 }
 
@@ -190,14 +183,14 @@ pa_tls* pa_tls_new(pa_free_cb_t free_cb) {
 }
 
 void pa_tls_free(pa_tls *t) {
-    assert(t);
+    pa_assert(t);
 
-    ASSERT_SUCCESS(pthread_key_delete(t->key));
+    pa_assert_se(pthread_key_delete(t->key) == 0);
     pa_xfree(t);
 }
 
 void *pa_tls_get(pa_tls *t) {
-    assert(t);
+    pa_assert(t);
 
     return pthread_getspecific(t->key);
 }
@@ -206,7 +199,7 @@ void *pa_tls_set(pa_tls *t, void *userdata) {
     void *r;
 
     r = pthread_getspecific(t->key);
-    ASSERT_SUCCESS(pthread_setspecific(t->key, userdata));
+    pa_assert_se(pthread_setspecific(t->key, userdata) == 0);
     return r;
 }
 
diff --git a/src/tests/asyncmsgq-test.c b/src/tests/asyncmsgq-test.c
new file mode 100644
index 0000000..8a0f5a3
--- /dev/null
+++ b/src/tests/asyncmsgq-test.c
@@ -0,0 +1,110 @@
+/* $Id$ */
+
+/***
+  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 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.
+***/
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <assert.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+#include <pulse/util.h>
+#include <pulse/xmalloc.h>
+#include <pulsecore/asyncmsgq.h>
+#include <pulsecore/thread.h>
+#include <pulsecore/log.h>
+#include <pulsecore/core-util.h>
+#include <pulsecore/macro.h>
+
+enum {
+    OPERATION_A,
+    OPERATION_B,
+    OPERATION_C,
+    QUIT
+};
+
+static void the_thread(void *_q) {
+    pa_asyncmsgq *q = _q;
+    int quit = 0;
+
+    do {
+        int code = 0;
+        
+        pa_assert_se(pa_asyncmsgq_get(q, NULL, &code, NULL, 1) == 0);
+
+        switch (code) {
+            
+            case OPERATION_A:
+                printf("Operation A\n");
+                break;
+
+            case OPERATION_B:
+                printf("Operation B\n");
+                break;
+
+            case OPERATION_C:
+                printf("Operation C\n");
+                break;
+                
+            case QUIT:
+                printf("quit\n");
+                quit = 1;
+                break;
+        }
+
+        pa_asyncmsgq_done(q);
+
+    } while (!quit);
+}
+
+int main(int argc, char *argv[]) {
+    pa_asyncmsgq *q;
+    pa_thread *t;
+    
+    pa_assert_se(q = pa_asyncmsgq_new(0));
+
+    pa_assert_se(t = pa_thread_new(the_thread, q));
+
+    printf("Operation A post\n");
+    pa_asyncmsgq_post(q, NULL, OPERATION_A, NULL, NULL, NULL);
+
+    pa_thread_yield();
+
+    printf("Operation B post\n");
+    pa_asyncmsgq_post(q, NULL, OPERATION_B, NULL, NULL, NULL);
+
+    pa_thread_yield();
+
+    printf("Operation C send\n");
+    pa_asyncmsgq_send(q, NULL, OPERATION_C, NULL);
+
+    pa_thread_yield();
+
+    printf("Quit post\n");
+    pa_asyncmsgq_post(q, NULL, QUIT, NULL, NULL, NULL);
+
+    pa_thread_free(t);
+
+    pa_asyncmsgq_free(q);
+
+    return 0;
+}
diff --git a/src/tests/asyncq-test.c b/src/tests/asyncq-test.c
new file mode 100644
index 0000000..10566db
--- /dev/null
+++ b/src/tests/asyncq-test.c
@@ -0,0 +1,87 @@
+/* $Id$ */
+
+/***
+  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 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.
+***/
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <assert.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+#include <pulse/util.h>
+#include <pulse/xmalloc.h>
+#include <pulsecore/asyncq.h>
+#include <pulsecore/thread.h>
+#include <pulsecore/log.h>
+#include <pulsecore/core-util.h>
+#include <pulsecore/macro.h>
+
+static void producer(void *_q) {
+    pa_asyncq *q = _q;
+    int i;
+    
+    for (i = 0; i < 1000; i++) {
+        pa_asyncq_push(q, (void*) (i+1), 1);
+        printf("pushed %i\n", i);
+    }
+
+    pa_asyncq_push(q, (void*) -1, 1);
+    printf("pushed end\n");
+}
+
+static void consumer(void *_q) {
+    pa_asyncq *q = _q;
+    void *p;
+    int i;
+
+    sleep(1);
+    
+    for (i = 0;; i++) {
+        p = pa_asyncq_pop(q, 1);
+
+        if (p == (void*) -1)
+            break;
+
+        pa_assert(p == (void *) (i+1));
+        
+        printf("popped %i\n", i);
+    }
+
+    printf("popped end\n");
+}
+
+int main(int argc, char *argv[]) {
+    pa_asyncq *q;
+    pa_thread *t1, *t2;
+    
+    pa_assert_se(q = pa_asyncq_new(0));
+
+    pa_assert_se(t1 = pa_thread_new(producer, q));
+    pa_assert_se(t2 = pa_thread_new(consumer, q));
+
+    pa_thread_free(t1);
+    pa_thread_free(t2);
+
+    pa_asyncq_free(q, NULL);
+
+    return 0;
+}
diff --git a/src/tests/mcalign-test.c b/src/tests/mcalign-test.c
index db76712..d101311 100644
--- a/src/tests/mcalign-test.c
+++ b/src/tests/mcalign-test.c
@@ -59,24 +59,29 @@ int main(PA_GCC_UNUSED int argc, PA_GCC_UNUSED char *argv[]) {
             c.index = c.length = 0;
         }
 
-        assert(c.index < c.memblock->length);
+        assert(c.index < pa_memblock_get_length(c.memblock));
 
-        l = c.memblock->length - c.index;
+        l = pa_memblock_get_length(c.memblock) - c.index;
 
         l = l <= 1 ? l : rand() % (l-1) +1 ;
 
-        if ((r = read(STDIN_FILENO, (uint8_t*) c.memblock->data + c.index, l)) <= 0) {
+        p = pa_memblock_acquire(c.memblock);
+
+        if ((r = read(STDIN_FILENO, (uint8_t*) p + c.index, l)) <= 0) {
+            pa_memblock_release(c.memblock);
             fprintf(stderr, "read() failed: %s\n", r < 0 ? strerror(errno) : "EOF");
             break;
         }
 
+        pa_memblock_release(c.memblock);
+
         c.length = r;
         pa_mcalign_push(a, &c);
         fprintf(stderr, "Read %ld bytes\n", (long)r);
 
         c.index += r;
 
-        if (c.index >= c.memblock->length) {
+        if (c.index >= pa_memblock_get_length(c.memblock)) {
             pa_memblock_unref(c.memblock);
             pa_memchunk_reset(&c);
         }
@@ -87,7 +92,9 @@ int main(PA_GCC_UNUSED int argc, PA_GCC_UNUSED char *argv[]) {
             if (pa_mcalign_pop(a, &t) < 0)
                 break;
 
-            pa_loop_write(STDOUT_FILENO, (uint8_t*) t.memblock->data + t.index, t.length, NULL);
+            p = pa_memblock_acquire(t.memblock);
+            pa_loop_write(STDOUT_FILENO, (uint8_t*) p + t.index, t.length, NULL);
+            pa_memblock_release(t.memblock);
             fprintf(stderr, "Wrote %lu bytes.\n", (unsigned long) t.length);
 
             pa_memblock_unref(t.memblock);
diff --git a/src/tests/memblock-test.c b/src/tests/memblock-test.c
index 8d25ba3..1f63499 100644
--- a/src/tests/memblock-test.c
+++ b/src/tests/memblock-test.c
@@ -76,6 +76,7 @@ int main(int argc, char *argv[]) {
     pa_memblock* blocks[5];
     uint32_t id, shm_id;
     size_t offset, size;
+    char *x;
 
     const char txt[] = "This is a test!";
 
@@ -90,10 +91,17 @@ int main(int argc, char *argv[]) {
     assert(pool_a && pool_b && pool_c);
 
     blocks[0] = pa_memblock_new_fixed(pool_a, (void*) txt, sizeof(txt), 1);
+
     blocks[1] = pa_memblock_new(pool_a, sizeof(txt));
-    snprintf(blocks[1]->data, blocks[1]->length, "%s", txt);
+    x = pa_memblock_acquire(blocks[1]);
+    snprintf(x, pa_memblock_get_length(blocks[1]), "%s", txt);
+    pa_memblock_release(blocks[1]);
+
     blocks[2] = pa_memblock_new_pool(pool_a, sizeof(txt));
-    snprintf(blocks[2]->data, blocks[2]->length, "%s", txt);
+    x = pa_memblock_acquire(blocks[2]);
+    snprintf(x, pa_memblock_get_length(blocks[2]), "%s", txt);
+    pa_memblock_release(blocks[1]);
+
     blocks[3] = pa_memblock_new_malloced(pool_a, pa_xstrdup(txt), sizeof(txt));
     blocks[4] = NULL;
 
@@ -130,14 +138,18 @@ int main(int argc, char *argv[]) {
 
         mb_c = pa_memimport_get(import_c, id, shm_id, offset, size);
         assert(mb_c);
-        printf("1 data=%s\n", (char*) mb_c->data);
+        x = pa_memblock_acquire(mb_c);
+        printf("1 data=%s\n", x);
+        pa_memblock_release(mb_c);
 
         print_stats(pool_a, "A");
         print_stats(pool_b, "B");
         print_stats(pool_c, "C");
 
         pa_memexport_free(export_b);
-        printf("2 data=%s\n", (char*) mb_c->data);
+        x = pa_memblock_acquire(mb_c);
+        printf("2 data=%s\n", x);
+        pa_memblock_release(mb_c);
         pa_memblock_unref(mb_c);
 
         pa_memimport_free(import_b);
diff --git a/src/tests/memblockq-test.c b/src/tests/memblockq-test.c
index 1c0b7fe..7ad3b2f 100644
--- a/src/tests/memblockq-test.c
+++ b/src/tests/memblockq-test.c
@@ -131,8 +131,10 @@ int main(int argc, char *argv[]) {
         if (pa_memblockq_peek(bq, &out) < 0)
             break;
 
-        for (e = (char*) out.memblock->data + out.index, n = 0; n < out.length; n++)
+        p = pa_memblock_acquire(out.memblock);
+        for (e = (char*) p + out.index, n = 0; n < out.length; n++)
             printf("%c", *e);
+        pa_memblock_release(out.memblock);
 
         pa_memblock_unref(out.memblock);
         pa_memblockq_drop(bq, &out, out.length);

commit a4fed0fbb568dc57762906fb7e48fc945925d2ca
Author: Lennart Poettering <lennart at poettering.net>
Date:   Mon Jun 11 12:17:40 2007 +0000

    make eolspace
    
    git-svn-id: file:///home/lennart/svn/public/pulseaudio/branches/lennart@1470 fefdeb5f-60dc-0310-8127-8f9354f1896f

diff --git a/src/modules/module-null-sink.c b/src/modules/module-null-sink.c
index 8cf961b..ce3b29b 100644
--- a/src/modules/module-null-sink.c
+++ b/src/modules/module-null-sink.c
@@ -94,7 +94,7 @@ static void thread_func(void *userdata) {
     pollfd.events = POLLIN;
 
     pa_gettimeofday(u->timestamp);
-    
+
     for (;;) {
         int code;
         void *data, *object;
@@ -116,7 +116,7 @@ static void thread_func(void *userdata) {
                         pa_sink_process_msg(u->sink->asyncmsgq, object, code, data);
 
                 }
-                
+
             } else if (object == u->sink) {
 
                 switch (code) {
@@ -124,29 +124,29 @@ static void thread_func(void *userdata) {
                         pa_assert(running);
                         running = 0;
                         break;
-                        
+
                     case PA_SINK_MESSAGE_START:
                         pa_assert(!running);
                         running = 1;
-                        
+
                         pa_gettimeofday(u->timestamp);
                         break;
-                        
+
                     case PA_SINK_MESSAGE_GET_LATENCY:
-                        
+
                         if (pa_timeval_cmp(&u->timestamp, &now) > 0)
                             *((pa_usec_t*) data) = 0;
                         else
                             *((pa_usec_t*) data) = pa_timeval_diff(&u->timestamp, &now);
                         break;
-                        
+
                         /* ... */
 
                     default:
                         pa_sink_process_msg(u->sink->asyncmsgq, object, code, data);
                 }
             }
-            
+
             pa_asyncmsgq_done(u->sink->asyncmsgq);
             continue;
         }
@@ -155,30 +155,30 @@ static void thread_func(void *userdata) {
 
         if (running) {
             pa_gettimeofday(&now);
-            
+
             if (pa_timeval_cmp(u->timestamp, &now) <= 0) {
                 pa_memchunk chunk;
                 size_t l;
-                
+
                 if (pa_sink_render(u->sink, u->block_size, &chunk) >= 0) {
                     l = chunk.length;
                     pa_memblock_unref(chunk.memblock);
                 } else
                     l = u->block_size;
-                
+
                 pa_timeval_add(&u->timestamp, pa_bytes_to_usec(l, &u->sink->sample_spec));
                 continue;
             }
 
             timeout = pa_timeval_diff(&u->timestamp, &now)/1000;
-            
+
             if (timeout < 1)
                 timeout = 1;
         } else
             timeout = -1;
 
         /* Hmm, nothing to do. Let's sleep */
-        
+
         if (pa_asyncmsgq_before_poll(u->sink->asyncmsgq) < 0)
             continue;
 
@@ -192,7 +192,7 @@ static void thread_func(void *userdata) {
             pa_log("poll() failed: %s", pa_cstrerror(errno));
             goto fail;
         }
-        
+
         pa_assert(r == 0 || pollfd.revents == POLLIN);
     }
 
@@ -241,7 +241,7 @@ int pa__init(pa_core *c, pa_module*m) {
     pa_sink_set_description(u->sink, pa_modargs_get_value(ma, "description", "NULL sink"));
 
     u->block_size = pa_bytes_per_second(&ss) / 20; /* 50 ms */
-    
+
     if (u->block_size <= 0)
         u->block_size = pa_frame_size(&ss);
 
@@ -249,7 +249,7 @@ int pa__init(pa_core *c, pa_module*m) {
         pa_log("Failed to create thread.");
         goto fail;
     }
-    
+
     pa_modargs_free(ma);
 
     return 0;
@@ -265,7 +265,7 @@ fail:
 
 void pa__done(pa_core *c, pa_module*m) {
     struct userdata *u;
-    
+
     pa_assert(c);
     pa_assert(m);
 
@@ -278,7 +278,7 @@ void pa__done(pa_core *c, pa_module*m) {
         pa_asyncmsgq_send(u->sink->asyncmsgq, PA_SINK_MESSAGE_SHUTDOWN, NULL);
         pa_thread_free(u->thread);
     }
-    
+
     pa_sink_unref(u->sink);
 
     pa_xfree(u);
diff --git a/src/modules/module-pipe-sink.c b/src/modules/module-pipe-sink.c
index 61672ed..e4735f6 100644
--- a/src/modules/module-pipe-sink.c
+++ b/src/modules/module-pipe-sink.c
@@ -124,9 +124,9 @@ static void thread_func(void *userdata) {
                     default:
                         pa_sink_process_msg(u->sink->asyncmsgq, object, code, data);
                 }
-                
+
             } else if (object == u->sink) {
-                        
+
                 case PA_SINK_MESSAGE_STOP:
                     pa_assert(running);
                     running = 0;
@@ -155,7 +155,7 @@ static void thread_func(void *userdata) {
                 default:
                     pa_sink_process_msg(u->sink->asyncmsgq, object, code, data);
             }
-            
+
             pa_asyncmsgq_done(u->sink->asyncmsgq);
             continue;
         }
@@ -171,20 +171,20 @@ static void thread_func(void *userdata) {
 
             if (!underrun) {
                 ssize_t l;
-                
+
                 p = pa_memblock_acquire(u->memchunk.memblock);
                 l = pa_write(u->fd, (uint8_t*) p + u->memchunk.index, u->memchunk.length);
                 pa_memblock_release(p);
-                    
+
                 if (l < 0) {
 
                     if (errno != EINTR && errno != EAGAIN) {
                         pa_log("Failed to write data to FIFO: %s", pa_cstrerror(errno));
                         goto fail;
                     }
-                    
+
                 } else {
-                        
+
                     u->memchunk.index += l;
                     u->memchunk.length -= l;
 
@@ -202,7 +202,7 @@ static void thread_func(void *userdata) {
         pollfd[POLLFD_FIFO].events = running && !underrun ? POLLOUT : 0;
 
         /* Hmm, nothing to do. Let's sleep */
-        
+
         if (pa_asyncmsgq_before_poll(u->sink->asyncmsgq) < 0)
             continue;
 
@@ -221,10 +221,10 @@ static void thread_func(void *userdata) {
             pa_log("FIFO shutdown.");
             goto fail;
         }
-        
+
         pa_assert(pollfd[POLLFD_ASYNCQ].revents & ~POLLIN == 0);
     }
-    
+
 fail:
     /* We have to continue processing messages until we receive the
      * SHUTDOWN message */
@@ -265,9 +265,9 @@ int pa__init(pa_core *c, pa_module*m) {
     u->memchunk.memblock = NULL;
     u->memchunk.length = 0;
     m->userdata = u;
-    
+
     mkfifo(u->filename, 0666);
-    
+
     if ((u->fd = open(u->filename, O_RDWR)) < 0) {
         pa_log("open('%s'): %s", p, pa_cstrerror(errno));
         goto fail;
@@ -290,7 +290,7 @@ int pa__init(pa_core *c, pa_module*m) {
         pa_log("Failed to create sink.");
         goto fail;
     }
-    
+
     u->sink->userdata = u;
     pa_sink_set_owner(u->sink, m);
     pa_sink_set_description(u->sink, t = pa_sprintf_malloc("Unix FIFO sink '%s'", p));
@@ -300,7 +300,7 @@ int pa__init(pa_core *c, pa_module*m) {
         pa_log("Failed to create thread.");
         goto fail;
     }
-    
+
     pa_modargs_free(ma);
 
     return 0;
@@ -328,7 +328,7 @@ void pa__done(pa_core *c, pa_module*m) {
         pa_asyncmsgq_send(u->sink->asyncmsgq, PA_SINK_MESSAGE_SHUTDOWN, NULL);
         pa_thread_free(u->thread);
     }
-    
+
     pa_sink_unref(u->sink);
 
     if (u->memchunk.memblock)
diff --git a/src/pulsecore/asyncmsgq.c b/src/pulsecore/asyncmsgq.c
index 31e27e7..de5b2f9 100644
--- a/src/pulsecore/asyncmsgq.c
+++ b/src/pulsecore/asyncmsgq.c
@@ -65,7 +65,7 @@ pa_asyncmsgq *pa_asyncmsgq_new(unsigned size) {
     pa_assert_se(a->asyncq = pa_asyncq_new(size));
     pa_assert_se(a->mutex = pa_mutex_new(0));
     a->current = NULL;
-    
+
     return a;
 }
 
@@ -82,10 +82,10 @@ void pa_asyncmsgq_free(pa_asyncmsgq *a) {
 
         if (i->memchunk.memblock)
             pa_memblock_unref(i->object);
-        
+
         if (i->userdata_free_cb)
             i->userdata_free_cb(i->userdata);
-        
+
         if (pa_flist_push(PA_STATIC_FLIST_GET(asyncmsgq), i) < 0)
             pa_xfree(i);
     }
@@ -162,7 +162,7 @@ int pa_asyncmsgq_get(pa_asyncmsgq *a, pa_msgobject **object, int *code, void **u
         *object = a->current->object;
     if (chunk)
         *chunk = a->chunk;
-    
+
     return 0;
 }
 
@@ -183,7 +183,7 @@ void pa_asyncmsgq_done(pa_asyncmsgq *a, int ret) {
 
         if (a->current->memchunk.memblock)
             pa_memblock_unref(a->current->memchunk.memblock);
-        
+
         if (pa_flist_push(PA_STATIC_FLIST_GET(asyncmsgq), a->current) < 0)
             pa_xfree(a->current);
     }
@@ -194,14 +194,14 @@ void pa_asyncmsgq_done(pa_asyncmsgq *a, int ret) {
 int pa_asyncmsgq_wait_for(pa_asyncmsgq *a, int code) {
     int c;
     pa_assert(a);
-    
+
     do {
-        
+
         if (pa_asyncmsgq_get(a, NULL, &c, NULL, 1) < 0)
             return -1;
 
         pa_asyncmsgq_done(a);
-        
+
     } while (c != code);
 
     return 0;
diff --git a/src/pulsecore/asyncq.c b/src/pulsecore/asyncq.c
index 779cd47..54d36dc 100644
--- a/src/pulsecore/asyncq.c
+++ b/src/pulsecore/asyncq.c
@@ -85,7 +85,7 @@ pa_asyncq *pa_asyncq_new(unsigned size) {
         pa_xfree(l);
         return NULL;
     }
-    
+
     if (pipe(l->write_fds) < 0) {
         pa_close(l->read_fds[0]);
         pa_close(l->read_fds[1]);
@@ -104,7 +104,7 @@ void pa_asyncq_free(pa_asyncq *l, pa_free_cb_t free_cb) {
 
     if (free_cb) {
         void *p;
-        
+
         while ((p = pa_asyncq_pop(l, 0)))
             free_cb(p);
     }
@@ -113,7 +113,7 @@ void pa_asyncq_free(pa_asyncq *l, pa_free_cb_t free_cb) {
     pa_close(l->read_fds[1]);
     pa_close(l->write_fds[0]);
     pa_close(l->write_fds[1]);
-    
+
     pa_xfree(l);
 }
 
@@ -125,12 +125,12 @@ int pa_asyncq_push(pa_asyncq*l, void *p, int wait) {
     pa_assert(p);
 
     cells = PA_ASYNCQ_CELLS(l);
-    
+
     _Y;
     idx = reduce(l, l->write_idx);
 
     if (!pa_atomic_ptr_cmpxchg(&cells[idx], NULL, p)) {
-        
+
         /* First try failed. Let's wait for changes. */
 
         if (!wait)
@@ -142,7 +142,7 @@ int pa_asyncq_push(pa_asyncq*l, void *p, int wait) {
 
         for (;;) {
             char x[20];
-            
+
             _Y;
 
             if (pa_atomic_ptr_cmpxchg(&cells[idx], NULL, p))
@@ -155,21 +155,21 @@ int pa_asyncq_push(pa_asyncq*l, void *p, int wait) {
                 return -1;
             }
         }
-        
+
         _Y;
 
         pa_atomic_dec(&l->write_waiting);
     }
-    
+
     _Y;
     l->write_idx++;
-    
+
     if (pa_atomic_load(&l->read_waiting)) {
         char x = 'x';
         _Y;
         write(l->read_fds[1], &x, sizeof(x));
     }
-    
+
     return 0;
 }
 
@@ -188,7 +188,7 @@ void* pa_asyncq_pop(pa_asyncq*l, int wait) {
     if (!(ret = pa_atomic_ptr_load(&cells[idx]))) {
 
         /* First try failed. Let's wait for changes. */
-    
+
         if (!wait)
             return NULL;
 
@@ -228,7 +228,7 @@ void* pa_asyncq_pop(pa_asyncq*l, int wait) {
         _Y;
         write(l->write_fds[1], &x, sizeof(x));
     }
-            
+
     return ret;
 }
 
@@ -253,7 +253,7 @@ int pa_asyncq_before_poll(pa_asyncq *l) {
         return -1;
 
     pa_atomic_inc(&l->read_waiting);
-    
+
     if (pa_atomic_ptr_load(&cells[idx])) {
         pa_atomic_dec(&l->read_waiting);
         return -1;
diff --git a/src/pulsecore/core.c b/src/pulsecore/core.c
index c80caf1..99ac74e 100644
--- a/src/pulsecore/core.c
+++ b/src/pulsecore/core.c
@@ -53,9 +53,9 @@ static int core_process_msg(pa_msgobject *o, int code, void *userdata, pa_memchu
     pa_core *c = PA_CORE(o);
 
     pa_core_assert_ref(c);
-    
+
     switch (code) {
-        
+
         case PA_CORE_MESSAGE_UNLOAD_MODULE:
             pa_module_unload(c, userdata);
             return 0;
@@ -67,7 +67,7 @@ static int core_process_msg(pa_msgobject *o, int code, void *userdata, pa_memchu
 
 static void asyncmsgq_cb(pa_mainloop_api*api, pa_io_event* e, int fd, pa_io_event_flags_t events, void *userdata) {
     pa_core *c = userdata;
-    
+
     pa_assert(pa_asyncmsgq_get_fd(c->asyncmsgq) == fd);
     pa_assert(events == PA_IO_EVENT_INPUT);
 
@@ -84,7 +84,7 @@ static void asyncmsgq_cb(pa_mainloop_api*api, pa_io_event* e, int fd, pa_io_even
             pa_asyncmsgq_dispatch(object, code, data, &chunk);
             pa_asyncmsgq_done(c->asyncmsgq, 0);
         }
-        
+
         if (pa_asyncmsgq_before_poll(c->asyncmsgq) == 0)
             break;
     }
@@ -97,7 +97,7 @@ pa_core* pa_core_new(pa_mainloop_api *m, int shared) {
     pa_mempool *pool;
 
     pa_assert(m);
-    
+
     if (shared) {
         if (!(pool = pa_mempool_new(shared))) {
             pa_log_warn("failed to allocate shared memory pool. Falling back to a normal memory pool.");
@@ -175,7 +175,7 @@ pa_core* pa_core_new(pa_mainloop_api *m, int shared) {
     pa_assert_se(c->asyncmsgq = pa_asyncmsgq_new(0));
     pa_assert_se(pa_asyncmsgq_before_poll(c->asyncmsgq) == 0);
     pa_assert_se(c->asyncmsgq_event = c->mainloop->io_new(c->mainloop, pa_asyncmsgq_get_fd(c->asyncmsgq), PA_IO_EVENT_INPUT, asyncmsgq_cb, c));
-            
+
     return c;
 }
 
diff --git a/src/pulsecore/core.h b/src/pulsecore/core.h
index dc2ebb4..86660b7 100644
--- a/src/pulsecore/core.h
+++ b/src/pulsecore/core.h
@@ -48,7 +48,7 @@ typedef struct pa_core pa_core;
 
 struct pa_core {
     pa_msgobject parent;
-    
+
     /* A random value which may be used to identify this instance of
      * PulseAudio. Not cryptographically secure in any way. */
     uint32_t cookie;
diff --git a/src/pulsecore/flist.c b/src/pulsecore/flist.c
index 3805e1d..022010b 100644
--- a/src/pulsecore/flist.c
+++ b/src/pulsecore/flist.c
@@ -163,7 +163,7 @@ int pa_flist_push(pa_flist*l, void *p) {
     assert(p);
 
     cells = PA_FLIST_CELLS(l);
-    
+
     n = len = (int) l->size - pa_atomic_load(&l->length) + N_EXTRA_SCAN;
     _Y;
     idx = reduce(l, pa_atomic_load(&l->write_idx));
diff --git a/src/pulsecore/msgobject.c b/src/pulsecore/msgobject.c
index ea404cc..ce9f22f 100644
--- a/src/pulsecore/msgobject.c
+++ b/src/pulsecore/msgobject.c
@@ -30,7 +30,7 @@
 
 pa_msgobject *pa_msgobject_new_internal(size_t size, const char *type_name) {
     pa_msgobject *o;
-    
+
     pa_assert(size > sizeof(pa_msgobject));
     pa_assert(type_name);
 
diff --git a/src/pulsecore/object.c b/src/pulsecore/object.c
index de7d5ad..e6ed53b 100644
--- a/src/pulsecore/object.c
+++ b/src/pulsecore/object.c
@@ -30,7 +30,7 @@
 
 pa_object *pa_object_new_internal(size_t size, const char *type_name) {
     pa_object *o;
-    
+
     pa_assert(size > sizeof(pa_object));
     pa_assert(type_name);
 
diff --git a/src/pulsecore/object.h b/src/pulsecore/object.h
index 8fccf19..e195a35 100644
--- a/src/pulsecore/object.h
+++ b/src/pulsecore/object.h
@@ -68,5 +68,5 @@ static inline int pa_object_refcnt(pa_object *o) {
         pa_object_assert_ref(PA_OBJECT(o));                     \
     }                                                           \
     struct __stupid_useless_struct_to_allow_trailing_semicolon
-        
+
 #endif
diff --git a/src/pulsecore/once-posix.c b/src/pulsecore/once-posix.c
index 7ccd08e..25ccb03 100644
--- a/src/pulsecore/once-posix.c
+++ b/src/pulsecore/once-posix.c
@@ -35,17 +35,17 @@
 /* Not reentrant -- how could it be? */
 void pa_once(pa_once_t *control, pa_once_func_t func) {
     pa_mutex *m;
-    
+
     pa_assert(control);
     pa_assert(func);
 
     if (pa_atomic_load(&control->done))
         return;
-    
+
     pa_atomic_inc(&control->ref);
-        
+
     for (;;) {
-        
+
         if ((m = pa_atomic_ptr_load(&control->mutex))) {
 
             /* The mutex is stored in locked state, hence let's just
@@ -57,7 +57,7 @@ void pa_once(pa_once_t *control, pa_once_func_t func) {
 
         pa_assert_se(m = pa_mutex_new(0));
         pa_mutex_lock(m);
-        
+
         if (pa_atomic_ptr_cmpxchg(&control->mutex, NULL, m)) {
             func();
             pa_atomic_store(&control->done, 1);
@@ -71,7 +71,7 @@ void pa_once(pa_once_t *control, pa_once_func_t func) {
     }
 
     pa_assert(pa_atomic_load(&control->done));
-    
+
     if (pa_atomic_dec(&control->ref) <= 1) {
         pa_assert(pa_atomic_ptr_cmpxchg(&control->mutex, m, NULL));
         pa_mutex_free(m);
diff --git a/src/pulsecore/protocol-simple.c b/src/pulsecore/protocol-simple.c
index 288cf87..b7a4cc7 100644
--- a/src/pulsecore/protocol-simple.c
+++ b/src/pulsecore/protocol-simple.c
@@ -86,11 +86,11 @@ enum {
 };
 
 enum {
-    MESSAGE_REQUEST_DATA,   /* data from source output to main loop */ 
+    MESSAGE_REQUEST_DATA,   /* data from source output to main loop */
     MESSAGE_POST_DATA       /* data from source output to main loop */
 };
 
-    
+
 #define PLAYBACK_BUFFER_SECONDS (.5)
 #define PLAYBACK_BUFFER_FRAGMENTS (10)
 #define RECORD_BUFFER_SECONDS (5)
@@ -105,15 +105,15 @@ static void connection_free(struct connection *c) {
         pa_sink_input_disconnect(c->sink_input);
         pa_sink_input_unref(c->sink_input);
     }
-    
+
     if (c->source_output) {
         pa_source_output_disconnect(c->source_output);
         pa_source_output_unref(c->source_output);
     }
-    
+
     if (c->playback.current_memblock)
         pa_memblock_unref(c->playback.current_memblock);
-    
+
     if (c->client)
         pa_client_free(c->client);
     if (c->io)
@@ -122,7 +122,7 @@ static void connection_free(struct connection *c) {
         pa_memblockq_free(c->input_memblockq);
     if (c->output_memblockq)
         pa_memblockq_free(c->output_memblockq);
-    
+
     pa_xfree(c);
 }
 
@@ -133,7 +133,7 @@ static int do_read(struct connection *c) {
     void *p;
 
     pa_assert(c);
-    
+
     if (!c->sink_input || !(l = pa_atomic_load(&c->playback.missing)))
         return 0;
 
@@ -155,12 +155,12 @@ static int do_read(struct connection *c) {
     p = pa_memblock_acquire(c->playback.current_memblock);
     r = pa_iochannel_read(c->io, (uint8_t*) p + c->playback.memblock_index, l);
     pa_memblock_release(c->playback.current_memblock);
-    
+
     if (r <= 0) {
 
         if (errno == EINTR || errno == EAGAIN)
             return 0;
-        
+
         pa_log_debug("read(): %s", r == 0 ? "EOF" : pa_cstrerror(errno));
         return -1;
     }
@@ -195,7 +195,7 @@ static int do_write(struct connection *c) {
     p = pa_memblock_acquire(chunk.memblock);
     r = pa_iochannel_write(c->io, (uint8_t*) p+chunk.index, chunk.length);
     pa_memblock_release(chunk.memblock);
-    
+
     pa_memblock_unref(chunk.memblock);
 
     if (r < 0) {
@@ -208,7 +208,7 @@ static int do_write(struct connection *c) {
     }
 
     pa_memblockq_drop(c->output_memblockq, &chunk, r);
-    
+
     return 0;
 }
 
@@ -251,7 +251,7 @@ fail:
 /* Called from thread context */
 static int sink_input_process_msg(pa_sink_input *i, int code, void *userdata, const pa_memchunk *chunk) {
     struct connection*c;
-    
+
     pa_assert(i);
     c = i->userdata;
     pa_assert(c);
@@ -265,10 +265,10 @@ static int sink_input_process_msg(pa_sink_input *i, int code, void *userdata, co
             pa_memblockq_push_align(c->input_memblockq, chunk);
             return 0;
         }
-        
+
         case PA_SINK_INPUT_MESSAGE_GET_LATENCY: {
             pa_usec_t *r = userdata;
-            
+
             *r = pa_bytes_to_usec(pa_memblockq_get_length(c->input_memblockq), &c->sink_input->sample_spec);
 
             /* Fall through, the default handler will add in the extra
@@ -283,7 +283,7 @@ static int sink_input_process_msg(pa_sink_input *i, int code, void *userdata, co
 /* Called from thread context */
 static int sink_input_peek_cb(pa_sink_input *i, pa_memchunk *chunk) {
     struct connection*c;
-    
+
     pa_assert(i);
     c = i->userdata;
     pa_assert(c);
@@ -301,7 +301,7 @@ static int sink_input_peek_cb(pa_sink_input *i, pa_memchunk *chunk) {
 static void sink_input_drop_cb(pa_sink_input *i, const pa_memchunk *chunk, size_t length) {
     struct connection*c = i->userdata;
     size_t old, new;
-    
+
     pa_assert(i);
     pa_assert(c);
     pa_assert(length);
@@ -320,7 +320,7 @@ static void sink_input_drop_cb(pa_sink_input *i, const pa_memchunk *chunk, size_
 static void sink_input_kill_cb(pa_sink_input *i) {
     pa_assert(i);
     pa_assert(i->userdata);
-    
+
     connection_free((struct connection *) i->userdata);
 }
 
@@ -328,7 +328,7 @@ static void sink_input_kill_cb(pa_sink_input *i) {
 
 static void source_output_push_cb(pa_source_output *o, const pa_memchunk *chunk) {
     struct connection *c;
-    
+
     pa_assert(o);
     c = o->userdata;
     pa_assert(c);
@@ -343,17 +343,17 @@ static void source_output_kill_cb(pa_source_output *o) {
     pa_assert(o);
     c = o->userdata;
     pa_assert(c);
-    
+
     connection_free(c);
 }
 
 static pa_usec_t source_output_get_latency_cb(pa_source_output *o) {
     struct connection*c;
-    
+
     pa_assert(o);
     c = o->userdata;
     pa_assert(c);
-    
+
     return pa_bytes_to_usec(pa_memblockq_get_length(c->output_memblockq), &c->source_output->sample_spec);
 }
 
@@ -361,7 +361,7 @@ static pa_usec_t source_output_get_latency_cb(pa_source_output *o) {
 
 static void client_kill_cb(pa_client *client) {
     struct connection*c;
-    
+
     pa_assert(client);
     c = client->userdata;
     pa_assert(c);
@@ -386,7 +386,7 @@ static void on_connection(pa_socket_server*s, pa_iochannel *io, void *userdata)
     pa_protocol_simple *p = userdata;
     struct connection *c = NULL;
     char cname[256];
-    
+
     pa_assert(s);
     pa_assert(io);
     pa_assert(p);
@@ -415,7 +415,7 @@ static void on_connection(pa_socket_server*s, pa_iochannel *io, void *userdata)
     c->client->kill = client_kill_cb;
     c->client->userdata = c;
 
-    
+
     if (p->mode & PLAYBACK) {
         pa_sink_input_new_data data;
         size_t l;
@@ -493,7 +493,7 @@ static void on_connection(pa_socket_server*s, pa_iochannel *io, void *userdata)
 
     pa_iochannel_set_callback(c->io, io_callback, c);
     pa_idxset_put(p->connections, c, NULL);
-    
+
     return;
 
 fail:
@@ -504,7 +504,7 @@ fail:
 static void asyncmsgq_cb(pa_mainloop_api*api, pa_io_event* e, int fd, pa_io_event_flags_t events, void *userdata) {
     pa_protocol_simple *p = userdata;
     int do_some_work = 0;
-    
+
     pa_assert(pa_asyncmsgq_get_fd(p->asyncmsgq) == fd);
     pa_assert(events == PA_IO_EVENT_INPUT);
 
@@ -520,7 +520,7 @@ static void asyncmsgq_cb(pa_mainloop_api*api, pa_io_event* e, int fd, pa_io_even
             connection *c = object;
 
             pa_assert(c);
-            
+
             switch (code) {
 
                 case MESSAGE_REQUEST_DATA:
@@ -535,7 +535,7 @@ static void asyncmsgq_cb(pa_mainloop_api*api, pa_io_event* e, int fd, pa_io_even
 
             pa_asyncmsgq_done(p->asyncmsgq);
         }
-        
+
         if (pa_asyncmsgq_before_poll(p->asyncmsgq) == 0)
             break;
     }
@@ -544,7 +544,7 @@ static void asyncmsgq_cb(pa_mainloop_api*api, pa_io_event* e, int fd, pa_io_even
 pa_protocol_simple* pa_protocol_simple_new(pa_core *core, pa_socket_server *server, pa_module *m, pa_modargs *ma) {
     pa_protocol_simple* p = NULL;
     int enable;
-    
+
     pa_assert(core);
     pa_assert(server);
     pa_assert(ma);
@@ -588,13 +588,13 @@ pa_protocol_simple* pa_protocol_simple_new(pa_core *core, pa_socket_server *serv
 
     pa_assert_se(pa_asyncmsgq_before_poll(p->asyncmsgq) == 0);
     pa_assert_se(p->asyncmsgq_event = core->mainloop->io_event_new(core->mainloop, pa_asyncmsgq_get_fd(p->asyncmsgq), PA_IO_EVENT_INPUT, p));
-    
+
     return p;
 
 fail:
     if (p)
         pa_protocol_simple_free(p);
-    
+
     return NULL;
 }
 
@@ -618,7 +618,7 @@ void pa_protocol_simple_free(pa_protocol_simple *p) {
         pa_asyncmsgq_after_poll(c->asyncmsgq);
         pa_asyncmsgq_free(p->asyncmsgq);
     }
-    
+
     pa_xfree(p);
 }
 
diff --git a/src/pulsecore/semaphore-posix.c b/src/pulsecore/semaphore-posix.c
index 71ec57a..750c2af 100644
--- a/src/pulsecore/semaphore-posix.c
+++ b/src/pulsecore/semaphore-posix.c
@@ -60,7 +60,7 @@ void pa_semaphore_post(pa_semaphore *s) {
 void pa_semaphore_wait(pa_semaphore *s) {
     int ret;
     pa_assert(s);
-    
+
     do {
         ret = sem_wait(&s->sem);
     } while (ret < 0 && errno == EINTR);
diff --git a/src/pulsecore/sink-input.c b/src/pulsecore/sink-input.c
index da7b58b..00b82d2 100644
--- a/src/pulsecore/sink-input.c
+++ b/src/pulsecore/sink-input.c
@@ -52,7 +52,7 @@ pa_sink_input_new_data* pa_sink_input_new_data_init(pa_sink_input_new_data *data
 
     memset(data, 0, sizeof(*data));
     data->resample_method = PA_RESAMPLER_INVALID;
-    
+
     return data;
 }
 
@@ -117,7 +117,7 @@ pa_sink_input* pa_sink_input_new(
     if (!data->channel_map_is_set) {
         if (data->sink->channel_map.channels == data->sample_spec.channels)
             data->channel_map = data->sink->channel_map;
-        else 
+        else
             pa_channel_map_init_auto(&data->channel_map, data->sample_spec.channels, PA_CHANNEL_MAP_DEFAULT);
     }
 
@@ -132,7 +132,7 @@ pa_sink_input* pa_sink_input_new(
 
     if (!data->muted_is_set)
         data->muted = 0;
-    
+
     if (data->resample_method == PA_RESAMPLER_INVALID)
         data->resample_method = core->resample_method;
 
@@ -163,7 +163,7 @@ pa_sink_input* pa_sink_input_new(
 
     i->parent.parent.free = sink_input_free;
     i->parent.process_msg = pa_sink_input_process_msg;
-    
+
     i->core = core;
     pa_atomic_load(&i->state, PA_SINK_INPUT_DRAINED);
     i->flags = flags;
@@ -172,14 +172,14 @@ pa_sink_input* pa_sink_input_new(
     i->module = data->module;
     i->sink = data->sink;
     i->client = data->client;
-    
+
     i->resample_method = data->resample_method;
     i->sample_spec = data->sample_spec;
     i->channel_map = data->channel_map;
 
     i->volume = data->volume;
     i->muted = data->muted;
-    
+
     i->process_msg = NULL;
     i->peek = NULL;
     i->drop = NULL;
@@ -214,7 +214,7 @@ void pa_sink_input_disconnect(pa_sink_input *i) {
     pa_return_if_fail(pa_sink_input_get_state(i) != PA_SINK_INPUT_DISCONNECTED);
 
     pa_asyncmsgq_send(i->sink->asyncmsgq, i->sink, PA_SINK_MESSAGE_REMOVE_INPUT, i, NULL);
-    
+
     pa_idxset_remove_by_data(i->sink->core->sink_inputs, i, NULL);
     pa_idxset_remove_by_data(i->sink->inputs, i, NULL);
 
@@ -236,7 +236,7 @@ static void sink_input_free(pa_msgobject *o) {
 
     pa_assert(i);
     pa_assert(pa_sink_input_refcnt(i) == 0);
-    
+
     pa_sink_input_disconnect(i);
 
     pa_log_info("Freeing output %u \"%s\"", i->index, i->name);
@@ -281,7 +281,7 @@ pa_usec_t pa_sink_input_get_latency(pa_sink_input *i) {
 
     if (pa_asyncmsgq_send(i->sink->asyncmsgq, i->sink, PA_SINK_INPUT_MESSAGE_GET_LATENCY, &r, NULL) < 0)
         r = 0;
-    
+
     if (i->get_latency)
         r += i->get_latency(i);
 
@@ -293,7 +293,7 @@ int pa_sink_input_peek(pa_sink_input *i, pa_memchunk *chunk, pa_cvolume *volume)
     int do_volume_adj_here;
     int volume_is_norm;
     pa_sink_input_state_t state;
-    
+
     pa_sink_input_assert_ref(i);
     pa_assert(chunk);
     pa_assert(volume);
@@ -508,7 +508,7 @@ int pa_sink_input_set_rate(pa_sink_input *i, uint32_t rate) {
     i->sample_spec.rate = rate;
 
     pa_asyncmsgq_post(s->asyncmsgq, pa_sink_input_ref(i), PA_SINK_INPUT_MESSAGE_SET_RATE, PA_UINT_TO_PTR(rate), NULL, pa_sink_input_unref, NULL);
-    
+
     pa_subscription_post(i->sink->core, PA_SUBSCRIPTION_EVENT_SINK_INPUT|PA_SUBSCRIPTION_EVENT_CHANGE, i->index);
     return 0
 }
@@ -543,7 +543,7 @@ int pa_sink_input_move_to(pa_sink_input *i, pa_sink *dest, int immediately) {
     pa_sink_assert_ref(dest);
 
     return -1;
-    
+
 /*     origin = i->sink; */
 
 /*     if (dest == origin) */
@@ -697,32 +697,32 @@ int pa_sink_input_move_to(pa_sink_input *i, pa_sink *dest, int immediately) {
 
 int pa_sink_input_process_msg(pa_msgobject *o, int code, void *userdata, pa_memchunk *chunk) {
     pa_sink_input *i = PA_SINK_INPUT(o);
-    
+
     pa_sink_input_assert_ref(i);
 
     switch (code) {
         case PA_SINK_INPUT_MESSAGE_SET_VOLUME:
             s->thread_info.soft_volume = *((pa_cvolume*) userdata);
             return 0;
-            
+
         case PA_SINK_INPUT_MESSAGE_SET_MUTE:
             s->thread_info.soft_muted = PA_PTR_TO_UINT(userdata);
             return 0;
-            
+
         case PA_SINK_INPUT_MESSAGE_GET_LATENCY: {
             pa_usec_t *r = userdata;
-            
+
             if (i->thread_info.resampled_chunk.memblock)
                 *r += pa_bytes_to_usec(i->resampled_chunk.length, &i->sink->sample_spec);
 
 /*             if (i->move_silence) */
 /*                 r += pa_bytes_to_usec(i->move_silence, &i->sink->sample_spec); */
-            
+
             return 0;
         }
-            
+
         case PA_SINK_INPUT_MESSAGE_SET_RATE: {
-            
+
             i->thread_info.sample_spec.rate = PA_PTR_TO_UINT(userdata);
             pa_resampler_set_input_rate(i->resampler, PA_PTR_TO_UINT(userdata));
 
diff --git a/src/pulsecore/sink-input.h b/src/pulsecore/sink-input.h
index 64a7a73..338d696 100644
--- a/src/pulsecore/sink-input.h
+++ b/src/pulsecore/sink-input.h
@@ -52,7 +52,7 @@ typedef enum pa_sink_input_flags {
 
 struct pa_sink_input {
     pa_msgobject parent;
-    
+
     uint32_t index;
     pa_core *core;
     pa_atomic_t state;
@@ -66,11 +66,11 @@ struct pa_sink_input {
 
     pa_sample_spec sample_spec;
     pa_channel_map channel_map;
-    
+
     pa_cvolume volume;
     int muted;
 
-    int (*process_msg)(pa_sink_input *i, int code, void *userdata); 
+    int (*process_msg)(pa_sink_input *i, int code, void *userdata);
     int (*peek) (pa_sink_input *i, pa_memchunk *chunk);
     void (*drop) (pa_sink_input *i, const pa_memchunk *chunk, size_t length);
     void (*kill) (pa_sink_input *i);             /* may be NULL */
@@ -81,10 +81,10 @@ struct pa_sink_input {
 
     struct {
         pa_sample_spec sample_spec;
-        
+
         pa_memchunk resampled_chunk;
         pa_resampler *resampler;                     /* may be NULL */
-        
+
         /* Some silence to play before the actual data. This is used to
          * compensate for latency differences when moving a sink input
          * "hot" between sinks. */
@@ -94,7 +94,7 @@ struct pa_sink_input {
         pa_cvolume volume;
         int muted;
     } thread_info;
-    
+
     void *userdata;
 };
 
diff --git a/src/pulsecore/sink.c b/src/pulsecore/sink.c
index 3620559..0e022d9 100644
--- a/src/pulsecore/sink.c
+++ b/src/pulsecore/sink.c
@@ -86,7 +86,7 @@ pa_sink* pa_sink_new(
 
     s->parent.parent.free = sink_free;
     s->parent.process_msg = pa_sink_process_msg;
-    
+
     s->core = core;
     pa_atomic_store(&s->state, PA_SINK_IDLE);
     s->name = pa_xstrdup(name);
@@ -115,7 +115,7 @@ pa_sink* pa_sink_new(
     s->userdata = NULL;
 
     pa_assert_se(s->asyncmsgq = pa_asyncmsgq_new(0));
-    
+
     r = pa_idxset_put(core->sinks, s, &s->index);
     pa_assert(s->index != PA_IDXSET_INVALID && r >= 0);
 
@@ -139,7 +139,7 @@ pa_sink* pa_sink_new(
     s->thread_info.inputs = pa_hashmap_new(pa_idxset_trivial_hash_func, pa_idxset_trivial_compare_func);
     s->thread_info.soft_volume = s->volume;
     s->thread_info.soft_muted = s->muted;
-    
+
     pa_subscription_post(core, PA_SUBSCRIPTION_EVENT_SINK | PA_SUBSCRIPTION_EVENT_NEW, s->index);
 
     return s;
@@ -163,7 +163,7 @@ static void sink_start(pa_sink *s) {
 static void sink_stop(pa_sink *s) {
     pa_sink_state_t state;
     int stop;
-    
+
     pa_assert(s);
     state = pa_sink_get_state(s);
     pa_return_if_fail(state == PA_SINK_RUNNING || state == PA_SINK_SUSPENDED);
@@ -216,7 +216,7 @@ void pa_sink_disconnect(pa_sink* s) {
 
 static void sink_free(pa_object *o) {
     pa_sink *s = PA_SINK(o);
-            
+
     pa_assert(s);
     pa_assert(pa_sink_refcnt(s) == 0);
 
@@ -230,11 +230,11 @@ static void sink_free(pa_object *o) {
     }
 
     pa_idxset_free(s->inputs, NULL, NULL);
-    
+
     pa_hashmap_free(s->thread_info.inputs, (pa_free2_cb_t) pa_sink_input_unref, NULL);
 
     pa_asyncmsgq_free(s->asyncmsgq);
-    
+
     pa_xfree(s->name);
     pa_xfree(s->description);
     pa_xfree(s->driver);
@@ -246,7 +246,7 @@ void pa_sink_update_status(pa_sink*s) {
 
     if (pa_sink_get_state(s) == PA_SINK_SUSPENDED)
         return;
-    
+
     if (pa_sink_used_by(s) > 0)
         sink_start(s);
     else
@@ -270,7 +270,7 @@ void pa_sink_suspend(pa_sink *s, int suspend) {
             s->stop(s);
         else
             pa_asyncmsgq_post(s->asyncmsgq, PA_MSGOBJECT(s), PA_SINK_MESSAGE_STOP, NULL, NULL, NULL);
-        
+
     } else {
         pa_atomic_store(&s->state, PA_SINK_RUNNING);
 
@@ -417,38 +417,38 @@ int pa_sink_render_into(pa_sink*s, pa_memchunk *target) {
         else {
             void *src, *ptr;
             pa_cvolume volume;
-            
+
             ptr = pa_memblock_acquire(target->memblock);
             src = pa_memblock_acquire(info[0].chunk.memblock);
-            
+
             memcpy((uint8_t*) ptr + target->index,
                    (uint8_t*) src + info[0].chunk.index,
                    target->length);
-            
+
             pa_memblock_release(target->memblock);
             pa_memblock_release(info[0].chunk.memblock);
-            
+
             pa_sw_cvolume_multiply(&volume, &s->thread_info.soft_volume, &info[0].volume);
 
             if (!pa_cvolume_is_norm(&volume))
                 pa_volume_memchunk(target, &s->sample_spec, &volume);
         }
-            
+
     } else {
         void *ptr;
 
         ptr = pa_memblock_acquire(target->memblock);
-        
+
         target->length = pa_mix(info, n,
                                 (uint8_t*) ptr + target->index,
                                 target->length,
                                 &s->sample_spec,
                                 &s->thread_info.soft_volume,
                                 s->thread_info.soft_muted);
-    
+
         pa_memblock_release(target->memblock);
     }
-    
+
     inputs_drop(s, info, n, target->length);
 
     if (s->monitor_source)
@@ -512,12 +512,12 @@ void pa_sink_render_full(pa_sink *s, size_t length, pa_memchunk *result) {
 
 pa_usec_t pa_sink_get_latency(pa_sink *s) {
     pa_usec_t usec = 0;
-    
+
     pa_sink_assert_ref(s);
 
     if (s->get_latency)
         return s->get_latency(s);
-    
+
     if (pa_asyncmsgq_send(s->asyncmsgq, PA_MSGOBJECT(s), PA_SINK_MESSAGE_GET_LATENCY, &usec, NULL) < 0)
         return 0;
 
@@ -532,7 +532,7 @@ void pa_sink_set_volume(pa_sink *s, const pa_cvolume *volume) {
 
     changed = !pa_cvolume_equal(volume, &s->volume);
     s->volume = *volume;
-    
+
     if (s->set_volume && s->set_volume(s) < 0)
         s->set_volume = NULL;
 
@@ -549,7 +549,7 @@ const pa_cvolume *pa_sink_get_volume(pa_sink *s) {
     pa_sink_assert_ref(s);
 
     old_volume = s->volume;
-    
+
     if (s->get_volume && s->get_volume(s) < 0)
         s->get_volume = NULL;
 
@@ -558,13 +558,13 @@ const pa_cvolume *pa_sink_get_volume(pa_sink *s) {
 
     if (!pa_cvolume_equal(&old_volume, &s->volume))
         pa_subscription_post(s->core, PA_SUBSCRIPTION_EVENT_SINK|PA_SUBSCRIPTION_EVENT_CHANGE, s->index);
-    
+
     return &s->volume;
 }
 
 void pa_sink_set_mute(pa_sink *s, int mute) {
     int changed;
-    
+
     pa_sink_assert_ref(s);
 
     changed = s->muted != mute;
@@ -581,11 +581,11 @@ void pa_sink_set_mute(pa_sink *s, int mute) {
 
 int pa_sink_get_mute(pa_sink *s) {
     int old_muted;
-    
+
     pa_sink_assert_ref(s);
 
     old_muted = s->muted;
-    
+
     if (s->get_mute && s->get_mute(s) < 0)
         s->get_mute = NULL;
 
@@ -594,7 +594,7 @@ int pa_sink_get_mute(pa_sink *s) {
 
     if (old_muted != s->muted)
         pa_subscription_post(s->core, PA_SUBSCRIPTION_EVENT_SINK|PA_SUBSCRIPTION_EVENT_CHANGE, s->index);
-    
+
     return s->muted;
 }
 
@@ -658,29 +658,29 @@ int pa_sink_process_msg(pa_msgobject *o, int code, void *userdata, pa_memchunk *
             pa_hashmap_put(s->thread_info.inputs, PA_UINT32_TO_PTR(i->index), pa_sink_input_ref(i));
             return 0;
         }
-            
+
         case PA_SINK_MESSAGE_REMOVE_INPUT: {
             pa_sink_input *i = userdata;
             pa_hashmap_remove(s->thread_info.inputs, PA_UINT32_TO_PTR(i->index));
             return 0;
         }
-            
+
         case PA_SINK_MESSAGE_SET_VOLUME:
             s->thread_info.soft_volume = *((pa_cvolume*) userdata);
             return 0;
-            
+
         case PA_SINK_MESSAGE_SET_MUTE:
             s->thread_info.soft_muted = PA_PTR_TO_UINT(userdata);
             return 0;
-            
+
         case PA_SINK_MESSAGE_GET_VOLUME:
             *((pa_cvolume*) userdata) = s->thread_info.soft_volume;
             return 0;
-            
+
         case PA_SINK_MESSAGE_GET_MUTE:
             *((int*) userdata) = s->thread_info.soft_muted;
             return 0;
-            
+
         default:
             return -1;
     }
diff --git a/src/pulsecore/source-output.c b/src/pulsecore/source-output.c
index c1aa339..517c033 100644
--- a/src/pulsecore/source-output.c
+++ b/src/pulsecore/source-output.c
@@ -113,7 +113,7 @@ pa_source_output* pa_source_output_new(
     if ((flags & PA_SOURCE_OUTPUT_VARIABLE_RATE) ||
         !pa_sample_spec_equal(&data->sample_spec, &data->source->sample_spec) ||
         !pa_channel_map_equal(&data->channel_map, &data->source->channel_map)) {
-        
+
         if (!(resampler = pa_resampler_new(
                       core->mempool,
                       &data->source->sample_spec, &data->source->channel_map,
@@ -127,10 +127,10 @@ pa_source_output* pa_source_output_new(
     }
 
     o = pa_source_output_new(pa_source_output);
-    
+
     o->parent.parent.free = source_output_free;
     o->parent.process_msg = pa_source_output_process_msg;
-    
+
     o->core = core;
     pa_atomic_load(&o->state, PA_SOURCE_OUTPUT_RUNNING);
     o->flags = flags;
@@ -173,7 +173,7 @@ void pa_source_output_disconnect(pa_source_output*o) {
     pa_assert(o->source->core);
 
     pa_asyncmsgq_send(i->sink->asyncmsgq, i->sink, PA_SOURCE_MESSAGE_REMOVE_OUTPUT, o, NULL);
-    
+
     pa_idxset_remove_by_data(o->source->core->source_outputs, o, NULL);
     pa_idxset_remove_by_data(o->source->outputs, o, NULL);
 
@@ -190,7 +190,7 @@ void pa_source_output_disconnect(pa_source_output*o) {
 
 static void source_output_free(pa_msgobject* mo) {
     pa_source_output *o = PA_SOURCE_OUTPUT(mo);
-    
+
     pa_assert(pa_source_output_refcnt(o) == 0);
 
     pa_source_output_disconnect(o);
@@ -207,7 +207,7 @@ static void source_output_free(pa_msgobject* mo) {
 
 void pa_source_output_put(pa_source_output *o) {
     pa_source_output_assert_ref(o);
-    
+
     pa_asyncmsgq_post(o->source->asyncmsgq, o->source, PA_SOURCE_MESSAGE_ADD_OUTPUT, o, NULL, pa_source_unref, pa_source_output_unref);
     pa_source_update_status(o->source);
 
@@ -228,7 +228,7 @@ pa_usec_t pa_source_output_get_latency(pa_source_output *o) {
 
     if (pa_asyncmsgq_send(o->source->asyncmsgq, i->source, PA_SOURCE_OUTPUT_MESSAGE_GET_LATENCY, &r, NULL) < 0)
         r = 0;
-    
+
     if (o->get_latency)
         r += o->get_latency(o);
 
@@ -244,12 +244,12 @@ void pa_source_output_push(pa_source_output *o, const pa_memchunk *chunk) {
     pa_assert(chunk->length);
 
     state = pa_source_output_get_state(o);
-    
+
     if (!o->push || state == PA_SOURCE_OUTPUT_DISCONNECTED || state == PA_SOURCE_OUTPUT_CORKED)
         return;
 
     pa_assert(state = PA_SOURCE_OUTPUT_RUNNING);
-    
+
     if (!o->resampler) {
         o->push(o, chunk);
         return;
@@ -289,7 +289,7 @@ int pa_source_output_set_rate(pa_source_output *o, uint32_t rate) {
     i->sample_spec.rate = rate;
 
     pa_asyncmsgq_post(s->asyncmsgq, pa_source_output_ref(i), PA_SOURCE_OUTPUT_MESSAGE_SET_RATE, PA_UINT_TO_PTR(rate), NULL, pa_source_output_unref, NULL);
-    
+
     pa_subscription_post(o->source->core, PA_SUBSCRIPTION_EVENT_SOURCE_OUTPUT!|PA_SUBSCRIPTION_EVENT_CHANGE, i->index);
     return 0;
 }
@@ -312,7 +312,7 @@ void pa_source_output_set_name(pa_source_output *o, const char *name) {
 pa_resample_method_t pa_source_output_get_resample_method(pa_source_output *o) {
     pa_source_output_assert_ref(o);
 
-    return o->resample_method; 
+    return o->resample_method;
 }
 
 int pa_source_output_move_to(pa_source_output *o, pa_source *dest) {
@@ -323,7 +323,7 @@ int pa_source_output_move_to(pa_source_output *o, pa_source *dest) {
     pa_source_assert_ref(dest);
 
     return -1;
-    
+
 /*     origin = o->source; */
 
 /*     if (dest == origin) */
@@ -377,13 +377,13 @@ int pa_source_output_move_to(pa_source_output *o, pa_source *dest) {
 
 int pa_source_output_process_msg(pa_msgobject *mo, int code, void *userdata, pa_memchunk* chunk) {
     pa_source_output *o = PA_SOURCE_OUTPUT(o);
-    
+
     pa_source_output_assert_ref(i);
 
     switch (code) {
 
         case PA_SOURCE_OUTPUT_MESSAGE_SET_RATE: {
-            
+
             i->thread_info.sample_spec.rate = PA_PTR_TO_UINT(userdata);
             pa_resampler_set_output_rate(i->resampler, PA_PTR_TO_UINT(userdata));
 
diff --git a/src/pulsecore/source-output.h b/src/pulsecore/source-output.h
index 0f9c3ba..e7c2c13 100644
--- a/src/pulsecore/source-output.h
+++ b/src/pulsecore/source-output.h
@@ -48,7 +48,7 @@ typedef enum pa_source_output_flags {
 
 struct pa_source_output {
     pa_msgobject parent;
-    
+
     uint32_t index;
     pa_core *core;
     pa_atomic_t state;
@@ -72,10 +72,10 @@ struct pa_source_output {
 
     struct {
         pa_sample_spec sample_spec;
-        
+
         pa_resampler* resampler;              /* may be NULL */
     } thread_info;
-        
+
     void *userdata;
 };
 
diff --git a/src/pulsecore/source.c b/src/pulsecore/source.c
index fd3c85d..7d01338 100644
--- a/src/pulsecore/source.c
+++ b/src/pulsecore/source.c
@@ -78,7 +78,7 @@ pa_source* pa_source_new(
 
     s->parent.parent.free = source_free;
     s->parent.process_msg = pa_source_process_msg;
-    
+
     s->core = core;
     pa_atomic_store(&s->state, PA_SOURCE_IDLE);
     s->name = pa_xstrdup(name);
@@ -108,7 +108,7 @@ pa_source* pa_source_new(
     s->userdata = NULL;
 
     pa_assert_se(s->asyncmsgq = pa_asyncmsgq_new(0));
-    
+
     r = pa_idxset_put(core->sources, s, &s->index);
     assert(s->index != PA_IDXSET_INVALID && r >= 0);
 
@@ -118,7 +118,7 @@ pa_source* pa_source_new(
     s->thread_info.outputs = pa_hashmap_new(pa_idxset_trivial_hash_func, pa_idxset_trivial_compare_func);
     s->thread_info.soft_volume = s->volume;
     s->thread_info.soft_muted = s->muted;
-    
+
     pa_subscription_post(core, PA_SUBSCRIPTION_EVENT_SOURCE | PA_SUBSCRIPTION_EVENT_NEW, s->index);
 
     return s;
@@ -142,7 +142,7 @@ static void source_start(pa_source *s) {
 static void source_stop(pa_source *s) {
     pa_source_state_t state;
     int stop;
-    
+
     pa_assert(s);
     state = pa_source_get_state(s);
     pa_return_if_fail(state == PA_SOURCE_RUNNING || state == PA_SOURCE_SUSPENDED);
@@ -165,7 +165,7 @@ void pa_source_disconnect(pa_source *s) {
     pa_return_if_fail(pa_sink_get_state(s) != PA_SINK_DISCONNECT);
 
     source_stop(s);
-    
+
     pa_atomic_store(&s->state, PA_SOURCE_DISCONNECTED);
     pa_namereg_unregister(s->core, s->name);
 
@@ -192,7 +192,7 @@ void pa_source_disconnect(pa_source *s) {
 
 static void source_free(pa_msgobject *o) {
     pa_source *s = PA_SOURCE(o);
-    
+
     pa_assert(s);
     pa_assert(pa_source_refcnt(s) == 0);
 
@@ -204,7 +204,7 @@ static void source_free(pa_msgobject *o) {
     pa_hashmap_free(s->thread_info.outputs, pa_sink_output_unref, NULL);
 
     pa_asyncmsgq_free(s->asyncmsgq);
-    
+
     pa_xfree(s->name);
     pa_xfree(s->description);
     pa_xfree(s->driver);
@@ -216,7 +216,7 @@ void pa_source_update_status(pa_source*s) {
 
     if (pa_source_get_state(s) == PA_SOURCE_STATE_SUSPENDED)
         return;
-    
+
     if (pa_source_used_by(s) > 0)
         source_start(s);
     else
@@ -240,7 +240,7 @@ void pa_source_suspend(pa_source *s, int suspend) {
             s->stop(s);
         else
             pa_asyncmsgq_post(s->asyncmsgq, s, PA_SOURCE_MESSAGE_STOP, NULL, NULL, pa_source_unref, NULL);
-        
+
     } else {
         pa_atomic_store(&s->state, PA_SOURCE_RUNNING);
 
@@ -254,7 +254,7 @@ void pa_source_suspend(pa_source *s, int suspend) {
 void pa_source_post(pa_source*s, const pa_memchunk *chunk) {
     pa_source_output *o;
     void *state = NULL;
-    
+
     pa_source_assert_ref(s);
     pa_assert(chunk);
 
@@ -263,7 +263,7 @@ void pa_source_post(pa_source*s, const pa_memchunk *chunk) {
 
         pa_memblock_ref(vchunk.memblock);
         pa_memchunk_make_writable(&vchunk, 0);
-        
+
         if (s->thread_info.muted || pa_cvolume_is_muted(s->thread_info.volume))
             pa_silence_memchunk(&vchunk, &s->sample_spec);
         else
@@ -271,10 +271,10 @@ void pa_source_post(pa_source*s, const pa_memchunk *chunk) {
 
         while ((o = pa_hashmap_iterate(s->thread_info.outputs, &state, NULL)))
             pa_source_output_push(o, &vchunk);
-            
+
         pa_memblock_unref(vchunk.memblock);
     } else {
-        
+
         while ((o = pa_hashmap_iterate(s->thread_info.outputs, &state, NULL)))
             pa_source_output_push(o, chunk);
 
@@ -303,7 +303,7 @@ void pa_source_set_volume(pa_source *s, const pa_cvolume *volume) {
 
     changed = !pa_cvolume_equal(volume, s->volume);
     s->volume = *volume;
-    
+
     if (s->set_volume && s->set_volume(s) < 0)
         s->set_volume = NULL;
 
@@ -318,7 +318,7 @@ const pa_cvolume *pa_source_get_volume(pa_source *s) {
     pa_source_assert_ref(s);
 
     old_volume = s->volume;
-    
+
     if (s->get_volume && s->get_volume(s) < 0)
         s->get_volume = NULL;
 
@@ -327,13 +327,13 @@ const pa_cvolume *pa_source_get_volume(pa_source *s) {
 
     if (!pa_cvolume_equal(&old_volume, &s->volume))
         pa_subscription_post(s->core, PA_SUBSCRIPTION_EVENT_SOURCE|PA_SUBSCRIPTION_EVENT_CHANGE, s->index);
-    
+
     return &s->volume;
 }
 
 void pa_source_set_mute(pa_source *s, pa_mixer_t m, int mute) {
     int changed;
-    
+
     pa_source_assert_ref(s);
 
     changed = s->muted != mute;
@@ -350,11 +350,11 @@ void pa_source_set_mute(pa_source *s, pa_mixer_t m, int mute) {
 
 int pa_source_get_mute(pa_source *s, pa_mixer_t m) {
     int old_muted;
-    
+
     pa_source_assert_ref(s);
 
     old_muted = s->muted;
-    
+
     if (s->get_mute && s->get_mute(s) < 0)
         s->get_mute = NULL;
 
@@ -363,7 +363,7 @@ int pa_source_get_mute(pa_source *s, pa_mixer_t m) {
 
     if (old_muted != s->muted)
         pa_subscription_post(s->core, PA_SUBSCRIPTION_EVENT_SOURCE|PA_SUBSCRIPTION_EVENT_CHANGE, s->index);
-    
+
     return s->muted;
 }
 
@@ -374,7 +374,7 @@ void pa_source_set_module(pa_source *s, pa_module *m) {
         return;
 
     s->module = m;
-    
+
     pa_subscription_post(s->core, PA_SUBSCRIPTION_EVENT_SOURCE|PA_SUBSCRIPTION_EVENT_CHANGE, s->index);
 }
 
@@ -409,29 +409,29 @@ int pa_source_process_msg(pa_msgobject *o, void *object, int code, pa_memchunk *
             pa_hashmap_put(s->thread_info.outputs, PA_UINT32_TO_PTR(i->index), pa_source_output_ref(i));
             return 0;
         }
-            
+
         case PA_SOURCE_MESSAGE_REMOVE_INPUT: {
             pa_source_input *i = userdata;
             pa_hashmap_remove(s->thread_info.outputs, PA_UINT32_TO_PTR(i->index), pa_source_output_ref(i));
             return 0;
         }
-            
+
         case PA_SOURCE_MESSAGE_SET_VOLUME:
             s->thread_info.soft_volume = *((pa_cvolume*) userdata);
             return 0;
-            
+
         case PA_SOURCE_MESSAGE_SET_MUTE:
             s->thread_info.soft_muted = PA_PTR_TO_UINT(userdata);
             return 0;
-            
+
         case PA_SOURCE_MESSAGE_GET_VOLUME:
             *((pa_cvolume*) userdata) = s->thread_info.soft_volume;
             return 0;
-            
+
         case PA_SOURCE_MESSAGE_GET_MUTE:
             *((int*) userdata) = s->thread_info.soft_muted;
             return 0;
-            
+
         default:
             return -1;
     }
diff --git a/src/pulsecore/source.h b/src/pulsecore/source.h
index 1e20c6e..b41b1bc 100644
--- a/src/pulsecore/source.h
+++ b/src/pulsecore/source.h
@@ -54,7 +54,7 @@ typedef enum pa_source_state {
 
 struct pa_source {
     pa_msgobject parent;
-    
+
     uint32_t index;
     pa_core *core;
     pa_atomic_t state;
@@ -91,7 +91,7 @@ struct pa_source {
         pa_cvolume soft_volume;
         int soft_muted;
     } thread_info;
-    
+
     void *userdata;
 };
 
diff --git a/src/tests/asyncmsgq-test.c b/src/tests/asyncmsgq-test.c
index 8a0f5a3..d10b512 100644
--- a/src/tests/asyncmsgq-test.c
+++ b/src/tests/asyncmsgq-test.c
@@ -48,11 +48,11 @@ static void the_thread(void *_q) {
 
     do {
         int code = 0;
-        
+
         pa_assert_se(pa_asyncmsgq_get(q, NULL, &code, NULL, 1) == 0);
 
         switch (code) {
-            
+
             case OPERATION_A:
                 printf("Operation A\n");
                 break;
@@ -64,7 +64,7 @@ static void the_thread(void *_q) {
             case OPERATION_C:
                 printf("Operation C\n");
                 break;
-                
+
             case QUIT:
                 printf("quit\n");
                 quit = 1;
@@ -79,7 +79,7 @@ static void the_thread(void *_q) {
 int main(int argc, char *argv[]) {
     pa_asyncmsgq *q;
     pa_thread *t;
-    
+
     pa_assert_se(q = pa_asyncmsgq_new(0));
 
     pa_assert_se(t = pa_thread_new(the_thread, q));
diff --git a/src/tests/asyncq-test.c b/src/tests/asyncq-test.c
index 10566db..600d9d0 100644
--- a/src/tests/asyncq-test.c
+++ b/src/tests/asyncq-test.c
@@ -38,7 +38,7 @@
 static void producer(void *_q) {
     pa_asyncq *q = _q;
     int i;
-    
+
     for (i = 0; i < 1000; i++) {
         pa_asyncq_push(q, (void*) (i+1), 1);
         printf("pushed %i\n", i);
@@ -54,7 +54,7 @@ static void consumer(void *_q) {
     int i;
 
     sleep(1);
-    
+
     for (i = 0;; i++) {
         p = pa_asyncq_pop(q, 1);
 
@@ -62,7 +62,7 @@ static void consumer(void *_q) {
             break;
 
         pa_assert(p == (void *) (i+1));
-        
+
         printf("popped %i\n", i);
     }
 
@@ -72,7 +72,7 @@ static void consumer(void *_q) {
 int main(int argc, char *argv[]) {
     pa_asyncq *q;
     pa_thread *t1, *t2;
-    
+
     pa_assert_se(q = pa_asyncq_new(0));
 
     pa_assert_se(t1 = pa_thread_new(producer, q));

commit 590ae20d4de57d94ff276b62a0c726ec7b2f8154
Author: Lennart Poettering <lennart at poettering.net>
Date:   Mon Jun 11 13:53:16 2007 +0000

    Add new untabify makefile target
    
    git-svn-id: file:///home/lennart/svn/public/pulseaudio/branches/lennart@1471 fefdeb5f-60dc-0310-8127-8f9354f1896f

diff --git a/Makefile.am b/Makefile.am
index abc3d77..0fd4ccc 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -48,4 +48,7 @@ doxygen:
 eolspace:
 	find \( -name '*.c' -o -name '*.h' -o -name 'Makefile.am' \) -exec perl -i -pe 's/\s+\n$$/\1\n/;' \{\} \;
 
+untabify:
+	find \( -name '*.c' -o -name '*.h' \) -exec perl -i -pe 's/\t/        /g;' \{\} \;
+
 .PHONY: homepage distcleancheck doxygen

commit 69115687ad1604ddfa9fa7cd86eb286e6bb5ea9a
Author: Lennart Poettering <lennart at poettering.net>
Date:   Mon Jun 11 13:53:31 2007 +0000

    make untabify
    
    git-svn-id: file:///home/lennart/svn/public/pulseaudio/branches/lennart@1472 fefdeb5f-60dc-0310-8127-8f9354f1896f

diff --git a/src/daemon/main.c b/src/daemon/main.c
index 91cc3a2..2424efa 100644
--- a/src/daemon/main.c
+++ b/src/daemon/main.c
@@ -568,7 +568,7 @@ int main(int argc, char *argv[]) {
     assert(mainloop);
 
     if (!(c = pa_core_new(pa_mainloop_get_api(mainloop), !conf->disable_shm))) {
-    	pa_log("pa_core_new() failed.");
+            pa_log("pa_core_new() failed.");
         goto finish;
     }
 
diff --git a/src/modules/alsa-util.c b/src/modules/alsa-util.c
index 40be531..0a51802 100644
--- a/src/modules/alsa-util.c
+++ b/src/modules/alsa-util.c
@@ -326,7 +326,7 @@ int pa_alsa_set_hw_params(snd_pcm_t *pcm_handle, pa_sample_spec *ss, uint32_t *p
     if ((ret = snd_pcm_hw_params_malloc(&hwparams)) < 0 ||
         (ret = snd_pcm_hw_params_any(pcm_handle, hwparams)) < 0 ||
         (ret = snd_pcm_hw_params_set_rate_resample(pcm_handle, hwparams, 0)) < 0 ||
-    	(ret = snd_pcm_hw_params_set_access(pcm_handle, hwparams, SND_PCM_ACCESS_RW_INTERLEAVED)) < 0)
+            (ret = snd_pcm_hw_params_set_access(pcm_handle, hwparams, SND_PCM_ACCESS_RW_INTERLEAVED)) < 0)
         goto finish;
 
     if ((ret = set_format(pcm_handle, hwparams, &f)) < 0)
diff --git a/src/modules/module-detect.c b/src/modules/module-detect.c
index 41b68ac..29d6fc2 100644
--- a/src/modules/module-detect.c
+++ b/src/modules/module-detect.c
@@ -139,7 +139,7 @@ static int detect_oss(pa_core *c, int just_one) {
         line[strcspn(line, "\r\n")] = 0;
 
         if (!b) {
-	     b = strcmp(line, "Audio devices:") == 0 || strcmp(line, "Installed devices:") == 0;
+             b = strcmp(line, "Audio devices:") == 0 || strcmp(line, "Installed devices:") == 0;
             continue;
         }
 
@@ -155,13 +155,13 @@ static int detect_oss(pa_core *c, int just_one) {
             if (!pa_module_load(c, "module-oss", args))
                 continue;
 
-	} else if (sscanf(line, "pcm%u: ", &device) == 1) {
+        } else if (sscanf(line, "pcm%u: ", &device) == 1) {
             /* FreeBSD support, the devices are named /dev/dsp0.0, dsp0.1 and so on */
             snprintf(args, sizeof(args), "device=/dev/dsp%u.0", device);
 
             if (!pa_module_load(c, "module-oss", args))
                 continue;
-	}
+        }
 
         n++;
 
diff --git a/src/modules/oss-util.c b/src/modules/oss-util.c
index fb53146..4be71e2 100644
--- a/src/modules/oss-util.c
+++ b/src/modules/oss-util.c
@@ -99,7 +99,7 @@ success:
 #ifdef DSP_CAP_BIND
                  *pcaps & DSP_CAP_BIND ? " BIND" : "",
 #else
-		 "",
+                 "",
 #endif
                  *pcaps & DSP_CAP_COPROC ? " COPROC" : "",
                  *pcaps & DSP_CAP_DUPLEX ? " DUPLEX" : "",
@@ -122,7 +122,7 @@ success:
 #ifdef DSP_CAP_MULTI
                  *pcaps & DSP_CAP_MULTI ? " MULTI" : "",
 #else
-		 "",
+                 "",
 #endif
 #ifdef DSP_CAP_OUTPUT
                  *pcaps & DSP_CAP_OUTPUT ? " OUTPUT" : "",
diff --git a/src/pulse/utf8.c b/src/pulse/utf8.c
index 2ac2d10..923e021 100644
--- a/src/pulse/utf8.c
+++ b/src/pulse/utf8.c
@@ -37,7 +37,7 @@
  *
  * This library 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
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.         See the GNU
  * Lesser General Public License for more details.
  *
  * You should have received a copy of the GNU Lesser General Public
diff --git a/src/pulsecore/g711.c b/src/pulsecore/g711.c
index 8c2bbf0..aa2d703 100644
--- a/src/pulsecore/g711.c
+++ b/src/pulsecore/g711.c
@@ -43,30 +43,30 @@
 
 #include "g711.h"
 
-#define	SIGN_BIT	(0x80)		/* Sign bit for a A-law byte. */
-#define	QUANT_MASK	(0xf)		/* Quantization field mask. */
-#define	NSEGS		(8)		/* Number of A-law segments. */
-#define	SEG_SHIFT	(4)		/* Left shift for segment number. */
-#define	SEG_MASK	(0x70)		/* Segment field mask. */
+#define        SIGN_BIT        (0x80)                /* Sign bit for a A-law byte. */
+#define        QUANT_MASK        (0xf)                /* Quantization field mask. */
+#define        NSEGS                (8)                /* Number of A-law segments. */
+#define        SEG_SHIFT        (4)                /* Left shift for segment number. */
+#define        SEG_MASK        (0x70)                /* Segment field mask. */
 
 #if !defined(FAST_ALAW_CONVERSION) || !defined(FAST_ULAW_CONVERSION)
 static int16_t seg_aend[8] = {0x1F, 0x3F, 0x7F, 0xFF,
-			      0x1FF, 0x3FF, 0x7FF, 0xFFF};
+                              0x1FF, 0x3FF, 0x7FF, 0xFFF};
 static int16_t seg_uend[8] = {0x3F, 0x7F, 0xFF, 0x1FF,
-			      0x3FF, 0x7FF, 0xFFF, 0x1FFF};
+                              0x3FF, 0x7FF, 0xFFF, 0x1FFF};
 
 static int16_t search(
-	int16_t	val,
-	int16_t *table,
-	int size)
+        int16_t        val,
+        int16_t *table,
+        int size)
 {
-	int i;
+        int i;
 
-	for (i = 0; i < size; i++) {
-		if (val <= *table++)
-			return (i);
-	}
-	return (size);
+        for (i = 0; i < size; i++) {
+                if (val <= *table++)
+                        return (i);
+        }
+        return (size);
 }
 #endif /* !FAST_*_CONVERSION */
 
@@ -77,55 +77,55 @@ static int16_t search(
  * the data shifted such that it only contains information in the lower
  * 13-bits.
  *
- *		Linear Input Code	Compressed Code
- *	------------------------	---------------
- *	0000000wxyza			000wxyz
- *	0000001wxyza			001wxyz
- *	000001wxyzab			010wxyz
- *	00001wxyzabc			011wxyz
- *	0001wxyzabcd			100wxyz
- *	001wxyzabcde			101wxyz
- *	01wxyzabcdef			110wxyz
- *	1wxyzabcdefg			111wxyz
+ *                Linear Input Code        Compressed Code
+ *        ------------------------        ---------------
+ *        0000000wxyza                        000wxyz
+ *        0000001wxyza                        001wxyz
+ *        000001wxyzab                        010wxyz
+ *        00001wxyzabc                        011wxyz
+ *        0001wxyzabcd                        100wxyz
+ *        001wxyzabcde                        101wxyz
+ *        01wxyzabcdef                        110wxyz
+ *        1wxyzabcdefg                        111wxyz
  *
  * For further information see John C. Bellamy's Digital Telephony, 1982,
  * John Wiley & Sons, pps 98-111 and 472-476.
  */
 unsigned char st_13linear2alaw(
-	int16_t		pcm_val)	/* 2's complement (13-bit range) */
+        int16_t                pcm_val)        /* 2's complement (13-bit range) */
 {
-	int16_t		mask;
-	short		seg;
-	unsigned char	aval;
+        int16_t                mask;
+        short                seg;
+        unsigned char        aval;
 
-	/* Have calling software do it since its already doing a shift
-	 * from 32-bits down to 16-bits.
-	 */
-	/* pcm_val = pcm_val >> 3; */
+        /* Have calling software do it since its already doing a shift
+         * from 32-bits down to 16-bits.
+         */
+        /* pcm_val = pcm_val >> 3; */
 
-	/* A-law using even bit inversion */
-	if (pcm_val >= 0) {
-		mask = 0xD5;		/* sign (7th) bit = 1 */
-	} else {
-		mask = 0x55;		/* sign bit = 0 */
-		pcm_val = -pcm_val - 1;
-	}
+        /* A-law using even bit inversion */
+        if (pcm_val >= 0) {
+                mask = 0xD5;                /* sign (7th) bit = 1 */
+        } else {
+                mask = 0x55;                /* sign bit = 0 */
+                pcm_val = -pcm_val - 1;
+        }
 
-	/* Convert the scaled magnitude to segment number. */
-	seg = search(pcm_val, seg_aend, 8);
+        /* Convert the scaled magnitude to segment number. */
+        seg = search(pcm_val, seg_aend, 8);
 
-	/* Combine the sign, segment, and quantization bits. */
+        /* Combine the sign, segment, and quantization bits. */
 
-	if (seg >= 8)		/* out of range, return maximum value. */
-		return (unsigned char) (0x7F ^ mask);
-	else {
-		aval = (unsigned char) seg << SEG_SHIFT;
-		if (seg < 2)
-			aval |= (pcm_val >> 1) & QUANT_MASK;
-		else
-			aval |= (pcm_val >> seg) & QUANT_MASK;
-		return (aval ^ mask);
-	}
+        if (seg >= 8)                /* out of range, return maximum value. */
+                return (unsigned char) (0x7F ^ mask);
+        else {
+                aval = (unsigned char) seg << SEG_SHIFT;
+                if (seg < 2)
+                        aval |= (pcm_val >> 1) & QUANT_MASK;
+                else
+                        aval |= (pcm_val >> seg) & QUANT_MASK;
+                return (aval ^ mask);
+        }
 }
 
 /*
@@ -133,31 +133,31 @@ unsigned char st_13linear2alaw(
  *
  */
 int16_t st_alaw2linear16(
-	unsigned char	a_val)
+        unsigned char        a_val)
 {
-	int16_t t;
-	int16_t seg;
+        int16_t t;
+        int16_t seg;
 
-	a_val ^= 0x55;
+        a_val ^= 0x55;
 
-	t = (a_val & QUANT_MASK) << 4;
-	seg = ((unsigned)a_val & SEG_MASK) >> SEG_SHIFT;
-	switch (seg) {
-	case 0:
-		t += 8;
-		break;
-	case 1:
-		t += 0x108;
-		break;
-	default:
-		t += 0x108;
-		t <<= seg - 1;
-	}
-	return ((a_val & SIGN_BIT) ? t : -t);
+        t = (a_val & QUANT_MASK) << 4;
+        seg = ((unsigned)a_val & SEG_MASK) >> SEG_SHIFT;
+        switch (seg) {
+        case 0:
+                t += 8;
+                break;
+        case 1:
+                t += 0x108;
+                break;
+        default:
+                t += 0x108;
+                t <<= seg - 1;
+        }
+        return ((a_val & SIGN_BIT) ? t : -t);
 }
 #endif /* !FAST_ALAW_CONVERSION */
 
-#define	BIAS		(0x84)		/* Bias for linear code. */
+#define        BIAS                (0x84)                /* Bias for linear code. */
 #define CLIP            8159
 
 #ifndef FAST_ULAW_CONVERSION
@@ -171,16 +171,16 @@ int16_t st_alaw2linear16(
  * is biased by adding 33 which shifts the encoding range from (0 - 8158) to
  * (33 - 8191). The result can be seen in the following encoding table:
  *
- *	Biased Linear Input Code	Compressed Code
- *	------------------------	---------------
- *	00000001wxyza			000wxyz
- *	0000001wxyzab			001wxyz
- *	000001wxyzabc			010wxyz
- *	00001wxyzabcd			011wxyz
- *	0001wxyzabcde			100wxyz
- *	001wxyzabcdef			101wxyz
- *	01wxyzabcdefg			110wxyz
- *	1wxyzabcdefgh			111wxyz
+ *        Biased Linear Input Code        Compressed Code
+ *        ------------------------        ---------------
+ *        00000001wxyza                        000wxyz
+ *        0000001wxyzab                        001wxyz
+ *        000001wxyzabc                        010wxyz
+ *        00001wxyzabcd                        011wxyz
+ *        0001wxyzabcde                        100wxyz
+ *        001wxyzabcdef                        101wxyz
+ *        01wxyzabcdefg                        110wxyz
+ *        1wxyzabcdefgh                        111wxyz
  *
  * Each biased linear code has a leading 1 which identifies the segment
  * number. The value of the segment number is equal to 7 minus the number
@@ -194,41 +194,41 @@ int16_t st_alaw2linear16(
  * John Wiley & Sons, pps 98-111 and 472-476.
  */
 unsigned char st_14linear2ulaw(
-	int16_t		pcm_val)	/* 2's complement (14-bit range) */
+        int16_t                pcm_val)        /* 2's complement (14-bit range) */
 {
-	int16_t		mask;
-	int16_t		seg;
-	unsigned char	uval;
+        int16_t                mask;
+        int16_t                seg;
+        unsigned char        uval;
 
-	/* Have calling software do it since its already doing a shift
-	 * from 32-bits down to 16-bits.
-	 */
-	/* pcm_val = pcm_val >> 2; */
+        /* Have calling software do it since its already doing a shift
+         * from 32-bits down to 16-bits.
+         */
+        /* pcm_val = pcm_val >> 2; */
 
-	/* u-law inverts all bits */
-	/* Get the sign and the magnitude of the value. */
-	if (pcm_val < 0) {
-		pcm_val = -pcm_val;
-		mask = 0x7F;
-	} else {
-		mask = 0xFF;
-	}
-        if ( pcm_val > CLIP ) pcm_val = CLIP;		/* clip the magnitude */
-	pcm_val += (BIAS >> 2);
+        /* u-law inverts all bits */
+        /* Get the sign and the magnitude of the value. */
+        if (pcm_val < 0) {
+                pcm_val = -pcm_val;
+                mask = 0x7F;
+        } else {
+                mask = 0xFF;
+        }
+        if ( pcm_val > CLIP ) pcm_val = CLIP;                /* clip the magnitude */
+        pcm_val += (BIAS >> 2);
 
-	/* Convert the scaled magnitude to segment number. */
-	seg = search(pcm_val, seg_uend, 8);
+        /* Convert the scaled magnitude to segment number. */
+        seg = search(pcm_val, seg_uend, 8);
 
-	/*
-	 * Combine the sign, segment, quantization bits;
-	 * and complement the code word.
-	 */
-	if (seg >= 8)		/* out of range, return maximum value. */
-		return (unsigned char) (0x7F ^ mask);
-	else {
-		uval = (unsigned char) (seg << 4) | ((pcm_val >> (seg + 1)) & 0xF);
-		return (uval ^ mask);
-	}
+        /*
+         * Combine the sign, segment, quantization bits;
+         * and complement the code word.
+         */
+        if (seg >= 8)                /* out of range, return maximum value. */
+                return (unsigned char) (0x7F ^ mask);
+        else {
+                uval = (unsigned char) (seg << 4) | ((pcm_val >> (seg + 1)) & 0xF);
+                return (uval ^ mask);
+        }
 
 }
 
@@ -242,21 +242,21 @@ unsigned char st_14linear2ulaw(
  * original code word. This is in keeping with ISDN conventions.
  */
 int16_t st_ulaw2linear16(
-	unsigned char	u_val)
+        unsigned char        u_val)
 {
-	int16_t		t;
+        int16_t                t;
 
-	/* Complement to obtain normal u-law value. */
-	u_val = ~u_val;
+        /* Complement to obtain normal u-law value. */
+        u_val = ~u_val;
 
-	/*
-	 * Extract and bias the quantization bits. Then
-	 * shift up by the segment number and subtract out the bias.
-	 */
-	t = ((u_val & QUANT_MASK) << 3) + BIAS;
-	t <<= ((unsigned)u_val & SEG_MASK) >> SEG_SHIFT;
+        /*
+         * Extract and bias the quantization bits. Then
+         * shift up by the segment number and subtract out the bias.
+         */
+        t = ((u_val & QUANT_MASK) << 3) + BIAS;
+        t <<= ((unsigned)u_val & SEG_MASK) >> SEG_SHIFT;
 
-	return ((u_val & SIGN_BIT) ? (BIAS - t) : (t - BIAS));
+        return ((u_val & SIGN_BIT) ? (BIAS - t) : (t - BIAS));
 }
 #endif /* !FAST_ULAW_CONVERSION */
 
@@ -2413,52 +2413,52 @@ int main()
     printf("int16_t _st_alaw2linear16[256] = {\n  ");
     for (x = 0; x < 256; x++)
     {
-	printf("%8d,", st_alaw2linear16(x));
-	y++;
-	if (y == 7)
-	{
-	    y = 0;
-	    printf("\n  ");
-	}
+        printf("%8d,", st_alaw2linear16(x));
+        y++;
+        if (y == 7)
+        {
+            y = 0;
+            printf("\n  ");
+        }
     }
 
     printf("\n};\n\nuint8_t _st_13linear2alaw[0x2000] = {\n  ");
     y = 0;
     for (x = 0; x < 0x2000; x++)
     {
-	printf(" 0x%02x,", st_13linear2alaw((-0x1000)+x));
-	y++;
-	if (y == 12)
-	{
-	    y = 0;
-	    printf("\n  ");
-	}
+        printf(" 0x%02x,", st_13linear2alaw((-0x1000)+x));
+        y++;
+        if (y == 12)
+        {
+            y = 0;
+            printf("\n  ");
+        }
     }
 
     printf("\n};\n\nint16_t _st_ulaw2linear16[256] = {\n  ");
     y = 0;
     for (x = 0; x < 256; x++)
     {
-	printf("%8d,", st_ulaw2linear16(x));
-	y++;
-	if (y == 7)
-	{
-	    y = 0;
-	    printf("\n  ");
-	}
+        printf("%8d,", st_ulaw2linear16(x));
+        y++;
+        if (y == 7)
+        {
+            y = 0;
+            printf("\n  ");
+        }
     }
 
     printf("\n};\n\nuint8_t _st_14linear2ulaw[0x4000] = {\n  ");
     y = 0;
     for (x = 0; x < 0x4000; x++)
     {
-	printf(" 0x%02x,", st_14linear2ulaw((-0x2000)+x));
-	y++;
-	if (y == 12)
-	{
-	    y = 0;
-	    printf("\n  ");
-	}
+        printf(" 0x%02x,", st_14linear2ulaw((-0x2000)+x));
+        y++;
+        if (y == 12)
+        {
+            y = 0;
+            printf("\n  ");
+        }
     }
     printf("\n};\n");
 
@@ -2468,64 +2468,64 @@ int main()
 /* The following is not used by SoX but kept for reference */
 #if 0
 /* copy from CCITT G.711 specifications */
-unsigned char _u2a[128] = {			/* u- to A-law conversions */
-	1,	1,	2,	2,	3,	3,	4,	4,
-	5,	5,	6,	6,	7,	7,	8,	8,
-	9,	10,	11,	12,	13,	14,	15,	16,
-	17,	18,	19,	20,	21,	22,	23,	24,
-	25,	27,	29,	31,	33,	34,	35,	36,
-	37,	38,	39,	40,	41,	42,	43,	44,
-	46,	48,	49,	50,	51,	52,	53,	54,
-	55,	56,	57,	58,	59,	60,	61,	62,
-	64,	65,	66,	67,	68,	69,	70,	71,
-	72,	73,	74,	75,	76,	77,	78,	79,
+unsigned char _u2a[128] = {                        /* u- to A-law conversions */
+        1,        1,        2,        2,        3,        3,        4,        4,
+        5,        5,        6,        6,        7,        7,        8,        8,
+        9,        10,        11,        12,        13,        14,        15,        16,
+        17,        18,        19,        20,        21,        22,        23,        24,
+        25,        27,        29,        31,        33,        34,        35,        36,
+        37,        38,        39,        40,        41,        42,        43,        44,
+        46,        48,        49,        50,        51,        52,        53,        54,
+        55,        56,        57,        58,        59,        60,        61,        62,
+        64,        65,        66,        67,        68,        69,        70,        71,
+        72,        73,        74,        75,        76,        77,        78,        79,
 /* corrected:
-	81,	82,	83,	84,	85,	86,	87,	88,
+        81,        82,        83,        84,        85,        86,        87,        88,
    should be: */
-	80,	82,	83,	84,	85,	86,	87,	88,
-	89,	90,	91,	92,	93,	94,	95,	96,
-	97,	98,	99,	100,	101,	102,	103,	104,
-	105,	106,	107,	108,	109,	110,	111,	112,
-	113,	114,	115,	116,	117,	118,	119,	120,
-	121,	122,	123,	124,	125,	126,	127,	128};
+        80,        82,        83,        84,        85,        86,        87,        88,
+        89,        90,        91,        92,        93,        94,        95,        96,
+        97,        98,        99,        100,        101,        102,        103,        104,
+        105,        106,        107,        108,        109,        110,        111,        112,
+        113,        114,        115,        116,        117,        118,        119,        120,
+        121,        122,        123,        124,        125,        126,        127,        128};
 
-unsigned char _a2u[128] = {			/* A- to u-law conversions */
-	1,	3,	5,	7,	9,	11,	13,	15,
-	16,	17,	18,	19,	20,	21,	22,	23,
-	24,	25,	26,	27,	28,	29,	30,	31,
-	32,	32,	33,	33,	34,	34,	35,	35,
-	36,	37,	38,	39,	40,	41,	42,	43,
-	44,	45,	46,	47,	48,	48,	49,	49,
-	50,	51,	52,	53,	54,	55,	56,	57,
-	58,	59,	60,	61,	62,	63,	64,	64,
-	65,	66,	67,	68,	69,	70,	71,	72,
+unsigned char _a2u[128] = {                        /* A- to u-law conversions */
+        1,        3,        5,        7,        9,        11,        13,        15,
+        16,        17,        18,        19,        20,        21,        22,        23,
+        24,        25,        26,        27,        28,        29,        30,        31,
+        32,        32,        33,        33,        34,        34,        35,        35,
+        36,        37,        38,        39,        40,        41,        42,        43,
+        44,        45,        46,        47,        48,        48,        49,        49,
+        50,        51,        52,        53,        54,        55,        56,        57,
+        58,        59,        60,        61,        62,        63,        64,        64,
+        65,        66,        67,        68,        69,        70,        71,        72,
 /* corrected:
-	73,	74,	75,	76,	77,	78,	79,	79,
+        73,        74,        75,        76,        77,        78,        79,        79,
    should be: */
-	73,	74,	75,	76,	77,	78,	79,	80,
+        73,        74,        75,        76,        77,        78,        79,        80,
 
-	80,	81,	82,	83,	84,	85,	86,	87,
-	88,	89,	90,	91,	92,	93,	94,	95,
-	96,	97,	98,	99,	100,	101,	102,	103,
-	104,	105,	106,	107,	108,	109,	110,	111,
-	112,	113,	114,	115,	116,	117,	118,	119,
-	120,	121,	122,	123,	124,	125,	126,	127};
+        80,        81,        82,        83,        84,        85,        86,        87,
+        88,        89,        90,        91,        92,        93,        94,        95,
+        96,        97,        98,        99,        100,        101,        102,        103,
+        104,        105,        106,        107,        108,        109,        110,        111,
+        112,        113,        114,        115,        116,        117,        118,        119,
+        120,        121,        122,        123,        124,        125,        126,        127};
 
 /* A-law to u-law conversion */
 unsigned char st_alaw2ulaw(
-	unsigned char	aval)
+        unsigned char        aval)
 {
-	aval &= 0xff;
-	return (unsigned char) ((aval & 0x80) ? (0xFF ^ _a2u[aval ^ 0xD5]) :
-	    (0x7F ^ _a2u[aval ^ 0x55]));
+        aval &= 0xff;
+        return (unsigned char) ((aval & 0x80) ? (0xFF ^ _a2u[aval ^ 0xD5]) :
+            (0x7F ^ _a2u[aval ^ 0x55]));
 }
 
 /* u-law to A-law conversion */
 unsigned char st_ulaw2alaw(
-	unsigned char	uval)
+        unsigned char        uval)
 {
-	uval &= 0xff;
-	return (unsigned char) ((uval & 0x80) ? (0xD5 ^ (_u2a[0xFF ^ uval] - 1)) :
-	    (unsigned char) (0x55 ^ (_u2a[0x7F ^ uval] - 1)));
+        uval &= 0xff;
+        return (unsigned char) ((uval & 0x80) ? (0xD5 ^ (_u2a[0xFF ^ uval] - 1)) :
+            (unsigned char) (0x55 ^ (_u2a[0x7F ^ uval] - 1)));
 }
 #endif
diff --git a/src/pulsecore/pipe.c b/src/pulsecore/pipe.c
index 7f6bb2e..e614c9c 100644
--- a/src/pulsecore/pipe.c
+++ b/src/pulsecore/pipe.c
@@ -149,14 +149,14 @@ int pipe(int filedes[2]) {
     return 0;
 
 error:
-	if (listener >= 0)
-		pa_close(listener);
-	if (filedes[0] >= 0)
-		pa_close(filedes[0]);
-	if (filedes[1] >= 0)
-		pa_close(filedes[0]);
-
-	return -1;
+        if (listener >= 0)
+                pa_close(listener);
+        if (filedes[0] >= 0)
+                pa_close(filedes[0]);
+        if (filedes[1] >= 0)
+                pa_close(filedes[0]);
+
+        return -1;
 }
 
 #endif /* HAVE_PIPE */
diff --git a/src/pulsecore/shm.c b/src/pulsecore/shm.c
index 444d401..8c7fb4d 100644
--- a/src/pulsecore/shm.c
+++ b/src/pulsecore/shm.c
@@ -113,7 +113,7 @@ int pa_shm_create_rw(pa_shm *m, size_t size, int shared, mode_t mode) {
         close(fd);
         m->do_unlink = 1;
 #else
-		return -1;
+                return -1;
 #endif
     }
 
@@ -139,36 +139,36 @@ void pa_shm_free(pa_shm *m) {
     assert(m->size > 0);
 
 #ifdef MAP_FAILED
-	assert(m->ptr != MAP_FAILED);
+        assert(m->ptr != MAP_FAILED);
 #endif
 
-	if (!m->shared) {
+        if (!m->shared) {
 #ifdef MAP_ANONYMOUS
-	    if (munmap(m->ptr, m->size) < 0)
-	        pa_log("munmap() failed: %s", pa_cstrerror(errno));
+            if (munmap(m->ptr, m->size) < 0)
+                pa_log("munmap() failed: %s", pa_cstrerror(errno));
 #elif defined(HAVE_POSIX_MEMALIGN)
         free(m->ptr);
 #else
         pa_xfree(m->ptr);
 #endif
-	} else {
+        } else {
 #ifdef HAVE_SHM_OPEN
-	    if (munmap(m->ptr, m->size) < 0)
-	        pa_log("munmap() failed: %s", pa_cstrerror(errno));
+            if (munmap(m->ptr, m->size) < 0)
+                pa_log("munmap() failed: %s", pa_cstrerror(errno));
 
-	    if (m->do_unlink) {
-		    char fn[32];
+            if (m->do_unlink) {
+                    char fn[32];
 
                     segment_name(fn, sizeof(fn), m->id);
 
                     if (shm_unlink(fn) < 0)
                         pa_log(" shm_unlink(%s) failed: %s", fn, pa_cstrerror(errno));
-	    }
+            }
 #else
-		/* We shouldn't be here without shm support */
-		assert(0);
+                /* We shouldn't be here without shm support */
+                assert(0);
 #endif
-	}
+        }
 
     memset(m, 0, sizeof(*m));
 }
@@ -182,7 +182,7 @@ void pa_shm_punch(pa_shm *m, size_t offset, size_t size) {
     assert(offset+size <= m->size);
 
 #ifdef MAP_FAILED
-	assert(m->ptr != MAP_FAILED);
+        assert(m->ptr != MAP_FAILED);
 #endif
 
     /* You're welcome to implement this as NOOP on systems that don't
@@ -270,7 +270,7 @@ fail:
 #else /* HAVE_SHM_OPEN */
 
 int pa_shm_attach_ro(pa_shm *m, unsigned id) {
-	return -1;
+        return -1;
 }
 
 #endif /* HAVE_SHM_OPEN */
diff --git a/src/pulsecore/socket-client.c b/src/pulsecore/socket-client.c
index b99c802..b83bfea 100644
--- a/src/pulsecore/socket-client.c
+++ b/src/pulsecore/socket-client.c
@@ -435,7 +435,7 @@ pa_socket_client* pa_socket_client_new_string(pa_mainloop_api *m, const char*nam
     switch (a.type) {
         case PA_PARSED_ADDRESS_UNIX:
             if ((c = pa_socket_client_new_unix(m, a.path_or_host)))
-            	start_timeout(c);
+                    start_timeout(c);
             break;
 
         case PA_PARSED_ADDRESS_TCP4:  /* Fallthrough */
@@ -479,7 +479,7 @@ pa_socket_client* pa_socket_client_new_string(pa_mainloop_api *m, const char*nam
                 if (res->ai_addr) {
                     if ((c = pa_socket_client_new_sockaddr(m, res->ai_addr, res->ai_addrlen)))
                         start_timeout(c);
-				}
+                                }
 
                 freeaddrinfo(res);
 #else /* HAVE_GETADDRINFO */
@@ -507,7 +507,7 @@ pa_socket_client* pa_socket_client_new_string(pa_mainloop_api *m, const char*nam
                 s.sin_port = htons(a.port);
 
                 if ((c = pa_socket_client_new_sockaddr(m, (struct sockaddr*)&s, sizeof(s))))
-                	start_timeout(c);
+                        start_timeout(c);
 #endif /* HAVE_GETADDRINFO */
             }
 #endif /* HAVE_LIBASYNCNS */
diff --git a/src/pulsecore/socket-util.c b/src/pulsecore/socket-util.c
index 673058e..05cb336 100644
--- a/src/pulsecore/socket-util.c
+++ b/src/pulsecore/socket-util.c
@@ -177,7 +177,7 @@ int pa_socket_tcp_low_delay(int fd) {
 #endif
 
 #if defined(IPTOS_LOWDELAY) && defined(IP_TOS) && (defined(SOL_IP) || \
-	defined(IPPROTO_IP))
+        defined(IPPROTO_IP))
     tos = IPTOS_LOWDELAY;
 #ifdef SOL_IP
     if (setsockopt(fd, SOL_IP, IP_TOS, (void*)&tos, sizeof(tos)) < 0)
diff --git a/src/utils/padsp.c b/src/utils/padsp.c
index 9a2bad4..041115e 100644
--- a/src/utils/padsp.c
+++ b/src/utils/padsp.c
@@ -259,9 +259,9 @@ if (!(i)->context || pa_context_get_state((i)->context) != PA_CONTEXT_READY || \
 
 static void debug(int level, const char *format, ...) PA_GCC_PRINTF_ATTR(2,3);
 
-#define DEBUG_LEVEL_ALWAYS		0
-#define DEBUG_LEVEL_NORMAL		1
-#define DEBUG_LEVEL_VERBOSE		2
+#define DEBUG_LEVEL_ALWAYS                0
+#define DEBUG_LEVEL_NORMAL                1
+#define DEBUG_LEVEL_VERBOSE                2
 
 static void debug(int level, const char *format, ...) {
     va_list ap;
@@ -421,7 +421,7 @@ static void fd_info_unref(fd_info *i) {
     pthread_mutex_lock(&i->mutex);
     assert(i->ref >= 1);
     r = --i->ref;
-	debug(DEBUG_LEVEL_VERBOSE, __FILE__": ref--, now %i\n", i->ref);
+        debug(DEBUG_LEVEL_VERBOSE, __FILE__": ref--, now %i\n", i->ref);
     pthread_mutex_unlock(&i->mutex);
 
     if (r <= 0)
@@ -1395,7 +1395,7 @@ static int sndstat_open(int flags, int *_errno) {
 
     if (flags != O_RDONLY
 #ifdef O_LARGEFILE
-	&& flags != (O_RDONLY|O_LARGEFILE)
+        && flags != (O_RDONLY|O_LARGEFILE)
 #endif
        ) {
         *_errno = EACCES;
@@ -1446,7 +1446,7 @@ int open(const char *filename, int flags, ...) {
     va_start(args, flags);
     if (flags & O_CREAT) {
       if (sizeof(mode_t) < sizeof(int))
-	mode = va_arg(args, int);
+        mode = va_arg(args, int);
       else
         mode = va_arg(args, mode_t);
     }
@@ -2023,9 +2023,9 @@ static int dsp_ioctl(fd_info *i, unsigned long request, void*argp, int *_errno)
 
             *(int*)  argp = DSP_CAP_DUPLEX | DSP_CAP_TRIGGER
 #ifdef DSP_CAP_MULTI
-	      | DSP_CAP_MULTI
+              | DSP_CAP_MULTI
 #endif
-	      ;
+              ;
             break;
 
         case SNDCTL_DSP_GETODELAY: {
@@ -2279,8 +2279,8 @@ static int dsp_ioctl(fd_info *i, unsigned long request, void*argp, int *_errno)
 
         case SNDCTL_DSP_SETDUPLEX:
             debug(DEBUG_LEVEL_NORMAL, __FILE__": SNDCTL_DSP_SETDUPLEX\n");
-	    /* this is a no-op */
-	    break;
+            /* this is a no-op */
+            break;
 
         default:
             debug(DEBUG_LEVEL_NORMAL, __FILE__": unknown ioctl 0x%08lx\n", request);

commit be4a8828360b3607414c3ebfd836494e6490267d
Author: Lennart Poettering <lennart at poettering.net>
Date:   Wed Jun 13 22:08:14 2007 +0000

    A lot of more work to get the lock-free stuff in place
    
    git-svn-id: file:///home/lennart/svn/public/pulseaudio/branches/lennart@1474 fefdeb5f-60dc-0310-8127-8f9354f1896f

diff --git a/src/Makefile.am b/src/Makefile.am
index eab465c..0a5d529 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -283,14 +283,14 @@ flist_test_CFLAGS = $(AM_CFLAGS)
 flist_test_LDADD = $(AM_LDADD) libpulsecore.la
 flist_test_LDFLAGS = $(AM_LDFLAGS) $(BINLDFLAGS)
 
-asyncq_test_SOURCES = tests/asyncq-test.c pulsecore/thread-posix.c pulsecore/thread.h pulsecore/asyncq.c pulsecore/asyncq.h pulsecore/core-util.c pulsecore/core-util.h pulse/xmalloc.c pulse/xmalloc.h pulsecore/log.h pulsecore/log.c pulsecore/core-error.h pulsecore/core-error.c pulsecore/once-posix.c pulsecore/once.h pulsecore/mutex-posix.c pulsecore/mutex.h pulse/utf8.c pulse/utf8.h pulse/util.h pulse/util.c
+asyncq_test_SOURCES = tests/asyncq-test.c
 asyncq_test_CFLAGS = $(AM_CFLAGS)
-asyncq_test_LDADD = $(AM_LDADD) #libpulsecore.la
+asyncq_test_LDADD = $(AM_LDADD) libpulsecore.la
 asyncq_test_LDFLAGS = $(AM_LDFLAGS) $(BINLDFLAGS)
 
-asyncmsgq_test_SOURCES = tests/asyncmsgq-test.c pulsecore/thread-posix.c pulsecore/thread.h pulsecore/asyncq.c pulsecore/asyncq.h pulsecore/asyncmsgq.c pulsecore/asyncmsgq.h pulsecore/core-util.c pulsecore/core-util.h pulse/xmalloc.c pulse/xmalloc.h pulsecore/log.h pulsecore/log.c pulsecore/core-error.h pulsecore/core-error.c pulsecore/once-posix.c pulsecore/once.h pulsecore/mutex-posix.c pulsecore/mutex.h pulse/utf8.c pulse/utf8.h pulse/util.h pulse/util.c pulsecore/semaphore.h pulsecore/semaphore-posix.c pulsecore/flist.h pulsecore/flist.c
+asyncmsgq_test_SOURCES = tests/asyncmsgq-test.c
 asyncmsgq_test_CFLAGS = $(AM_CFLAGS)
-asyncmsgq_test_LDADD = $(AM_LDADD) #libpulsecore.la
+asyncmsgq_test_LDADD = $(AM_LDADD) libpulsecore.la
 asyncmsgq_test_LDFLAGS = $(AM_LDFLAGS) $(BINLDFLAGS)
 
 mcalign_test_SOURCES = tests/mcalign-test.c
@@ -653,7 +653,10 @@ libpulsecore_la_SOURCES += \
 		pulsecore/hook-list.c pulsecore/hook-list.h \
 		pulsecore/shm.c pulsecore/shm.h \
 		pulsecore/flist.c pulsecore/flist.h \
-		pulsecore/anotify.c pulsecore/anotify.h \
+		pulsecore/asyncmsgq.c pulsecore/asyncmsgqq.h \
+		pulsecore/asyncq.c pulsecore/asyncq.h \
+		pulsecore/object.c pulsecore/object.h \
+		pulsecore/msgobject.c pulsecore/msgobject.h \
 		$(PA_THREAD_OBJS)
 
 if OS_IS_WIN32
@@ -718,9 +721,10 @@ modlibexec_LTLIBRARIES = \
 		libauthkey-prop.la \
 		libstrlist.la \
 		libprotocol-simple.la \
-		libprotocol-esound.la \
-		libprotocol-native.la \
-		libprotocol-http.la
+		libprotocol-http.la 
+
+#		libprotocol-esound.la
+#		libprotocol-native.la
 
 # We need to emulate sendmsg/recvmsg to support this on Win32
 if !OS_IS_WIN32
@@ -870,6 +874,11 @@ modlibexec_LTLIBRARIES += \
 		module-cli-protocol-tcp.la \
 		module-simple-protocol-tcp.la \
 		module-null-sink.la
+		module-detect.la \
+		module-volume-restore.la \
+		module-rescue-streams.la \
+		module-http-protocol-tcp.la 
+
 #		module-esound-protocol-tcp.la \
 #		module-native-protocol-tcp.la \
 #		module-native-protocol-fd.la \
@@ -877,11 +886,7 @@ modlibexec_LTLIBRARIES += \
 #		module-combine.la \
 #		module-tunnel-sink.la \
 #		module-tunnel-source.la \
-#		module-esound-sink.la \
-#		module-http-protocol-tcp.la \
-#		module-detect.la \
-#		module-volume-restore.la \
-#		module-rescue-streams.la
+#		module-esound-sink.la
 
 # See comment at librtp.la above
 #if !OS_IS_WIN32
@@ -894,9 +899,9 @@ if HAVE_AF_UNIX
 modlibexec_LTLIBRARIES += \
 		module-cli-protocol-unix.la \
 		module-simple-protocol-unix.la
+		module-http-protocol-unix.la
 #		module-esound-protocol-unix.la \
-#		module-native-protocol-unix.la \
-#		module-http-protocol-unix.la
+#		module-native-protocol-unix.la
 endif
 
 if HAVE_MKFIFO
@@ -1079,44 +1084,44 @@ module_http_protocol_unix_la_LIBADD = $(AM_LIBADD) libpulsecore.la libprotocol-h
 
 # Native protocol
 
-module_native_protocol_tcp_la_SOURCES = modules/module-protocol-stub.c
-module_native_protocol_tcp_la_CFLAGS = -DUSE_TCP_SOCKETS -DUSE_PROTOCOL_NATIVE $(AM_CFLAGS)
-module_native_protocol_tcp_la_LDFLAGS = -module -avoid-version
-module_native_protocol_tcp_la_LIBADD = $(AM_LIBADD) libpulsecore.la libprotocol-native.la libsocket-server.la
+#module_native_protocol_tcp_la_SOURCES = modules/module-protocol-stub.c
+#module_native_protocol_tcp_la_CFLAGS = -DUSE_TCP_SOCKETS -DUSE_PROTOCOL_NATIVE $(AM_CFLAGS)
+#module_native_protocol_tcp_la_LDFLAGS = -module -avoid-version
+#module_native_protocol_tcp_la_LIBADD = $(AM_LIBADD) libpulsecore.la libprotocol-native.la libsocket-server.la
 
-module_native_protocol_unix_la_SOURCES = modules/module-protocol-stub.c
-module_native_protocol_unix_la_CFLAGS = -DUSE_UNIX_SOCKETS -DUSE_PROTOCOL_NATIVE $(AM_CFLAGS)
-module_native_protocol_unix_la_LDFLAGS = -module -avoid-version
-module_native_protocol_unix_la_LIBADD = $(AM_LIBADD) libpulsecore.la libprotocol-native.la libsocket-server.la libsocket-util.la
+#module_native_protocol_unix_la_SOURCES = modules/module-protocol-stub.c
+#module_native_protocol_unix_la_CFLAGS = -DUSE_UNIX_SOCKETS -DUSE_PROTOCOL_NATIVE $(AM_CFLAGS)
+#module_native_protocol_unix_la_LDFLAGS = -module -avoid-version
+#module_native_protocol_unix_la_LIBADD = $(AM_LIBADD) libpulsecore.la libprotocol-native.la libsocket-server.la libsocket-util.la
 
-module_native_protocol_fd_la_SOURCES = modules/module-native-protocol-fd.c
-module_native_protocol_fd_la_CFLAGS = $(AM_CFLAGS)
-module_native_protocol_fd_la_LDFLAGS = -module -avoid-version
-module_native_protocol_fd_la_LIBADD = $(AM_LIBADD) libpulsecore.la libprotocol-native.la libsocket-server.la libsocket-util.la libiochannel.la
+#module_native_protocol_fd_la_SOURCES = modules/module-native-protocol-fd.c
+#module_native_protocol_fd_la_CFLAGS = $(AM_CFLAGS)
+#module_native_protocol_fd_la_LDFLAGS = -module -avoid-version
+#module_native_protocol_fd_la_LIBADD = $(AM_LIBADD) libpulsecore.la libprotocol-native.la libsocket-server.la libsocket-util.la libiochannel.la
 
 # EsounD protocol
 
-module_esound_protocol_tcp_la_SOURCES = modules/module-protocol-stub.c
-module_esound_protocol_tcp_la_CFLAGS = -DUSE_TCP_SOCKETS -DUSE_PROTOCOL_ESOUND $(AM_CFLAGS)
-module_esound_protocol_tcp_la_LDFLAGS = -module -avoid-version
-module_esound_protocol_tcp_la_LIBADD = $(AM_LIBADD) libpulsecore.la libprotocol-esound.la libsocket-server.la
+#module_esound_protocol_tcp_la_SOURCES = modules/module-protocol-stub.c
+#module_esound_protocol_tcp_la_CFLAGS = -DUSE_TCP_SOCKETS -DUSE_PROTOCOL_ESOUND $(AM_CFLAGS)
+#module_esound_protocol_tcp_la_LDFLAGS = -module -avoid-version
+#module_esound_protocol_tcp_la_LIBADD = $(AM_LIBADD) libpulsecore.la libprotocol-esound.la libsocket-server.la
 
-module_esound_protocol_unix_la_SOURCES = modules/module-protocol-stub.c
-module_esound_protocol_unix_la_CFLAGS = -DUSE_UNIX_SOCKETS -DUSE_PROTOCOL_ESOUND $(AM_CFLAGS)
-module_esound_protocol_unix_la_LDFLAGS = -module -avoid-version
-module_esound_protocol_unix_la_LIBADD = $(AM_LIBADD) libpulsecore.la libprotocol-esound.la libsocket-server.la libsocket-util.la
+#module_esound_protocol_unix_la_SOURCES = modules/module-protocol-stub.c
+#module_esound_protocol_unix_la_CFLAGS = -DUSE_UNIX_SOCKETS -DUSE_PROTOCOL_ESOUND $(AM_CFLAGS)
+#module_esound_protocol_unix_la_LDFLAGS = -module -avoid-version
+#module_esound_protocol_unix_la_LIBADD = $(AM_LIBADD) libpulsecore.la libprotocol-esound.la libsocket-server.la libsocket-util.la
 
-module_esound_compat_spawnfd_la_SOURCES = modules/module-esound-compat-spawnfd.c
-module_esound_compat_spawnfd_la_LDFLAGS = -module -avoid-version
-module_esound_compat_spawnfd_la_LIBADD = $(AM_LIBADD) libpulsecore.la
+#module_esound_compat_spawnfd_la_SOURCES = modules/module-esound-compat-spawnfd.c
+#module_esound_compat_spawnfd_la_LDFLAGS = -module -avoid-version
+#module_esound_compat_spawnfd_la_LIBADD = $(AM_LIBADD) libpulsecore.la
 
-module_esound_compat_spawnpid_la_SOURCES = modules/module-esound-compat-spawnpid.c
-module_esound_compat_spawnpid_la_LDFLAGS = -module -avoid-version
-module_esound_compat_spawnpid_la_LIBADD = $(AM_LIBADD) libpulsecore.la
+#module_esound_compat_spawnpid_la_SOURCES = modules/module-esound-compat-spawnpid.c
+#module_esound_compat_spawnpid_la_LDFLAGS = -module -avoid-version
+#module_esound_compat_spawnpid_la_LIBADD = $(AM_LIBADD) libpulsecore.la
 
-module_esound_sink_la_SOURCES = modules/module-esound-sink.c
-module_esound_sink_la_LDFLAGS = -module -avoid-version
-module_esound_sink_la_LIBADD = $(AM_LIBADD) libpulsecore.la libiochannel.la libsocket-client.la libauthkey.la
+#module_esound_sink_la_SOURCES = modules/module-esound-sink.c
+#module_esound_sink_la_LDFLAGS = -module -avoid-version
+#module_esound_sink_la_LIBADD = $(AM_LIBADD) libpulsecore.la libiochannel.la libsocket-client.la libauthkey.la
 
 # Pipes
 
@@ -1140,22 +1145,22 @@ module_null_sink_la_LIBADD = $(AM_LIBADD) libpulsecore.la
 
 # Couplings
 
-module_combine_la_SOURCES = modules/module-combine.c
-module_combine_la_LDFLAGS = -module -avoid-version
-module_combine_la_LIBADD = $(AM_LIBADD) libpulsecore.la
+#module_combine_la_SOURCES = modules/module-combine.c
+#module_combine_la_LDFLAGS = -module -avoid-version
+#module_combine_la_LIBADD = $(AM_LIBADD) libpulsecore.la
 
 module_match_la_SOURCES = modules/module-match.c
 module_match_la_LDFLAGS = -module -avoid-version
 module_match_la_LIBADD = $(AM_LIBADD) libpulsecore.la
 
-module_tunnel_sink_la_SOURCES = modules/module-tunnel.c
-module_tunnel_sink_la_CFLAGS = -DTUNNEL_SINK=1 $(AM_CFLAGS)
-module_tunnel_sink_la_LDFLAGS = -module -avoid-version
-module_tunnel_sink_la_LIBADD = $(AM_LIBADD) libpulsecore.la libsocket-client.la libpstream.la libpstream-util.la libpdispatch.la libtagstruct.la libauthkey.la libauthkey-prop.la libsocket-util.la libiochannel.la
+#module_tunnel_sink_la_SOURCES = modules/module-tunnel.c
+#module_tunnel_sink_la_CFLAGS = -DTUNNEL_SINK=1 $(AM_CFLAGS)
+#module_tunnel_sink_la_LDFLAGS = -module -avoid-version
+#module_tunnel_sink_la_LIBADD = $(AM_LIBADD) libpulsecore.la libsocket-client.la libpstream.la libpstream-util.la libpdispatch.la libtagstruct.la libauthkey.la libauthkey-prop.la libsocket-util.la libiochannel.la
 
-module_tunnel_source_la_SOURCES = modules/module-tunnel.c
-module_tunnel_source_la_LDFLAGS = -module -avoid-version
-module_tunnel_source_la_LIBADD = $(AM_LIBADD) libpulsecore.la libsocket-client.la libpstream.la libpstream-util.la libpdispatch.la libtagstruct.la libauthkey.la libauthkey-prop.la libsocket-util.la libiochannel.la
+#module_tunnel_source_la_SOURCES = modules/module-tunnel.c
+#module_tunnel_source_la_LDFLAGS = -module -avoid-version
+#module_tunnel_source_la_LIBADD = $(AM_LIBADD) libpulsecore.la libsocket-client.la libpstream.la libpstream-util.la libpdispatch.la libtagstruct.la libauthkey.la libauthkey-prop.la libsocket-util.la libiochannel.la
 
 # X11
 
@@ -1171,34 +1176,34 @@ module_x11_publish_la_LIBADD = $(AM_LIBADD) $(X_PRE_LIBS) -lX11 $(X_LIBS) $(X_EX
 
 # OSS
 
-liboss_util_la_SOURCES = modules/oss-util.c modules/oss-util.h
-liboss_util_la_LDFLAGS = -avoid-version
-liboss_util_la_LIBADD = libpulsecore.la
+#liboss_util_la_SOURCES = modules/oss-util.c modules/oss-util.h
+#liboss_util_la_LDFLAGS = -avoid-version
+#liboss_util_la_LIBADD = libpulsecore.la
 
-module_oss_la_SOURCES = modules/module-oss.c
-module_oss_la_LDFLAGS = -module -avoid-version
-module_oss_la_LIBADD = $(AM_LIBADD) libiochannel.la liboss-util.la
+#module_oss_la_SOURCES = modules/module-oss.c
+#module_oss_la_LDFLAGS = -module -avoid-version
+#module_oss_la_LIBADD = $(AM_LIBADD) libiochannel.la liboss-util.la
 
-module_oss_mmap_la_SOURCES = modules/module-oss-mmap.c
-module_oss_mmap_la_LDFLAGS = -module -avoid-version
-module_oss_mmap_la_LIBADD = $(AM_LIBADD) liboss-util.la libpulsecore.la
+#module_oss_mmap_la_SOURCES = modules/module-oss-mmap.c
+#module_oss_mmap_la_LDFLAGS = -module -avoid-version
+#module_oss_mmap_la_LIBADD = $(AM_LIBADD) liboss-util.la libpulsecore.la
 
 # ALSA
 
-libalsa_util_la_SOURCES = modules/alsa-util.c modules/alsa-util.h
-libalsa_util_la_LDFLAGS = -avoid-version
-libalsa_util_la_LIBADD = $(AM_LIBADD) $(ASOUNDLIB_LIBS) libpulsecore.la
-libalsa_util_la_CFLAGS = $(AM_CFLAGS) $(ASOUNDLIB_CFLAGS)
+#libalsa_util_la_SOURCES = modules/alsa-util.c modules/alsa-util.h
+#libalsa_util_la_LDFLAGS = -avoid-version
+#libalsa_util_la_LIBADD = $(AM_LIBADD) $(ASOUNDLIB_LIBS) libpulsecore.la
+#libalsa_util_la_CFLAGS = $(AM_CFLAGS) $(ASOUNDLIB_CFLAGS)
 
-module_alsa_sink_la_SOURCES = modules/module-alsa-sink.c
-module_alsa_sink_la_LDFLAGS = -module -avoid-version
-module_alsa_sink_la_LIBADD = $(AM_LIBADD) $(ASOUNDLIB_LIBS) libalsa-util.la libpulsecore.la
-module_alsa_sink_la_CFLAGS = $(AM_CFLAGS) $(ASOUNDLIB_CFLAGS)
+#module_alsa_sink_la_SOURCES = modules/module-alsa-sink.c
+#module_alsa_sink_la_LDFLAGS = -module -avoid-version
+#module_alsa_sink_la_LIBADD = $(AM_LIBADD) $(ASOUNDLIB_LIBS) libalsa-util.la libpulsecore.la
+#module_alsa_sink_la_CFLAGS = $(AM_CFLAGS) $(ASOUNDLIB_CFLAGS)
 
-module_alsa_source_la_SOURCES = modules/module-alsa-source.c
-module_alsa_source_la_LDFLAGS = -module -avoid-version
-module_alsa_source_la_LIBADD = $(AM_LIBADD) $(ASOUNDLIB_LIBS) libalsa-util.la libpulsecore.la
-module_alsa_source_la_CFLAGS = $(AM_CFLAGS) $(ASOUNDLIB_CFLAGS)
+#module_alsa_source_la_SOURCES = modules/module-alsa-source.c
+#module_alsa_source_la_LDFLAGS = -module -avoid-version
+#module_alsa_source_la_LIBADD = $(AM_LIBADD) $(ASOUNDLIB_LIBS) libalsa-util.la libpulsecore.la
+#module_alsa_source_la_CFLAGS = $(AM_CFLAGS) $(ASOUNDLIB_CFLAGS)
 
 # Solaris
 
@@ -1265,15 +1270,15 @@ module_rtp_recv_la_CFLAGS = $(AM_CFLAGS)
 
 # JACK
 
-module_jack_sink_la_SOURCES = modules/module-jack-sink.c
-module_jack_sink_la_LDFLAGS = -module -avoid-version
-module_jack_sink_la_LIBADD = $(AM_LIBADD) libpulsecore.la $(JACK_LIBS)
-module_jack_sink_la_CFLAGS = $(AM_LIBADD) $(JACK_CFLAGS)
+#module_jack_sink_la_SOURCES = modules/module-jack-sink.c
+#module_jack_sink_la_LDFLAGS = -module -avoid-version
+#module_jack_sink_la_LIBADD = $(AM_LIBADD) libpulsecore.la $(JACK_LIBS)
+#module_jack_sink_la_CFLAGS = $(AM_LIBADD) $(JACK_CFLAGS)
 
-module_jack_source_la_SOURCES = modules/module-jack-source.c
-module_jack_source_la_LDFLAGS = -module -avoid-version
-module_jack_source_la_LIBADD = $(AM_LIBADD) libpulsecore.la $(JACK_LIBS)
-module_jack_source_la_CFLAGS = $(AM_LIBADD) $(JACK_CFLAGS)
+#module_jack_source_la_SOURCES = modules/module-jack-source.c
+#module_jack_source_la_LDFLAGS = -module -avoid-version
+#module_jack_source_la_LIBADD = $(AM_LIBADD) libpulsecore.la $(JACK_LIBS)
+#module_jack_source_la_CFLAGS = $(AM_LIBADD) $(JACK_CFLAGS)
 
 # HAL
 libdbus_util_la_SOURCES = modules/dbus-util.c modules/dbus-util.h
diff --git a/src/daemon/main.c b/src/daemon/main.c
index 2424efa..a1926fe 100644
--- a/src/daemon/main.c
+++ b/src/daemon/main.c
@@ -656,7 +656,7 @@ int main(int argc, char *argv[]) {
     pa_mainloop_get_api(mainloop)->time_free(timer);
 #endif
 
-    pa_core_free(c);
+    pa_core_unref(c);
 
     if (!conf->no_cpu_limit)
         pa_cpu_limit_done();
diff --git a/src/modules/module-lirc.c b/src/modules/module-lirc.c
index c8adbc8..452fa1f 100644
--- a/src/modules/module-lirc.c
+++ b/src/modules/module-lirc.c
@@ -121,7 +121,7 @@ static void io_callback(pa_mainloop_api *io, PA_GCC_UNUSED pa_io_event *e, PA_GC
                     pa_log("failed to get sink '%s'", u->sink_name);
                 else {
                     int i;
-                    pa_cvolume cv = *pa_sink_get_volume(s, PA_MIXER_HARDWARE);
+                    pa_cvolume cv = *pa_sink_get_volume(s);
 
 #define DELTA (PA_VOLUME_NORM/20)
 
@@ -134,7 +134,7 @@ static void io_callback(pa_mainloop_api *io, PA_GCC_UNUSED pa_io_event *e, PA_GC
                                     cv.values[i] = PA_VOLUME_NORM;
                             }
 
-                            pa_sink_set_volume(s, PA_MIXER_HARDWARE, &cv);
+                            pa_sink_set_volume(s, &cv);
                             break;
 
                         case DOWN:
@@ -145,20 +145,20 @@ static void io_callback(pa_mainloop_api *io, PA_GCC_UNUSED pa_io_event *e, PA_GC
                                     cv.values[i] = PA_VOLUME_MUTED;
                             }
 
-                            pa_sink_set_volume(s, PA_MIXER_HARDWARE, &cv);
+                            pa_sink_set_volume(s, &cv);
                             break;
 
                         case MUTE:
-                            pa_sink_set_mute(s, PA_MIXER_HARDWARE, 0);
+                            pa_sink_set_mute(s, 0);
                             break;
 
                         case RESET:
-                            pa_sink_set_mute(s, PA_MIXER_HARDWARE, 1);
+                            pa_sink_set_mute(s, 1);
                             break;
 
                         case MUTE_TOGGLE:
 
-                            pa_sink_set_mute(s, PA_MIXER_HARDWARE, !pa_sink_get_mute(s, PA_MIXER_HARDWARE));
+                            pa_sink_set_mute(s, !pa_sink_get_mute(s));
                             break;
 
                         case INVALID:
diff --git a/src/modules/module-mmkbd-evdev.c b/src/modules/module-mmkbd-evdev.c
index b7433ac..919b399 100644
--- a/src/modules/module-mmkbd-evdev.c
+++ b/src/modules/module-mmkbd-evdev.c
@@ -114,7 +114,7 @@ static void io_callback(pa_mainloop_api *io, PA_GCC_UNUSED pa_io_event *e, PA_GC
                     pa_log("failed to get sink '%s'", u->sink_name);
                 else {
                     int i;
-                    pa_cvolume cv = *pa_sink_get_volume(s, PA_MIXER_HARDWARE);
+                    pa_cvolume cv = *pa_sink_get_volume(s);
 
 #define DELTA (PA_VOLUME_NORM/20)
 
@@ -127,7 +127,7 @@ static void io_callback(pa_mainloop_api *io, PA_GCC_UNUSED pa_io_event *e, PA_GC
                                     cv.values[i] = PA_VOLUME_NORM;
                             }
 
-                            pa_sink_set_volume(s, PA_MIXER_HARDWARE, &cv);
+                            pa_sink_set_volume(s, &cv);
                             break;
 
                         case DOWN:
@@ -138,12 +138,12 @@ static void io_callback(pa_mainloop_api *io, PA_GCC_UNUSED pa_io_event *e, PA_GC
                                     cv.values[i] = PA_VOLUME_MUTED;
                             }
 
-                            pa_sink_set_volume(s, PA_MIXER_HARDWARE, &cv);
+                            pa_sink_set_volume(s, &cv);
                             break;
 
                         case MUTE_TOGGLE:
 
-                            pa_sink_set_mute(s, PA_MIXER_HARDWARE, !pa_sink_get_mute(s, PA_MIXER_HARDWARE));
+                            pa_sink_set_mute(s, !pa_sink_get_mute(s));
                             break;
 
                         case INVALID:
diff --git a/src/modules/module-null-sink.c b/src/modules/module-null-sink.c
index ce3b29b..afe130d 100644
--- a/src/modules/module-null-sink.c
+++ b/src/modules/module-null-sink.c
@@ -33,17 +33,19 @@
 #include <fcntl.h>
 #include <unistd.h>
 #include <limits.h>
+#include <sys/poll.h>
 
 #include <pulse/timeval.h>
 #include <pulse/xmalloc.h>
 
 #include <pulsecore/macro.h>
-#include <pulsecore/iochannel.h>
 #include <pulsecore/sink.h>
 #include <pulsecore/module.h>
 #include <pulsecore/core-util.h>
+#include <pulsecore/core-error.h>
 #include <pulsecore/modargs.h>
 #include <pulsecore/log.h>
+#include <pulsecore/thread.h>
 
 #include "module-null-sink-symdef.h"
 
@@ -65,7 +67,9 @@ struct userdata {
     pa_module *module;
     pa_sink *sink;
     pa_thread *thread;
+    pa_asyncmsgq *asyncmsgq;
     size_t block_size;
+    
     struct timeval timestamp;
 };
 
@@ -79,85 +83,74 @@ static const char* const valid_modargs[] = {
     NULL
 };
 
+static int sink_process_msg(pa_msgobject *o, int code, void *data, pa_memchunk *chunk) {
+    struct userdata *u = PA_SINK(o)->userdata;
+
+    switch (code) {
+        case PA_SINK_MESSAGE_SET_STATE:
+
+            if (PA_PTR_TO_UINT(data) == PA_SINK_RUNNING)
+                pa_gettimeofday(&u->timestamp);
+            
+            break;
+            
+        case PA_SINK_MESSAGE_GET_LATENCY: {
+            struct timeval now;
+    
+            pa_gettimeofday(&now);
+            
+            if (pa_timeval_cmp(&u->timestamp, &now) > 0)
+                *((pa_usec_t*) data) = 0;
+            else
+                *((pa_usec_t*) data) = pa_timeval_diff(&u->timestamp, &now);
+            break;
+        }
+    }
+    
+    return pa_sink_process_msg(o, code, data, chunk);
+}
+
 static void thread_func(void *userdata) {
     struct userdata *u = userdata;
-    int quit = 0;
     struct pollfd pollfd;
-    int running = 1;
 
     pa_assert(u);
 
     pa_log_debug("Thread starting up");
 
+    pa_gettimeofday(&u->timestamp);
+
     memset(&pollfd, 0, sizeof(pollfd));
-    pollfd.fd = pa_asyncmsgq_get_fd(u->sink->asyncmsgq, PA_ASYNCQ_POP);
+    pollfd.fd = pa_asyncmsgq_get_fd(u->asyncmsgq);
     pollfd.events = POLLIN;
 
-    pa_gettimeofday(u->timestamp);
-
     for (;;) {
+        pa_msgobject *object;
         int code;
-        void *data, *object;
+        void *data;
+        pa_memchunk chunk;
         int r, timeout;
         struct timeval now;
 
         /* Check whether there is a message for us to process */
-        if (pa_asyncmsgq_get(u->sink->asyncmsgq, &object, &code, &data) == 0) {
-
-
-            /* Now process these messages our own way */
-            if (!object) {
-
-                switch (code) {
-                    case PA_MESSAGE_SHUTDOWN:
-                        goto finish;
-
-                    default:
-                        pa_sink_process_msg(u->sink->asyncmsgq, object, code, data);
-
-                }
+        if (pa_asyncmsgq_get(u->asyncmsgq, &object, &code, &data, &chunk, 0) == 0) {
+            int ret;
 
-            } else if (object == u->sink) {
-
-                switch (code) {
-                    case PA_SINK_MESSAGE_STOP:
-                        pa_assert(running);
-                        running = 0;
-                        break;
-
-                    case PA_SINK_MESSAGE_START:
-                        pa_assert(!running);
-                        running = 1;
-
-                        pa_gettimeofday(u->timestamp);
-                        break;
-
-                    case PA_SINK_MESSAGE_GET_LATENCY:
-
-                        if (pa_timeval_cmp(&u->timestamp, &now) > 0)
-                            *((pa_usec_t*) data) = 0;
-                        else
-                            *((pa_usec_t*) data) = pa_timeval_diff(&u->timestamp, &now);
-                        break;
-
-                        /* ... */
-
-                    default:
-                        pa_sink_process_msg(u->sink->asyncmsgq, object, code, data);
-                }
+            if (!object && code == PA_MESSAGE_SHUTDOWN) {
+                pa_asyncmsgq_done(u->asyncmsgq, 0);
+                goto finish;
             }
-
-            pa_asyncmsgq_done(u->sink->asyncmsgq);
+                    
+            ret = pa_asyncmsgq_dispatch(object, code, data, &chunk);
+            pa_asyncmsgq_done(u->asyncmsgq, ret);
             continue;
         }
 
         /* Render some data and drop it immediately */
-
-        if (running) {
+        if (u->sink->thread_info.state == PA_SINK_RUNNING) {
             pa_gettimeofday(&now);
 
-            if (pa_timeval_cmp(u->timestamp, &now) <= 0) {
-                pa_memchunk chunk;
+            if (pa_timeval_cmp(&u->timestamp, &now) <= 0) {
                 size_t l;
 
                 if (pa_sink_render(u->sink, u->block_size, &chunk) >= 0) {
@@ -179,11 +172,11 @@ static void thread_func(void *userdata) {
 
         /* Hmm, nothing to do. Let's sleep */
 
-        if (pa_asyncmsgq_before_poll(u->sink->asyncmsgq) < 0)
+        if (pa_asyncmsgq_before_poll(u->asyncmsgq) < 0)
             continue;
 
         r = poll(&pollfd, 1, timeout);
-        pa_asyncmsgq_after_poll(u->sink->asyncmsgq);
+        pa_asyncmsgq_after_poll(u->asyncmsgq);
 
         if (r < 0) {
             if (errno == EINTR)
@@ -199,8 +192,8 @@ static void thread_func(void *userdata) {
 fail:
     /* We have to continue processing messages until we receive the
      * SHUTDOWN message */
-    pa_asyncmsgq_post(u->core->asyncmsgq, u->core, PA_CORE_MESSAGE_UNLOAD_MODULE, pa_module_ref(u->module), NULL, pa_module_unref);
-    pa_asyncmsgq_wait_for(PA_MESSAGE_SHUTDOWN);
+    pa_asyncmsgq_post(u->core->asyncmsgq, PA_MSGOBJECT(u->core), PA_CORE_MESSAGE_UNLOAD_MODULE, u->module, NULL, NULL);
+    pa_asyncmsgq_wait_for(u->asyncmsgq, PA_MESSAGE_SHUTDOWN);
 
 finish:
     pa_log_debug("Thread shutting down");
@@ -231,20 +224,24 @@ int pa__init(pa_core *c, pa_module*m) {
     u->module = m;
     m->userdata = u;
 
+    pa_assert_se(u->asyncmsgq = pa_asyncmsgq_new(0));
+    
     if (!(u->sink = pa_sink_new(c, __FILE__, pa_modargs_get_value(ma, "sink_name", DEFAULT_SINK_NAME), 0, &ss, &map))) {
         pa_log("Failed to create sink.");
         goto fail;
     }
 
+    u->sink->parent.process_msg = sink_process_msg;
     u->sink->userdata = u;
-    pa_sink_set_owner(u->sink, m);
+
+    pa_sink_set_module(u->sink, m);
+    pa_sink_set_asyncmsgq(u->sink, u->asyncmsgq);
     pa_sink_set_description(u->sink, pa_modargs_get_value(ma, "description", "NULL sink"));
 
     u->block_size = pa_bytes_per_second(&ss) / 20; /* 50 ms */
-
     if (u->block_size <= 0)
         u->block_size = pa_frame_size(&ss);
-
+    
     if (!(u->thread = pa_thread_new(thread_func, u))) {
         pa_log("Failed to create thread.");
         goto fail;
@@ -272,14 +269,19 @@ void pa__done(pa_core *c, pa_module*m) {
     if (!(u = m->userdata))
         return;
 
-    pa_sink_disconnect(u->sink);
+    if (u->sink)
+        pa_sink_disconnect(u->sink);
 
     if (u->thread) {
-        pa_asyncmsgq_send(u->sink->asyncmsgq, PA_SINK_MESSAGE_SHUTDOWN, NULL);
+        pa_asyncmsgq_send(u->asyncmsgq, NULL, PA_MESSAGE_SHUTDOWN, NULL, NULL);
         pa_thread_free(u->thread);
     }
 
-    pa_sink_unref(u->sink);
+    if (u->asyncmsgq)
+        pa_asyncmsgq_free(u->asyncmsgq);
+
+    if (u->sink)
+        pa_sink_unref(u->sink);
 
     pa_xfree(u);
 }
diff --git a/src/modules/module-pipe-sink.c b/src/modules/module-pipe-sink.c
index e4735f6..da9124a 100644
--- a/src/modules/module-pipe-sink.c
+++ b/src/modules/module-pipe-sink.c
@@ -34,6 +34,8 @@
 #include <fcntl.h>
 #include <unistd.h>
 #include <limits.h>
+#include <sys/ioctl.h>
+#include <sys/poll.h>
 
 #include <pulse/xmalloc.h>
 
@@ -44,6 +46,7 @@
 #include <pulsecore/core-util.h>
 #include <pulsecore/modargs.h>
 #include <pulsecore/log.h>
+#include <pulsecore/thread.h>
 
 #include "module-pipe-sink-symdef.h"
 
@@ -65,9 +68,12 @@ struct userdata {
     pa_core *core;
     pa_module *module;
     pa_sink *sink;
+    pa_thread *thread;
+    pa_asyncmsgq *asyncmsgq;
     char *filename;
     int fd;
-    pa_thread *thread;
+
+    pa_memchunk memchunk;
 };
 
 static const char* const valid_modargs[] = {
@@ -80,109 +86,99 @@ static const char* const valid_modargs[] = {
     NULL
 };
 
-enum {
-    POLLFD_ASYNCQ,
-    POLLFD_FIFO,
-    POLLFD_MAX,
-};
+static int sink_process_msg(pa_msgobject *o, int code, void *data, pa_memchunk *chunk) {
+    struct userdata *u = PA_SINK(o)->userdata;
+
+    switch (code) {
+            
+        case PA_SINK_MESSAGE_GET_LATENCY: {
+            size_t n = 0;
+            int l;
+            
+            if (ioctl(u->fd, TIOCINQ, &l) >= 0 && l > 0)
+                n = (size_t) l;
+            
+            n += u->memchunk.length;
+            
+            *((pa_usec_t*) data) = pa_bytes_to_usec(n, &u->sink->sample_spec);
+            break;
+        }
+    }
+    
+    return pa_sink_process_msg(o, code, data, chunk);
+}
 
 static void thread_func(void *userdata) {
+    enum {
+        POLLFD_ASYNCQ,
+        POLLFD_FIFO,
+        POLLFD_MAX,
+    };
+    
     struct userdata *u = userdata;
-    int quit = 0;
     struct pollfd pollfd[POLLFD_MAX];
-    int running = 1, underrun = 0;
-    pa_memchunk memchunk;
+    int underrun = 0;
+    int write_type = 0;
 
     pa_assert(u);
 
     pa_log_debug("Thread starting up");
 
+    pa_memchunk_reset(&u->memchunk);
+    
     memset(&pollfd, 0, sizeof(pollfd));
-    pollfd[POLLFD_ASYNCQ].fd = pa_asyncmsgq_get_fd(u->sink->asyncmsgq, PA_ASYNCQ_POP);
+    
+    pollfd[POLLFD_ASYNCQ].fd = pa_asyncmsgq_get_fd(u->asyncmsgq);
     pollfd[POLLFD_ASYNCQ].events = POLLIN;
-
     pollfd[POLLFD_FIFO].fd = u->fd;
 
-    memset(&memchunk, 0, sizeof(memchunk));
-
     for (;;) {
+        pa_msgobject *object;
         int code;
-        void *object, *data;
+        void *data;
+        pa_memchunk chunk;
         int r;
-        struct timeval now;
 
         /* Check whether there is a message for us to process */
-        if (pa_asyncmsgq_get(u->sink->asyncmsgq, &object, &code, &data) == 0) {
-
-
-            /* Now process these messages our own way */
-            if (!object) {
-                switch (code) {
-                    case PA_SINK_MESSAGE_SHUTDOWN:
-                        goto finish;
-
-                    default:
-                        pa_sink_process_msg(u->sink->asyncmsgq, object, code, data);
-                }
+        if (pa_asyncmsgq_get(u->asyncmsgq, &object, &code, &data, &chunk, 0) == 0) {
+            int ret;
 
-            } else if (object == u->sink) {
-
-                case PA_SINK_MESSAGE_STOP:
-                    pa_assert(running);
-                    running = 0;
-                    break;
-
-                case PA_SINK_MESSAGE_START:
-                    pa_assert(!running);
-                    running = 1;
-                    break;
-
-                case PA_SINK_MESSAGE_GET_LATENCY: {
-                    size_t n = 0;
-                    int l;
-
-                    if (ioctl(u->fd, TIOCINQ, &l) >= 0 && l > 0)
-                        n = (size_t) l;
-
-                    n += memchunk.length;
-
-                    *((pa_usec_t*) data) pa_bytes_to_usec(n, &u->sink->sample_spec);
-                    break;
-                }
-
-                /* ... */
-
-                default:
-                    pa_sink_process_msg(u->sink->asyncmsgq, object, code, data);
+            if (!object && code == PA_MESSAGE_SHUTDOWN) {
+                pa_asyncmsgq_done(u->asyncmsgq, 0);
+                goto finish;
             }
 
-            pa_asyncmsgq_done(u->sink->asyncmsgq);
+            ret = pa_asyncmsgq_dispatch(object, code, data, &chunk);
+            pa_asyncmsgq_done(u->asyncmsgq, ret);
             continue;
         }
 
         /* Render some data and write it to the fifo */
 
-        if (running && (pollfd[POLLFD_FIFO].revents || underrun)) {
+        if (u->sink->thread_info.state == PA_SINK_RUNNING && (pollfd[POLLFD_FIFO].revents || underrun)) {
 
-            if (chunk.length <= 0)
-                pa_sink_render(u->fd, PIPE_BUF, &chunk);
+            if (u->memchunk.length <= 0)
+                pa_sink_render(u->sink, PIPE_BUF, &u->memchunk);
 
-            underrun = chunk.length <= 0;
+            underrun = u->memchunk.length <= 0;
 
             if (!underrun) {
                 ssize_t l;
+                void *p;
 
                 p = pa_memblock_acquire(u->memchunk.memblock);
-                l = pa_write(u->fd, (uint8_t*) p + u->memchunk.index, u->memchunk.length);
-                pa_memblock_release(p);
+                l = pa_write(u->fd, (uint8_t*) p + u->memchunk.index, u->memchunk.length, &write_type);
+                pa_memblock_release(u->memchunk.memblock);
 
                 if (l < 0) {
 
-                    if (errno != EINTR && errno != EAGAIN) {
+                    if (errno == EINTR)
+                        continue;
+                    else if (errno != EAGAIN) {
                         pa_log("Failed to write data to FIFO: %s", pa_cstrerror(errno));
                         goto fail;
                     }
-
+                    
                 } else {
 
                     u->memchunk.index += l;
@@ -190,24 +186,24 @@ static void thread_func(void *userdata) {
 
                     if (u->memchunk.length <= 0) {
                         pa_memblock_unref(u->memchunk.memblock);
-                        u->memchunk.memblock = NULL;
+                        pa_memchunk_reset(&u->memchunk);
                     }
-                }
 
-                pollfd[POLLFD_FIFO].revents = 0;
-                continue;
+                    pollfd[POLLFD_FIFO].revents = 0;
+                    continue;
+                }
             }
         }
 
-        pollfd[POLLFD_FIFO].events = running && !underrun ? POLLOUT : 0;
+        pollfd[POLLFD_FIFO].events = (u->sink->thread_info.state == PA_SINK_RUNNING && !underrun) ? POLLOUT : 0;
 
         /* Hmm, nothing to do. Let's sleep */
 
-        if (pa_asyncmsgq_before_poll(u->sink->asyncmsgq) < 0)
+        if (pa_asyncmsgq_before_poll(u->asyncmsgq) < 0)
             continue;
 
-        r = poll(&pollfd, 1, 0);
-        pa_asyncmsgq_after_poll(u->sink->asyncmsgq);
+        r = poll(pollfd, POLLFD_MAX, -1);
+        pa_asyncmsgq_after_poll(u->asyncmsgq);
 
         if (r < 0) {
             if (errno == EINTR)
@@ -217,19 +213,19 @@ static void thread_func(void *userdata) {
             goto fail;
         }
 
-        if (pollfd[POLLFD_FIFO].revents & ~POLLIN) {
+        if (pollfd[POLLFD_FIFO].revents & ~POLLOUT) {
             pa_log("FIFO shutdown.");
             goto fail;
         }
 
-        pa_assert(pollfd[POLLFD_ASYNCQ].revents & ~POLLIN == 0);
+        pa_assert((pollfd[POLLFD_ASYNCQ].revents & ~POLLIN) == 0);
     }
 
 fail:
     /* We have to continue processing messages until we receive the
      * SHUTDOWN message */
-    pa_asyncmsgq_post(u->core->asyncmsgq, u->core, PA_CORE_MESSAGE_UNLOAD_MODULE, pa_module_ref(u->module), pa_module_unref);
-    pa_asyncmsgq_wait_for(PA_SINK_MESSAGE_SHUTDOWN);
+    pa_asyncmsgq_post(u->core->asyncmsgq, PA_MSGOBJECT(u->core), PA_CORE_MESSAGE_UNLOAD_MODULE, u->module, NULL, NULL);
+    pa_asyncmsgq_wait_for(u->asyncmsgq, PA_MESSAGE_SHUTDOWN);
 
 finish:
     pa_log_debug("Thread shutting down");
@@ -253,23 +249,22 @@ int pa__init(pa_core *c, pa_module*m) {
 
     ss = c->default_sample_spec;
     if (pa_modargs_get_sample_spec_and_channel_map(ma, &ss, &map, PA_CHANNEL_MAP_DEFAULT) < 0) {
-        pa_log("Invalid sample format specification");
+        pa_log("Invalid sample format specification or channel map");
         goto fail;
     }
 
     u = pa_xnew0(struct userdata, 1);
     u->core = c;
     u->module = m;
-    u->filename = pa_xstrdup(pa_modargs_get_value(ma, "file", DEFAULT_FIFO_NAME));
-    u->fd = fd;
-    u->memchunk.memblock = NULL;
-    u->memchunk.length = 0;
     m->userdata = u;
 
-    mkfifo(u->filename, 0666);
+    pa_assert_se(u->asyncmsgq = pa_asyncmsgq_new(0));
+    
+    u->filename = pa_xstrdup(pa_modargs_get_value(ma, "file", DEFAULT_FILE_NAME));
 
-    if ((u->fd = open(u->filename, O_RDWR)) < 0) {
-        pa_log("open('%s'): %s", p, pa_cstrerror(errno));
+    mkfifo(u->filename, 0666);
+    if ((u->fd = open(u->filename, O_RDWR|O_NOCTTY)) < 0) {
+        pa_log("open('%s'): %s", u->filename, pa_cstrerror(errno));
         goto fail;
     }
 
@@ -277,12 +272,12 @@ int pa__init(pa_core *c, pa_module*m) {
     pa_make_nonblock_fd(u->fd);
 
     if (fstat(u->fd, &st) < 0) {
-        pa_log("fstat('%s'): %s", p, pa_cstrerror(errno));
+        pa_log("fstat('%s'): %s", u->filename, pa_cstrerror(errno));
         goto fail;
     }
 
     if (!S_ISFIFO(st.st_mode)) {
-        pa_log("'%s' is not a FIFO.", p);
+        pa_log("'%s' is not a FIFO.", u->filename);
         goto fail;
     }
 
@@ -291,9 +286,12 @@ int pa__init(pa_core *c, pa_module*m) {
         goto fail;
     }
 
+    u->sink->parent.process_msg = sink_process_msg;
     u->sink->userdata = u;
-    pa_sink_set_owner(u->sink, m);
-    pa_sink_set_description(u->sink, t = pa_sprintf_malloc("Unix FIFO sink '%s'", p));
+    
+    pa_sink_set_module(u->sink, m);
+    pa_sink_set_asyncmsgq(u->sink, u->asyncmsgq);
+    pa_sink_set_description(u->sink, t = pa_sprintf_malloc("Unix FIFO sink '%s'", u->filename));
     pa_xfree(t);
 
     if (!(u->thread = pa_thread_new(thread_func, u))) {
@@ -316,20 +314,26 @@ fail:
 
 void pa__done(pa_core *c, pa_module*m) {
     struct userdata *u;
+    
     pa_assert(c);
     pa_assert(m);
 
     if (!(u = m->userdata))
         return;
 
-    pa_sink_disconnect(u->sink);
+    if (u->sink)
+        pa_sink_disconnect(u->sink);
 
     if (u->thread) {
-        pa_asyncmsgq_send(u->sink->asyncmsgq, PA_SINK_MESSAGE_SHUTDOWN, NULL);
+        pa_asyncmsgq_send(u->asyncmsgq, NULL, PA_MESSAGE_SHUTDOWN, NULL, NULL);
         pa_thread_free(u->thread);
     }
 
-    pa_sink_unref(u->sink);
+    if (u->asyncmsgq)
+        pa_asyncmsgq_free(u->asyncmsgq);
+    
+    if (u->sink)
+        pa_sink_unref(u->sink);
 
     if (u->memchunk.memblock)
        pa_memblock_unref(u->memchunk.memblock);
diff --git a/src/modules/module-pipe-source.c b/src/modules/module-pipe-source.c
index f275c5d..ac2bef7 100644
--- a/src/modules/module-pipe-source.c
+++ b/src/modules/module-pipe-source.c
@@ -179,7 +179,7 @@ int pa__init(pa_core *c, pa_module*m) {
         goto fail;
     }
     u->source->userdata = u;
-    pa_source_set_owner(u->source, m);
+    pa_source_set_module(u->source, m);
     pa_source_set_description(u->source, t = pa_sprintf_malloc("Unix FIFO source '%s'", p));
     pa_xfree(t);
 
diff --git a/src/pulsecore/asyncmsgq.c b/src/pulsecore/asyncmsgq.c
index de5b2f9..6becb62 100644
--- a/src/pulsecore/asyncmsgq.c
+++ b/src/pulsecore/asyncmsgq.c
@@ -48,6 +48,7 @@ struct asyncmsgq_item {
     pa_free_cb_t free_cb;
     pa_memchunk memchunk;
     pa_semaphore *semaphore;
+    int ret;
 };
 
 struct pa_asyncmsgq {
@@ -81,10 +82,10 @@ void pa_asyncmsgq_free(pa_asyncmsgq *a) {
             pa_msgobject_unref(i->object);
 
         if (i->memchunk.memblock)
-            pa_memblock_unref(i->object);
+            pa_memblock_unref(i->memchunk.memblock);
 
-        if (i->userdata_free_cb)
-            i->userdata_free_cb(i->userdata);
+        if (i->free_cb)
+            i->free_cb(i->userdata);
 
         if (pa_flist_push(PA_STATIC_FLIST_GET(asyncmsgq), i) < 0)
             pa_xfree(i);
@@ -103,7 +104,7 @@ void pa_asyncmsgq_post(pa_asyncmsgq *a, pa_msgobject *object, int code, const vo
         i = pa_xnew(struct asyncmsgq_item, 1);
 
     i->code = code;
-    i->object = pa_msgobject_ref(object);
+    i->object = object ? pa_msgobject_ref(object) : NULL;
     i->userdata = (void*) userdata;
     i->free_cb = free_cb;
     if (chunk) {
@@ -131,9 +132,9 @@ int pa_asyncmsgq_send(pa_asyncmsgq *a, pa_msgobject *object, int code, const voi
     i.ret = -1;
     if (chunk) {
         pa_assert(chunk->memblock);
-        i->memchunk = *chunk;
+        i.memchunk = *chunk;
     } else
-        pa_memchunk_reset(&i->memchunk);
+        pa_memchunk_reset(&i.memchunk);
     pa_assert_se(i.semaphore = pa_semaphore_new(0));
 
     /* Thus mutex makes the queue multiple-writer safe. This lock is only used on the writing side */
@@ -161,8 +162,10 @@ int pa_asyncmsgq_get(pa_asyncmsgq *a, pa_msgobject **object, int *code, void **u
     if (object)
         *object = a->current->object;
     if (chunk)
-        *chunk = a->chunk;
+        *chunk = a->current->memchunk;
 
+    pa_log_debug("q=%p object=%p code=%i data=%p", a, a->current->object, a->current->code, a->current->userdata);
+    
     return 0;
 }
 
@@ -196,11 +199,16 @@ int pa_asyncmsgq_wait_for(pa_asyncmsgq *a, int code) {
     pa_assert(a);
 
     do {
+        pa_msgobject *o;
+        void *data;
+        pa_memchunk chunk;
+        int ret;
 
-        if (pa_asyncmsgq_get(a, NULL, &c, NULL, 1) < 0)
+        if (pa_asyncmsgq_get(a, &o, &c, &data, &chunk, 1) < 0)
             return -1;
 
-        pa_asyncmsgq_done(a);
+        ret = pa_asyncmsgq_dispatch(o, c, data, &chunk);
+        pa_asyncmsgq_done(a, ret);
 
     } while (c != code);
 
@@ -226,10 +234,9 @@ void pa_asyncmsgq_after_poll(pa_asyncmsgq *a) {
 }
 
 int pa_asyncmsgq_dispatch(pa_msgobject *object, int code, void *userdata, pa_memchunk *memchunk) {
-    pa_assert(q);
 
     if (object)
-        return object->msg_process(object, code, userdata, memchunk);
+        return object->process_msg(object, code, userdata, memchunk);
 
     return 0;
 }
diff --git a/src/pulsecore/asyncq.c b/src/pulsecore/asyncq.c
index 54d36dc..da1f16f 100644
--- a/src/pulsecore/asyncq.c
+++ b/src/pulsecore/asyncq.c
@@ -52,8 +52,8 @@ struct pa_asyncq {
     unsigned size;
     unsigned read_idx;
     unsigned write_idx;
-    pa_atomic_int_t read_waiting;
-    pa_atomic_int_t write_waiting;
+    pa_atomic_t read_waiting, n_read;
+    pa_atomic_t write_waiting, n_written;
     int read_fds[2], write_fds[2];
 };
 
@@ -80,6 +80,8 @@ pa_asyncq *pa_asyncq_new(unsigned size) {
     l->size = size;
     pa_atomic_store(&l->read_waiting, 0);
     pa_atomic_store(&l->write_waiting, 0);
+    pa_atomic_store(&l->n_written, 0);
+    pa_atomic_store(&l->n_read, 0);
 
     if (pipe(l->read_fds) < 0) {
         pa_xfree(l);
@@ -131,10 +133,26 @@ int pa_asyncq_push(pa_asyncq*l, void *p, int wait) {
 
     if (!pa_atomic_ptr_cmpxchg(&cells[idx], NULL, p)) {
 
-        /* First try failed. Let's wait for changes. */
-
-        if (!wait)
+        if (!wait) {
+            /* Let's empty the FIFO from old notifications, before we return */
+            
+            while (pa_atomic_load(&l->n_read) > 0) {
+                ssize_t r;
+                int x[20];
+                
+                errno = 0;
+                if ((r = read(l->write_fds[0], x, sizeof(x))) <= 0 && errno != EINTR)
+                    return -1;
+                
+                if (r > 0)
+                    if (pa_atomic_sub(&l->n_read, r) <= r)
+                        break;
+            }
+            
             return -1;
+        }
+
+        /* First try failed. Let's wait for changes. */
 
         _Y;
 
@@ -142,6 +160,7 @@ int pa_asyncq_push(pa_asyncq*l, void *p, int wait) {
 
         for (;;) {
             char x[20];
+            ssize_t r;
 
             _Y;
 
@@ -150,10 +169,13 @@ int pa_asyncq_push(pa_asyncq*l, void *p, int wait) {
 
             _Y;
 
-            if (read(l->write_fds[0], x, sizeof(x)) < 0 && errno != EINTR) {
+            if ((r = read(l->write_fds[0], x, sizeof(x))) < 0 && errno != EINTR) {
                 pa_atomic_dec(&l->write_waiting);
                 return -1;
             }
+
+            if (r > 0)
+                pa_atomic_sub(&l->n_read, r);
         }
 
         _Y;
@@ -167,7 +189,8 @@ int pa_asyncq_push(pa_asyncq*l, void *p, int wait) {
     if (pa_atomic_load(&l->read_waiting)) {
         char x = 'x';
         _Y;
-        write(l->read_fds[1], &x, sizeof(x));
+        if (write(l->read_fds[1], &x, sizeof(x)) > 0)
+            pa_atomic_inc(&l->n_written);
     }
 
     return 0;
@@ -189,8 +212,24 @@ void* pa_asyncq_pop(pa_asyncq*l, int wait) {
 
         /* First try failed. Let's wait for changes. */
 
-        if (!wait)
+        if (!wait) {
+            /* Let's empty the FIFO from old notifications, before we return */
+            
+            while (pa_atomic_load(&l->n_written) > 0) {
+                ssize_t r;
+                int x[20];
+                
+                errno = 0;
+                if ((r = read(l->read_fds[0], x, sizeof(x))) <= 0 && errno != EINTR)
+                    return NULL;
+                
+                if (r > 0)
+                    if (pa_atomic_sub(&l->n_written, r) <= r)
+                        break;
+            }
+            
             return NULL;
+        }
 
         _Y;
 
@@ -198,6 +237,7 @@ void* pa_asyncq_pop(pa_asyncq*l, int wait) {
 
         for (;;) {
             char x[20];
+            ssize_t r;
 
             _Y;
 
@@ -206,10 +246,13 @@ void* pa_asyncq_pop(pa_asyncq*l, int wait) {
 
             _Y;
 
-            if (read(l->read_fds[0], x, sizeof(x)) < 0 && errno != EINTR) {
+            if ((r = read(l->read_fds[0], x, sizeof(x)) < 0) && errno != EINTR) {
                 pa_atomic_dec(&l->read_waiting);
                 return NULL;
             }
+
+            if (r > 0)
+                pa_atomic_sub(&l->n_written, r);
         }
 
         _Y;
@@ -226,7 +269,8 @@ void* pa_asyncq_pop(pa_asyncq*l, int wait) {
     if (pa_atomic_load(&l->write_waiting)) {
         char x = 'x';
         _Y;
-        write(l->write_fds[1], &x, sizeof(x));
+        if (write(l->write_fds[1], &x, sizeof(x)) >= 0)
+            pa_atomic_inc(&l->n_read);
     }
 
     return ret;
@@ -262,10 +306,13 @@ int pa_asyncq_before_poll(pa_asyncq *l) {
     return 0;
 }
 
-int pa_asyncq_after_poll(pa_asyncq *l) {
+void pa_asyncq_after_poll(pa_asyncq *l) {
     pa_assert(l);
 
     pa_assert(pa_atomic_load(&l->read_waiting) > 0);
 
     pa_atomic_dec(&l->read_waiting);
+
+
+    
 }
diff --git a/src/pulsecore/asyncq.h b/src/pulsecore/asyncq.h
index aac45b1..729ec46 100644
--- a/src/pulsecore/asyncq.h
+++ b/src/pulsecore/asyncq.h
@@ -51,6 +51,6 @@ int pa_asyncq_push(pa_asyncq *q, void *p, int wait);
 
 int pa_asyncq_get_fd(pa_asyncq *q);
 int pa_asyncq_before_poll(pa_asyncq *a);
-int pa_asyncq_after_poll(pa_asyncq *a);
+void pa_asyncq_after_poll(pa_asyncq *a);
 
 #endif
diff --git a/src/pulsecore/cli-command.c b/src/pulsecore/cli-command.c
index 36c85d6..d761353 100644
--- a/src/pulsecore/cli-command.c
+++ b/src/pulsecore/cli-command.c
@@ -115,6 +115,8 @@ static int pa_cli_command_list_props(pa_core *c, pa_tokenizer *t, pa_strbuf *buf
 static int pa_cli_command_move_sink_input(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, int *fail);
 static int pa_cli_command_move_source_output(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, int *fail);
 static int pa_cli_command_vacuum(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, int *fail);
+static int pa_cli_command_suspend_sink(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, int *fail);
+static int pa_cli_command_suspend_source(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, int *fail);
 
 /* A method table for all available commands */
 
@@ -134,11 +136,11 @@ static const struct command commands[] = {
     { "load-module",             pa_cli_command_load,               "Load a module (args: name, arguments)", 3},
     { "unload-module",           pa_cli_command_unload,             "Unload a module (args: index)", 2},
     { "set-sink-volume",         pa_cli_command_sink_volume,        "Set the volume of a sink (args: index|name, volume)", 3},
-    { "set-sink-input-volume",   pa_cli_command_sink_input_volume,  "Set the volume of a sink input (args: index|name, volume)", 3},
+    { "set-sink-input-volume",   pa_cli_command_sink_input_volume,  "Set the volume of a sink input (args: index, volume)", 3},
     { "set-source-volume",       pa_cli_command_source_volume,      "Set the volume of a source (args: index|name, volume)", 3},
-    { "set-sink-mute",           pa_cli_command_sink_mute,          "Set the mute switch of a sink (args: index|name, mute)", 3},
-    { "set-sink-input-mute",     pa_cli_command_sink_input_mute,    "Set the mute switch of a sink input (args: index|name, mute)", 3},
-    { "set-source-mute",         pa_cli_command_source_mute,        "Set the mute switch of a source (args: index|name, mute)", 3},
+    { "set-sink-mute",           pa_cli_command_sink_mute,          "Set the mute switch of a sink (args: index|name, bool)", 3},
+    { "set-sink-input-mute",     pa_cli_command_sink_input_mute,    "Set the mute switch of a sink input (args: index, bool)", 3},
+    { "set-source-mute",         pa_cli_command_source_mute,        "Set the mute switch of a source (args: index|name, bool)", 3},
     { "set-default-sink",        pa_cli_command_sink_default,       "Set the default sink (args: index|name)", 2},
     { "set-default-source",      pa_cli_command_source_default,     "Set the default source (args: index|name)", 2},
     { "kill-client",             pa_cli_command_kill_client,        "Kill a client (args: index)", 2},
@@ -161,6 +163,8 @@ static const struct command commands[] = {
     { "move-sink-input",         pa_cli_command_move_sink_input,    "Move sink input to another sink (args: index, sink)", 3},
     { "move-source-output",      pa_cli_command_move_source_output, "Move source output to another source (args: index, source)", 3},
     { "vacuum",                  pa_cli_command_vacuum,             NULL, 1},
+    { "suspend-sink",            pa_cli_command_suspend_sink,       "Suspend sink (args: index|name, bool)", 3},
+    { "suspend-source",          pa_cli_command_suspend_source,     "Suspend source (args: index|name, bool)", 3},
     { NULL, NULL, NULL, 0 }
 };
 
@@ -899,6 +903,64 @@ static int pa_cli_command_move_source_output(pa_core *c, pa_tokenizer *t, pa_str
     return 0;
 }
 
+static int pa_cli_command_suspend_sink(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, int *fail) {
+    const char *n, *m;
+    pa_sink *sink;
+    int suspend;
+
+    if (!(n = pa_tokenizer_get(t, 1))) {
+        pa_strbuf_puts(buf, "You need to specify a sink either by its name or its index.\n");
+        return -1;
+    }
+
+    if (!(m = pa_tokenizer_get(t, 2))) {
+        pa_strbuf_puts(buf, "You need to specify a suspend switch setting (0/1).\n");
+        return -1;
+    }
+
+    if (pa_atoi(m, &suspend) < 0) {
+        pa_strbuf_puts(buf, "Failed to parse suspend switch.\n");
+        return -1;
+    }
+
+    if (!(sink = pa_namereg_get(c, n, PA_NAMEREG_SINK, 1))) {
+        pa_strbuf_puts(buf, "No sink found by this name or index.\n");
+        return -1;
+    }
+
+    pa_sink_suspend(sink, suspend);
+    return 0;
+}
+
+static int pa_cli_command_suspend_source(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, int *fail) {
+    const char *n, *m;
+    pa_source *source;
+    int suspend;
+
+    if (!(n = pa_tokenizer_get(t, 1))) {
+        pa_strbuf_puts(buf, "You need to specify a source either by its name or its index.\n");
+        return -1;
+    }
+
+    if (!(m = pa_tokenizer_get(t, 2))) {
+        pa_strbuf_puts(buf, "You need to specify a suspend switch setting (0/1).\n");
+        return -1;
+    }
+
+    if (pa_atoi(m, &suspend) < 0) {
+        pa_strbuf_puts(buf, "Failed to parse suspend switch.\n");
+        return -1;
+    }
+
+    if (!(source = pa_namereg_get(c, n, PA_NAMEREG_SOURCE, 1))) {
+        pa_strbuf_puts(buf, "No source found by this name or index.\n");
+        return -1;
+    }
+
+    pa_source_suspend(source, suspend);
+    return 0;
+}
+
 static int pa_cli_command_dump(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, PA_GCC_UNUSED int *fail) {
     pa_module *m;
     pa_sink *sink;
@@ -1162,3 +1224,4 @@ int pa_cli_command_execute(pa_core *c, const char *s, pa_strbuf *buf, int *fail)
 
     return 0;
 }
+
diff --git a/src/pulsecore/cli-text.c b/src/pulsecore/cli-text.c
index 05d681e..c919e46 100644
--- a/src/pulsecore/cli-text.c
+++ b/src/pulsecore/cli-text.c
@@ -114,14 +114,15 @@ char *pa_sink_list_to_string(pa_core *c) {
             "  %c index: %u\n"
             "\tname: <%s>\n"
             "\tdriver: <%s>\n"
-            "\tis_hardware: <%i>\n"
+            "\tis hardware: <%i>\n"
             "\tstate: %s\n"
             "\tvolume: <%s>\n"
             "\tmute: <%i>\n"
             "\tlatency: <%0.0f usec>\n"
-            "\tmonitor_source: <%u>\n"
+            "\tmonitor source: <%u>\n"
             "\tsample spec: <%s>\n"
-            "\tchannel map: <%s>\n",
+            "\tchannel map: <%s>\n"
+            "\tused by: <%u>\n", 
             c->default_sink_name && !strcmp(sink->name, c->default_sink_name) ? '*' : ' ',
             sink->index,
             sink->name,
@@ -133,7 +134,8 @@ char *pa_sink_list_to_string(pa_core *c) {
             (double) pa_sink_get_latency(sink),
             sink->monitor_source ? sink->monitor_source->index : PA_INVALID_INDEX,
             pa_sample_spec_snprint(ss, sizeof(ss), &sink->sample_spec),
-            pa_channel_map_snprint(cm, sizeof(cm), &sink->channel_map));
+            pa_channel_map_snprint(cm, sizeof(cm), &sink->channel_map),
+            pa_sink_used_by(sink));
 
         if (sink->module)
             pa_strbuf_printf(s, "\tmodule: <%u>\n", sink->module->index);
@@ -170,13 +172,14 @@ char *pa_source_list_to_string(pa_core *c) {
             "  %c index: %u\n"
             "\tname: <%s>\n"
             "\tdriver: <%s>\n"
-            "\tis_hardware: <%i>\n"
+            "\tis hardware: <%i>\n"
             "\tstate: %s\n"
             "\tvolume: <%s>\n"
             "\tmute: <%u>\n"
             "\tlatency: <%0.0f usec>\n"
             "\tsample spec: <%s>\n"
-            "\tchannel map: <%s>\n",
+            "\tchannel map: <%s>\n"
+            "\tused by: <%u>\n",
             c->default_source_name && !strcmp(source->name, c->default_source_name) ? '*' : ' ',
             source->index,
             source->name,
@@ -187,7 +190,8 @@ char *pa_source_list_to_string(pa_core *c) {
             !!pa_source_get_mute(source),
             (double) pa_source_get_latency(source),
             pa_sample_spec_snprint(ss, sizeof(ss), &source->sample_spec),
-            pa_channel_map_snprint(cm, sizeof(cm), &source->channel_map));
+            pa_channel_map_snprint(cm, sizeof(cm), &source->channel_map),
+            pa_source_used_by(source));
 
         if (source->monitor_of)
             pa_strbuf_printf(s, "\tmonitor_of: <%u>\n", source->monitor_of->index);
diff --git a/src/pulsecore/core-subscribe.c b/src/pulsecore/core-subscribe.c
index 6608d57..288d107 100644
--- a/src/pulsecore/core-subscribe.c
+++ b/src/pulsecore/core-subscribe.c
@@ -207,7 +207,7 @@ static void sched_event(pa_core *c) {
 }
 
 /* Append a new subscription event to the subscription event queue and schedule a main loop event */
-void pa_subscription_post(pa_core *c, pa_subscription_event_type_t t, uint32_t index) {
+void pa_subscription_post(pa_core *c, pa_subscription_event_type_t t, uint32_t idx) {
     pa_subscription_event *e;
     assert(c);
 
@@ -227,7 +227,7 @@ void pa_subscription_post(pa_core *c, pa_subscription_event_type_t t, uint32_t i
                 continue;
 
             /* not the same object */
-            if (i->index != index)
+            if (i->index != idx)
                 continue;
 
             if ((t & PA_SUBSCRIPTION_EVENT_TYPE_MASK) == PA_SUBSCRIPTION_EVENT_REMOVE) {
@@ -253,7 +253,7 @@ void pa_subscription_post(pa_core *c, pa_subscription_event_type_t t, uint32_t i
     e = pa_xnew(pa_subscription_event, 1);
     e->core = c;
     e->type = t;
-    e->index = index;
+    e->index = idx;
 
     PA_LLIST_INSERT_AFTER(pa_subscription_event, c->subscription_event_queue, c->subscription_event_last, e);
     c->subscription_event_last = e;
diff --git a/src/pulsecore/core.c b/src/pulsecore/core.c
index 99ac74e..a940bfc 100644
--- a/src/pulsecore/core.c
+++ b/src/pulsecore/core.c
@@ -49,6 +49,8 @@
 
 #include "core.h"
 
+static PA_DEFINE_CHECK_TYPE(pa_core, core_check_type, pa_msgobject_check_type);
+
 static int core_process_msg(pa_msgobject *o, int code, void *userdata, pa_memchunk *chunk) {
     pa_core *c = PA_CORE(o);
 
@@ -81,8 +83,10 @@ static void asyncmsgq_cb(pa_mainloop_api*api, pa_io_event* e, int fd, pa_io_even
 
         /* Check whether there is a message for us to process */
         while (pa_asyncmsgq_get(c->asyncmsgq, &object, &code, &data, &chunk, 0) == 0) {
-            pa_asyncmsgq_dispatch(object, code, data, &chunk);
-            pa_asyncmsgq_done(c->asyncmsgq, 0);
+            int ret;
+
+            ret = pa_asyncmsgq_dispatch(object, code, data, &chunk);
+            pa_asyncmsgq_done(c->asyncmsgq, ret);
         }
 
         if (pa_asyncmsgq_before_poll(c->asyncmsgq) == 0)
@@ -112,7 +116,7 @@ pa_core* pa_core_new(pa_mainloop_api *m, int shared) {
         }
     }
 
-    c = pa_msgobject_new(pa_core);
+    c = pa_msgobject_new(pa_core, core_check_type);
     c->parent.parent.free = core_free;
     c->parent.process_msg = core_process_msg;
 
@@ -181,7 +185,7 @@ pa_core* pa_core_new(pa_mainloop_api *m, int shared) {
 
 static void core_free(pa_object *o) {
     pa_core *c = PA_CORE(o);
-    pa_core_assert_ref(c);
+    pa_assert(c);
 
     pa_module_unload_all(c);
     assert(!c->modules);
@@ -212,13 +216,14 @@ static void core_free(pa_object *o) {
     pa_xfree(c->default_source_name);
     pa_xfree(c->default_sink_name);
 
+    pa_asyncmsgq_after_poll(c->asyncmsgq);
+    pa_asyncmsgq_free(c->asyncmsgq);
+
     pa_mempool_free(c->mempool);
 
     pa_property_cleanup(c);
 
     c->mainloop->io_free(c->asyncmsgq_event);
-    pa_asyncmsgq_after_poll(c->asyncmsgq);
-    pa_asyncmsgq_free(c->asyncmsgq);
 
     pa_hook_free(&c->hook_sink_input_new);
     pa_hook_free(&c->hook_sink_disconnect);
diff --git a/src/pulsecore/core.h b/src/pulsecore/core.h
index 86660b7..a64f217 100644
--- a/src/pulsecore/core.h
+++ b/src/pulsecore/core.h
@@ -98,7 +98,7 @@ struct pa_core {
 };
 
 PA_DECLARE_CLASS(pa_core);
-#define PA_CORE(o) ((pa_core*) o)
+#define PA_CORE(o) pa_core_cast(o)
 
 enum {
     PA_CORE_MESSAGE_UNLOAD_MODULE,
diff --git a/src/pulsecore/log.c b/src/pulsecore/log.c
index 0033adb..a1197eb 100644
--- a/src/pulsecore/log.c
+++ b/src/pulsecore/log.c
@@ -71,14 +71,11 @@ static const char level_to_char[] = {
 };
 
 void pa_log_set_ident(const char *p) {
-    if (log_ident)
-        pa_xfree(log_ident);
-    if (log_ident_local)
-        pa_xfree(log_ident_local);
+    pa_xfree(log_ident);
+    pa_xfree(log_ident_local);
 
     log_ident = pa_xstrdup(p);
-    log_ident_local = pa_utf8_to_locale(log_ident);
-    if (!log_ident_local)
+    if (!(log_ident_local = pa_utf8_to_locale(log_ident)))
         log_ident_local = pa_xstrdup(log_ident);
 }
 
diff --git a/src/pulsecore/msgobject.c b/src/pulsecore/msgobject.c
index ce9f22f..6db630c 100644
--- a/src/pulsecore/msgobject.c
+++ b/src/pulsecore/msgobject.c
@@ -28,13 +28,15 @@
 
 #include "msgobject.h"
 
-pa_msgobject *pa_msgobject_new_internal(size_t size, const char *type_name) {
+PA_DEFINE_CHECK_TYPE(pa_msgobject, pa_msgobject_check_type, pa_object_check_type);
+
+pa_msgobject *pa_msgobject_new_internal(size_t size, const char *type_name, int (*check_type)(pa_object *o, const char *type_name)) {
     pa_msgobject *o;
 
     pa_assert(size > sizeof(pa_msgobject));
     pa_assert(type_name);
 
-    o = PA_MSGOBJECT(pa_object_new_internal(size, type_name));
+    o = PA_MSGOBJECT(pa_object_new_internal(size, type_name, check_type ? check_type : pa_msgobject_check_type));
     o->process_msg = NULL;
     return o;
 }
diff --git a/src/pulsecore/msgobject.h b/src/pulsecore/msgobject.h
index 317ebd2..65761ae 100644
--- a/src/pulsecore/msgobject.h
+++ b/src/pulsecore/msgobject.h
@@ -40,12 +40,14 @@ struct pa_msgobject {
     int (*process_msg)(pa_msgobject *o, int code, void *userdata, pa_memchunk *chunk);
 };
 
-pa_msgobject *pa_msgobject_new_internal(size_t size, const char *type_name);
+pa_msgobject *pa_msgobject_new_internal(size_t size, const char *type_name, int (*check_type)(pa_object *o, const char *type_name));
 
-#define pa_msgobject_new(type) ((type*) pa_msgobject_new_internal(sizeof(type), #type))
+int pa_msgobject_check_type(pa_object *o, const char *type);
+
+#define pa_msgobject_new(type, check_type) ((type*) pa_msgobject_new_internal(sizeof(type), #type, check_type))
 #define pa_msgobject_free ((void (*) (pa_msgobject* o)) pa_object_free)
 
-#define PA_MSGOBJECT(o) ((pa_msgobject*) (o))
+#define PA_MSGOBJECT(o) pa_msgobject_cast(o)
 
 PA_DECLARE_CLASS(pa_msgobject);
 
diff --git a/src/pulsecore/object.c b/src/pulsecore/object.c
index e6ed53b..a983c5a 100644
--- a/src/pulsecore/object.c
+++ b/src/pulsecore/object.c
@@ -28,7 +28,7 @@
 
 #include "object.h"
 
-pa_object *pa_object_new_internal(size_t size, const char *type_name) {
+pa_object *pa_object_new_internal(size_t size, const char *type_name, int (*check_type)(pa_object *o, const char *type_name)) {
     pa_object *o;
 
     pa_assert(size > sizeof(pa_object));
@@ -38,24 +38,30 @@ pa_object *pa_object_new_internal(size_t size, const char *type_name) {
     PA_REFCNT_INIT(o);
     o->type_name = type_name;
     o->free = pa_object_free;
+    o->check_type = check_type ? check_type : pa_object_check_type;
 
     return o;
 }
 
 pa_object *pa_object_ref(pa_object *o) {
-    pa_assert(o);
-    pa_assert(PA_REFCNT_VALUE(o) >= 1);
+    pa_object_assert_ref(o);
 
     PA_REFCNT_INC(o);
     return o;
 }
 
 void pa_object_unref(pa_object *o) {
-    pa_assert(o);
-    pa_assert(PA_REFCNT_VALUE(o) >= 1);
+    pa_object_assert_ref(o);
 
     if (PA_REFCNT_DEC(o) <= 0) {
         pa_assert(o->free);
         o->free(o);
     }
 }
+
+int pa_object_check_type(pa_object *o, const char *type_name) {
+    pa_assert(o);
+    pa_assert(type_name);
+    
+    return type_name == "pa_object" || strcmp(type_name, "pa_object") == 0;
+}
diff --git a/src/pulsecore/object.h b/src/pulsecore/object.h
index e195a35..270f289 100644
--- a/src/pulsecore/object.h
+++ b/src/pulsecore/object.h
@@ -25,7 +25,9 @@
   USA.
 ***/
 
+#include <string.h>
 #include <sys/types.h>
+
 #include <pulse/xmalloc.h>
 #include <pulsecore/refcnt.h>
 #include <pulsecore/macro.h>
@@ -36,13 +38,22 @@ struct pa_object {
     PA_REFCNT_DECLARE;
     const char *type_name;
     void (*free)(pa_object *o);
+    int (*check_type)(pa_object *o, const char *type_name);
 };
 
-pa_object *pa_object_new_internal(size_t size, const char *type_name);
-#define pa_object_new(type) ((type*) pa_object_new_internal(sizeof(type), #type))
+pa_object *pa_object_new_internal(size_t size, const char *type_name, int (*check_type)(pa_object *o, const char *type_name));
+#define pa_object_new(type, check_type) ((type*) pa_object_new_internal(sizeof(type), #type, check_type)
 
 #define pa_object_free ((void (*) (pa_object* o)) pa_xfree)
 
+int pa_object_check_type(pa_object *o, const char *type);
+
+static inline int pa_object_isinstance(void *o) {
+    pa_object *obj = (pa_object*) o;
+    pa_assert(obj);
+    return obj->check_type(obj, "pa_object");
+}
+
 pa_object *pa_object_ref(pa_object *o);
 void pa_object_unref(pa_object *o);
 
@@ -50,23 +61,50 @@ static inline int pa_object_refcnt(pa_object *o) {
     return o ? PA_REFCNT_VALUE(o) : 0;
 }
 
+static inline pa_object* pa_object_cast(void *o) {
+    pa_object *obj = (pa_object*) o;
+    pa_assert(obj->check_type(obj, "pa_object"));
+    return obj;
+}
+
 #define pa_object_assert_ref(o) pa_assert(pa_object_refcnt(o))
 
-#define PA_OBJECT(o) ((pa_object*) (o))
-
-#define PA_DECLARE_CLASS(c) \
-    static inline c* c##_ref(c *o) {                            \
-        return (c*) pa_object_ref(PA_OBJECT(o));                \
-    }                                                           \
-    static inline void c##_unref(c* o) {                        \
-        pa_object_unref(PA_OBJECT(o));                          \
-    }                                                           \
-    static inline int c##_refcnt(c* o) {                        \
-        return pa_object_refcnt(PA_OBJECT(o));                  \
-    }                                                           \
-    static inline void c##_assert_ref(c *o) {                   \
-        pa_object_assert_ref(PA_OBJECT(o));                     \
-    }                                                           \
+#define PA_OBJECT(o) pa_object_cast(o)
+
+#define PA_DECLARE_CLASS(c)                                             \
+    static inline int c##_isinstance(void *o) {                         \
+        pa_object *obj = (pa_object*) o;                                \
+        pa_assert(obj);                                                 \
+        return obj->check_type(obj, #c);                                \
+    }                                                                   \
+    static inline c* c##_cast(void *o) {                                \
+        pa_assert(c##_isinstance(o));                                   \
+        return (c*) o;                                                  \
+    }                                                                   \
+    static inline c* c##_ref(c *o) {                                    \
+        return (c*) pa_object_ref(PA_OBJECT(o));                        \
+    }                                                                   \
+    static inline void c##_unref(c* o) {                                \
+        pa_object_unref(PA_OBJECT(o));                                  \
+    }                                                                   \
+    static inline int c##_refcnt(c* o) {                                \
+        return pa_object_refcnt(PA_OBJECT(o));                          \
+    }                                                                   \
+    static inline void c##_assert_ref(c *o) {                           \
+        pa_object_assert_ref(PA_OBJECT(o));                             \
+    }                                                                   \
+    struct __stupid_useless_struct_to_allow_trailing_semicolon
+
+#define PA_DEFINE_CHECK_TYPE(c, func, parent)                           \
+    int func(pa_object *o, const char *type) {                          \
+        pa_assert(o);                                                   \
+        pa_assert(type);                                                \
+        if (type == #c ||                                               \
+            strcmp(type, #c) == 0)                                      \
+            return 1;                                                   \
+        return parent(o, type);                                         \
+    }                                                                   \
     struct __stupid_useless_struct_to_allow_trailing_semicolon
 
+
 #endif
diff --git a/src/pulsecore/protocol-simple.c b/src/pulsecore/protocol-simple.c
index b7a4cc7..67741bd 100644
--- a/src/pulsecore/protocol-simple.c
+++ b/src/pulsecore/protocol-simple.c
@@ -40,13 +40,15 @@
 #include <pulsecore/namereg.h>
 #include <pulsecore/log.h>
 #include <pulsecore/core-error.h>
+#include <pulsecore/atomic.h>
 
 #include "protocol-simple.h"
 
 /* Don't allow more than this many concurrent connections */
 #define MAX_CONNECTIONS 10
 
-struct connection {
+typedef struct connection {
+    pa_msgobject parent;
     pa_protocol_simple *protocol;
     pa_iochannel *io;
     pa_sink_input *sink_input;
@@ -59,18 +61,21 @@ struct connection {
     struct {
         pa_memblock *current_memblock;
         size_t memblock_index, fragment_size;
-        pa_atomic_int missing;
+        pa_atomic_t missing;
     } playback;
-};
+} connection;
+
+PA_DECLARE_CLASS(connection);
+#define CONNECTION(o) (connection_cast(o))
 
+static PA_DEFINE_CHECK_TYPE(connection, connection_check_type, pa_msgobject_check_type);
+                     
 struct pa_protocol_simple {
     pa_module *module;
     pa_core *core;
     pa_socket_server*server;
     pa_idxset *connections;
 
-    pa_asyncmsgq *asyncmsgq;
-
     enum {
         RECORD = 1,
         PLAYBACK = 2,
@@ -86,8 +91,9 @@ enum {
 };
 
 enum {
-    MESSAGE_REQUEST_DATA,   /* data from source output to main loop */
-    MESSAGE_POST_DATA       /* data from source output to main loop */
+    MESSAGE_REQUEST_DATA,      /* data requested from sink input from the main loop */
+    MESSAGE_POST_DATA,         /* data from source output to main loop */
+    MESSAGE_DROP_CONNECTION    /* Please drop a aconnection now */
 };
 
 
@@ -96,37 +102,49 @@ enum {
 #define RECORD_BUFFER_SECONDS (5)
 #define RECORD_BUFFER_FRAGMENTS (100)
 
-static void connection_free(struct connection *c) {
+static void connection_free(pa_object *o) {
+    connection *c = CONNECTION(o);
     pa_assert(c);
 
+    if (c->playback.current_memblock)
+        pa_memblock_unref(c->playback.current_memblock);
+
+    if (c->io)
+        pa_iochannel_free(c->io);
+    if (c->input_memblockq)
+        pa_memblockq_free(c->input_memblockq);
+    if (c->output_memblockq)
+        pa_memblockq_free(c->output_memblockq);
+
+    pa_xfree(c);
+}
+
+static void connection_drop(connection *c) {
+    pa_assert(c);
+    
     pa_idxset_remove_by_data(c->protocol->connections, c, NULL);
 
     if (c->sink_input) {
         pa_sink_input_disconnect(c->sink_input);
         pa_sink_input_unref(c->sink_input);
+        c->sink_input = NULL;
     }
 
     if (c->source_output) {
         pa_source_output_disconnect(c->source_output);
         pa_source_output_unref(c->source_output);
+        c->source_output = NULL;
     }
 
-    if (c->playback.current_memblock)
-        pa_memblock_unref(c->playback.current_memblock);
-
-    if (c->client)
+    if (c->client) {
         pa_client_free(c->client);
-    if (c->io)
-        pa_iochannel_free(c->io);
-    if (c->input_memblockq)
-        pa_memblockq_free(c->input_memblockq);
-    if (c->output_memblockq)
-        pa_memblockq_free(c->output_memblockq);
+        c->client = NULL;
+    }
 
-    pa_xfree(c);
+    connection_unref(c);
 }
 
-static int do_read(struct connection *c) {
+static int do_read(connection *c) {
     pa_memchunk chunk;
     ssize_t r;
     size_t l;
@@ -171,17 +189,17 @@ static int do_read(struct connection *c) {
 
     c->playback.memblock_index += r;
 
-    pa_asyncmsgq_post(c->protocol->asyncmsgq, c, MESSAGE_POST_DATA, NULL, &chunk, NULL, NULL);
+    pa_asyncmsgq_post(c->protocol->core->asyncmsgq, PA_MSGOBJECT(c->sink_input), SINK_INPUT_MESSAGE_POST_DATA, NULL, &chunk, NULL);
 
     return 0;
 }
 
-static int do_write(struct connection *c) {
+static int do_write(connection *c) {
     pa_memchunk chunk;
     ssize_t r;
     void *p;
 
-    p_assert(c);
+    pa_assert(c);
 
     if (!c->source_output)
         return 0;
@@ -212,7 +230,7 @@ static int do_write(struct connection *c) {
     return 0;
 }
 
-static void do_work(struct connection *c) {
+static void do_work(connection *c) {
     pa_assert(c);
 
     if (c->dead)
@@ -243,14 +261,39 @@ fail:
 
         pa_memblockq_prebuf_disable(c->input_memblockq);
     } else
-        connection_free(c);
+        connection_drop(c);
+}
+
+static int connection_process_msg(pa_msgobject *o, int code, void*userdata, pa_memchunk *chunk) {
+    connection *c = CONNECTION(o);
+    
+    connection_assert_ref(c);
+
+    switch (code) {
+        case MESSAGE_REQUEST_DATA:
+            do_work(c);
+            break;
+            
+        case MESSAGE_POST_DATA:
+            pa_memblockq_push(c->output_memblockq, chunk);
+            do_work(c);
+            break;
+
+        case MESSAGE_DROP_CONNECTION:
+            connection_drop(c);
+            break;
+
+    }
+
+    return 0;
 }
 
 /*** sink_input callbacks ***/
 
 /* Called from thread context */
-static int sink_input_process_msg(pa_sink_input *i, int code, void *userdata, const pa_memchunk *chunk) {
-    struct connection*c;
+static int sink_input_process_msg(pa_msgobject *o, int code, void *userdata, pa_memchunk *chunk) {
+    pa_sink_input *i = PA_SINK_INPUT(o);
+    connection*c;
 
     pa_assert(i);
     c = i->userdata;
@@ -263,6 +306,8 @@ static int sink_input_process_msg(pa_sink_input *i, int code, void *userdata, co
 
             /* New data from the main loop */
             pa_memblockq_push_align(c->input_memblockq, chunk);
+            pa_atomic_store(&c->playback.missing, pa_memblockq_missing(c->input_memblockq));
+            
             return 0;
         }
 
@@ -276,13 +321,14 @@ static int sink_input_process_msg(pa_sink_input *i, int code, void *userdata, co
         }
 
         default:
-            return pa_sink_input_process_msg(i, code, userdata);
+            return pa_sink_input_process_msg(o, code, userdata, chunk);
     }
 }
 
 /* Called from thread context */
 static int sink_input_peek_cb(pa_sink_input *i, pa_memchunk *chunk) {
-    struct connection*c;
+    connection*c;
+    int r;
 
     pa_assert(i);
     c = i->userdata;
@@ -292,14 +338,14 @@ static int sink_input_peek_cb(pa_sink_input *i, pa_memchunk *chunk) {
     r = pa_memblockq_peek(c->input_memblockq, chunk);
 
     if (c->dead && r < 0)
-        connection_free(c);
+        pa_asyncmsgq_post(c->protocol->core->asyncmsgq, PA_MSGOBJECT(c), MESSAGE_DROP_CONNECTION, c, NULL, NULL);
 
     return r;
 }
 
 /* Called from thread context */
 static void sink_input_drop_cb(pa_sink_input *i, const pa_memchunk *chunk, size_t length) {
-    struct connection*c = i->userdata;
+    connection*c = i->userdata;
     size_t old, new;
 
     pa_assert(i);
@@ -310,10 +356,10 @@ static void sink_input_drop_cb(pa_sink_input *i, const pa_memchunk *chunk, size_
     pa_memblockq_drop(c->input_memblockq, chunk, length);
     new = pa_memblockq_missing(c->input_memblockq);
 
-    pa_atomic_store(&c->playback.missing, &new);
+    pa_atomic_store(&c->playback.missing, new);
 
     if (new > old)
-        pa_asyncmsgq_post(c->protocol->asyncmsgq, c, MESSAGE_REQUEST_DATA, NULL, NULL, NULL, NULL);
+        pa_asyncmsgq_post(c->protocol->core->asyncmsgq, PA_MSGOBJECT(c), MESSAGE_REQUEST_DATA, NULL, NULL, NULL);
 }
 
 /* Called from main context */
@@ -321,34 +367,34 @@ static void sink_input_kill_cb(pa_sink_input *i) {
     pa_assert(i);
     pa_assert(i->userdata);
 
-    connection_free((struct connection *) i->userdata);
+    connection_drop((connection *) i->userdata);
 }
 
 /*** source_output callbacks ***/
 
 static void source_output_push_cb(pa_source_output *o, const pa_memchunk *chunk) {
-    struct connection *c;
+    connection *c;
 
     pa_assert(o);
     c = o->userdata;
     pa_assert(c);
     pa_assert(chunk);
 
-    pa_asyncmsgq_post(c->protocol->asyncmsgq, c, MESSAGE_REQUEST_DATA, NULL, chunk, NULL, NULL);
+    pa_asyncmsgq_post(c->protocol->core->asyncmsgq, PA_MSGOBJECT(c), MESSAGE_POST_DATA, NULL, chunk, NULL);
 }
 
 static void source_output_kill_cb(pa_source_output *o) {
-    struct connection*c;
+    connection*c;
 
     pa_assert(o);
     c = o->userdata;
     pa_assert(c);
 
-    connection_free(c);
+    connection_drop(c);
 }
 
 static pa_usec_t source_output_get_latency_cb(pa_source_output *o) {
-    struct connection*c;
+    connection*c;
 
     pa_assert(o);
     c = o->userdata;
@@ -360,19 +406,19 @@ static pa_usec_t source_output_get_latency_cb(pa_source_output *o) {
 /*** client callbacks ***/
 
 static void client_kill_cb(pa_client *client) {
-    struct connection*c;
+    connection*c;
 
     pa_assert(client);
     c = client->userdata;
     pa_assert(c);
 
-    connection_free(client);
+    connection_drop(c);
 }
 
 /*** pa_iochannel callbacks ***/
 
 static void io_callback(pa_iochannel*io, void *userdata) {
-    struct connection *c = userdata;
+    connection *c = userdata;
 
     pa_assert(io);
     pa_assert(c);
@@ -384,7 +430,7 @@ static void io_callback(pa_iochannel*io, void *userdata) {
 
 static void on_connection(pa_socket_server*s, pa_iochannel *io, void *userdata) {
     pa_protocol_simple *p = userdata;
-    struct connection *c = NULL;
+    connection *c = NULL;
     char cname[256];
 
     pa_assert(s);
@@ -397,7 +443,9 @@ static void on_connection(pa_socket_server*s, pa_iochannel *io, void *userdata)
         return;
     }
 
-    c = pa_xnew(struct connection, 1);
+    c = pa_msgobject_new(connection, connection_check_type);
+    c->parent.parent.free = connection_free;
+    c->parent.process_msg = connection_process_msg;
     c->io = io;
     c->sink_input = NULL;
     c->source_output = NULL;
@@ -415,7 +463,6 @@ static void on_connection(pa_socket_server*s, pa_iochannel *io, void *userdata)
     c->client->kill = client_kill_cb;
     c->client->userdata = c;
 
-
     if (p->mode & PLAYBACK) {
         pa_sink_input_new_data data;
         size_t l;
@@ -432,10 +479,10 @@ static void on_connection(pa_socket_server*s, pa_iochannel *io, void *userdata)
             goto fail;
         }
 
+        c->sink_input->parent.process_msg = sink_input_process_msg;
         c->sink_input->peek = sink_input_peek_cb;
         c->sink_input->drop = sink_input_drop_cb;
         c->sink_input->kill = sink_input_kill_cb;
-        c->sink_input->get_latency = sink_input_get_latency_cb;
         c->sink_input->userdata = c;
 
         l = (size_t) (pa_bytes_per_second(&p->sample_spec)*PLAYBACK_BUFFER_SECONDS);
@@ -449,7 +496,7 @@ static void on_connection(pa_socket_server*s, pa_iochannel *io, void *userdata)
                 NULL);
         pa_assert(c->input_memblockq);
         pa_iochannel_socket_set_rcvbuf(io, l/PLAYBACK_BUFFER_FRAGMENTS*5);
-        c->playback.fragment_size = l/10;
+        c->playback.fragment_size = l/PLAYBACK_BUFFER_FRAGMENTS;
 
         pa_atomic_store(&c->playback.missing, pa_memblockq_missing(c->input_memblockq));
 
@@ -498,47 +545,7 @@ static void on_connection(pa_socket_server*s, pa_iochannel *io, void *userdata)
 
 fail:
     if (c)
-        connection_free(c);
-}
-
-static void asyncmsgq_cb(pa_mainloop_api*api, pa_io_event* e, int fd, pa_io_event_flags_t events, void *userdata) {
-    pa_protocol_simple *p = userdata;
-    int do_some_work = 0;
-
-    pa_assert(pa_asyncmsgq_get_fd(p->asyncmsgq) == fd);
-    pa_assert(events == PA_IO_EVENT_INPUT);
-
-    pa_asyncmsgq_after_poll(p->asyncmsgq);
-
-    for (;;) {
-        int code;
-        void *object, *data;
-
-        /* Check whether there is a message for us to process */
-        while (pa_asyncmsgq_get(p->asyncmsgq, &object, &code, &data) == 0) {
-
-            connection *c = object;
-
-            pa_assert(c);
-
-            switch (code) {
-
-                case MESSAGE_REQUEST_DATA:
-                    do_work(c);
-                    break;
-
-                case MESSAGE_POST_DATA:
-                    pa_memblockq_push(c->output_memblockq, chunk);
-                    do_work(c);
-                    break;
-            }
-
-            pa_asyncmsgq_done(p->asyncmsgq);
-        }
-
-        if (pa_asyncmsgq_before_poll(p->asyncmsgq) == 0)
-            break;
-    }
+        connection_drop(c);
 }
 
 pa_protocol_simple* pa_protocol_simple_new(pa_core *core, pa_socket_server *server, pa_module *m, pa_modargs *ma) {
@@ -554,7 +561,6 @@ pa_protocol_simple* pa_protocol_simple_new(pa_core *core, pa_socket_server *serv
     p->core = core;
     p->server = server;
     p->connections = pa_idxset_new(NULL, NULL);
-    pa_assert_se(p->asyncmsgq = pa_asyncmsgq_new(0));
 
     p->sample_spec = core->default_sample_spec;
     if (pa_modargs_get_sample_spec(ma, &p->sample_spec) < 0) {
@@ -586,9 +592,6 @@ pa_protocol_simple* pa_protocol_simple_new(pa_core *core, pa_socket_server *serv
 
     pa_socket_server_set_callback(p->server, on_connection, p);
 
-    pa_assert_se(pa_asyncmsgq_before_poll(p->asyncmsgq) == 0);
-    pa_assert_se(p->asyncmsgq_event = core->mainloop->io_event_new(core->mainloop, pa_asyncmsgq_get_fd(p->asyncmsgq), PA_IO_EVENT_INPUT, p));
-
     return p;
 
 fail:
@@ -600,12 +603,12 @@ fail:
 
 
 void pa_protocol_simple_free(pa_protocol_simple *p) {
-    struct connection *c;
+    connection *c;
     pa_assert(p);
 
     if (p->connections) {
         while((c = pa_idxset_first(p->connections, NULL)))
-            connection_free(c);
+            connection_drop(c);
 
         pa_idxset_free(p->connections, NULL, NULL);
     }
@@ -613,12 +616,6 @@ void pa_protocol_simple_free(pa_protocol_simple *p) {
     if (p->server)
         pa_socket_server_unref(p->server);
 
-    if (p->asyncmsgq) {
-        c->mainloop->io_event_free(c->asyncmsgq_event);
-        pa_asyncmsgq_after_poll(c->asyncmsgq);
-        pa_asyncmsgq_free(p->asyncmsgq);
-    }
-
     pa_xfree(p);
 }
 
diff --git a/src/pulsecore/resampler.c b/src/pulsecore/resampler.c
index 248d733..a43c7c7 100644
--- a/src/pulsecore/resampler.c
+++ b/src/pulsecore/resampler.c
@@ -48,6 +48,7 @@ struct pa_resampler {
 
     void (*impl_free)(pa_resampler *r);
     void (*impl_update_input_rate)(pa_resampler *r, uint32_t rate);
+    void (*impl_update_output_rate)(pa_resampler *r, uint32_t rate);
     void (*impl_run)(pa_resampler *r, const pa_memchunk *in, pa_memchunk *out);
     void *impl_data;
 };
@@ -165,6 +166,19 @@ void pa_resampler_set_input_rate(pa_resampler *r, uint32_t rate) {
         r->impl_update_input_rate(r, rate);
 }
 
+void pa_resampler_set_output_rate(pa_resampler *r, uint32_t rate) {
+    assert(r);
+    assert(rate > 0);
+
+    if (r->o_ss.rate == rate)
+        return;
+
+    r->o_ss.rate = rate;
+
+    if (r->impl_update_output_rate)
+        r->impl_update_output_rate(r, rate);
+}
+
 void pa_resampler_run(pa_resampler *r, const pa_memchunk *in, pa_memchunk *out) {
     assert(r && in && out && r->impl_run);
 
@@ -512,6 +526,25 @@ static void libsamplerate_update_input_rate(pa_resampler *r, uint32_t rate) {
     }
 }
 
+
+static void libsamplerate_update_output_rate(pa_resampler *r, uint32_t rate) {
+    struct impl_libsamplerate *u;
+
+    assert(r);
+    assert(rate > 0);
+    assert(r->impl_data);
+    u = r->impl_data;
+
+    if (!u->src_state) {
+        int err;
+        u->src_state = src_new(r->resample_method, r->o_ss.channels, &err);
+        assert(u->src_state);
+    } else {
+        int ret = src_set_ratio(u->src_state, (double) rate / r->i_ss.rate);
+        assert(ret == 0);
+    }
+}
+
 static int libsamplerate_init(pa_resampler *r) {
     struct impl_libsamplerate *u = NULL;
     int err;
@@ -541,6 +574,7 @@ static int libsamplerate_init(pa_resampler *r) {
 
     r->impl_free = libsamplerate_free;
     r->impl_update_input_rate = libsamplerate_update_input_rate;
+    r->impl_update_output_rate = libsamplerate_update_output_rate;
     r->impl_run = libsamplerate_run;
 
     calc_map_table(r);
@@ -631,7 +665,7 @@ static void trivial_free(pa_resampler *r) {
     pa_xfree(r->impl_data);
 }
 
-static void trivial_update_input_rate(pa_resampler *r, uint32_t rate) {
+static void trivial_update_rate(pa_resampler *r, uint32_t rate) {
     struct impl_trivial *u;
 
     assert(r);
@@ -655,7 +689,8 @@ static int trivial_init(pa_resampler*r) {
 
     r->impl_run = trivial_run;
     r->impl_free = trivial_free;
-    r->impl_update_input_rate = trivial_update_input_rate;
+    r->impl_update_input_rate = trivial_update_rate;
+    r->impl_update_output_rate = trivial_update_rate;
 
     return 0;
 }
diff --git a/src/pulsecore/resampler.h b/src/pulsecore/resampler.h
index c283593..ada293e 100644
--- a/src/pulsecore/resampler.h
+++ b/src/pulsecore/resampler.h
@@ -63,6 +63,9 @@ void pa_resampler_run(pa_resampler *r, const pa_memchunk *in, pa_memchunk *out);
 /* Change the input rate of the resampler object */
 void pa_resampler_set_input_rate(pa_resampler *r, uint32_t rate);
 
+/* Change the output rate of the resampler object */
+void pa_resampler_set_output_rate(pa_resampler *r, uint32_t rate);
+
 /* Return the resampling method of the resampler object */
 pa_resample_method_t pa_resampler_get_method(pa_resampler *r);
 
diff --git a/src/pulsecore/sink-input.c b/src/pulsecore/sink-input.c
index 00b82d2..2c6b356 100644
--- a/src/pulsecore/sink-input.c
+++ b/src/pulsecore/sink-input.c
@@ -45,7 +45,9 @@
 #define MOVE_BUFFER_LENGTH (1024*1024)
 #define SILENCE_BUFFER_LENGTH (64*1024)
 
-static void sink_input_free(pa_msgobject *o);
+static PA_DEFINE_CHECK_TYPE(pa_sink_input, sink_input_check_type, pa_msgobject_check_type);
+
+static void sink_input_free(pa_object *o);
 
 pa_sink_input_new_data* pa_sink_input_new_data_init(pa_sink_input_new_data *data) {
     pa_assert(data);
@@ -159,13 +161,12 @@ pa_sink_input* pa_sink_input_new(
         data->resample_method = pa_resampler_get_method(resampler);
     }
 
-    i = pa_msgobject_new(pa_sink_input);
-
+    i = pa_msgobject_new(pa_sink_input, sink_input_check_type);
     i->parent.parent.free = sink_input_free;
     i->parent.process_msg = pa_sink_input_process_msg;
 
     i->core = core;
-    pa_atomic_load(&i->state, PA_SINK_INPUT_DRAINED);
+    pa_atomic_store(&i->state, PA_SINK_INPUT_DRAINED);
     i->flags = flags;
     i->name = pa_xstrdup(data->name);
     i->driver = pa_xstrdup(data->driver);
@@ -189,11 +190,11 @@ pa_sink_input* pa_sink_input_new(
     i->userdata = NULL;
 
     i->thread_info.silence_memblock = NULL;
-    i->thread_info.move_silence = 0;
+/*     i->thread_info.move_silence = 0; */
     pa_memchunk_reset(&i->thread_info.resampled_chunk);
     i->thread_info.resampler = resampler;
-    i->thread_info.soft_volume = i->volume;
-    i->thread_info.soft_muted = i->muted;
+    i->thread_info.volume = i->volume;
+    i->thread_info.muted = i->muted;
 
     pa_assert_se(pa_idxset_put(core->sink_inputs, i, &i->index) == 0);
     pa_assert_se(pa_idxset_put(i->sink->inputs, i, NULL) == 0);
@@ -213,14 +214,16 @@ void pa_sink_input_disconnect(pa_sink_input *i) {
     pa_assert(i);
     pa_return_if_fail(pa_sink_input_get_state(i) != PA_SINK_INPUT_DISCONNECTED);
 
-    pa_asyncmsgq_send(i->sink->asyncmsgq, i->sink, PA_SINK_MESSAGE_REMOVE_INPUT, i, NULL);
+    pa_asyncmsgq_send(i->sink->asyncmsgq, PA_MSGOBJECT(i->sink), PA_SINK_MESSAGE_REMOVE_INPUT, i, NULL);
 
     pa_idxset_remove_by_data(i->sink->core->sink_inputs, i, NULL);
     pa_idxset_remove_by_data(i->sink->inputs, i, NULL);
 
     pa_subscription_post(i->sink->core, PA_SUBSCRIPTION_EVENT_SINK_INPUT|PA_SUBSCRIPTION_EVENT_REMOVE, i->index);
-    i->sink = NULL;
 
+    pa_sink_update_status(i->sink);
+
+    i->sink = NULL;
     i->process_msg = NULL;
     i->peek = NULL;
     i->drop = NULL;
@@ -228,10 +231,10 @@ void pa_sink_input_disconnect(pa_sink_input *i) {
     i->get_latency = NULL;
     i->underrun = NULL;
 
-    pa_atomic_load(&i->state, PA_SINK_INPUT_DISCONNECTED);
+    pa_atomic_store(&i->state, PA_SINK_INPUT_DISCONNECTED);
 }
 
-static void sink_input_free(pa_msgobject *o) {
+static void sink_input_free(pa_object *o) {
     pa_sink_input* i = PA_SINK_INPUT(o);
 
     pa_assert(i);
@@ -241,8 +244,8 @@ static void sink_input_free(pa_msgobject *o) {
 
     pa_log_info("Freeing output %u \"%s\"", i->index, i->name);
 
-    if (i->resampled_chunk.memblock)
-        pa_memblock_unref(i->resampled_chunk.memblock);
+    if (i->thread_info.resampled_chunk.memblock)
+        pa_memblock_unref(i->thread_info.resampled_chunk.memblock);
 
     if (i->thread_info.resampler)
         pa_resampler_free(i->thread_info.resampler);
@@ -261,10 +264,10 @@ void pa_sink_input_put(pa_sink_input *i) {
     i->thread_info.volume = i->volume;
     i->thread_info.muted = i->muted;
 
-    pa_asyncmsgq_post(i->sink->asyncmsgq, i->sink, PA_SINK_MESSAGE_ADD_INPUT, i, NULL, pa_sink_unref, pa_sink_input_unref);
+    pa_asyncmsgq_post(i->sink->asyncmsgq, PA_MSGOBJECT(i->sink), PA_SINK_MESSAGE_ADD_INPUT, pa_sink_input_ref(i), NULL, (pa_free_cb_t) pa_sink_input_unref);
     pa_sink_update_status(i->sink);
 
-    pa_subscription_post(core, PA_SUBSCRIPTION_EVENT_SINK_INPUT|PA_SUBSCRIPTION_EVENT_NEW, i->index);
+    pa_subscription_post(i->sink->core, PA_SUBSCRIPTION_EVENT_SINK_INPUT|PA_SUBSCRIPTION_EVENT_NEW, i->index);
 }
 
 void pa_sink_input_kill(pa_sink_input*i) {
@@ -279,7 +282,7 @@ pa_usec_t pa_sink_input_get_latency(pa_sink_input *i) {
 
     pa_sink_input_assert_ref(i);
 
-    if (pa_asyncmsgq_send(i->sink->asyncmsgq, i->sink, PA_SINK_INPUT_MESSAGE_GET_LATENCY, &r, NULL) < 0)
+    if (pa_asyncmsgq_send(i->sink->asyncmsgq, PA_MSGOBJECT(i), PA_SINK_INPUT_MESSAGE_GET_LATENCY, &r, NULL) < 0)
         r = 0;
 
     if (i->get_latency)
@@ -327,14 +330,14 @@ int pa_sink_input_peek(pa_sink_input *i, pa_memchunk *chunk, pa_cvolume *volume)
 /*         goto finish; */
 /*     } */
 
-    if (!i->resampler) {
+    if (!i->thread_info.resampler) {
         do_volume_adj_here = 0;
         ret = i->peek(i, chunk);
         goto finish;
     }
 
     do_volume_adj_here = !pa_channel_map_equal(&i->channel_map, &i->sink->channel_map);
-    volume_is_norm = pa_cvolume_is_norm(&i->thread_info.soft_volume) && !i->thread_info.soft_muted;
+    volume_is_norm = pa_cvolume_is_norm(&i->thread_info.volume) && !i->thread_info.muted;
 
     while (!i->thread_info.resampled_chunk.memblock) {
         pa_memchunk tchunk;
@@ -345,7 +348,7 @@ int pa_sink_input_peek(pa_sink_input *i, pa_memchunk *chunk, pa_cvolume *volume)
 
         pa_assert(tchunk.length);
 
-        l = pa_resampler_request(i->resampler, CONVERT_BUFFER_LENGTH);
+        l = pa_resampler_request(i->thread_info.resampler, CONVERT_BUFFER_LENGTH);
 
         if (l > tchunk.length)
             l = tchunk.length;
@@ -356,10 +359,10 @@ int pa_sink_input_peek(pa_sink_input *i, pa_memchunk *chunk, pa_cvolume *volume)
         /* It might be necessary to adjust the volume here */
         if (do_volume_adj_here && !volume_is_norm) {
             pa_memchunk_make_writable(&tchunk, 0);
-            pa_volume_memchunk(&tchunk, &i->sample_spec, &i->thread_info.soft_volume);
+            pa_volume_memchunk(&tchunk, &i->sample_spec, &i->thread_info.volume);
         }
 
-        pa_resampler_run(i->resampler, &tchunk, &i->thread_info.resampled_chunk);
+        pa_resampler_run(i->thread_info.resampler, &tchunk, &i->thread_info.resampled_chunk);
         pa_memblock_unref(tchunk.memblock);
     }
 
@@ -378,7 +381,7 @@ finish:
 
     if (ret >= 0)
         pa_atomic_cmpxchg(&i->state, state, PA_SINK_INPUT_RUNNING);
-    else if (ret < 0 && i->state == PA_SINK_INPUT_RUNNING)
+    else if (ret < 0 && state == PA_SINK_INPUT_RUNNING)
         pa_atomic_cmpxchg(&i->state, state, PA_SINK_INPUT_DRAINED);
 
     if (ret >= 0) {
@@ -427,7 +430,7 @@ void pa_sink_input_drop(pa_sink_input *i, const pa_memchunk *chunk, size_t lengt
 /*         return; */
 /*     } */
 
-    if (!i->resampler) {
+    if (!i->thread_info.resampler) {
         if (i->drop)
             i->drop(i, chunk, length);
         return;
@@ -454,7 +457,7 @@ void pa_sink_input_set_volume(pa_sink_input *i, const pa_cvolume *volume) {
 
     i->volume = *volume;
 
-    pa_asyncmsgq_post(s->asyncmsgq, pa_sink_input_ref(i), PA_SINK_INPUT_MESSAGE_SET_VOLUME, pa_xnewdup(struct pa_cvolume, volume, 1), pa_sink_input_unref, pa_xfree);
+    pa_asyncmsgq_post(i->sink->asyncmsgq, PA_MSGOBJECT(i), PA_SINK_INPUT_MESSAGE_SET_VOLUME, pa_xnewdup(struct pa_cvolume, volume, 1), NULL, pa_xfree);
     pa_subscription_post(i->sink->core, PA_SUBSCRIPTION_EVENT_SINK_INPUT|PA_SUBSCRIPTION_EVENT_CHANGE, i->index);
 }
 
@@ -473,18 +476,17 @@ void pa_sink_input_set_mute(pa_sink_input *i, int mute) {
 
     i->muted = mute;
 
-    pa_asyncmsgq_post(s->asyncmsgq, pa_sink_input_ref(i), PA_SINK_INPUT_MESSAGE_SET_MUTE, PA_UINT_TO_PTR(mute), pa_sink_input_unref, NULL);
+    pa_asyncmsgq_post(i->sink->asyncmsgq, PA_MSGOBJECT(i), PA_SINK_INPUT_MESSAGE_SET_MUTE, PA_UINT_TO_PTR(mute), NULL, NULL);
     pa_subscription_post(i->sink->core, PA_SUBSCRIPTION_EVENT_SINK_INPUT|PA_SUBSCRIPTION_EVENT_CHANGE, i->index);
 }
 
 int pa_sink_input_get_mute(pa_sink_input *i) {
     pa_sink_input_assert_ref(i);
 
-    return !!i->mute;
+    return !!i->muted;
 }
 
 void pa_sink_input_cork(pa_sink_input *i, int b) {
-    int n;
     pa_sink_input_state_t state;
 
     pa_sink_input_assert_ref(i);
@@ -493,24 +495,24 @@ void pa_sink_input_cork(pa_sink_input *i, int b) {
     pa_assert(state != PA_SINK_INPUT_DISCONNECTED);
 
     if (b && state != PA_SINK_INPUT_CORKED)
-        pa_atomic_store(i->state, PA_SINK_INPUT_CORKED);
+        pa_atomic_store(&i->state, PA_SINK_INPUT_CORKED);
     else if (!b && state == PA_SINK_INPUT_CORKED)
-        pa_atomic_cmpxchg(i->state, state, PA_SINK_INPUT_DRAINED);
+        pa_atomic_cmpxchg(&i->state, state, PA_SINK_INPUT_DRAINED);
 }
 
 int pa_sink_input_set_rate(pa_sink_input *i, uint32_t rate) {
     pa_sink_input_assert_ref(i);
-    pa_return_val_if_fail(u->thread_info.resampler, -1);
+    pa_return_val_if_fail(i->thread_info.resampler, -1);
 
     if (i->sample_spec.rate == rate)
         return 0;
 
     i->sample_spec.rate = rate;
 
-    pa_asyncmsgq_post(s->asyncmsgq, pa_sink_input_ref(i), PA_SINK_INPUT_MESSAGE_SET_RATE, PA_UINT_TO_PTR(rate), NULL, pa_sink_input_unref, NULL);
+    pa_asyncmsgq_post(i->sink->asyncmsgq, PA_MSGOBJECT(i), PA_SINK_INPUT_MESSAGE_SET_RATE, PA_UINT_TO_PTR(rate), NULL, NULL);
 
     pa_subscription_post(i->sink->core, PA_SUBSCRIPTION_EVENT_SINK_INPUT|PA_SUBSCRIPTION_EVENT_CHANGE, i->index);
-    return 0
+    return 0;
 }
 
 void pa_sink_input_set_name(pa_sink_input *i, const char *name) {
@@ -535,9 +537,9 @@ pa_resample_method_t pa_sink_input_get_resample_method(pa_sink_input *i) {
 }
 
 int pa_sink_input_move_to(pa_sink_input *i, pa_sink *dest, int immediately) {
-    pa_resampler *new_resampler = NULL;
-    pa_memblockq *buffer = NULL;
-    pa_sink *origin;
+/*     pa_resampler *new_resampler = NULL; */
+/*     pa_memblockq *buffer = NULL; */
+/*     pa_sink *origin; */
 
     pa_sink_input_assert_ref(i);
     pa_sink_assert_ref(dest);
@@ -702,18 +704,18 @@ int pa_sink_input_process_msg(pa_msgobject *o, int code, void *userdata, pa_memc
 
     switch (code) {
         case PA_SINK_INPUT_MESSAGE_SET_VOLUME:
-            s->thread_info.soft_volume = *((pa_cvolume*) userdata);
+            i->thread_info.volume = *((pa_cvolume*) userdata);
             return 0;
 
         case PA_SINK_INPUT_MESSAGE_SET_MUTE:
-            s->thread_info.soft_muted = PA_PTR_TO_UINT(userdata);
+            i->thread_info.muted = PA_PTR_TO_UINT(userdata);
             return 0;
 
         case PA_SINK_INPUT_MESSAGE_GET_LATENCY: {
             pa_usec_t *r = userdata;
 
             if (i->thread_info.resampled_chunk.memblock)
-                *r += pa_bytes_to_usec(i->resampled_chunk.length, &i->sink->sample_spec);
+                *r += pa_bytes_to_usec(i->thread_info.resampled_chunk.length, &i->sink->sample_spec);
 
 /*             if (i->move_silence) */
 /*                 r += pa_bytes_to_usec(i->move_silence, &i->sink->sample_spec); */
@@ -724,7 +726,7 @@ int pa_sink_input_process_msg(pa_msgobject *o, int code, void *userdata, pa_memc
         case PA_SINK_INPUT_MESSAGE_SET_RATE: {
 
             i->thread_info.sample_spec.rate = PA_PTR_TO_UINT(userdata);
-            pa_resampler_set_input_rate(i->resampler, PA_PTR_TO_UINT(userdata));
+            pa_resampler_set_input_rate(i->thread_info.resampler, PA_PTR_TO_UINT(userdata));
 
             return 0;
         }
diff --git a/src/pulsecore/sink-input.h b/src/pulsecore/sink-input.h
index 338d696..a8c05b8 100644
--- a/src/pulsecore/sink-input.h
+++ b/src/pulsecore/sink-input.h
@@ -99,7 +99,7 @@ struct pa_sink_input {
 };
 
 PA_DECLARE_CLASS(pa_sink_input);
-#define PA_SINK_INPUT(o) ((pa_sink_input*) (o))
+#define PA_SINK_INPUT(o) pa_sink_input_cast(o)
 
 enum {
     PA_SINK_INPUT_MESSAGE_SET_VOLUME,
@@ -160,7 +160,7 @@ int pa_sink_input_get_mute(pa_sink_input *i);
 
 void pa_sink_input_cork(pa_sink_input *i, int b);
 
-void pa_sink_input_set_rate(pa_sink_input *i, uint32_t rate);
+int pa_sink_input_set_rate(pa_sink_input *i, uint32_t rate);
 
 pa_resample_method_t pa_sink_input_get_resample_method(pa_sink_input *i);
 
diff --git a/src/pulsecore/sink.c b/src/pulsecore/sink.c
index 0e022d9..7f00904 100644
--- a/src/pulsecore/sink.c
+++ b/src/pulsecore/sink.c
@@ -47,6 +47,8 @@
 
 #define MAX_MIX_CHANNELS 32
 
+static PA_DEFINE_CHECK_TYPE(pa_sink, sink_check_type, pa_msgobject_check_type);
+
 static void sink_free(pa_object *s);
 
 pa_sink* pa_sink_new(
@@ -77,7 +79,7 @@ pa_sink* pa_sink_new(
     pa_return_null_if_fail(!driver || pa_utf8_valid(driver));
     pa_return_null_if_fail(name && pa_utf8_valid(name) && *name);
 
-    s = pa_msgobject_new(pa_sink);
+    s = pa_msgobject_new(pa_sink, sink_check_type);
 
     if (!(name = pa_namereg_register(core, name, PA_NAMEREG_SINK, s, fail))) {
         pa_xfree(s);
@@ -88,7 +90,7 @@ pa_sink* pa_sink_new(
     s->parent.process_msg = pa_sink_process_msg;
 
     s->core = core;
-    pa_atomic_store(&s->state, PA_SINK_IDLE);
+    s->state = PA_SINK_IDLE;
     s->name = pa_xstrdup(name);
     s->description = NULL;
     s->driver = pa_xstrdup(driver);
@@ -110,11 +112,10 @@ pa_sink* pa_sink_new(
     s->get_volume = NULL;
     s->set_mute = NULL;
     s->get_mute = NULL;
-    s->start = NULL;
-    s->stop = NULL;
+    s->set_state = NULL;
     s->userdata = NULL;
 
-    pa_assert_se(s->asyncmsgq = pa_asyncmsgq_new(0));
+    s->asyncmsgq = NULL;
 
     r = pa_idxset_put(core->sinks, s, &s->index);
     pa_assert(s->index != PA_IDXSET_INVALID && r >= 0);
@@ -139,56 +140,40 @@ pa_sink* pa_sink_new(
     s->thread_info.inputs = pa_hashmap_new(pa_idxset_trivial_hash_func, pa_idxset_trivial_compare_func);
     s->thread_info.soft_volume = s->volume;
     s->thread_info.soft_muted = s->muted;
+    s->thread_info.state = s->state;
 
     pa_subscription_post(core, PA_SUBSCRIPTION_EVENT_SINK | PA_SUBSCRIPTION_EVENT_NEW, s->index);
 
     return s;
 }
 
-static void sink_start(pa_sink *s) {
-    pa_sink_state_t state;
+static int sink_set_state(pa_sink *s, pa_sink_state_t state) {
+    int ret;
+    
     pa_assert(s);
 
-    state = pa_sink_get_state(s);
-    pa_return_if_fail(state == PA_SINK_IDLE || state == PA_SINK_SUSPENDED);
-
-    pa_atomic_store(&s->state, PA_SINK_RUNNING);
-
-    if (s->start)
-        s->start(s);
-    else
-        pa_asyncmsgq_post(s->asyncmsgq, PA_MSGOBJECT(s), PA_SINK_MESSAGE_START, NULL, NULL, NULL);
-}
-
-static void sink_stop(pa_sink *s) {
-    pa_sink_state_t state;
-    int stop;
+    if (s->state == state)
+        return 0;
 
-    pa_assert(s);
-    state = pa_sink_get_state(s);
-    pa_return_if_fail(state == PA_SINK_RUNNING || state == PA_SINK_SUSPENDED);
+    if (s->set_state)
+        if ((ret = s->set_state(s, state)) < 0)
+            return -1;
 
-    stop = state == PA_SINK_RUNNING;
-    pa_atomic_store(&s->state, PA_SINK_IDLE);
+    if (pa_asyncmsgq_send(s->asyncmsgq, PA_MSGOBJECT(s), PA_SINK_MESSAGE_SET_STATE, PA_UINT_TO_PTR(state), NULL) < 0)
+        return -1;
 
-    if (stop) {
-        if (s->stop)
-            s->stop(s);
-        else
-            pa_asyncmsgq_post(s->asyncmsgq, PA_MSGOBJECT(s), PA_SINK_MESSAGE_STOP, NULL, NULL, NULL);
-    }
+    s->state = state;
+    return 0;
 }
 
 void pa_sink_disconnect(pa_sink* s) {
     pa_sink_input *i, *j = NULL;
 
     pa_assert(s);
-    pa_return_if_fail(pa_sink_get_state(s) != PA_SINK_DISCONNECTED);
-
-    sink_stop(s);
+    pa_return_if_fail(s->state != PA_SINK_DISCONNECTED);
 
-    pa_atomic_store(&s->state, PA_SINK_DISCONNECTED);
     pa_namereg_unregister(s->core, s->name);
+    pa_idxset_remove_by_data(s->core->sinks, s, NULL);
 
     pa_hook_fire(&s->core->hook_sink_disconnect, s);
 
@@ -201,26 +186,27 @@ void pa_sink_disconnect(pa_sink* s) {
     if (s->monitor_source)
         pa_source_disconnect(s->monitor_source);
 
-    pa_idxset_remove_by_data(s->core->sinks, s, NULL);
+    sink_set_state(s, PA_SINK_DISCONNECTED);
 
     s->get_latency = NULL;
     s->get_volume = NULL;
     s->set_volume = NULL;
     s->set_mute = NULL;
     s->get_mute = NULL;
-    s->start = NULL;
-    s->stop = NULL;
+    s->set_state = NULL;
 
     pa_subscription_post(s->core, PA_SUBSCRIPTION_EVENT_SINK | PA_SUBSCRIPTION_EVENT_REMOVE, s->index);
 }
 
 static void sink_free(pa_object *o) {
     pa_sink *s = PA_SINK(o);
+    pa_sink_input *i;
 
     pa_assert(s);
     pa_assert(pa_sink_refcnt(s) == 0);
 
-    pa_sink_disconnect(s);
+    if (s->state != PA_SINK_DISCONNECTED)
+        pa_sink_disconnect(s);
 
     pa_log_info("Freeing sink %u \"%s\"", s->index, s->name);
 
@@ -231,9 +217,10 @@ static void sink_free(pa_object *o) {
 
     pa_idxset_free(s->inputs, NULL, NULL);
 
-    pa_hashmap_free(s->thread_info.inputs, (pa_free2_cb_t) pa_sink_input_unref, NULL);
-
-    pa_asyncmsgq_free(s->asyncmsgq);
+    while ((i = pa_hashmap_steal_first(s->thread_info.inputs)))
+        pa_sink_input_unref(i);
+    
+    pa_hashmap_free(s->thread_info.inputs, NULL, NULL);
 
     pa_xfree(s->name);
     pa_xfree(s->description);
@@ -241,44 +228,38 @@ static void sink_free(pa_object *o) {
     pa_xfree(s);
 }
 
-void pa_sink_update_status(pa_sink*s) {
+void pa_sink_set_asyncmsgq(pa_sink *s, pa_asyncmsgq *q) {
     pa_sink_assert_ref(s);
+    pa_assert(q);
 
-    if (pa_sink_get_state(s) == PA_SINK_SUSPENDED)
-        return;
+    s->asyncmsgq = q;
 
-    if (pa_sink_used_by(s) > 0)
-        sink_start(s);
-    else
-        sink_stop(s);
+    if (s->monitor_source)
+        pa_source_set_asyncmsgq(s->monitor_source, q);
 }
 
-void pa_sink_suspend(pa_sink *s, int suspend) {
-    pa_sink_state_t state;
-
+int pa_sink_update_status(pa_sink*s) {
     pa_sink_assert_ref(s);
 
-    state = pa_sink_get_state(s);
-    pa_return_if_fail(suspend && (state == PA_SINK_RUNNING || state == PA_SINK_IDLE));
-    pa_return_if_fail(!suspend && (state == PA_SINK_SUSPENDED));
+    if (s->state == PA_SINK_SUSPENDED)
+        return 0;
 
+    return sink_set_state(s, pa_sink_used_by(s) ? PA_SINK_RUNNING : PA_SINK_IDLE);
+}
 
-    if (suspend) {
-        pa_atomic_store(&s->state, PA_SINK_SUSPENDED);
+int pa_sink_suspend(pa_sink *s, int suspend) {
+    pa_sink_assert_ref(s);
 
-        if (s->stop)
-            s->stop(s);
-        else
-            pa_asyncmsgq_post(s->asyncmsgq, PA_MSGOBJECT(s), PA_SINK_MESSAGE_STOP, NULL, NULL, NULL);
+    if (suspend)
+        return sink_set_state(s, PA_SINK_SUSPENDED);
+    else
+        return sink_set_state(s, pa_sink_used_by(s) ? PA_SINK_RUNNING : PA_SINK_IDLE);
+}
 
-    } else {
-        pa_atomic_store(&s->state, PA_SINK_RUNNING);
+void pa_sink_ping(pa_sink *s) {
+    pa_sink_assert_ref(s);
 
-        if (s->start)
-            s->start(s);
-        else
-            pa_asyncmsgq_post(s->asyncmsgq, PA_MSGOBJECT(s), PA_SINK_MESSAGE_START, NULL, NULL, NULL);
-    }
+    pa_asyncmsgq_post(s->asyncmsgq, PA_MSGOBJECT(s), PA_SINK_MESSAGE_PING, NULL, NULL, NULL);
 }
 
 static unsigned fill_mix_info(pa_sink *s, pa_mix_info *info, unsigned maxinfo) {
@@ -652,7 +633,7 @@ int pa_sink_process_msg(pa_msgobject *o, int code, void *userdata, pa_memchunk *
     pa_sink *s = PA_SINK(o);
     pa_sink_assert_ref(s);
 
-    switch (code) {
+    switch ((pa_sink_message_t) code) {
         case PA_SINK_MESSAGE_ADD_INPUT: {
             pa_sink_input *i = userdata;
             pa_hashmap_put(s->thread_info.inputs, PA_UINT32_TO_PTR(i->index), pa_sink_input_ref(i));
@@ -681,7 +662,17 @@ int pa_sink_process_msg(pa_msgobject *o, int code, void *userdata, pa_memchunk *
             *((int*) userdata) = s->thread_info.soft_muted;
             return 0;
 
-        default:
-            return -1;
+        case PA_SINK_MESSAGE_PING:
+            return 0;
+
+        case PA_SINK_MESSAGE_SET_STATE:
+            s->thread_info.state = PA_PTR_TO_UINT(userdata);
+            return 0;
+            
+        case PA_SINK_MESSAGE_GET_LATENCY:
+        case PA_SINK_MESSAGE_MAX:
+            ;
     }
+
+    return -1;
 }
diff --git a/src/pulsecore/sink.h b/src/pulsecore/sink.h
index 2939cc4..0b308e5 100644
--- a/src/pulsecore/sink.h
+++ b/src/pulsecore/sink.h
@@ -55,7 +55,7 @@ struct pa_sink {
 
     uint32_t index;
     pa_core *core;
-    pa_atomic_t state;
+    pa_sink_state_t state;
 
     char *name;
     char *description, *driver;            /* may be NULL */
@@ -74,8 +74,7 @@ struct pa_sink {
     int refresh_volume;
     int refresh_mute;
 
-    int (*start)(pa_sink *s);
-    int (*stop)(pa_sink *s);
+    int (*set_state)(pa_sink *s, pa_sink_state_t state);
     int (*set_volume)(pa_sink *s);      /* dito */
     int (*get_volume)(pa_sink *s);      /* dito */
     int (*get_mute)(pa_sink *s);        /* dito */
@@ -87,6 +86,7 @@ struct pa_sink {
     /* Contains copies of the above data so that the real-time worker
      * thread can work without access locking */
     struct {
+        pa_sink_state_t state;
         pa_hashmap *inputs;
         pa_cvolume soft_volume;
         int soft_muted;
@@ -96,7 +96,7 @@ struct pa_sink {
 };
 
 PA_DECLARE_CLASS(pa_sink);
-#define PA_SINK(s) ((pa_sink*) (s))
+#define PA_SINK(s) (pa_sink_cast(s))
 
 typedef enum pa_sink_message {
     PA_SINK_MESSAGE_ADD_INPUT,
@@ -106,8 +106,8 @@ typedef enum pa_sink_message {
     PA_SINK_MESSAGE_GET_MUTE,
     PA_SINK_MESSAGE_SET_MUTE,
     PA_SINK_MESSAGE_GET_LATENCY,
-    PA_SINK_MESSAGE_START,
-    PA_SINK_MESSAGE_STOP,
+    PA_SINK_MESSAGE_SET_STATE,
+    PA_SINK_MESSAGE_PING,
     PA_SINK_MESSAGE_MAX
 } pa_sink_message_t;
 
@@ -125,13 +125,19 @@ void pa_sink_disconnect(pa_sink* s);
 
 void pa_sink_set_module(pa_sink *sink, pa_module *m);
 void pa_sink_set_description(pa_sink *s, const char *description);
+void pa_sink_set_asyncmsgq(pa_sink *s, pa_asyncmsgq *q);
 
 /* Usable by everyone */
 
 pa_usec_t pa_sink_get_latency(pa_sink *s);
 
-void pa_sink_update_status(pa_sink*s);
-void pa_sink_suspend(pa_sink *s, int suspend);
+int pa_sink_update_status(pa_sink*s);
+int pa_sink_suspend(pa_sink *s, int suspend);
+
+/* Sends a ping message to the sink thread, to make it wake up and
+ * check for data to process even if there is no real message is
+ * sent */
+void pa_sink_ping(pa_sink *s); 
 
 void pa_sink_set_volume(pa_sink *sink, const pa_cvolume *volume);
 const pa_cvolume *pa_sink_get_volume(pa_sink *sink);
@@ -139,7 +145,7 @@ void pa_sink_set_mute(pa_sink *sink, int mute);
 int pa_sink_get_mute(pa_sink *sink);
 
 unsigned pa_sink_used_by(pa_sink *s);
-#define pa_sink_get_state(s) ((pa_sink_state_t) pa_atomic_load(&(s)->state))
+#define pa_sink_get_state(s) ((s)->state)
 
 /* To be used exclusively by the sink driver thread */
 
@@ -149,5 +155,5 @@ int pa_sink_render_into(pa_sink*s, pa_memchunk *target);
 void pa_sink_render_into_full(pa_sink *s, pa_memchunk *target);
 
 int pa_sink_process_msg(pa_msgobject *o, int code, void *userdata, pa_memchunk *chunk);
-
+    
 #endif
diff --git a/src/pulsecore/sound-file-stream.c b/src/pulsecore/sound-file-stream.c
index a682ee6..974c053 100644
--- a/src/pulsecore/sound-file-stream.c
+++ b/src/pulsecore/sound-file-stream.c
@@ -200,7 +200,7 @@ int pa_play_file(
     u->sink_input->kill = sink_input_kill;
     u->sink_input->userdata = u;
 
-    pa_sink_notify(u->sink_input->sink);
+/*     pa_sink_notify(u->sink_input->sink); */
 
     return 0;
 
diff --git a/src/pulsecore/source-output.c b/src/pulsecore/source-output.c
index 517c033..2211f25 100644
--- a/src/pulsecore/source-output.c
+++ b/src/pulsecore/source-output.c
@@ -38,6 +38,10 @@
 
 #include "source-output.h"
 
+static PA_DEFINE_CHECK_TYPE(pa_source_output, source_output_check_type, pa_msgobject_check_type);
+
+static void source_output_free(pa_object* mo);
+
 pa_source_output_new_data* pa_source_output_new_data_init(pa_source_output_new_data *data) {
     pa_assert(data);
 
@@ -126,13 +130,12 @@ pa_source_output* pa_source_output_new(
         data->resample_method = pa_resampler_get_method(resampler);
     }
 
-    o = pa_source_output_new(pa_source_output);
-
+    o = pa_msgobject_new(pa_source_output, source_output_check_type);
     o->parent.parent.free = source_output_free;
     o->parent.process_msg = pa_source_output_process_msg;
 
     o->core = core;
-    pa_atomic_load(&o->state, PA_SOURCE_OUTPUT_RUNNING);
+    pa_atomic_store(&o->state, PA_SOURCE_OUTPUT_RUNNING);
     o->flags = flags;
     o->name = pa_xstrdup(data->name);
     o->driver = pa_xstrdup(data->driver);
@@ -168,27 +171,29 @@ pa_source_output* pa_source_output_new(
 
 void pa_source_output_disconnect(pa_source_output*o) {
     pa_assert(o);
-    pa_return_if_fail(pa_source_output_get_state(i) != PA_SOURCE_OUTPUT_DISCONNECTED);
+    pa_return_if_fail(pa_source_output_get_state(o) != PA_SOURCE_OUTPUT_DISCONNECTED);
     pa_assert(o->source);
     pa_assert(o->source->core);
 
-    pa_asyncmsgq_send(i->sink->asyncmsgq, i->sink, PA_SOURCE_MESSAGE_REMOVE_OUTPUT, o, NULL);
+    pa_asyncmsgq_send(o->source->asyncmsgq, PA_MSGOBJECT(o->source), PA_SOURCE_MESSAGE_REMOVE_OUTPUT, o, NULL);
 
     pa_idxset_remove_by_data(o->source->core->source_outputs, o, NULL);
     pa_idxset_remove_by_data(o->source->outputs, o, NULL);
 
     pa_subscription_post(o->source->core, PA_SUBSCRIPTION_EVENT_SOURCE_OUTPUT|PA_SUBSCRIPTION_EVENT_REMOVE, o->index);
-    o->source = NULL;
 
+    pa_source_update_status(o->source);
+
+    o->source = NULL;
     o->process_msg = NULL;
     o->push = NULL;
     o->kill = NULL;
     o->get_latency = NULL;
 
-    pa_atomic_load(&i->state, PA_SOURCE_OUTPUT_DISCONNECTED);
+    pa_atomic_store(&o->state, PA_SOURCE_OUTPUT_DISCONNECTED);
 }
 
-static void source_output_free(pa_msgobject* mo) {
+static void source_output_free(pa_object* mo) {
     pa_source_output *o = PA_SOURCE_OUTPUT(mo);
 
     pa_assert(pa_source_output_refcnt(o) == 0);
@@ -208,10 +213,10 @@ static void source_output_free(pa_msgobject* mo) {
 void pa_source_output_put(pa_source_output *o) {
     pa_source_output_assert_ref(o);
 
-    pa_asyncmsgq_post(o->source->asyncmsgq, o->source, PA_SOURCE_MESSAGE_ADD_OUTPUT, o, NULL, pa_source_unref, pa_source_output_unref);
+    pa_asyncmsgq_post(o->source->asyncmsgq, PA_MSGOBJECT(o->source), PA_SOURCE_MESSAGE_ADD_OUTPUT, pa_source_output_ref(o), NULL, (pa_free_cb_t) pa_source_output_unref);
     pa_source_update_status(o->source);
 
-    pa_subscription_post(core, PA_SUBSCRIPTION_EVENT_SOURCE_OUTPUT|PA_SUBSCRIPTION_EVENT_NEW, o->index);
+    pa_subscription_post(o->source->core, PA_SUBSCRIPTION_EVENT_SOURCE_OUTPUT|PA_SUBSCRIPTION_EVENT_NEW, o->index);
 }
 
 void pa_source_output_kill(pa_source_output*o) {
@@ -226,7 +231,7 @@ pa_usec_t pa_source_output_get_latency(pa_source_output *o) {
 
     pa_source_output_assert_ref(o);
 
-    if (pa_asyncmsgq_send(o->source->asyncmsgq, i->source, PA_SOURCE_OUTPUT_MESSAGE_GET_LATENCY, &r, NULL) < 0)
+    if (pa_asyncmsgq_send(o->source->asyncmsgq, PA_MSGOBJECT(o), PA_SOURCE_OUTPUT_MESSAGE_GET_LATENCY, &r, NULL) < 0)
         r = 0;
 
     if (o->get_latency)
@@ -250,12 +255,12 @@ void pa_source_output_push(pa_source_output *o, const pa_memchunk *chunk) {
 
     pa_assert(state = PA_SOURCE_OUTPUT_RUNNING);
 
-    if (!o->resampler) {
+    if (!o->thread_info.resampler) {
         o->push(o, chunk);
         return;
     }
 
-    pa_resampler_run(o->resampler, chunk, &rchunk);
+    pa_resampler_run(o->thread_info.resampler, chunk, &rchunk);
     if (!rchunk.length)
         return;
 
@@ -265,7 +270,6 @@ void pa_source_output_push(pa_source_output *o, const pa_memchunk *chunk) {
 }
 
 void pa_source_output_cork(pa_source_output *o, int b) {
-    int n;
     pa_source_output_state_t state;
 
     pa_source_output_assert_ref(o);
@@ -274,23 +278,23 @@ void pa_source_output_cork(pa_source_output *o, int b) {
     pa_assert(state != PA_SOURCE_OUTPUT_DISCONNECTED);
 
     if (b && state != PA_SOURCE_OUTPUT_CORKED)
-        pa_atomic_store(o->state, PA_SOURCE_OUTPUT_CORKED);
+        pa_atomic_store(&o->state, PA_SOURCE_OUTPUT_CORKED);
     else if (!b && state == PA_SOURCE_OUTPUT_CORKED)
-        pa_atomic_cmpxchg(o->state, state, PA_SOURCE_OUTPUT_RUNNING);
+        pa_atomic_cmpxchg(&o->state, state, PA_SOURCE_OUTPUT_RUNNING);
 }
 
 int pa_source_output_set_rate(pa_source_output *o, uint32_t rate) {
     pa_source_output_assert_ref(o);
     pa_return_val_if_fail(o->thread_info.resampler, -1);
 
-    if (i->sample_spec.rate == rate)
+    if (o->sample_spec.rate == rate)
         return 0;
 
-    i->sample_spec.rate = rate;
+    o->sample_spec.rate = rate;
 
-    pa_asyncmsgq_post(s->asyncmsgq, pa_source_output_ref(i), PA_SOURCE_OUTPUT_MESSAGE_SET_RATE, PA_UINT_TO_PTR(rate), NULL, pa_source_output_unref, NULL);
+    pa_asyncmsgq_post(o->source->asyncmsgq, PA_MSGOBJECT(o), PA_SOURCE_OUTPUT_MESSAGE_SET_RATE, PA_UINT_TO_PTR(rate), NULL, NULL);
 
-    pa_subscription_post(o->source->core, PA_SUBSCRIPTION_EVENT_SOURCE_OUTPUT!|PA_SUBSCRIPTION_EVENT_CHANGE, i->index);
+    pa_subscription_post(o->source->core, PA_SUBSCRIPTION_EVENT_SOURCE_OUTPUT|PA_SUBSCRIPTION_EVENT_CHANGE, o->index);
     return 0;
 }
 
@@ -316,8 +320,8 @@ pa_resample_method_t pa_source_output_get_resample_method(pa_source_output *o) {
 }
 
 int pa_source_output_move_to(pa_source_output *o, pa_source *dest) {
-    pa_source *origin;
-    pa_resampler *new_resampler = NULL;
+/*     pa_source *origin; */
+/*     pa_resampler *new_resampler = NULL; */
 
     pa_source_output_assert_ref(o);
     pa_source_assert_ref(dest);
@@ -344,7 +348,7 @@ int pa_source_output_move_to(pa_source_output *o, pa_source *dest) {
 /*     else if (!pa_sample_spec_equal(&o->sample_spec, &dest->sample_spec) || */
 /*         !pa_channel_map_equal(&o->channel_map, &dest->channel_map)) { */
 
-/*         /\* Okey, we need a new resampler for the new sink *\/ */
+/*         /\* Okey, we need a new resampler for the new source *\/ */
 
 /*         if (!(new_resampler = pa_resampler_new( */
 /*                       dest->core->mempool, */
@@ -376,16 +380,16 @@ int pa_source_output_move_to(pa_source_output *o, pa_source *dest) {
 }
 
 int pa_source_output_process_msg(pa_msgobject *mo, int code, void *userdata, pa_memchunk* chunk) {
-    pa_source_output *o = PA_SOURCE_OUTPUT(o);
+    pa_source_output *o = PA_SOURCE_OUTPUT(mo);
 
-    pa_source_output_assert_ref(i);
+    pa_source_output_assert_ref(o);
 
     switch (code) {
 
         case PA_SOURCE_OUTPUT_MESSAGE_SET_RATE: {
 
-            i->thread_info.sample_spec.rate = PA_PTR_TO_UINT(userdata);
-            pa_resampler_set_output_rate(i->resampler, PA_PTR_TO_UINT(userdata));
+            o->thread_info.sample_spec.rate = PA_PTR_TO_UINT(userdata);
+            pa_resampler_set_output_rate(o->thread_info.resampler, PA_PTR_TO_UINT(userdata));
 
             return 0;
         }
diff --git a/src/pulsecore/source-output.h b/src/pulsecore/source-output.h
index e7c2c13..d3bc0bc 100644
--- a/src/pulsecore/source-output.h
+++ b/src/pulsecore/source-output.h
@@ -80,7 +80,7 @@ struct pa_source_output {
 };
 
 PA_DECLARE_CLASS(pa_source_output);
-#define PA_SOURCE_OUTPUT(o) ((pa_source_output*) (o))
+#define PA_SOURCE_OUTPUT(o) pa_source_output_cast(o)
 
 enum {
     PA_SOURCE_OUTPUT_MESSAGE_GET_LATENCY,
@@ -129,7 +129,7 @@ pa_usec_t pa_source_output_get_latency(pa_source_output *i);
 
 void pa_source_output_cork(pa_source_output *i, int b);
 
-void pa_source_output_set_rate(pa_source_output *o, uint32_t rate);
+int pa_source_output_set_rate(pa_source_output *o, uint32_t rate);
 
 pa_resample_method_t pa_source_output_get_resample_method(pa_source_output *o);
 
diff --git a/src/pulsecore/source.c b/src/pulsecore/source.c
index 7d01338..f0a898f 100644
--- a/src/pulsecore/source.c
+++ b/src/pulsecore/source.c
@@ -42,6 +42,10 @@
 
 #include "source.h"
 
+static PA_DEFINE_CHECK_TYPE(pa_source, source_check_type, pa_msgobject_check_type);
+
+static void source_free(pa_object *o);
+
 pa_source* pa_source_new(
         pa_core *core,
         const char *driver,
@@ -69,7 +73,7 @@ pa_source* pa_source_new(
     pa_return_null_if_fail(!driver || pa_utf8_valid(driver));
     pa_return_null_if_fail(pa_utf8_valid(name) && *name);
 
-    s = pa_msgobject_new(pa_source);
+    s = pa_msgobject_new(pa_source, source_check_type);
 
     if (!(name = pa_namereg_register(core, name, PA_NAMEREG_SOURCE, s, fail))) {
         pa_xfree(s);
@@ -80,7 +84,7 @@ pa_source* pa_source_new(
     s->parent.process_msg = pa_source_process_msg;
 
     s->core = core;
-    pa_atomic_store(&s->state, PA_SOURCE_IDLE);
+    s->state = PA_SOURCE_IDLE;
     s->name = pa_xstrdup(name);
     s->description = NULL;
     s->driver = pa_xstrdup(driver);
@@ -94,7 +98,7 @@ pa_source* pa_source_new(
 
     pa_cvolume_reset(&s->volume, spec->channels);
     s->muted = 0;
-    s->refresh_volume = s->refresh_mute = 0;
+    s->refresh_volume = s->refresh_muted = 0;
 
     s->is_hardware = 0;
 
@@ -103,11 +107,10 @@ pa_source* pa_source_new(
     s->get_volume = NULL;
     s->set_mute = NULL;
     s->get_mute = NULL;
-    s->start = NULL;
-    s->stop = NULL;
+    s->set_state = NULL;
     s->userdata = NULL;
 
-    pa_assert_se(s->asyncmsgq = pa_asyncmsgq_new(0));
+    s->asyncmsgq = NULL;
 
     r = pa_idxset_put(core->sources, s, &s->index);
     assert(s->index != PA_IDXSET_INVALID && r >= 0);
@@ -118,56 +121,40 @@ pa_source* pa_source_new(
     s->thread_info.outputs = pa_hashmap_new(pa_idxset_trivial_hash_func, pa_idxset_trivial_compare_func);
     s->thread_info.soft_volume = s->volume;
     s->thread_info.soft_muted = s->muted;
+    s->thread_info.state = s->state;
 
     pa_subscription_post(core, PA_SUBSCRIPTION_EVENT_SOURCE | PA_SUBSCRIPTION_EVENT_NEW, s->index);
 
     return s;
 }
 
-static void source_start(pa_source *s) {
-    pa_source_state_t state;
+static int source_set_state(pa_source *s, pa_source_state_t state) {
+    int ret;
+    
     pa_assert(s);
 
-    state = pa_source_get_state(s);
-    pa_return_if_fail(state == PA_SOURCE_IDLE || state == PA_SOURCE_SUSPENDED);
-
-    pa_atomic_store(&s->state, PA_SOURCE_RUNNING);
-
-    if (s->start)
-        s->start(s);
-    else
-        pa_asyncmsgq_post(s->asyncmsgq, s, PA_SOURCE_MESSAGE_START, NULL, NULL, pa_source_unref, NULL);
-}
-
-static void source_stop(pa_source *s) {
-    pa_source_state_t state;
-    int stop;
+    if (s->state == state)
+        return 0;
 
-    pa_assert(s);
-    state = pa_source_get_state(s);
-    pa_return_if_fail(state == PA_SOURCE_RUNNING || state == PA_SOURCE_SUSPENDED);
+    if (s->set_state)
+        if ((ret = s->set_state(s, state)) < 0)
+            return -1;
 
-    stop = state == PA_SOURCE_RUNNING;
-    pa_atomic_store(&s->state, PA_SOURCE_IDLE);
+    if (pa_asyncmsgq_send(s->asyncmsgq, PA_MSGOBJECT(s), PA_SOURCE_MESSAGE_SET_STATE, PA_UINT_TO_PTR(state), NULL) < 0)
+        return -1;
 
-    if (stop) {
-        if (s->stop)
-            s->stop(s);
-        else
-            pa_asyncmsgq_post(s->asyncmsgq, s, PA_SOURCE_MESSAGE_STOP, NULL, NULL, pa_source_unref, NULL);
-    }
+    s->state = state;
+    return 0;
 }
 
 void pa_source_disconnect(pa_source *s) {
     pa_source_output *o, *j = NULL;
 
     pa_assert(s);
-    pa_return_if_fail(pa_sink_get_state(s) != PA_SINK_DISCONNECT);
-
-    source_stop(s);
+    pa_return_if_fail(s->state != PA_SOURCE_DISCONNECTED);
 
-    pa_atomic_store(&s->state, PA_SOURCE_DISCONNECTED);
     pa_namereg_unregister(s->core, s->name);
+    pa_idxset_remove_by_data(s->core->sources, s, NULL);
 
     pa_hook_fire(&s->core->hook_source_disconnect, s);
 
@@ -177,33 +164,36 @@ void pa_source_disconnect(pa_source *s) {
         j = o;
     }
 
-    pa_idxset_remove_by_data(s->core->sources, s, NULL);
+    source_set_state(s, PA_SOURCE_DISCONNECTED);
 
     s->get_latency = NULL;
     s->get_volume = NULL;
     s->set_volume = NULL;
     s->set_mute = NULL;
     s->get_mute = NULL;
-    s->start = NULL;
-    s->stop = NULL;
+    s->set_state = NULL;
 
     pa_subscription_post(s->core, PA_SUBSCRIPTION_EVENT_SOURCE | PA_SUBSCRIPTION_EVENT_REMOVE, s->index);
 }
 
-static void source_free(pa_msgobject *o) {
+static void source_free(pa_object *o) {
+    pa_source_output *so;
     pa_source *s = PA_SOURCE(o);
 
     pa_assert(s);
     pa_assert(pa_source_refcnt(s) == 0);
 
-    pa_source_disconnect(s);
+    if (s->state != PA_SOURCE_DISCONNECTED)
+        pa_source_disconnect(s);
 
     pa_log_info("Freeing source %u \"%s\"", s->index, s->name);
 
     pa_idxset_free(s->outputs, NULL, NULL);
-    pa_hashmap_free(s->thread_info.outputs, pa_sink_output_unref, NULL);
 
-    pa_asyncmsgq_free(s->asyncmsgq);
+    while ((so = pa_hashmap_steal_first(s->thread_info.outputs)))
+        pa_source_output_unref(so);
+    
+    pa_hashmap_free(s->thread_info.outputs, NULL, NULL);
 
     pa_xfree(s->name);
     pa_xfree(s->description);
@@ -211,44 +201,28 @@ static void source_free(pa_msgobject *o) {
     pa_xfree(s);
 }
 
-void pa_source_update_status(pa_source*s) {
+int pa_source_update_status(pa_source*s) {
     pa_source_assert_ref(s);
 
-    if (pa_source_get_state(s) == PA_SOURCE_STATE_SUSPENDED)
-        return;
+    if (s->state == PA_SOURCE_SUSPENDED)
+        return 0;
 
-    if (pa_source_used_by(s) > 0)
-        source_start(s);
-    else
-        source_stop(s);
+    return source_set_state(s, pa_source_used_by(s) ? PA_SOURCE_RUNNING : PA_SOURCE_IDLE);
 }
 
-void pa_source_suspend(pa_source *s, int suspend) {
-    pa_source_state_t state;
-
+int pa_source_suspend(pa_source *s, int suspend) {
     pa_source_assert_ref(s);
 
-    state = pa_source_get_state(s);
-    pa_return_if_fail(suspend && (s->state == PA_SOURCE_RUNNING || s->state == PA_SOURCE_IDLE));
-    pa_return_if_fail(!suspend && (s->state == PA_SOURCE_SUSPENDED));
-
-
-    if (suspend) {
-        pa_atomic_store(&s->state, PA_SOURCE_SUSPENDED);
-
-        if (s->stop)
-            s->stop(s);
-        else
-            pa_asyncmsgq_post(s->asyncmsgq, s, PA_SOURCE_MESSAGE_STOP, NULL, NULL, pa_source_unref, NULL);
+    if (suspend)
+        return source_set_state(s, PA_SOURCE_SUSPENDED);
+    else
+        return source_set_state(s, pa_source_used_by(s) ? PA_SOURCE_RUNNING : PA_SOURCE_IDLE);
+}
 
-    } else {
-        pa_atomic_store(&s->state, PA_SOURCE_RUNNING);
+void pa_source_ping(pa_source *s) {
+    pa_source_assert_ref(s);
 
-        if (s->start)
-            s->start(s);
-        else
-            pa_asyncmsgq_post(s->asyncmsgq, s, PA_SOURCE_MESSAGE_START, NULL, NULL, pa_source_unref, NULL);
-    }
+    pa_asyncmsgq_post(s->asyncmsgq, PA_MSGOBJECT(s), PA_SOURCE_MESSAGE_PING, NULL, NULL, NULL);
 }
 
 void pa_source_post(pa_source*s, const pa_memchunk *chunk) {
@@ -258,16 +232,16 @@ void pa_source_post(pa_source*s, const pa_memchunk *chunk) {
     pa_source_assert_ref(s);
     pa_assert(chunk);
 
-    if (s->sw_muted || !pa_cvolume_is_norm(&s->sw_volume)) {
+    if (s->thread_info.soft_muted || !pa_cvolume_is_norm(&s->thread_info.soft_volume)) {
         pa_memchunk vchunk = *chunk;
 
         pa_memblock_ref(vchunk.memblock);
         pa_memchunk_make_writable(&vchunk, 0);
 
-        if (s->thread_info.muted || pa_cvolume_is_muted(s->thread_info.volume))
+        if (s->thread_info.soft_muted || pa_cvolume_is_muted(&s->thread_info.soft_volume))
             pa_silence_memchunk(&vchunk, &s->sample_spec);
         else
-            pa_volume_memchunk(&vchunk, &s->sample_spec, &s->thread_info.volume);
+            pa_volume_memchunk(&vchunk, &s->sample_spec, &s->thread_info.soft_volume);
 
         while ((o = pa_hashmap_iterate(s->thread_info.outputs, &state, NULL)))
             pa_source_output_push(o, &vchunk);
@@ -289,32 +263,33 @@ pa_usec_t pa_source_get_latency(pa_source *s) {
     if (s->get_latency)
         return s->get_latency(s);
 
-    if (pa_asyncmsgq_send(s->asyncmsgq, s, PA_SOURCE_MESSAGE_GET_LATENCY, &usec, NULL) < 0)
+    if (pa_asyncmsgq_send(s->asyncmsgq, PA_MSGOBJECT(s), PA_SOURCE_MESSAGE_GET_LATENCY, &usec, NULL) < 0)
         return 0;
 
     return usec;
 }
 
 void pa_source_set_volume(pa_source *s, const pa_cvolume *volume) {
-    pa_cvolume *v;
+    int changed;
 
     pa_source_assert_ref(s);
     pa_assert(volume);
 
-    changed = !pa_cvolume_equal(volume, s->volume);
+    changed = !pa_cvolume_equal(volume, &s->volume);
     s->volume = *volume;
 
     if (s->set_volume && s->set_volume(s) < 0)
         s->set_volume = NULL;
 
     if (!s->set_volume)
-        pa_asyncmsgq_post(s->asyncmsgq, pa_source_ref(s), PA_SOURCE_MESSAGE_SET_VOLUME, pa_xnewdup(struct pa_cvolume, volume, 1), pa_source_unref, pa_xfree);
+        pa_asyncmsgq_post(s->asyncmsgq, PA_MSGOBJECT(s), PA_SOURCE_MESSAGE_SET_VOLUME, pa_xnewdup(struct pa_cvolume, volume, 1), NULL, pa_xfree);
 
     if (changed)
         pa_subscription_post(s->core, PA_SUBSCRIPTION_EVENT_SOURCE|PA_SUBSCRIPTION_EVENT_CHANGE, s->index);
 }
 
 const pa_cvolume *pa_source_get_volume(pa_source *s) {
+    pa_cvolume old_volume;
     pa_source_assert_ref(s);
 
     old_volume = s->volume;
@@ -323,7 +298,7 @@ const pa_cvolume *pa_source_get_volume(pa_source *s) {
         s->get_volume = NULL;
 
     if (!s->get_volume && s->refresh_volume)
-        pa_asyncmsgq_send(s->asyncmsgq, s, PA_SOURCE_MESSAGE_GET_VOLUME, &s->volume);
+        pa_asyncmsgq_send(s->asyncmsgq, PA_MSGOBJECT(s), PA_SOURCE_MESSAGE_GET_VOLUME, &s->volume, NULL);
 
     if (!pa_cvolume_equal(&old_volume, &s->volume))
         pa_subscription_post(s->core, PA_SUBSCRIPTION_EVENT_SOURCE|PA_SUBSCRIPTION_EVENT_CHANGE, s->index);
@@ -331,7 +306,7 @@ const pa_cvolume *pa_source_get_volume(pa_source *s) {
     return &s->volume;
 }
 
-void pa_source_set_mute(pa_source *s, pa_mixer_t m, int mute) {
+void pa_source_set_mute(pa_source *s, int mute) {
     int changed;
 
     pa_source_assert_ref(s);
@@ -342,13 +317,13 @@ void pa_source_set_mute(pa_source *s, pa_mixer_t m, int mute) {
         s->set_mute = NULL;
 
     if (!s->set_mute)
-        pa_asyncmsgq_post(s->asyncmsgq, pa_source_ref(s), PA_SOURCE_MESSAGE_SET_MUTE, PA_UINT_TO_PTR(mute), pa_source_unref, NULL);
+        pa_asyncmsgq_post(s->asyncmsgq, PA_MSGOBJECT(s), PA_SOURCE_MESSAGE_SET_MUTE, PA_UINT_TO_PTR(mute), NULL, NULL);
 
     if (changed)
         pa_subscription_post(s->core, PA_SUBSCRIPTION_EVENT_SOURCE|PA_SUBSCRIPTION_EVENT_CHANGE, s->index);
 }
 
-int pa_source_get_mute(pa_source *s, pa_mixer_t m) {
+int pa_source_get_mute(pa_source *s) {
     int old_muted;
 
     pa_source_assert_ref(s);
@@ -358,8 +333,8 @@ int pa_source_get_mute(pa_source *s, pa_mixer_t m) {
     if (s->get_mute && s->get_mute(s) < 0)
         s->get_mute = NULL;
 
-    if (!s->get_mute && s->refresh_mute)
-        pa_asyncmsgq_send(s->asyncmsgq, s, PA_SOURCE_MESSAGE_GET_MUTE, &s->muted);
+    if (!s->get_mute && s->refresh_muted)
+        pa_asyncmsgq_send(s->asyncmsgq, PA_MSGOBJECT(s), PA_SOURCE_MESSAGE_GET_MUTE, &s->muted, NULL);
 
     if (old_muted != s->muted)
         pa_subscription_post(s->core, PA_SUBSCRIPTION_EVENT_SOURCE|PA_SUBSCRIPTION_EVENT_CHANGE, s->index);
@@ -393,26 +368,33 @@ void pa_source_set_description(pa_source *s, const char *description) {
     pa_subscription_post(s->core, PA_SUBSCRIPTION_EVENT_SOURCE|PA_SUBSCRIPTION_EVENT_CHANGE, s->index);
 }
 
+void pa_source_set_asyncmsgq(pa_source *s, pa_asyncmsgq *q) {
+    pa_source_assert_ref(s);
+    pa_assert(q);
+
+    s->asyncmsgq = q;
+}
+
 unsigned pa_source_used_by(pa_source *s) {
     pa_source_assert_ref(s);
 
     return pa_idxset_size(s->outputs);
 }
 
-int pa_source_process_msg(pa_msgobject *o, void *object, int code, pa_memchunk *chunk, void *userdata) {
+int pa_source_process_msg(pa_msgobject *o, int code, void *userdata, pa_memchunk *chunk) {
     pa_source *s = PA_SOURCE(o);
     pa_source_assert_ref(s);
 
-    switch (code) {
+    switch ((pa_source_message_t) code) {
         case PA_SOURCE_MESSAGE_ADD_OUTPUT: {
             pa_source_output *i = userdata;
             pa_hashmap_put(s->thread_info.outputs, PA_UINT32_TO_PTR(i->index), pa_source_output_ref(i));
             return 0;
         }
 
-        case PA_SOURCE_MESSAGE_REMOVE_INPUT: {
-            pa_source_input *i = userdata;
-            pa_hashmap_remove(s->thread_info.outputs, PA_UINT32_TO_PTR(i->index), pa_source_output_ref(i));
+        case PA_SOURCE_MESSAGE_REMOVE_OUTPUT: {
+            pa_source_output *i = userdata;
+            pa_hashmap_remove(s->thread_info.outputs, PA_UINT32_TO_PTR(i->index));
             return 0;
         }
 
@@ -432,7 +414,17 @@ int pa_source_process_msg(pa_msgobject *o, void *object, int code, pa_memchunk *
             *((int*) userdata) = s->thread_info.soft_muted;
             return 0;
 
-        default:
-            return -1;
+        case PA_SOURCE_MESSAGE_PING:
+            return 0;
+
+        case PA_SOURCE_MESSAGE_SET_STATE:
+            s->thread_info.state = PA_PTR_TO_UINT(userdata);
+            return 0;
+            
+        case PA_SOURCE_MESSAGE_GET_LATENCY:
+        case PA_SOURCE_MESSAGE_MAX:
+            ;
     }
+
+    return -1;
 }
diff --git a/src/pulsecore/source.h b/src/pulsecore/source.h
index b41b1bc..4db2ded 100644
--- a/src/pulsecore/source.h
+++ b/src/pulsecore/source.h
@@ -57,7 +57,7 @@ struct pa_source {
 
     uint32_t index;
     pa_core *core;
-    pa_atomic_t state;
+    pa_source_state_t state;
 
     char *name;
     char *description, *driver;              /* may be NULL */
@@ -74,10 +74,9 @@ struct pa_source {
     pa_cvolume volume;
     int muted;
     int refresh_volume;
-    int referesh_mute;
+    int refresh_muted;
 
-    void (*start)(pa_source*source);         /* may be NULL */
-    void (*stop)(pa_source*source);          /* may be NULL */
+    int (*set_state)(pa_source*source, pa_source_state_t state);          /* may be NULL */
     int (*set_volume)(pa_source *s);         /* dito */
     int (*get_volume)(pa_source *s);         /* dito */
     int (*set_mute)(pa_source *s);           /* dito */
@@ -87,6 +86,7 @@ struct pa_source {
     pa_asyncmsgq *asyncmsgq;
 
     struct {
+        pa_source_state_t state;
         pa_hashmap *outputs;
         pa_cvolume soft_volume;
         int soft_muted;
@@ -96,7 +96,7 @@ struct pa_source {
 };
 
 PA_DECLARE_CLASS(pa_source);
-#define PA_SOURCE(s) ((pa_source*) (s))
+#define PA_SOURCE(s) pa_source_cast(s)
 
 typedef enum pa_source_message {
     PA_SOURCE_MESSAGE_ADD_OUTPUT,
@@ -106,8 +106,8 @@ typedef enum pa_source_message {
     PA_SOURCE_MESSAGE_GET_MUTE,
     PA_SOURCE_MESSAGE_SET_MUTE,
     PA_SOURCE_MESSAGE_GET_LATENCY,
-    PA_SOURCE_MESSAGE_START,
-    PA_SOURCE_MESSAGE_STOP,
+    PA_SOURCE_MESSAGE_SET_STATE,
+    PA_SOURCE_MESSAGE_PING,
     PA_SOURCE_MESSAGE_MAX
 } pa_source_message_t;
 
@@ -125,13 +125,15 @@ void pa_source_disconnect(pa_source *s);
 
 void pa_source_set_module(pa_source *s, pa_module *m);
 void pa_source_set_description(pa_source *s, const char *description);
+void pa_source_set_asyncmsgq(pa_source *s, pa_asyncmsgq *q);
 
 /* Callable by everyone */
 
 pa_usec_t pa_source_get_latency(pa_source *s);
 
-void pa_source_update_status(pa_source*s);
-void pa_source_suspend(pa_source *s);
+int pa_source_update_status(pa_source*s);
+int pa_source_suspend(pa_source *s, int suspend);
+void pa_source_ping(pa_source *s);
 
 void pa_source_set_volume(pa_source *source, const pa_cvolume *volume);
 const pa_cvolume *pa_source_get_volume(pa_source *source);
@@ -139,11 +141,11 @@ void pa_source_set_mute(pa_source *source, int mute);
 int pa_source_get_mute(pa_source *source);
 
 unsigned pa_source_used_by(pa_source *s);
-#define pa_source_get_state(s) ((pa_source_state_t) pa_atomic_load(&(s)->state))
+#define pa_source_get_state(s) ((pa_source_state_t) (s)->state)
 
 /* To be used exclusively by the source driver thread */
 
 void pa_source_post(pa_source*s, const pa_memchunk *b);
-void pa_source_process_msg(pa_msgobject *o, int code, void *userdata, pa_memchunk *chunk);
+int pa_source_process_msg(pa_msgobject *o, int code, void *userdata, pa_memchunk *chunk);
 
 #endif
diff --git a/src/tests/asyncmsgq-test.c b/src/tests/asyncmsgq-test.c
index d10b512..847d5be 100644
--- a/src/tests/asyncmsgq-test.c
+++ b/src/tests/asyncmsgq-test.c
@@ -49,7 +49,7 @@ static void the_thread(void *_q) {
     do {
         int code = 0;
 
-        pa_assert_se(pa_asyncmsgq_get(q, NULL, &code, NULL, 1) == 0);
+        pa_assert_se(pa_asyncmsgq_get(q, NULL, &code, NULL, NULL, 1) == 0);
 
         switch (code) {
 
@@ -71,7 +71,7 @@ static void the_thread(void *_q) {
                 break;
         }
 
-        pa_asyncmsgq_done(q);
+        pa_asyncmsgq_done(q, 0);
 
     } while (!quit);
 }
@@ -91,11 +91,11 @@ int main(int argc, char *argv[]) {
 
     printf("Operation B post\n");
     pa_asyncmsgq_post(q, NULL, OPERATION_B, NULL, NULL, NULL);
-
+    
     pa_thread_yield();
 
     printf("Operation C send\n");
-    pa_asyncmsgq_send(q, NULL, OPERATION_C, NULL);
+    pa_asyncmsgq_send(q, NULL, OPERATION_C, NULL, NULL);
 
     pa_thread_yield();
 

commit 111dcd5e34434324adafd9f43c656592f3a02d60
Author: Lennart Poettering <lennart at poettering.net>
Date:   Thu Jun 14 16:53:40 2007 +0000

    trivial cleanups
    
    git-svn-id: file:///home/lennart/svn/public/pulseaudio/branches/lennart@1475 fefdeb5f-60dc-0310-8127-8f9354f1896f

diff --git a/src/modules/module-pipe-sink.c b/src/modules/module-pipe-sink.c
index da9124a..216e42a 100644
--- a/src/modules/module-pipe-sink.c
+++ b/src/modules/module-pipe-sink.c
@@ -28,7 +28,6 @@
 #include <stdlib.h>
 #include <sys/stat.h>
 #include <stdio.h>
-#include <assert.h>
 #include <errno.h>
 #include <string.h>
 #include <fcntl.h>
@@ -40,7 +39,6 @@
 #include <pulse/xmalloc.h>
 
 #include <pulsecore/core-error.h>
-#include <pulsecore/iochannel.h>
 #include <pulsecore/sink.h>
 #include <pulsecore/module.h>
 #include <pulsecore/core-util.h>
@@ -170,6 +168,8 @@ static void thread_func(void *userdata) {
                 l = pa_write(u->fd, (uint8_t*) p + u->memchunk.index, u->memchunk.length, &write_type);
                 pa_memblock_release(u->memchunk.memblock);
 
+                pa_assert(l != 0);
+                
                 if (l < 0) {
 
                     if (errno == EINTR)
@@ -202,7 +202,10 @@ static void thread_func(void *userdata) {
         if (pa_asyncmsgq_before_poll(u->asyncmsgq) < 0)
             continue;
 
+/*         pa_log("polling for %u (underrun=%i)", pollfd[POLLFD_FIFO].events, underrun);  */
         r = poll(pollfd, POLLFD_MAX, -1);
+/*         pa_log("polling got %u", r > 0 ? pollfd[POLLFD_FIFO].revents : 0);  */
+
         pa_asyncmsgq_after_poll(u->asyncmsgq);
 
         if (r < 0) {
@@ -232,11 +235,11 @@ finish:
 }
 
 int pa__init(pa_core *c, pa_module*m) {
-    struct userdata *u = NULL;
+    struct userdata *u;
     struct stat st;
     pa_sample_spec ss;
     pa_channel_map map;
-    pa_modargs *ma = NULL;
+    pa_modargs *ma;
     char *t;
 
     pa_assert(c);

commit 1b99fd2fc4c80ab581b08e1fb03ed8543dc763ec
Author: Lennart Poettering <