[pulseaudio-commits] r1971 - in /trunk: ./ libltdl/ src/ src/daemon/ src/modules/ src/modules/gconf/ src/modules/rtp/ src/pulse/ src/pulsecore/ src/pulsecore/ffmpeg/ src/pulsecore/speex/ src/tests/ src/utils/

svnmailer-noreply at 0pointer.de svnmailer-noreply at 0pointer.de
Sun Oct 28 12:13:53 PDT 2007


Author: lennart
Date: Sun Oct 28 20:13:50 2007
New Revision: 1971

URL: http://0pointer.de/cgi-bin/viewcvs.cgi?rev=1971&root=pulseaudio&view=rev
Log:
merge 'lennart' branch back into trunk.

Added:
    trunk/libltdl/   (props changed)
      - copied from r1970, branches/lennart/libltdl/
    trunk/pulseaudio-text.svg
      - copied unchanged from r1970, branches/lennart/pulseaudio-text.svg
    trunk/src/daemon/ltdl-bind-now.c
      - copied, changed from r1970, branches/lennart/src/daemon/ltdl-bind-now.c
    trunk/src/daemon/ltdl-bind-now.h
      - copied unchanged from r1970, branches/lennart/src/daemon/ltdl-bind-now.h
    trunk/src/daemon/pulseaudio-module-xsmp.desktop
      - copied unchanged from r1970, branches/lennart/src/daemon/pulseaudio-module-xsmp.desktop
    trunk/src/modules/ladspa.h
      - copied, changed from r1970, branches/lennart/src/modules/ladspa.h
    trunk/src/modules/module-default-device-restore.c
      - copied, changed from r1970, branches/lennart/src/modules/module-default-device-restore.c
    trunk/src/modules/module-ladspa-sink.c
      - copied unchanged from r1970, branches/lennart/src/modules/module-ladspa-sink.c
    trunk/src/modules/module-remap-sink.c
      - copied unchanged from r1970, branches/lennart/src/modules/module-remap-sink.c
    trunk/src/modules/module-suspend-on-idle.c
      - copied unchanged from r1970, branches/lennart/src/modules/module-suspend-on-idle.c
    trunk/src/modules/module-x11-xsmp.c
      - copied, changed from r1970, branches/lennart/src/modules/module-x11-xsmp.c
    trunk/src/pulsecore/asyncmsgq.c
      - copied unchanged from r1970, branches/lennart/src/pulsecore/asyncmsgq.c
    trunk/src/pulsecore/asyncmsgq.h
      - copied unchanged from r1970, branches/lennart/src/pulsecore/asyncmsgq.h
    trunk/src/pulsecore/asyncq.c
      - copied, changed from r1970, branches/lennart/src/pulsecore/asyncq.c
    trunk/src/pulsecore/asyncq.h
      - copied unchanged from r1970, branches/lennart/src/pulsecore/asyncq.h
    trunk/src/pulsecore/fdsem.c
      - copied unchanged from r1970, branches/lennart/src/pulsecore/fdsem.c
    trunk/src/pulsecore/fdsem.h
      - copied unchanged from r1970, branches/lennart/src/pulsecore/fdsem.h
    trunk/src/pulsecore/ffmpeg/
      - copied from r1970, branches/lennart/src/pulsecore/ffmpeg/
    trunk/src/pulsecore/ltdl-helper.c
      - copied, changed from r1970, branches/lennart/src/pulsecore/ltdl-helper.c
    trunk/src/pulsecore/ltdl-helper.h
      - copied unchanged from r1970, branches/lennart/src/pulsecore/ltdl-helper.h
    trunk/src/pulsecore/macro.h
      - copied unchanged from r1970, branches/lennart/src/pulsecore/macro.h
    trunk/src/pulsecore/msgobject.c
      - copied unchanged from r1970, branches/lennart/src/pulsecore/msgobject.c
    trunk/src/pulsecore/msgobject.h
      - copied unchanged from r1970, branches/lennart/src/pulsecore/msgobject.h
    trunk/src/pulsecore/object.c
      - copied, changed from r1970, branches/lennart/src/pulsecore/object.c
    trunk/src/pulsecore/object.h
      - copied unchanged from r1970, branches/lennart/src/pulsecore/object.h
    trunk/src/pulsecore/once.c
      - copied, changed from r1970, branches/lennart/src/pulsecore/once.c
    trunk/src/pulsecore/rtclock.c
      - copied unchanged from r1970, branches/lennart/src/pulsecore/rtclock.c
    trunk/src/pulsecore/rtclock.h
      - copied unchanged from r1970, branches/lennart/src/pulsecore/rtclock.h
    trunk/src/pulsecore/rtpoll.c
      - copied unchanged from r1970, branches/lennart/src/pulsecore/rtpoll.c
    trunk/src/pulsecore/rtpoll.h
      - copied, changed from r1970, branches/lennart/src/pulsecore/rtpoll.h
    trunk/src/pulsecore/rtsig.c
      - copied unchanged from r1970, branches/lennart/src/pulsecore/rtsig.c
    trunk/src/pulsecore/rtsig.h
      - copied unchanged from r1970, branches/lennart/src/pulsecore/rtsig.h
    trunk/src/pulsecore/semaphore-posix.c
      - copied unchanged from r1970, branches/lennart/src/pulsecore/semaphore-posix.c
    trunk/src/pulsecore/semaphore-win32.c
      - copied unchanged from r1970, branches/lennart/src/pulsecore/semaphore-win32.c
    trunk/src/pulsecore/semaphore.h
      - copied unchanged from r1970, branches/lennart/src/pulsecore/semaphore.h
    trunk/src/pulsecore/speex/
      - copied from r1970, branches/lennart/src/pulsecore/speex/
    trunk/src/pulsecore/speexwrap.h
      - copied unchanged from r1970, branches/lennart/src/pulsecore/speexwrap.h
    trunk/src/pulsecore/thread-mq.c
      - copied, changed from r1970, branches/lennart/src/pulsecore/thread-mq.c
    trunk/src/pulsecore/thread-mq.h
      - copied unchanged from r1970, branches/lennart/src/pulsecore/thread-mq.h
    trunk/src/pulsecore/time-smoother.c
      - copied unchanged from r1970, branches/lennart/src/pulsecore/time-smoother.c
    trunk/src/pulsecore/time-smoother.h
      - copied unchanged from r1970, branches/lennart/src/pulsecore/time-smoother.h
    trunk/src/tests/asyncmsgq-test.c
      - copied, changed from r1970, branches/lennart/src/tests/asyncmsgq-test.c
    trunk/src/tests/asyncq-test.c
      - copied unchanged from r1970, branches/lennart/src/tests/asyncq-test.c
    trunk/src/tests/queue-test.c
      - copied, changed from r1970, branches/lennart/src/tests/queue-test.c
    trunk/src/tests/resampler-test.c
      - copied unchanged from r1970, branches/lennart/src/tests/resampler-test.c
    trunk/src/tests/rtpoll-test.c
      - copied unchanged from r1970, branches/lennart/src/tests/rtpoll-test.c
    trunk/src/tests/sig2str-test.c
      - copied, changed from r1970, branches/lennart/src/tests/sig2str-test.c
    trunk/src/tests/smoother-test.c
      - copied unchanged from r1970, branches/lennart/src/tests/smoother-test.c
    trunk/src/utils/pasuspender.c
      - copied, changed from r1970, branches/lennart/src/utils/pasuspender.c
Removed:
    trunk/src/modules/module-oss-mmap.c
    trunk/src/pulsecore/anotify.c
    trunk/src/pulsecore/anotify.h
    trunk/src/pulsecore/once-posix.c
    trunk/src/pulsecore/once-win32.c
Modified:
    trunk/   (props changed)
    trunk/Makefile.am
    trunk/bootstrap.sh
    trunk/configure.ac
    trunk/libltdl/config.h
    trunk/libltdl/ltdl.c
    trunk/libltdl/ltdl.h
    trunk/src/   (props changed)
    trunk/src/Makefile.am
    trunk/src/daemon/caps.c
    trunk/src/daemon/cmdline.c
    trunk/src/daemon/cpulimit.c
    trunk/src/daemon/daemon-conf.c
    trunk/src/daemon/daemon-conf.h
    trunk/src/daemon/daemon.conf.in
    trunk/src/daemon/default.pa.in
    trunk/src/daemon/dumpmodules.c
    trunk/src/daemon/main.c
    trunk/src/modules/alsa-util.c
    trunk/src/modules/alsa-util.h
    trunk/src/modules/dbus-util.c
    trunk/src/modules/gconf/gconf-helper.c
    trunk/src/modules/gconf/module-gconf.c
    trunk/src/modules/module-alsa-sink.c
    trunk/src/modules/module-alsa-source.c
    trunk/src/modules/module-cli.c
    trunk/src/modules/module-combine.c
    trunk/src/modules/module-defs.h.m4
    trunk/src/modules/module-detect.c
    trunk/src/modules/module-esound-compat-spawnfd.c
    trunk/src/modules/module-esound-compat-spawnpid.c
    trunk/src/modules/module-esound-sink.c
    trunk/src/modules/module-hal-detect.c
    trunk/src/modules/module-jack-sink.c
    trunk/src/modules/module-jack-source.c
    trunk/src/modules/module-lirc.c
    trunk/src/modules/module-match.c
    trunk/src/modules/module-mmkbd-evdev.c
    trunk/src/modules/module-native-protocol-fd.c
    trunk/src/modules/module-null-sink.c
    trunk/src/modules/module-oss.c
    trunk/src/modules/module-pipe-sink.c
    trunk/src/modules/module-pipe-source.c
    trunk/src/modules/module-protocol-stub.c
    trunk/src/modules/module-rescue-streams.c
    trunk/src/modules/module-sine.c
    trunk/src/modules/module-solaris.c
    trunk/src/modules/module-tunnel.c
    trunk/src/modules/module-volume-restore.c
    trunk/src/modules/module-x11-bell.c
    trunk/src/modules/module-x11-publish.c
    trunk/src/modules/module-zeroconf-publish.c
    trunk/src/modules/oss-util.c
    trunk/src/modules/oss-util.h
    trunk/src/modules/rtp/module-rtp-recv.c
    trunk/src/modules/rtp/module-rtp-send.c
    trunk/src/modules/rtp/rtp.c
    trunk/src/modules/rtp/sap.c
    trunk/src/modules/rtp/sdp.c
    trunk/src/pulse/browser.c
    trunk/src/pulse/cdecl.h
    trunk/src/pulse/channelmap.c
    trunk/src/pulse/channelmap.h
    trunk/src/pulse/client-conf-x11.c
    trunk/src/pulse/client-conf.c
    trunk/src/pulse/context.c
    trunk/src/pulse/glib-mainloop.c
    trunk/src/pulse/internal.h
    trunk/src/pulse/introspect.c
    trunk/src/pulse/introspect.h
    trunk/src/pulse/mainloop-api.c
    trunk/src/pulse/mainloop-signal.c
    trunk/src/pulse/mainloop.c
    trunk/src/pulse/operation.c
    trunk/src/pulse/sample.c
    trunk/src/pulse/sample.h
    trunk/src/pulse/scache.c
    trunk/src/pulse/simple.c
    trunk/src/pulse/simple.h
    trunk/src/pulse/stream.c
    trunk/src/pulse/subscribe.c
    trunk/src/pulse/thread-mainloop.c
    trunk/src/pulse/thread-mainloop.h
    trunk/src/pulse/timeval.c
    trunk/src/pulse/timeval.h
    trunk/src/pulse/utf8.c
    trunk/src/pulse/utf8.h
    trunk/src/pulse/util.c
    trunk/src/pulse/util.h
    trunk/src/pulse/volume.c
    trunk/src/pulse/volume.h
    trunk/src/pulse/xmalloc.c
    trunk/src/pulse/xmalloc.h
    trunk/src/pulsecore/atomic.h
    trunk/src/pulsecore/authkey-prop.c
    trunk/src/pulsecore/authkey.c
    trunk/src/pulsecore/autoload.c
    trunk/src/pulsecore/avahi-wrap.c
    trunk/src/pulsecore/cli-command.c
    trunk/src/pulsecore/cli-text.c
    trunk/src/pulsecore/cli.c
    trunk/src/pulsecore/client.c
    trunk/src/pulsecore/conf-parser.c
    trunk/src/pulsecore/core-def.h
    trunk/src/pulsecore/core-error.c
    trunk/src/pulsecore/core-scache.c
    trunk/src/pulsecore/core-scache.h
    trunk/src/pulsecore/core-subscribe.c
    trunk/src/pulsecore/core-util.c
    trunk/src/pulsecore/core-util.h
    trunk/src/pulsecore/core.c
    trunk/src/pulsecore/core.h
    trunk/src/pulsecore/creds.h
    trunk/src/pulsecore/dynarray.c
    trunk/src/pulsecore/endianmacros.h
    trunk/src/pulsecore/esound.h
    trunk/src/pulsecore/ffmpeg/avcodec.h
    trunk/src/pulsecore/flist.c
    trunk/src/pulsecore/flist.h
    trunk/src/pulsecore/g711.c
    trunk/src/pulsecore/gccmacro.h
    trunk/src/pulsecore/hashmap.c
    trunk/src/pulsecore/hashmap.h
    trunk/src/pulsecore/hook-list.c
    trunk/src/pulsecore/idxset.c
    trunk/src/pulsecore/idxset.h
    trunk/src/pulsecore/inet_ntop.c
    trunk/src/pulsecore/iochannel.c
    trunk/src/pulsecore/iochannel.h
    trunk/src/pulsecore/ioline.c
    trunk/src/pulsecore/ipacl.c
    trunk/src/pulsecore/llist.h
    trunk/src/pulsecore/log.c
    trunk/src/pulsecore/mcalign.c
    trunk/src/pulsecore/memblock.c
    trunk/src/pulsecore/memblock.h
    trunk/src/pulsecore/memblockq.c
    trunk/src/pulsecore/memblockq.h
    trunk/src/pulsecore/memchunk.c
    trunk/src/pulsecore/memchunk.h
    trunk/src/pulsecore/modargs.c
    trunk/src/pulsecore/modargs.h
    trunk/src/pulsecore/modinfo.c
    trunk/src/pulsecore/modinfo.h
    trunk/src/pulsecore/module.c
    trunk/src/pulsecore/module.h
    trunk/src/pulsecore/mutex-posix.c
    trunk/src/pulsecore/mutex-win32.c
    trunk/src/pulsecore/mutex.h
    trunk/src/pulsecore/namereg.c
    trunk/src/pulsecore/native-common.h
    trunk/src/pulsecore/once.h
    trunk/src/pulsecore/packet.c
    trunk/src/pulsecore/packet.h
    trunk/src/pulsecore/parseaddr.c
    trunk/src/pulsecore/pdispatch.c
    trunk/src/pulsecore/pid.c
    trunk/src/pulsecore/pipe.c
    trunk/src/pulsecore/play-memblockq.c
    trunk/src/pulsecore/play-memblockq.h
    trunk/src/pulsecore/play-memchunk.c
    trunk/src/pulsecore/poll.c
    trunk/src/pulsecore/props.c
    trunk/src/pulsecore/protocol-cli.c
    trunk/src/pulsecore/protocol-esound.c
    trunk/src/pulsecore/protocol-http.c
    trunk/src/pulsecore/protocol-native.c
    trunk/src/pulsecore/protocol-simple.c
    trunk/src/pulsecore/pstream-util.c
    trunk/src/pulsecore/pstream.c
    trunk/src/pulsecore/pstream.h
    trunk/src/pulsecore/queue.c
    trunk/src/pulsecore/random.c
    trunk/src/pulsecore/refcnt.h
    trunk/src/pulsecore/resampler.c
    trunk/src/pulsecore/resampler.h
    trunk/src/pulsecore/sample-util.c
    trunk/src/pulsecore/sample-util.h
    trunk/src/pulsecore/sconv-s16be.c
    trunk/src/pulsecore/sconv-s16be.h
    trunk/src/pulsecore/sconv-s16le.c
    trunk/src/pulsecore/sconv-s16le.h
    trunk/src/pulsecore/sconv.c
    trunk/src/pulsecore/sconv.h
    trunk/src/pulsecore/shm.c
    trunk/src/pulsecore/shm.h
    trunk/src/pulsecore/sink-input.c
    trunk/src/pulsecore/sink-input.h
    trunk/src/pulsecore/sink.c
    trunk/src/pulsecore/sink.h
    trunk/src/pulsecore/sioman.c
    trunk/src/pulsecore/socket-client.c
    trunk/src/pulsecore/socket-server.c
    trunk/src/pulsecore/socket-util.c
    trunk/src/pulsecore/socket-util.h
    trunk/src/pulsecore/sound-file-stream.c
    trunk/src/pulsecore/sound-file.c
    trunk/src/pulsecore/source-output.c
    trunk/src/pulsecore/source-output.h
    trunk/src/pulsecore/source.c
    trunk/src/pulsecore/source.h
    trunk/src/pulsecore/speex/arch.h
    trunk/src/pulsecore/speex/fixed_generic.h
    trunk/src/pulsecore/speex/resample.c
    trunk/src/pulsecore/speex/speex_resampler.h
    trunk/src/pulsecore/strbuf.c
    trunk/src/pulsecore/strlist.c
    trunk/src/pulsecore/tagstruct.c
    trunk/src/pulsecore/thread-posix.c
    trunk/src/pulsecore/thread-win32.c
    trunk/src/pulsecore/thread.h
    trunk/src/pulsecore/tokenizer.c
    trunk/src/pulsecore/winsock.h
    trunk/src/pulsecore/x11prop.c
    trunk/src/pulsecore/x11wrap.c
    trunk/src/tests/hook-list-test.c
    trunk/src/tests/interpol-test.c
    trunk/src/tests/mcalign-test.c
    trunk/src/tests/memblock-test.c
    trunk/src/tests/memblockq-test.c
    trunk/src/tests/thread-mainloop-test.c
    trunk/src/tests/thread-test.c
    trunk/src/utils/pactl.c
    trunk/src/utils/padsp.c
    trunk/src/utils/paplay.c
    trunk/todo

Propchange: trunk/
------------------------------------------------------------------------------
--- svn:ignore (original)
+++ svn:ignore Sun Oct 28 20:13:50 2007
@@ -1,3 +1,4 @@
+config.rpath
 libltdl
 *.cache
 autoscan.log

Modified: trunk/Makefile.am
URL: http://0pointer.de/cgi-bin/viewcvs.cgi/trunk/Makefile.am?rev=1971&root=pulseaudio&r1=1970&r2=1971&view=diff
==============================================================================
--- trunk/Makefile.am (original)
+++ trunk/Makefile.am Sun Oct 28 20:13:50 2007
@@ -48,4 +48,10 @@
 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;' \{\} \;
+
+fedora-snapshot: dist
+	cp $(distdir).tar.gz $$HOME/cvs.fedora/pulseaudio/devel/$(distdir).svn`date +%Y%m%d`.tar.gz
+
 .PHONY: homepage distcleancheck doxygen

Modified: trunk/bootstrap.sh
URL: http://0pointer.de/cgi-bin/viewcvs.cgi/trunk/bootstrap.sh?rev=1971&root=pulseaudio&r1=1970&r2=1971&view=diff
==============================================================================
--- trunk/bootstrap.sh (original)
+++ trunk/bootstrap.sh Sun Oct 28 20:13:50 2007
@@ -25,10 +25,10 @@
 
     V=$(echo "$2" | sed -e 's,\.,,g')
     
-    if [ -e "`which $1$V`" ] ; then
+    if [ -e "`which $1$V 2> /dev/null`" ] ; then
     	P="$1$V" 
     else
-	if [ -e "`which $1-$2`" ] ; then
+	if [ -e "`which $1-$2 2> /dev/null`" ] ; then
 	    P="$1-$2" 
 	else
 	    P="$1"
@@ -48,13 +48,14 @@
     rm -rf autom4te.cache
     rm -f config.cache
 
+    touch config.rpath
     test "x$LIBTOOLIZE" = "x" && LIBTOOLIZE=libtoolize
 
     "$LIBTOOLIZE" -c --force --ltdl
     run_versioned aclocal "$VERSION"
     run_versioned autoconf 2.59 -Wall
     run_versioned autoheader 2.59
-    run_versioned automake "$VERSION" -a -c --foreign
+    run_versioned automake "$VERSION" --copy --foreign --add-missing
 
     if test "x$NOCONFIGURE" = "x"; then
         CFLAGS="-g -O0" ./configure --sysconfdir=/etc --localstatedir=/var --enable-force-preopen "$@" 

Modified: trunk/configure.ac
URL: http://0pointer.de/cgi-bin/viewcvs.cgi/trunk/configure.ac?rev=1971&root=pulseaudio&r1=1970&r2=1971&view=diff
==============================================================================
--- trunk/configure.ac (original)
+++ trunk/configure.ac Sun Oct 28 20:13:50 2007
@@ -26,7 +26,7 @@
 
 m4_define(PA_MAJOR, [0])
 m4_define(PA_MINOR, [9])
-m4_define(PA_MICRO, [6])
+m4_define(PA_MICRO, [7])
 
 AC_INIT([pulseaudio], PA_MAJOR.PA_MINOR.PA_MICRO,[mzcbylcnhqvb (at) 0pointer (dot) de])
 AC_CONFIG_SRCDIR([src/daemon/main.c])
@@ -34,13 +34,13 @@
 AM_INIT_AUTOMAKE([foreign -Wall])
 
 AC_SUBST(PA_MAJORMINOR, "PA_MAJOR.PA_MINOR")
-AC_SUBST(PACKAGE_URL, [http://0pointer.de/lennart/projects/pulseaudio/])
+AC_SUBST(PACKAGE_URL, [http://pulseaudio.org/])
 
 AC_SUBST(PA_API_VERSION, 10)
-AC_SUBST(PA_PROTOCOL_VERSION, 10)
-
-AC_SUBST(LIBPULSE_VERSION_INFO, [2:0:2])
-AC_SUBST(LIBPULSECORE_VERSION_INFO, [3:0:0])
+AC_SUBST(PA_PROTOCOL_VERSION, 11)
+
+AC_SUBST(LIBPULSE_VERSION_INFO, [3:0:3])
+AC_SUBST(LIBPULSECORE_VERSION_INFO, [4:0:0])
 AC_SUBST(LIBPULSE_SIMPLE_VERSION_INFO, [0:0:0])
 AC_SUBST(LIBPULSE_BROWSE_VERSION_INFO, [1:0:1])
 AC_SUBST(LIBPULSE_MAINLOOP_GLIB_VERSION_INFO, [0:2:0])
@@ -81,8 +81,8 @@
 # GCC flags
 
 test_gcc_flag() {
-    AC_LANG_CONFTEST([int main() {}])
-    $CC -c conftest.c $CFLAGS $@ > /dev/null 2> /dev/null
+    AC_LANG_CONFTEST([int main(int argc, char*argv[]) {}])
+    $CC -c conftest.c $CFLAGS -o conftest.o > /dev/null 2> /dev/null
     ret=$?
     rm -f conftest.o
     return $ret
@@ -93,28 +93,64 @@
 
     # We use gnu99 instead of c99 because many have interpreted the standard
     # in a way that int64_t isn't defined on non-64 bit platforms.
-    DESIRED_FLAGS="-std=gnu99 -Wall -W -Wextra -pedantic -pipe -Wformat -Wold-style-definition -Wdeclaration-after-statement -Wfloat-equal -Wmissing-declarations -Wmissing-prototypes -Wstrict-prototypes -Wredundant-decls -Wmissing-noreturn -Wshadow -Wendif-labels -Wpointer-arith -Wcast-align -Wwrite-strings -Winline -Wno-unused-parameter"
+    DESIRED_FLAGS="-std=gnu99 -Wall -W -Wextra -pedantic -pipe -Wformat -Wold-style-definition -Wdeclaration-after-statement -Wfloat-equal -Wmissing-declarations -Wmissing-prototypes -Wstrict-prototypes -Wredundant-decls -Wmissing-noreturn -Wshadow -Wendif-labels -Wpointer-arith -Wcast-align -Wwrite-strings -Winline -Wno-unused-parameter -ffast-math"
 
     for flag in $DESIRED_FLAGS ; do
         AC_MSG_CHECKING([whether $CC accepts $flag])
-        if test_gcc_flag $flag ; then 
+        if test_gcc_flag $flag ; then
            CFLAGS="$CFLAGS $flag"
            AC_MSG_RESULT([yes])
         else
            AC_MSG_RESULT([no])
         fi
-    done 
+    done
+fi
+
+AC_MSG_CHECKING([whether $CC knows __sync_bool_compare_and_swap()])
+AC_LANG_CONFTEST([int main() { int a = 4; __sync_bool_compare_and_swap(&a, 4, 5); }])
+$CC conftest.c $CFLAGS -o conftest > /dev/null 2> /dev/null
+ret=$?
+rm -f conftest.o conftest
+if test $ret -eq 0 ; then
+    AC_DEFINE([HAVE_ATOMIC_BUILTINS], 1, [Have __sync_bool_compare_and_swap() and friends.])
+    AC_MSG_RESULT([yes])
+else
+    AC_MSG_RESULT([no])
+fi
+
+AC_MSG_CHECKING([whether $CC knows __thread])
+AC_LANG_CONFTEST([static __thread int a = 6; int main() { a = 5; }])
+$CC conftest.c $CFLAGS -o conftest > /dev/null 2> /dev/null
+ret=$?
+rm -f conftest.o conftest
+if test $ret -eq 0 ; then
+    AC_DEFINE([HAVE_TLS_BUILTIN], 1, [Have __thread().])
+    AC_MSG_RESULT([yes])
+else
+    AC_MSG_RESULT([no])
+fi
+
+AC_MSG_CHECKING([whether $CC knows _Bool])
+AC_LANG_CONFTEST([int main() { _Bool b; }])
+$CC conftest.c $CFLAGS -o conftest > /dev/null 2> /dev/null
+ret=$?
+rm -f conftest.o conftest
+if test $ret -eq 0 ; then
+    AC_DEFINE([HAVE_STD_BOOL], 1, [Have _Bool.])
+    AC_MSG_RESULT([yes])
+else
+    AC_MSG_RESULT([no])
 fi
 
 #### 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_SUBST(LTDLINCL)
+AC_SUBST(LIBLTDL)
 AC_CONFIG_SUBDIRS(libltdl)
 
 if test "x$enable_ltdl_install" = "xno" && test "x$ac_cv_lib_ltdl_lt_dlinit" = "xno" ; then
@@ -149,9 +185,9 @@
 
 # POSIX
 AC_CHECK_HEADERS([arpa/inet.h glob.h grp.h netdb.h netinet/in.h \
-    netinet/in_systm.h netinet/tcp.h pwd.h sched.h \
+    netinet/in_systm.h netinet/tcp.h poll.h pwd.h sched.h \
     sys/mman.h sys/resource.h sys/select.h sys/socket.h sys/wait.h \
-    syslog.h])
+    syslog.h sys/dl.h dlfcn.h linux/sockios.h])
 AC_CHECK_HEADERS([netinet/ip.h], [], [],
 		 [#include <sys/types.h>
 		  #if HAVE_NETINET_IN_H
@@ -167,9 +203,6 @@
 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])
 
@@ -185,6 +218,8 @@
 
 # Other
 AC_CHECK_HEADERS([sys/ioctl.h])
+AC_CHECK_HEADERS([byteswap.h])
+AC_CHECK_HEADERS([sys/syscall.h])
 
 #### Typdefs, structures, etc. ####
 
@@ -235,13 +270,17 @@
 
 #### Check for functions ####
 
+# ISO
+AC_CHECK_FUNCS([lrintf strtof])
+
 # POSIX
 AC_FUNC_FORK
 AC_FUNC_GETGROUPS
 AC_FUNC_SELECT_ARGTYPES
-AC_CHECK_FUNCS([chmod chown getaddrinfo getgrgid_r getpwuid_r gettimeofday \
-    getuid inet_ntop inet_pton nanosleep pipe posix_memalign setpgid setsid \
-    shm_open sigaction sleep sysconf])
+AC_CHECK_FUNCS([chmod chown clock_gettime getaddrinfo getgrgid_r \
+    getpwuid_r gettimeofday getuid inet_ntop inet_pton mlock nanosleep \
+    pipe posix_fadvise posix_madvise posix_memalign setpgid setsid shm_open \
+    sigaction sleep sysconf])
 AC_CHECK_FUNCS([mkfifo], [HAVE_MKFIFO=1], [HAVE_MKFIFO=0])
 
 AM_CONDITIONAL(HAVE_MKFIFO, test "x$HAVE_MKFIFO" = "x1")
@@ -260,7 +299,22 @@
 
 # Non-standard
 
-AC_CHECK_FUNCS([setresuid setresgid setreuid setregid seteuid setegid])
+AC_CHECK_FUNCS([setresuid setresgid setreuid setregid seteuid setegid ppoll strsignal sig2str strtof_l])
+
+AC_MSG_CHECKING([for PTHREAD_PRIO_INHERIT])
+AC_LANG_CONFTEST([AC_LANG_SOURCE([[
+#include <pthread.h>
+int main() { int i = PTHREAD_PRIO_INHERIT; }]])])
+$PTHREAD_CC conftest.c $PTHREAD_CFLAGS $CFLAGS $PTHREAD_LIBS -o conftest > /dev/null 2> /dev/null
+ret=$?
+rm -f conftest.o conftest
+
+if test $ret -eq 0 ; then
+    AC_DEFINE([HAVE_PTHREAD_PRIO_INHERIT], 1, [Have PTHREAD_PRIO_INHERIT.])
+    AC_MSG_RESULT([yes])
+else
+    AC_MSG_RESULT([no])
+fi
 
 #### Large File-Support (LFS) ####
 
@@ -324,12 +378,6 @@
 
 PKG_PROG_PKG_CONFIG
 
-#### 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 ])
@@ -347,10 +395,45 @@
     LIBS="$LIBS -latomic_ops"
 fi
 
+#### Libsamplerate support (optional) ####
+
+AC_ARG_ENABLE([samplerate],
+    AC_HELP_STRING([--disable-samplerate], [Disable optional libsamplerate support]),
+        [
+            case "${enableval}" in
+                yes) samplerate=yes ;;
+                no) samplerate=no ;;
+                *) AC_MSG_ERROR(bad value ${enableval} for --disable-samplerate) ;;
+            esac
+        ],
+        [samplerate=auto])
+
+if test "x${samplerate}" != xno ; then
+    PKG_CHECK_MODULES(LIBSAMPLERATE, [ samplerate >= 0.1.0 ],
+        HAVE_LIBSAMPLERATE=1,
+        [
+            HAVE_LIBSAMPLERATE=0
+            if test "x$samplerate" = xyes ; then
+                AC_MSG_ERROR([*** Libsamplerate not found])
+            fi
+        ])
+else
+    HAVE_LIBSAMPLERATE=0
+fi
+
+if test "x${HAVE_LIBSAMPLERATE}" = x1 ; then
+   AC_DEFINE([HAVE_LIBSAMPLERATE], 1, [Have libsamplerate?])
+fi
+
+AC_SUBST(LIBSAMPLERATE_CFLAGS)
+AC_SUBST(LIBSAMPLERATE_LIBS)
+AC_SUBST(HAVE_LIBSAMPLERATE)
+AM_CONDITIONAL([HAVE_LIBSAMPLERATE], [test "x$HAVE_LIBSAMPLERATE" = x1])
+
 #### OSS support (optional) ####
 
-AC_ARG_ENABLE([oss], 
-    AC_HELP_STRING([--disable-oss], [Disable optional OSS support]), 
+AC_ARG_ENABLE([oss],
+    AC_HELP_STRING([--disable-oss], [Disable optional OSS support]),
         [
             case "${enableval}" in
                 yes) oss=yes ;;
@@ -382,8 +465,8 @@
 
 #### ALSA support (optional) ####
 
-AC_ARG_ENABLE([alsa], 
-    AC_HELP_STRING([--disable-alsa], [Disable optional ALSA support]), 
+AC_ARG_ENABLE([alsa],
+    AC_HELP_STRING([--disable-alsa], [Disable optional ALSA support]),
         [
             case "${enableval}" in
                 yes) alsa=yes ;;
@@ -410,14 +493,14 @@
 fi
 
 AC_SUBST(ASOUNDLIB_CFLAGS)
-AC_SUBST(ASOUNDLIB_LIBS) 
+AC_SUBST(ASOUNDLIB_LIBS)
 AC_SUBST(HAVE_ALSA)
 AM_CONDITIONAL([HAVE_ALSA], [test "x$HAVE_ALSA" = x1])
 
 #### Solaris audio support (optional) ####
 
-AC_ARG_ENABLE([solaris], 
-    AC_HELP_STRING([--disable-solaris], [Disable optional Solaris audio support]), 
+AC_ARG_ENABLE([solaris],
+    AC_HELP_STRING([--disable-solaris], [Disable optional Solaris audio support]),
         [
             case "${enableval}" in
                 yes) solaris=yes ;;
@@ -448,8 +531,8 @@
 
 #### GLib 2 support (optional) ####
 
-AC_ARG_ENABLE([glib2], 
-    AC_HELP_STRING([--disable-glib2], [Disable optional GLib 2 support]), 
+AC_ARG_ENABLE([glib2],
+    AC_HELP_STRING([--disable-glib2], [Disable optional GLib 2 support]),
         [
             case "${enableval}" in
                 yes) glib2=yes ;;
@@ -479,8 +562,8 @@
 
 #### GConf support (optional) ####
 
-AC_ARG_ENABLE([gconf], 
-    AC_HELP_STRING([--disable-gconf], [Disable optional GConf support]), 
+AC_ARG_ENABLE([gconf],
+    AC_HELP_STRING([--disable-gconf], [Disable optional GConf support]),
         [
             case "${enableval}" in
                 yes) gconf=yes ;;
@@ -510,8 +593,8 @@
 
 #### Avahi support (optional) ####
 
-AC_ARG_ENABLE([avahi], 
-    AC_HELP_STRING([--disable-avahi], [Disable optional Avahi support]), 
+AC_ARG_ENABLE([avahi],
+    AC_HELP_STRING([--disable-avahi], [Disable optional Avahi support]),
         [
             case "${enableval}" in
                 yes) avahi=yes ;;
@@ -547,8 +630,8 @@
 
 ### JACK (optional) ####
 
-AC_ARG_ENABLE([jack], 
-    AC_HELP_STRING([--disable-jack], [Disable optional JACK support]), 
+AC_ARG_ENABLE([jack],
+    AC_HELP_STRING([--disable-jack], [Disable optional JACK support]),
         [
             case "${enableval}" in
                 yes) jack=yes ;;
@@ -578,8 +661,8 @@
 
 #### Async DNS support (optional) ####
 
-AC_ARG_ENABLE([asyncns], 
-    AC_HELP_STRING([--disable-asyncns], [Disable optional Async DNS support]), 
+AC_ARG_ENABLE([asyncns],
+    AC_HELP_STRING([--disable-asyncns], [Disable optional Async DNS support]),
         [
             case "${enableval}" in
                 yes) asyncns=yes ;;
@@ -613,8 +696,8 @@
 
 #### TCP wrappers (optional) ####
 
-AC_ARG_ENABLE([tcpwrap], 
-    AC_HELP_STRING([--disable-tcpwrap], [Disable optional TCP wrappers support]), 
+AC_ARG_ENABLE([tcpwrap],
+    AC_HELP_STRING([--disable-tcpwrap], [Disable optional TCP wrappers support]),
         [
             case "${enableval}" in
                 yes) tcpwrap=yes ;;
@@ -637,8 +720,8 @@
 
 #### LIRC support (optional) ####
 
-AC_ARG_ENABLE([lirc], 
-    AC_HELP_STRING([--disable-lirc], [Disable optional LIRC support]), 
+AC_ARG_ENABLE([lirc],
+    AC_HELP_STRING([--disable-lirc], [Disable optional LIRC support]),
         [
             case "${enableval}" in
                 yes) lirc=yes ;;
@@ -663,8 +746,8 @@
 
 #### HAL support (optional) ####
 
-AC_ARG_ENABLE([hal], 
-    AC_HELP_STRING([--disable-hal], [Disable optional HAL support]), 
+AC_ARG_ENABLE([hal],
+    AC_HELP_STRING([--disable-hal], [Disable optional HAL support]),
         [
             case "${enableval}" in
                 yes) hal=yes ;;
@@ -673,7 +756,6 @@
             esac
         ],
         [hal=auto])
-
 if test "x${hal}" != xno -a \( "x$HAVE_OSS" = "x1" -o "x$HAVE_ALSA" = "x1" \) ; then
     PKG_CHECK_MODULES(HAL, [ hal >= 0.5.7 ],
         HAVE_HAL=1,
@@ -691,6 +773,49 @@
 AC_SUBST(HAL_LIBS)
 AC_SUBST(HAVE_HAL)
 AM_CONDITIONAL([HAVE_HAL], [test "x$HAVE_HAL" = x1])
+
+#### D-Bus support (optional) ####
+
+AC_ARG_ENABLE([dbus],
+    AC_HELP_STRING([--disable-dbus], [Disable optional D-Bus support]),
+        [
+            case "${enableval}" in
+                yes) dbus=yes ;;
+                no) dbus=no ;;
+                *) AC_MSG_ERROR(bad value ${enableval} for --disable-dbus) ;;
+            esac
+        ],
+        [dbus=auto])
+
+if test "x$HAVE_HAL" = x1 ; then
+   dbus=yes
+fi
+
+if test "x${dbus}" != xno ; then
+
+    PKG_CHECK_MODULES(DBUS, [ dbus-1 >= 1.0.0 ],
+        [
+            HAVE_DBUS=1
+            saved_LIBS="$LIBS"
+            LIBS="$LIBS $DBUS_LIBS"
+            AC_CHECK_FUNCS(dbus_watch_get_unix_fd)
+            LIBS="$saved_LIBS"
+            AC_DEFINE([HAVE_DBUS], 1, [Have D-Bus.])
+        ],
+        [
+            HAVE_DBUS=0
+            if test "x$dbus" = xyes ; then
+                AC_MSG_ERROR([*** D-Bus support not found])
+            fi
+        ])
+else
+    HAVE_DBUS=0
+fi
+
+AC_SUBST(DBUS_CFLAGS)
+AC_SUBST(DBUS_LIBS)
+AC_SUBST(HAVE_DBUS)
+AM_CONDITIONAL([HAVE_DBUS], [test "x$HAVE_DBUS" = x1])
 
 #### PulseAudio system group & user  #####
 
@@ -843,6 +968,11 @@
 ENABLE_TCPWRAP=no
 if test "x${LIBWRAP_LIBS}" != x ; then
    ENABLE_TCPWRAP=yes
+fi
+
+ENABLE_LIBSAMPLERATE=no
+if test "x${HAVE_LIBSAMPLERATE}" = "x1" ; then
+   ENABLE_LIBSAMPLERATE=yes
 fi
 
 echo "
@@ -866,6 +996,7 @@
     Enable LIRC:            ${ENABLE_LIRC}
     Enable HAL:             ${ENABLE_HAL}
     Enable TCP Wrappers:    ${ENABLE_TCPWRAP}
+    Enable libsamplerate:   ${ENABLE_LIBSAMPLERATE}
     System User:            ${PA_SYSTEM_USER}
     System Group:           ${PA_SYSTEM_GROUP}
     Realtime Group:         ${PA_REALTIME_GROUP}

Propchange: trunk/libltdl/
------------------------------------------------------------------------------
--- svn:ignore (added)
+++ svn:ignore Sun Oct 28 20:13:50 2007
@@ -1,0 +1,5 @@
+*.cache
+*.log
+*.status
+libtool
+Makefile

Modified: trunk/libltdl/config.h
URL: http://0pointer.de/cgi-bin/viewcvs.cgi/trunk/libltdl/config.h?rev=1971&root=pulseaudio&r1=1970&r2=1971&view=diff
==============================================================================
--- trunk/libltdl/config.h (original)
+++ trunk/libltdl/config.h Sun Oct 28 20:13:50 2007
@@ -2,22 +2,22 @@
 /* config-h.in.  Generated from configure.ac by autoheader.  */
 
 /* Define to 1 if you have the `argz_append' function. */
-/* #undef HAVE_ARGZ_APPEND */
+#define HAVE_ARGZ_APPEND 1
 
 /* Define to 1 if you have the `argz_create_sep' function. */
-/* #undef HAVE_ARGZ_CREATE_SEP */
+#define HAVE_ARGZ_CREATE_SEP 1
 
 /* Define to 1 if you have the <argz.h> header file. */
-/* #undef HAVE_ARGZ_H */
+#define HAVE_ARGZ_H 1
 
 /* Define to 1 if you have the `argz_insert' function. */
-/* #undef HAVE_ARGZ_INSERT */
+#define HAVE_ARGZ_INSERT 1
 
 /* Define to 1 if you have the `argz_next' function. */
-/* #undef HAVE_ARGZ_NEXT */
+#define HAVE_ARGZ_NEXT 1
 
 /* Define to 1 if you have the `argz_stringify' function. */
-/* #undef HAVE_ARGZ_STRINGIFY */
+#define HAVE_ARGZ_STRINGIFY 1
 
 /* Define to 1 if you have the <assert.h> header file. */
 #define HAVE_ASSERT_H 1
@@ -42,10 +42,10 @@
 /* #undef HAVE_DLD_H */
 
 /* Define to 1 if you have the `dlerror' function. */
-/* #undef HAVE_DLERROR */
+#define HAVE_DLERROR 1
 
 /* Define to 1 if you have the <dlfcn.h> header file. */
-/* #undef HAVE_DLFCN_H */
+#define HAVE_DLFCN_H 1
 
 /* Define to 1 if you have the <dl.h> header file. */
 /* #undef HAVE_DL_H */
@@ -57,7 +57,7 @@
 #define HAVE_ERRNO_H 1
 
 /* Define to 1 if the system has the type `error_t'. */
-/* #undef HAVE_ERROR_T */
+#define HAVE_ERROR_T 1
 
 /* Define to 1 if you have the `index' function. */
 /* #undef HAVE_INDEX */
@@ -66,7 +66,7 @@
 #define HAVE_INTTYPES_H 1
 
 /* Define if you have the libdl library or equivalent. */
-/* #undef HAVE_LIBDL */
+#define HAVE_LIBDL 1
 
 /* Define to 1 if you have the <mach-o/dyld.h> header file. */
 /* #undef HAVE_MACH_O_DYLD_H */
@@ -146,7 +146,7 @@
 #define HAVE_UNISTD_H 1
 
 /* Define if the OS needs help to load dependent libraries for dlopen(). */
-#define LTDL_DLOPEN_DEPLIBS 1
+/* #undef LTDL_DLOPEN_DEPLIBS */
 
 /* Define to the sub-directory in which libtool stores uninstalled libraries.
    */
@@ -154,13 +154,13 @@
 
 /* Define to the name of the environment variable that determines the dynamic
    library search path. */
-#define LTDL_SHLIBPATH_VAR "PATH"
+#define LTDL_SHLIBPATH_VAR "LD_LIBRARY_PATH"
 
 /* Define to the extension used for shared libraries, say, ".so". */
-#define LTDL_SHLIB_EXT ".dll"
+#define LTDL_SHLIB_EXT ".so"
 
 /* Define to the system default library search path. */
-#define LTDL_SYSSEARCHPATH "/lib:/usr/lib"
+#define LTDL_SYSSEARCHPATH "/lib:/usr/lib:/usr/lib/atlas:/usr/local/lib:/lib/i486-linux-gnu:/usr/lib/i486-linux-gnu:/usr/local/lib"
 
 /* Define if dlsym() requires a leading underscore in symbol names. */
 /* #undef NEED_USCORE */
@@ -187,7 +187,7 @@
 /* #undef const */
 
 /* Define to a type to use for `error_t' if it is not otherwise available. */
-#define error_t int
+/* #undef error_t */
 
 /* Define to `__inline__' or `__inline' if that's what the C compiler
    calls it, or to nothing if 'inline' is not supported under any name.  */

Modified: trunk/libltdl/ltdl.c
URL: http://0pointer.de/cgi-bin/viewcvs.cgi/trunk/libltdl/ltdl.c?rev=1971&root=pulseaudio&r1=1970&r2=1971&view=diff
==============================================================================
--- trunk/libltdl/ltdl.c (original)
+++ trunk/libltdl/ltdl.c Sun Oct 28 20:13:50 2007
@@ -134,7 +134,7 @@
 
 
 
-
+
 /* --- WINDOWS SUPPORT --- */
 
 /* DLL building support on win32 hosts;  mostly to workaround their
@@ -181,7 +181,7 @@
 
 #endif /* LT_USE_WINDOWS_DIRENT_EMULATION */
 
-
+
 /* --- MANIFEST CONSTANTS --- */
 
 
@@ -208,7 +208,7 @@
 
 
 
-
+
 /* --- MEMORY HANDLING --- */
 
 
@@ -258,7 +258,7 @@
 	if ((p) != (q)) { if (p) lt_dlfree (p); (p) = (q); (q) = 0; }	\
 						} LT_STMT_END
 
-
+
 /* --- REPLACEMENT FUNCTIONS --- */
 
 
@@ -804,7 +804,7 @@
 
 
 
-
+
 /* --- TYPE DEFINITIONS -- */
 
 
@@ -816,7 +816,7 @@
 
 
 
-
+
 /* --- OPAQUE STRUCTURES DECLARED IN LTDL.H --- */
 
 
@@ -880,7 +880,7 @@
 
 
 
-
+
 /* --- MUTEX LOCKING --- */
 
 
@@ -956,7 +956,7 @@
 
 
 
-
+
 /* --- ERROR HANDLING --- */
 
 
@@ -1052,7 +1052,7 @@
 
 
 
-
+
 /* --- DLOPEN() INTERFACE LOADER --- */
 
 
@@ -1158,7 +1158,7 @@
 #endif /* HAVE_LIBDL */
 
 
-
+
 /* --- SHL_LOAD() INTERFACE LOADER --- */
 
 #if HAVE_SHL_LOAD
@@ -1292,7 +1292,7 @@
 
 
 
-
+
 /* --- LOADLIBRARY() INTERFACE LOADER --- */
 
 #ifdef __WINDOWS__
@@ -1443,7 +1443,7 @@
 
 
 
-
+
 /* --- LOAD_ADD_ON() INTERFACE LOADER --- */
 
 
@@ -1523,7 +1523,7 @@
 
 
 
-
+
 /* --- DLD_LINK() INTERFACE LOADER --- */
 
 
@@ -1939,7 +1939,7 @@
 
 #endif /* HAVE_DYLD */
 
-
+
 /* --- DLPREOPEN() INTERFACE LOADER --- */
 
 
@@ -2132,7 +2132,7 @@
 
 
 
-
+
 /* --- DYNAMIC MODULE LOADING --- */
 
 
@@ -4162,7 +4162,7 @@
 
 
 
-
+
 /* --- MODULE INFORMATION --- */
 
 const lt_dlinfo *
@@ -4311,7 +4311,7 @@
 }
 
 
-
+
 /* --- USER MODULE LOADER API --- */
 
 

Modified: trunk/libltdl/ltdl.h
URL: http://0pointer.de/cgi-bin/viewcvs.cgi/trunk/libltdl/ltdl.h?rev=1971&root=pulseaudio&r1=1970&r2=1971&view=diff
==============================================================================
--- trunk/libltdl/ltdl.h (original)
+++ trunk/libltdl/ltdl.h Sun Oct 28 20:13:50 2007
@@ -30,7 +30,7 @@
 
 #include <sys/types.h>		/* for size_t declaration */
 
-
+
 /* --- MACROS FOR PORTABILITY --- */
 
 
@@ -89,7 +89,7 @@
 #define LT_STRLEN(s)	(((s) && (s)[0]) ? strlen (s) : 0)
 
 
-
+
 /* --- WINDOWS SUPPORT --- */
 
 
@@ -147,7 +147,7 @@
 #endif
 
 
-
+
 /* --- DYNAMIC MODULE LOADING API --- */
 
 
@@ -182,7 +182,7 @@
 
 
 
-
+
 /* --- MUTEX LOCKING --- */
 
 
@@ -198,7 +198,7 @@
 
 
 
-
+
 /* --- MEMORY HANDLING --- */
 
 
@@ -213,7 +213,7 @@
 
 
 
-
+
 /* --- PRELOADED MODULE SUPPORT --- */
 
 
@@ -235,7 +235,7 @@
 
 
 
-
+
 /* --- MODULE INFORMATION --- */
 
 
@@ -264,7 +264,7 @@
 						lt_dlhandle handle));
 
 
-
+
 /* --- USER MODULE LOADER API --- */
 
 
@@ -303,7 +303,7 @@
 						const char *loader_name));
 
 
-
+
 /* --- ERROR MESSAGE HANDLING --- */
 
 
@@ -347,7 +347,7 @@
 
 
 
-
+
 /* --- SOURCE COMPATIBILITY WITH OLD LIBLTDL --- */
 
 

Propchange: trunk/src/
------------------------------------------------------------------------------
--- svn:ignore (original)
+++ svn:ignore Sun Oct 28 20:13:50 2007
@@ -1,3 +1,11 @@
+smoother-test
+resampler-test
+sig2str-test
+rtpoll-test
+pasuspender
+queue-test
+asyncmsgq-test
+asyncq-test
 flist-test
 thread-test
 memblock-test

Modified: trunk/src/Makefile.am
URL: http://0pointer.de/cgi-bin/viewcvs.cgi/trunk/src/Makefile.am?rev=1971&root=pulseaudio&r1=1970&r2=1971&view=diff
==============================================================================
--- trunk/src/Makefile.am (original)
+++ trunk/src/Makefile.am Sun Oct 28 20:13:50 2007
@@ -30,6 +30,7 @@
 pulsecoreincludedir=$(includedir)/pulsecore
 pulseconfdir=$(sysconfdir)/pulse
 pulselibexecdir=$(libexecdir)/pulse
+xdgautostartdir=$(sysconfdir)/xdg/autostart
 
 ###################################
 #            Defines              #
@@ -76,15 +77,14 @@
 
 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
 
 ###################################
@@ -100,12 +100,18 @@
 		depmod.py \
 		daemon/esdcompat.in \
 		utils/padsp \
-		modules/module-defs.h.m4
+		modules/module-defs.h.m4 \
+		daemon/pulseaudio-module-xsmp.desktop
 
 pulseconf_DATA = \
 		default.pa \
 		daemon.conf \
 		client.conf
+
+if HAVE_X11
+xdgautostart_DATA = \
+		daemon/pulseaudio-module-xsmp.desktop
+endif
 
 BUILT_SOURCES = \
 		pulse/version.h
@@ -122,13 +128,13 @@
 		daemon/cpulimit.c daemon/cpulimit.h \
 		daemon/daemon-conf.c daemon/daemon-conf.h \
 		daemon/dumpmodules.c daemon/dumpmodules.h \
+		daemon/ltdl-bind-now.c daemon/ltdl-bind-now.h \
 		daemon/main.c \
 		pulsecore/gccmacro.h
 
-pulseaudio_CFLAGS = $(AM_CFLAGS) $(LIBOIL_CFLAGS)
+pulseaudio_CFLAGS = $(AM_CFLAGS) $(LIBOIL_CFLAGS) $(LIBSAMPLERATE_CFLAGS) $(LIBSNDFILE_CFLAGS) $(CAP_CFLAGS) $(LIBOIL_CFLAGS) $(DBUS_CFLAGS)
 pulseaudio_CPPFLAGS = $(AM_CPPFLAGS)
-pulseaudio_LDADD = $(AM_LDADD) libpulsecore.la $(LIBLTDL) \
-		$(LIBSAMPLERATE_LIBS) $(LIBSNDFILE_LIBS) $(CAP_LIBS) $(LIBOIL_LIBS)
+pulseaudio_LDADD = $(AM_LDADD) libpulsecore.la $(LIBLTDL) $(LIBSAMPLERATE_LIBS) $(LIBSNDFILE_LIBS) $(CAP_LIBS) $(LIBOIL_LIBS) $(DBUS_LIBS)
 # This is needed because automake doesn't properly expand the foreach below
 pulseaudio_DEPENDENCIES = libpulsecore.la $(PREOPEN_LIBS)
 
@@ -151,7 +157,8 @@
 bin_PROGRAMS += \
 		pacat \
 		pactl \
-		paplay
+		paplay \
+		pasuspender
 
 if HAVE_AF_UNIX
 bin_PROGRAMS += pacmd
@@ -181,6 +188,11 @@
 pactl_LDADD = $(AM_LDADD) libpulse.la $(LIBSNDFILE_LIBS)
 pactl_CFLAGS = $(AM_CFLAGS) $(LIBSNDFILE_CFLAGS)
 pactl_LDFLAGS = $(AM_LDFLAGS) $(BINLDFLAGS)
+
+pasuspender_SOURCES = utils/pasuspender.c
+pasuspender_LDADD = $(AM_LDADD) libpulse.la $(LIBSNDFILE_LIBS)
+pasuspender_CFLAGS = $(AM_CFLAGS) $(LIBSNDFILE_CFLAGS)
+pasuspender_LDFLAGS = $(AM_LDFLAGS) $(BINLDFLAGS)
 
 pacmd_SOURCES = utils/pacmd.c pulsecore/pid.c pulsecore/pid.h
 pacmd_CFLAGS = $(AM_CFLAGS)
@@ -219,7 +231,14 @@
 		hook-list-test \
 		memblock-test \
 		thread-test \
-		flist-test
+		flist-test \
+		asyncq-test \
+		asyncmsgq-test \
+		queue-test \
+		rtpoll-test \
+		sig2str-test \
+		resampler-test \
+		smoother-test
 
 if HAVE_SIGXCPU
 noinst_PROGRAMS += \
@@ -274,12 +293,30 @@
 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
+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
+asyncmsgq_test_CFLAGS = $(AM_CFLAGS)
+asyncmsgq_test_LDADD = $(AM_LDADD) libpulsecore.la
+asyncmsgq_test_LDFLAGS = $(AM_LDFLAGS) $(BINLDFLAGS)
+
+queue_test_SOURCES = tests/queue-test.c
+queue_test_CFLAGS = $(AM_CFLAGS)
+queue_test_LDADD = $(AM_LDADD) libpulsecore.la
+queue_test_LDFLAGS = $(AM_LDFLAGS) $(BINLDFLAGS)
+
+rtpoll_test_SOURCES = tests/rtpoll-test.c
+rtpoll_test_CFLAGS = $(AM_CFLAGS)
+rtpoll_test_LDADD = $(AM_LDADD) libpulsecore.la
+rtpoll_test_LDFLAGS = $(AM_LDFLAGS) $(BINLDFLAGS)
 
 mcalign_test_SOURCES = tests/mcalign-test.c
 mcalign_test_CFLAGS = $(AM_CFLAGS)
@@ -340,6 +377,21 @@
 interpol_test_LDADD = $(AM_LDADD) libpulse.la
 interpol_test_CFLAGS = $(AM_CFLAGS)
 interpol_test_LDFLAGS = $(AM_LDFLAGS) $(BINLDFLAGS)
+
+sig2str_test_SOURCES = tests/sig2str-test.c
+sig2str_test_LDADD = $(AM_LDADD) libpulsecore.la
+sig2str_test_CFLAGS = $(AM_CFLAGS)
+sig2str_test_LDFLAGS = $(AM_LDFLAGS) $(BINLDFLAGS)
+
+resampler_test_SOURCES = tests/resampler-test.c
+resampler_test_LDADD = $(AM_LDADD) libpulsecore.la
+resampler_test_CFLAGS = $(AM_CFLAGS) $(LIBOIL_CFLAGS)
+resampler_test_LDFLAGS = $(AM_LDFLAGS) $(BINLDFLAGS) $(LIBOIL_LIBS)
+
+smoother_test_SOURCES = tests/smoother-test.c
+smoother_test_LDADD = $(AM_LDADD) libpulsecore.la
+smoother_test_CFLAGS = $(AM_CFLAGS)
+smoother_test_LDFLAGS = $(AM_LDFLAGS) $(BINLDFLAGS)
 
 ###################################
 #         Client library          #
@@ -455,6 +507,10 @@
 		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 \
+		pulsecore/once.c pulsecore/once.h \
 		$(PA_THREAD_OBJS)
 
 if OS_IS_WIN32
@@ -515,10 +571,26 @@
 libpulsedsp_la_LDFLAGS = -avoid-version
 
 ###################################
+#      Speex Resampler            #
+###################################
+
+noinst_LTLIBRARIES = libspeex-resampler-fixed.la libspeex-resampler-float.la libffmpeg-resampler.la
+
+libspeex_resampler_fixed_la_CPPFLAGS = $(AM_CPPFLAGS) -DRANDOM_PREFIX=paspfx -DOUTSIDE_SPEEX -DFIXED_POINT
+libspeex_resampler_fixed_la_SOURCES = pulsecore/speex/resample.c pulsecore/speex/speex_resampler.h pulsecore/speex/arch.h pulsecore/speex/fixed_generic.h pulsecore/speexwrap.h
+
+libspeex_resampler_float_la_CPPFLAGS = $(AM_CPPFLAGS) -DRANDOM_PREFIX=paspfl -DOUTSIDE_SPEEX
+libspeex_resampler_float_la_SOURCES = pulsecore/speex/resample.c pulsecore/speex/speex_resampler.h pulsecore/speex/arch.h
+
+libffmpeg_resampler_la_CPPFLAGS = $(AM_CPPFLAGS)
+libffmpeg_resampler_la_SOURCES = pulsecore/ffmpeg/resample2.c pulsecore/ffmpeg/avcodec.h pulsecore/ffmpeg/dsputil.h
+
+###################################
 #      Daemon core library        #
 ###################################
 
-pulsecoreinclude_HEADERS = \
+#pulsecoreinclude_HEADERS =
+noinst_HEADERS = \
 		pulsecore/autoload.h \
 		pulsecore/atomic.h \
 		pulsecore/cli-command.h \
@@ -567,6 +639,7 @@
 		pulsecore/refcnt.h \
 		pulsecore/mutex.h \
 		pulsecore/thread.h \
+		pulsecore/semaphore.h \
 		pulsecore/once.h
 
 lib_LTLIBRARIES += libpulsecore.la
@@ -608,6 +681,7 @@
 		pulsecore/memchunk.c pulsecore/memchunk.h \
 		pulsecore/modargs.c pulsecore/modargs.h \
 		pulsecore/modinfo.c pulsecore/modinfo.h \
+		pulsecore/ltdl-helper.c pulsecore/ltdl-helper.h \
 		pulsecore/module.c pulsecore/module.h \
 		pulsecore/namereg.c pulsecore/namereg.h \
 		pulsecore/pid.c pulsecore/pid.h \
@@ -636,6 +710,19 @@
 		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/asyncmsgq.c pulsecore/asyncmsgq.h \
+		pulsecore/asyncq.c pulsecore/asyncq.h \
+		pulsecore/thread-mq.c pulsecore/thread-mq.h \
+		pulsecore/fdsem.c pulsecore/fdsem.h \
+		pulsecore/object.c pulsecore/object.h \
+		pulsecore/msgobject.c pulsecore/msgobject.h \
+		pulsecore/rtsig.c pulsecore/rtsig.h \
+		pulsecore/rtpoll.c pulsecore/rtpoll.h \
+		pulsecore/rtclock.c pulsecore/rtclock.h \
+		pulsecore/macro.h \
+		pulsecore/once.c pulsecore/once.h \
+		pulsecore/time-smoother.c pulsecore/time-smoother.h \
 		$(PA_THREAD_OBJS)
 
 if OS_IS_WIN32
@@ -645,13 +732,14 @@
 
 libpulsecore_la_CPPFLAGS = $(AM_CPPFLAGS) $(LIBOIL_CFLAGS)
 libpulsecore_la_LDFLAGS = -version-info $(LIBPULSECORE_VERSION_INFO)
-libpulsecore_la_LIBADD = $(AM_LIBADD) $(LIBLTDL) $(LIBSAMPLERATE_LIBS) $(LIBSNDFILE_LIBS) $(WINSOCK_LIBS) $(LIBOIL_LIBS) $(LIBICONV)
+libpulsecore_la_LIBADD = $(AM_LIBADD) $(LIBLTDL) $(LIBSAMPLERATE_LIBS) $(LIBSNDFILE_LIBS) $(WINSOCK_LIBS) $(LIBOIL_LIBS) $(LIBICONV) libspeex-resampler-fixed.la libspeex-resampler-float.la libffmpeg-resampler.la
 
 ###################################
 #   Plug-in support libraries     #
 ###################################
 
-pulsecoreinclude_HEADERS += \
+#pulsecoreinclude_HEADERS +=
+noinst_HEADERS += \
 		pulsecore/socket-util.h \
 		pulsecore/iochannel.h \
 		pulsecore/socket-server.h \
@@ -700,9 +788,9 @@
 		libauthkey-prop.la \
 		libstrlist.la \
 		libprotocol-simple.la \
-		libprotocol-esound.la \
+		libprotocol-http.la \
 		libprotocol-native.la \
-		libprotocol-http.la
+		libprotocol-esound.la
 
 # We need to emulate sendmsg/recvmsg to support this on Win32
 if !OS_IS_WIN32
@@ -711,7 +799,8 @@
 endif
 
 if HAVE_X11
-pulsecoreinclude_HEADERS += \
+#pulsecoreinclude_HEADERS +=
+noinst_HEADERS += \
 		pulsecore/x11wrap.h \
 		pulsecore/x11prop.h
 
@@ -721,7 +810,8 @@
 endif
 
 if HAVE_AVAHI
-pulsecoreinclude_HEADERS += \
+#pulsecoreinclude_HEADERS +=
+noinst_HEADERS += \
 		pulsecore/avahi-wrap.h
 
 modlibexec_LTLIBRARIES += \
@@ -851,19 +941,23 @@
 		module-cli.la \
 		module-cli-protocol-tcp.la \
 		module-simple-protocol-tcp.la \
-		module-esound-protocol-tcp.la \
+		module-null-sink.la \
+		module-detect.la \
+		module-volume-restore.la \
+		module-default-device-restore.la \
+		module-rescue-streams.la \
+		module-suspend-on-idle.la \
+		module-http-protocol-tcp.la \
+		module-sine.la \
 		module-native-protocol-tcp.la \
 		module-native-protocol-fd.la \
-		module-sine.la \
+		module-esound-protocol-tcp.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-remap-sink.la \
+		module-ladspa-sink.la \
+		module-esound-sink.la
+#		module-tunnel-sink.la
+#		module-tunnel-source.la
 
 # See comment at librtp.la above
 if !OS_IS_WIN32
@@ -876,9 +970,9 @@
 modlibexec_LTLIBRARIES += \
 		module-cli-protocol-unix.la \
 		module-simple-protocol-unix.la \
-		module-esound-protocol-unix.la \
+		module-http-protocol-unix.la \
 		module-native-protocol-unix.la \
-		module-http-protocol-unix.la
+		module-esound-protocol-unix.la
 endif
 
 if HAVE_MKFIFO
@@ -901,14 +995,14 @@
 if HAVE_X11
 modlibexec_LTLIBRARIES += \
 		module-x11-bell.la \
-		module-x11-publish.la
+		module-x11-publish.la \
+		module-x11-xsmp.la
 endif
 
 if HAVE_OSS
 modlibexec_LTLIBRARIES += \
 		liboss-util.la \
-		module-oss.la \
-		module-oss-mmap.la
+		module-oss.la
 endif
 
 if HAVE_ALSA
@@ -952,10 +1046,10 @@
 		gconf-helper
 endif
 
-if OS_IS_WIN32
-modlibexec_LTLIBRARIES += \
-		module-waveout.la
-endif
+#if OS_IS_WIN32
+#modlibexec_LTLIBRARIES += \
+#		module-waveout.la
+#endif
 
 if HAVE_HAL
 modlibexec_LTLIBRARIES += \
@@ -980,6 +1074,8 @@
 		modules/module-native-protocol-fd-symdef.h \
 		modules/module-sine-symdef.h \
 		modules/module-combine-symdef.h \
+		modules/module-remap-sink-symdef.h \
+		modules/module-ladspa-sink-symdef.h \
 		modules/module-esound-compat-spawnfd-symdef.h \
 		modules/module-esound-compat-spawnpid-symdef.h \
 		modules/module-match-symdef.h \
@@ -994,8 +1090,8 @@
 		modules/module-http-protocol-unix-symdef.h \
 		modules/module-x11-bell-symdef.h \
 		modules/module-x11-publish-symdef.h \
+		modules/module-x11-xsmp-symdef.h \
 		modules/module-oss-symdef.h \
-		modules/module-oss-mmap-symdef.h \
 		modules/module-alsa-sink-symdef.h \
 		modules/module-alsa-source-symdef.h \
 		modules/module-solaris-symdef.h \
@@ -1006,7 +1102,9 @@
 		modules/module-jack-sink-symdef.h \
 		modules/module-jack-source-symdef.h \
 		modules/module-volume-restore-symdef.h \
+		modules/module-default-device-restore-symdef.h \
 		modules/module-rescue-streams-symdef.h \
+		modules/module-suspend-on-idle-symdef.h \
 		modules/module-hal-detect-symdef.h \
 		modules/gconf/module-gconf-symdef.h
 
@@ -1126,18 +1224,27 @@
 module_combine_la_LDFLAGS = -module -avoid-version
 module_combine_la_LIBADD = $(AM_LIBADD) libpulsecore.la
 
+module_remap_sink_la_SOURCES = modules/module-remap-sink.c
+module_remap_sink_la_LDFLAGS = -module -avoid-version
+module_remap_sink_la_LIBADD = $(AM_LIBADD) libpulsecore.la
+
+module_ladspa_sink_la_SOURCES = modules/module-ladspa-sink.c modules/ladspa.h
+module_ladspa_sink_la_CFLAGS = -DLADSPA_PATH=\"$(libdir)/ladspa:/usr/local/lib/ladspa:/usr/lib/ladspa\" $(AM_CFLAGS)
+module_ladspa_sink_la_LDFLAGS = -module -avoid-version
+module_ladspa_sink_la_LIBADD = $(AM_LIBADD) $(LIBLTDL) 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_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_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
 
 # X11
 
@@ -1151,6 +1258,11 @@
 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 libpulsecore.la
 
+module_x11_xsmp_la_SOURCES = modules/module-x11-xsmp.c
+module_x11_xsmp_la_CFLAGS = $(AM_CFLAGS) $(X_CFLAGS)
+module_x11_xsmp_la_LDFLAGS = -module -avoid-version
+module_x11_xsmp_la_LIBADD = $(AM_LIBADD) $(X_PRE_LIBS) -lX11 $(X_LIBS) $(X_EXTRA_LIBS) libpulsecore.la
+
 # OSS
 
 liboss_util_la_SOURCES = modules/oss-util.c modules/oss-util.h
@@ -1160,10 +1272,6 @@
 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 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
 
@@ -1211,10 +1319,10 @@
 
 # Windows waveout
 
-module_waveout_la_SOURCES = modules/module-waveout.c
-module_waveout_la_LDFLAGS = -module -avoid-version
-module_waveout_la_LIBADD = $(AM_LIBADD) libpulsecore.la -lwinmm
-module_waveout_la_CFLAGS = $(AM_CFLAGS)
+#module_waveout_la_SOURCES = modules/module-waveout.c
+#module_waveout_la_LDFLAGS = -module -avoid-version
+#module_waveout_la_LIBADD = $(AM_LIBADD) libpulsecore.la -lwinmm
+#module_waveout_la_CFLAGS = $(AM_CFLAGS)
 
 # Hardware autodetection module
 module_detect_la_SOURCES = modules/module-detect.c
@@ -1228,16 +1336,28 @@
 module_volume_restore_la_LIBADD = $(AM_LIBADD) libpulsecore.la
 module_volume_restore_la_CFLAGS = $(AM_CFLAGS)
 
+# Default sink/source restore module
+module_default_device_restore_la_SOURCES = modules/module-default-device-restore.c
+module_default_device_restore_la_LDFLAGS = -module -avoid-version
+module_default_device_restore_la_LIBADD = $(AM_LIBADD) libpulsecore.la
+module_default_device_restore_la_CFLAGS = $(AM_CFLAGS)
+
 # Rescue streams module
 module_rescue_streams_la_SOURCES = modules/module-rescue-streams.c
 module_rescue_streams_la_LDFLAGS = -module -avoid-version
 module_rescue_streams_la_LIBADD = $(AM_LIBADD) libpulsecore.la
 module_rescue_streams_la_CFLAGS = $(AM_CFLAGS)
 
+# Suspend-on-idle module
+module_suspend_on_idle_la_SOURCES = modules/module-suspend-on-idle.c
+module_suspend_on_idle_la_LDFLAGS = -module -avoid-version
+module_suspend_on_idle_la_LIBADD = $(AM_LIBADD) libpulsecore.la
+module_suspend_on_idle_la_CFLAGS = $(AM_CFLAGS)
+
 # RTP modules
 module_rtp_send_la_SOURCES = modules/rtp/module-rtp-send.c
 module_rtp_send_la_LDFLAGS = -module -avoid-version
-module_rtp_send_la_LIBADD = $(AM_LIBADD) libpulsecore.la librtp.la
+module_rtp_send_la_LIBADD = $(AM_LIBADD) libpulsecore.la librtp.la libsocket-util.la
 module_rtp_send_la_CFLAGS = $(AM_CFLAGS)
 
 module_rtp_recv_la_SOURCES = modules/rtp/module-rtp-recv.c
@@ -1275,7 +1395,7 @@
 module_gconf_la_CFLAGS = $(AM_CFLAGS) -DPA_GCONF_HELPER=\"$(pulselibexecdir)/gconf-helper\"
 
 gconf_helper_SOURCES = modules/gconf/gconf-helper.c
-gconf_helper_LDADD = $(AM_LDADD) $(GCONF_LIBS)
+gconf_helper_LDADD = $(AM_LDADD) $(GCONF_LIBS) libpulsecore.la
 gconf_helper_CFLAGS = $(AM_CFLAGS) $(GCONF_CFLAGS)
 gconf_helper_LDFLAGS = $(AM_LDFLAGS) $(BINLDFLAGS)
 
@@ -1304,8 +1424,8 @@
 else
 default.pa: daemon/default.pa.in Makefile
 	sed -e 's, at PA_BINARY\@,$(PA_BINARY),g' \
-	    -e 's, at HAVE_HAL_TRUE\@, at HAVE_HAL_TRUE@,g' \
-	    -e 's, at HAVE_HAL_FALSE\@, at HAVE_HAL_FALSE@,g' < $< > $@
+            -e 's, at PA_DLSEARCHPATH\@,$(modlibexecdir),g' \
+	    -e 's, at PA_SOEXT\@,.so,g' < $< > $@
 endif
 
 daemon.conf: daemon/daemon.conf.in Makefile
@@ -1323,4 +1443,13 @@
 massif: pulseaudio
 	libtool --mode=execute valgrind --tool=massif --depth=6  --alloc-fn=pa_xmalloc --alloc-fn=pa_xmalloc0 --alloc-fn=pa_xrealloc --alloc-fn=dbus_realloc --alloc-fn=pa_xnew0_internal --alloc-fn=pa_xnew_internal ./pulseaudio
 
+update-speex:
+	wget -O pulsecore/speex/speex_resampler.h http://svn.xiph.org/trunk/speex/include/speex/speex_resampler.h
+	wget -O pulsecore/speex/resample.c http://svn.xiph.org/trunk/speex/libspeex/resample.c
+	wget -O pulsecore/speex/arch.h http://svn.xiph.org/trunk/speex/libspeex/arch.h
+	wget -O pulsecore/speex/fixed_generic.h http://svn.xiph.org/trunk/speex/libspeex/fixed_generic.h
+
+update-ffmpeg:
+	wget -O pulsecore/ffmpeg/resample2.c http://svn.mplayerhq.hu/ffmpeg/trunk/libavcodec/resample2.c?view=co
+
 .PHONY: utils/padsp

Modified: trunk/src/daemon/caps.c
URL: http://0pointer.de/cgi-bin/viewcvs.cgi/trunk/src/daemon/caps.c?rev=1971&root=pulseaudio&r1=1970&r2=1971&view=diff
==============================================================================
--- trunk/src/daemon/caps.c (original)
+++ trunk/src/daemon/caps.c Sun Oct 28 20:13:50 2007
@@ -26,11 +26,11 @@
 #include <config.h>
 #endif
 
-#include <assert.h>
 #include <unistd.h>
 #include <errno.h>
 #include <string.h>
 #include <sys/types.h>
+#include <pulsecore/macro.h>
 
 #ifdef HAVE_SYS_CAPABILITY_H
 #include <sys/capability.h>
@@ -60,7 +60,7 @@
     if (uid == 0 || geteuid() != 0)
         return;
 
-    pa_log_info("dropping root rights.");
+    pa_log_info("Dropping root priviliges.");
 
 #if defined(HAVE_SETRESUID)
     setresuid(uid, uid, uid);
@@ -88,8 +88,9 @@
     cap_value_t nice_cap = CAP_SYS_NICE;
 
     caps = cap_init();
-    assert(caps);
+    pa_assert(caps);
     cap_clear(caps);
+    cap_set_flag(caps, CAP_EFFECTIVE, 1, &nice_cap, CAP_SET);
     cap_set_flag(caps, CAP_PERMITTED, 1, &nice_cap, CAP_SET);
 
     if (cap_set_proc(caps) < 0)
@@ -98,7 +99,7 @@
     if (prctl(PR_SET_KEEPCAPS, 1, 0, 0, 0) < 0)
         goto fail;
 
-    pa_log_info("dropped capabilities successfully.");
+    pa_log_info("Dropped capabilities successfully.");
 
     r = 1;
 
@@ -114,14 +115,14 @@
     int r = -1;
 
     caps = cap_init();
-    assert(caps);
+    pa_assert(caps);
 
     cap_clear(caps);
 
     prctl(PR_SET_KEEPCAPS, 0, 0, 0, 0);
 
     if (cap_set_proc(caps) < 0) {
-        pa_log("failed to drop capabilities: %s", pa_cstrerror(errno));
+        pa_log("Failed to drop capabilities: %s", pa_cstrerror(errno));
         goto fail;
     }
 

Modified: trunk/src/daemon/cmdline.c
URL: http://0pointer.de/cgi-bin/viewcvs.cgi/trunk/src/daemon/cmdline.c?rev=1971&root=pulseaudio&r1=1970&r2=1971&view=diff
==============================================================================
--- trunk/src/daemon/cmdline.c (original)
+++ trunk/src/daemon/cmdline.c Sun Oct 28 20:13:50 2007
@@ -26,7 +26,6 @@
 #endif
 
 #include <string.h>
-#include <assert.h>
 #include <stdlib.h>
 #include <stdio.h>
 #include <getopt.h>
@@ -36,6 +35,7 @@
 
 #include <pulsecore/core-util.h>
 #include <pulsecore/strbuf.h>
+#include <pulsecore/macro.h>
 
 #include "cmdline.h"
 
@@ -63,7 +63,9 @@
     ARG_CHECK,
     ARG_NO_CPU_LIMIT,
     ARG_DISABLE_SHM,
-    ARG_SYSTEM
+    ARG_DUMP_RESAMPLE_METHODS,
+    ARG_SYSTEM,
+    ARG_CLEANUP_SHM
 };
 
 /* Tabel for getopt_long() */
@@ -92,11 +94,15 @@
     {"system",                      2, 0, ARG_SYSTEM},
     {"no-cpu-limit",                2, 0, ARG_NO_CPU_LIMIT},
     {"disable-shm",                 2, 0, ARG_DISABLE_SHM},
+    {"dump-resample-methods",       2, 0, ARG_DUMP_RESAMPLE_METHODS},
+    {"cleanup-shm",                 2, 0, ARG_CLEANUP_SHM},
     {NULL, 0, 0, 0}
 };
 
 void pa_cmdline_help(const char *argv0) {
     const char *e;
+
+    pa_assert(argv0);
 
     if ((e = strrchr(argv0, '/')))
         e++;
@@ -109,6 +115,8 @@
            "      --version                         Show version\n"
            "      --dump-conf                       Dump default configuration\n"
            "      --dump-modules                    Dump list of available modules\n"
+           "      --dump-resample-methods           Dump available resample methods\n"
+           "      --cleanup-shm                     Cleanup stale shared memory segments\n"
            "  -k  --kill                            Kill a running daemon\n"
            "      --check                           Check for a running daemon\n\n"
 
@@ -131,9 +139,8 @@
            "  -p, --dl-search-path=PATH             Set the search path for dynamic shared\n"
            "                                        objects (plugins)\n"
            "      --resample-method=[METHOD]        Use the specified resampling method\n"
-           "                                        (one of src-sinc-medium-quality,\n"
-           "                                        src-sinc-best-quality,src-sinc-fastest\n"
-           "                                        src-zero-order-hold,src-linear,trivial)\n"
+           "                                        (See --dump-resample-methods for\n"
+           "                                        possible values)\n"
            "      --use-pid-file[=BOOL]             Create a PID file\n"
            "      --no-cpu-limit[=BOOL]             Do not install CPU load limiter on\n"
            "                                        platforms that support it.\n"
@@ -152,7 +159,10 @@
 int pa_cmdline_parse(pa_daemon_conf *conf, int argc, char *const argv [], int *d) {
     pa_strbuf *buf = NULL;
     int c;
-    assert(conf && argc && argv);
+
+    pa_assert(conf);
+    pa_assert(argc > 0);
+    pa_assert(argv);
 
     buf = pa_strbuf_new();
 
@@ -178,6 +188,14 @@
                 conf->cmd = PA_CMD_DUMP_MODULES;
                 break;
 
+            case ARG_DUMP_RESAMPLE_METHODS:
+                conf->cmd = PA_CMD_DUMP_RESAMPLE_METHODS;
+                break;
+
+            case ARG_CLEANUP_SHM:
+                conf->cmd = PA_CMD_CLEANUP_SHM;
+                break;
+
             case 'k':
             case ARG_KILL:
                 conf->cmd = PA_CMD_KILL;
@@ -193,9 +211,12 @@
                 break;
 
             case ARG_FILE:
-            case 'F':
-                pa_strbuf_printf(buf, ".include %s\n", optarg);
-                break;
+            case 'F': {
+                char *p;
+                pa_strbuf_printf(buf, ".include %s\n", p = pa_make_path_absolute(optarg));
+                pa_xfree(p);
+                break;
+            }
 
             case 'C':
                 pa_strbuf_puts(buf, "load-module module-cli exit_on_eof=1\n");

Modified: trunk/src/daemon/cpulimit.c
URL: http://0pointer.de/cgi-bin/viewcvs.cgi/trunk/src/daemon/cpulimit.c?rev=1971&root=pulseaudio&r1=1970&r2=1971&view=diff
==============================================================================
--- trunk/src/daemon/cpulimit.c (original)
+++ trunk/src/daemon/cpulimit.c Sun Oct 28 20:13:50 2007
@@ -30,6 +30,7 @@
 #include <pulsecore/core-util.h>
 #include <pulsecore/core-error.h>
 #include <pulsecore/log.h>
+#include <pulsecore/macro.h>
 
 #include "cpulimit.h"
 
@@ -38,7 +39,6 @@
 #include <errno.h>
 #include <stdio.h>
 #include <string.h>
-#include <assert.h>
 #include <sys/time.h>
 #include <unistd.h>
 #include <signal.h>
@@ -92,23 +92,18 @@
 
 /* Reset the SIGXCPU timer to the next t seconds */
 static void reset_cpu_time(int t) {
-    int r;
     long n;
     struct rlimit rl;
     struct rusage ru;
 
     /* Get the current CPU time of the current process */
-    r = getrusage(RUSAGE_SELF, &ru);
-    assert(r >= 0);
+    pa_assert_se(getrusage(RUSAGE_SELF, &ru) >= 0);
 
     n = ru.ru_utime.tv_sec + ru.ru_stime.tv_sec + t;
-
-    r = getrlimit(RLIMIT_CPU, &rl);
-    assert(r >= 0);
+    pa_assert_se(getrlimit(RLIMIT_CPU, &rl) >= 0);
 
     rl.rlim_cur = n;
-    r = setrlimit(RLIMIT_CPU, &rl);
-    assert(r >= 0);
+    pa_assert_se(setrlimit(RLIMIT_CPU, &rl) >= 0);
 }
 
 /* A simple, thread-safe puts() work-alike */
@@ -118,7 +113,7 @@
 
 /* The signal handler, called on every SIGXCPU */
 static void signal_handler(int sig) {
-    assert(sig == SIGXCPU);
+    pa_assert(sig == SIGXCPU);
 
     if (phase == PHASE_IDLE) {
         time_t now;
@@ -130,7 +125,7 @@
         time(&now);
 
 #ifdef PRINT_CPU_LOAD
-        snprintf(t, sizeof(t), "Using %0.1f%% CPU\n", (double)CPUTIME_INTERVAL_SOFT/(now-last_time)*100);
+        pa_snprintf(t, sizeof(t), "Using %0.1f%% CPU\n", (double)CPUTIME_INTERVAL_SOFT/(now-last_time)*100);
         write_err(t);
 #endif
 
@@ -160,7 +155,12 @@
 /* Callback for IO events on the FIFO */
 static void callback(pa_mainloop_api*m, pa_io_event*e, int fd, pa_io_event_flags_t f, void *userdata) {
     char c;
-    assert(m && e && f == PA_IO_EVENT_INPUT && e == io_event && fd == the_pipe[0]);
+    pa_assert(m);
+    pa_assert(e);
+    pa_assert(f == PA_IO_EVENT_INPUT);
+    pa_assert(e == io_event);
+    pa_assert(fd == the_pipe[0]);
+
     pa_read(the_pipe[0], &c, sizeof(c), NULL);
     m->quit(m, 1); /* Quit the main loop */
 }
@@ -168,7 +168,13 @@
 /* Initializes CPU load limiter */
 int pa_cpu_limit_init(pa_mainloop_api *m) {
     struct sigaction sa;
-    assert(m && !api && !io_event && the_pipe[0] == -1 && the_pipe[1] == -1 && !installed);
+
+    pa_assert(m);
+    pa_assert(!api);
+    pa_assert(!io_event);
+    pa_assert(the_pipe[0] == -1);
+    pa_assert(the_pipe[1] == -1);
+    pa_assert(!installed);
 
     time(&last_time);
 
@@ -178,10 +184,10 @@
         return -1;
     }
 
-    pa_make_nonblock_fd(the_pipe[0]);
-    pa_make_nonblock_fd(the_pipe[1]);
-    pa_fd_set_cloexec(the_pipe[0], 1);
-    pa_fd_set_cloexec(the_pipe[1], 1);
+    pa_make_fd_nonblock(the_pipe[0]);
+    pa_make_fd_nonblock(the_pipe[1]);
+    pa_make_fd_cloexec(the_pipe[0]);
+    pa_make_fd_cloexec(the_pipe[1]);
 
     api = m;
     io_event = api->io_new(m, the_pipe[0], PA_IO_EVENT_INPUT, callback, NULL);
@@ -208,24 +214,18 @@
 
 /* Shutdown CPU load limiter */
 void pa_cpu_limit_done(void) {
-    int r;
 
     if (io_event) {
-        assert(api);
+        pa_assert(api);
         api->io_free(io_event);
         io_event = NULL;
         api = NULL;
     }
 
-    if (the_pipe[0] >= 0)
-        close(the_pipe[0]);
-    if (the_pipe[1] >= 0)
-        close(the_pipe[1]);
-    the_pipe[0] = the_pipe[1] = -1;
+    pa_close_pipe(the_pipe);
 
     if (installed) {
-        r = sigaction(SIGXCPU, &sigaction_prev, NULL);
-        assert(r >= 0);
+        pa_assert_se(sigaction(SIGXCPU, &sigaction_prev, NULL) >= 0);
         installed = 0;
     }
 }

Modified: trunk/src/daemon/daemon-conf.c
URL: http://0pointer.de/cgi-bin/viewcvs.cgi/trunk/src/daemon/daemon-conf.c?rev=1971&root=pulseaudio&r1=1970&r2=1971&view=diff
==============================================================================
--- trunk/src/daemon/daemon-conf.c (original)
+++ trunk/src/daemon/daemon-conf.c Sun Oct 28 20:13:50 2007
@@ -29,7 +29,6 @@
 #include <errno.h>
 #include <stdio.h>
 #include <string.h>
-#include <assert.h>
 #include <unistd.h>
 
 #include <pulse/xmalloc.h>
@@ -39,19 +38,14 @@
 #include <pulsecore/strbuf.h>
 #include <pulsecore/conf-parser.h>
 #include <pulsecore/resampler.h>
+#include <pulsecore/macro.h>
 
 #include "daemon-conf.h"
 
-#ifndef OS_IS_WIN32
-# define PATH_SEP "/"
-#else
-# define PATH_SEP "\\"
-#endif
-
-#define DEFAULT_SCRIPT_FILE PA_DEFAULT_CONFIG_DIR PATH_SEP "default.pa"
-#define DEFAULT_SCRIPT_FILE_USER PATH_SEP "default.pa"
-#define DEFAULT_CONFIG_FILE PA_DEFAULT_CONFIG_DIR PATH_SEP "daemon.conf"
-#define DEFAULT_CONFIG_FILE_USER PATH_SEP "daemon.conf"
+#define DEFAULT_SCRIPT_FILE PA_DEFAULT_CONFIG_DIR PA_PATH_SEP "default.pa"
+#define DEFAULT_SCRIPT_FILE_USER PA_PATH_SEP "default.pa"
+#define DEFAULT_CONFIG_FILE PA_DEFAULT_CONFIG_DIR PA_PATH_SEP "daemon.conf"
+#define DEFAULT_CONFIG_FILE_USER PA_PATH_SEP "daemon.conf"
 
 #define ENV_SCRIPT_FILE "PULSE_SCRIPT"
 #define ENV_CONFIG_FILE "PULSE_CONFIG"
@@ -72,31 +66,34 @@
     .default_script_file = NULL,
     .log_target = PA_LOG_SYSLOG,
     .log_level = PA_LOG_NOTICE,
-    .resample_method = PA_RESAMPLER_SRC_SINC_FASTEST,
+    .resample_method = PA_RESAMPLER_AUTO,
     .config_file = NULL,
     .use_pid_file = 1,
     .system_instance = 0,
     .no_cpu_limit = 0,
-    .disable_shm = 0
+    .disable_shm = 0,
+    .default_n_fragments = 4,
+    .default_fragment_size_msec = 25,
+    .default_sample_spec = { .format = PA_SAMPLE_S16NE, .rate = 44100, .channels = 2 }
 #ifdef HAVE_SYS_RESOURCE_H
     , .rlimit_as = { .value = 0, .is_set = 0 },
     .rlimit_core = { .value = 0, .is_set = 0 },
     .rlimit_data = { .value = 0, .is_set = 0 },
     .rlimit_fsize = { .value = 0, .is_set = 0 },
-    .rlimit_nofile = { .value = 200, .is_set = 1 },
+    .rlimit_nofile = { .value = 256, .is_set = 1 },
     .rlimit_stack = { .value = 0, .is_set = 0 }
 #ifdef RLIMIT_NPROC
     , .rlimit_nproc = { .value = 0, .is_set = 0 }
 #endif
 #ifdef RLIMIT_MEMLOCK
-    , .rlimit_memlock = { .value = 0, .is_set = 1 }
+    , .rlimit_memlock = { .value = 16384, .is_set = 1 }
 #endif
 #endif
 };
 
 pa_daemon_conf* pa_daemon_conf_new(void) {
     FILE *f;
-    pa_daemon_conf *c = pa_xmemdup(&default_conf, sizeof(default_conf));
+    pa_daemon_conf *c = pa_xnewdup(pa_daemon_conf, &default_conf, 1);
 
     if ((f = pa_open_config_file(DEFAULT_SCRIPT_FILE, DEFAULT_SCRIPT_FILE_USER, ENV_SCRIPT_FILE, &c->default_script_file, "r")))
         fclose(f);
@@ -106,7 +103,7 @@
 }
 
 void pa_daemon_conf_free(pa_daemon_conf *c) {
-    assert(c);
+    pa_assert(c);
     pa_xfree(c->script_commands);
     pa_xfree(c->dl_search_path);
     pa_xfree(c->default_script_file);
@@ -115,7 +112,8 @@
 }
 
 int pa_daemon_conf_set_log_target(pa_daemon_conf *c, const char *string) {
-    assert(c && string);
+    pa_assert(c);
+    pa_assert(string);
 
     if (!strcmp(string, "auto"))
         c->auto_log_target = 1;
@@ -133,7 +131,8 @@
 
 int pa_daemon_conf_set_log_level(pa_daemon_conf *c, const char *string) {
     uint32_t u;
-    assert(c && string);
+    pa_assert(c);
+    pa_assert(string);
 
     if (pa_atou(string, &u) >= 0) {
         if (u >= PA_LOG_LEVEL_MAX)
@@ -158,7 +157,8 @@
 
 int pa_daemon_conf_set_resample_method(pa_daemon_conf *c, const char *string) {
     int m;
-    assert(c && string);
+    pa_assert(c);
+    pa_assert(string);
 
     if ((m = pa_parse_resample_method(string)) < 0)
         return -1;
@@ -169,7 +169,11 @@
 
 static int parse_log_target(const char *filename, unsigned line, const char *lvalue, const char *rvalue, void *data, PA_GCC_UNUSED void *userdata) {
     pa_daemon_conf *c = data;
-    assert(filename && lvalue && rvalue && data);
+
+    pa_assert(filename);
+    pa_assert(lvalue);
+    pa_assert(rvalue);
+    pa_assert(data);
 
     if (pa_daemon_conf_set_log_target(c, rvalue) < 0) {
         pa_log("[%s:%u] Invalid log target '%s'.", filename, line, rvalue);
@@ -181,7 +185,11 @@
 
 static int parse_log_level(const char *filename, unsigned line, const char *lvalue, const char *rvalue, void *data, PA_GCC_UNUSED void *userdata) {
     pa_daemon_conf *c = data;
-    assert(filename && lvalue && rvalue && data);
+
+    pa_assert(filename);
+    pa_assert(lvalue);
+    pa_assert(rvalue);
+    pa_assert(data);
 
     if (pa_daemon_conf_set_log_level(c, rvalue) < 0) {
         pa_log("[%s:%u] Invalid log level '%s'.", filename, line, rvalue);
@@ -193,10 +201,14 @@
 
 static int parse_resample_method(const char *filename, unsigned line, const char *lvalue, const char *rvalue, void *data, PA_GCC_UNUSED void *userdata) {
     pa_daemon_conf *c = data;
-    assert(filename && lvalue && rvalue && data);
+
+    pa_assert(filename);
+    pa_assert(lvalue);
+    pa_assert(rvalue);
+    pa_assert(data);
 
     if (pa_daemon_conf_set_resample_method(c, rvalue) < 0) {
-        pa_log("[%s:%u] Inavalid resample method '%s'.", filename, line, rvalue);
+        pa_log("[%s:%u] Invalid resample method '%s'.", filename, line, rvalue);
         return -1;
     }
 
@@ -206,10 +218,11 @@
 static int parse_rlimit(const char *filename, unsigned line, const char *lvalue, const char *rvalue, void *data, PA_GCC_UNUSED void *userdata) {
 #ifdef HAVE_SYS_RESOURCE_H
     struct pa_rlimit *r = data;
-    assert(filename);
-    assert(lvalue);
-    assert(rvalue);
-    assert(r);
+
+    pa_assert(filename);
+    pa_assert(lvalue);
+    pa_assert(rvalue);
+    pa_assert(r);
 
     if (rvalue[strspn(rvalue, "\t ")] == 0) {
         /* Empty string */
@@ -218,7 +231,7 @@
     } else {
         int32_t k;
         if (pa_atoi(rvalue, &k) < 0) {
-            pa_log("[%s:%u] Inavalid rlimit '%s'.", filename, line, rvalue);
+            pa_log("[%s:%u] Invalid rlimit '%s'.", filename, line, rvalue);
             return -1;
         }
         r->is_set = k >= 0;
@@ -231,43 +244,138 @@
     return 0;
 }
 
+static int parse_sample_format(const char *filename, unsigned line, const char *lvalue, const char *rvalue, void *data, PA_GCC_UNUSED void *userdata) {
+    pa_daemon_conf *c = data;
+    pa_sample_format_t f;
+
+    pa_assert(filename);
+    pa_assert(lvalue);
+    pa_assert(rvalue);
+    pa_assert(data);
+
+    if ((f = pa_parse_sample_format(rvalue)) < 0) {
+        pa_log("[%s:%u] Invalid sample format '%s'.", filename, line, rvalue);
+        return -1;
+    }
+
+    c->default_sample_spec.format = f;
+    return 0;
+}
+
+static int parse_sample_rate(const char *filename, unsigned line, const char *lvalue, const char *rvalue, void *data, PA_GCC_UNUSED void *userdata) {
+    pa_daemon_conf *c = data;
+    int32_t r;
+
+    pa_assert(filename);
+    pa_assert(lvalue);
+    pa_assert(rvalue);
+    pa_assert(data);
+
+    if (pa_atoi(rvalue, &r) < 0 || r > PA_RATE_MAX || r <= 0) {
+        pa_log("[%s:%u] Invalid sample rate '%s'.", filename, line, rvalue);
+        return -1;
+    }
+
+    c->default_sample_spec.rate = r;
+    return 0;
+}
+
+static int parse_sample_channels(const char *filename, unsigned line, const char *lvalue, const char *rvalue, void *data, PA_GCC_UNUSED void *userdata) {
+    pa_daemon_conf *c = data;
+    int32_t n;
+
+    pa_assert(filename);
+    pa_assert(lvalue);
+    pa_assert(rvalue);
+    pa_assert(data);
+
+    if (pa_atoi(rvalue, &n) < 0 || n > PA_CHANNELS_MAX || n <= 0) {
+        pa_log("[%s:%u] Invalid sample channels '%s'.", filename, line, rvalue);
+        return -1;
+    }
+
+    c->default_sample_spec.channels = (uint8_t) n;
+    return 0;
+}
+
+static int parse_fragments(const char *filename, unsigned line, const char *lvalue, const char *rvalue, void *data, PA_GCC_UNUSED void *userdata) {
+    pa_daemon_conf *c = data;
+    int32_t n;
+
+    pa_assert(filename);
+    pa_assert(lvalue);
+    pa_assert(rvalue);
+    pa_assert(data);
+
+    if (pa_atoi(rvalue, &n) < 0 || n < 2) {
+        pa_log("[%s:%u] Invalid number of fragments '%s'.", filename, line, rvalue);
+        return -1;
+    }
+
+    c->default_n_fragments = (unsigned) n;
+    return 0;
+}
+
+static int parse_fragment_size_msec(const char *filename, unsigned line, const char *lvalue, const char *rvalue, void *data, PA_GCC_UNUSED void *userdata) {
+    pa_daemon_conf *c = data;
+    int32_t n;
+
+    pa_assert(filename);
+    pa_assert(lvalue);
+    pa_assert(rvalue);
+    pa_assert(data);
+
+    if (pa_atoi(rvalue, &n) < 0 || n < 1) {
+        pa_log("[%s:%u] Invalid fragment size '%s'.", filename, line, rvalue);
+        return -1;
+    }
+
+    c->default_fragment_size_msec = (unsigned) n;
+    return 0;
+}
+
 int pa_daemon_conf_load(pa_daemon_conf *c, const char *filename) {
     int r = -1;
     FILE *f = NULL;
 
     pa_config_item table[] = {
-        { "daemonize",               pa_config_parse_bool,    NULL },
-        { "fail",                    pa_config_parse_bool,    NULL },
-        { "high-priority",           pa_config_parse_bool,    NULL },
-        { "disallow-module-loading", pa_config_parse_bool,    NULL },
-        { "exit-idle-time",          pa_config_parse_int,     NULL },
-        { "module-idle-time",        pa_config_parse_int,     NULL },
-        { "scache-idle-time",        pa_config_parse_int,     NULL },
-        { "dl-search-path",          pa_config_parse_string,  NULL },
-        { "default-script-file",     pa_config_parse_string,  NULL },
-        { "log-target",              parse_log_target,        NULL },
-        { "log-level",               parse_log_level,         NULL },
-        { "verbose",                 parse_log_level,         NULL },
-        { "resample-method",         parse_resample_method,   NULL },
-        { "use-pid-file",            pa_config_parse_bool,    NULL },
-        { "system-instance",         pa_config_parse_bool,    NULL },
-        { "no-cpu-limit",            pa_config_parse_bool,    NULL },
-        { "disable-shm",             pa_config_parse_bool,    NULL },
+        { "daemonize",                  pa_config_parse_bool,     NULL },
+        { "fail",                       pa_config_parse_bool,     NULL },
+        { "high-priority",              pa_config_parse_bool,     NULL },
+        { "disallow-module-loading",    pa_config_parse_bool,     NULL },
+        { "exit-idle-time",             pa_config_parse_int,      NULL },
+        { "module-idle-time",           pa_config_parse_int,      NULL },
+        { "scache-idle-time",           pa_config_parse_int,      NULL },
+        { "dl-search-path",             pa_config_parse_string,   NULL },
+        { "default-script-file",        pa_config_parse_string,   NULL },
+        { "log-target",                 parse_log_target,         NULL },
+        { "log-level",                  parse_log_level,          NULL },
+        { "verbose",                    parse_log_level,          NULL },
+        { "resample-method",            parse_resample_method,    NULL },
+        { "use-pid-file",               pa_config_parse_bool,     NULL },
+        { "system-instance",            pa_config_parse_bool,     NULL },
+        { "no-cpu-limit",               pa_config_parse_bool,     NULL },
+        { "disable-shm",                pa_config_parse_bool,     NULL },
+        { "default-sample-format",      parse_sample_format,      NULL },
+        { "default-sample-rate",        parse_sample_rate,        NULL },
+        { "default-sample-channels",    parse_sample_channels,    NULL },
+        { "default-fragments",          parse_fragments,          NULL },
+        { "default-fragment-size-msec", parse_fragment_size_msec, NULL },
 #ifdef HAVE_SYS_RESOURCE_H
-        { "rlimit-as",               parse_rlimit,            NULL },
-        { "rlimit-core",             parse_rlimit,            NULL },
-        { "rlimit-data",             parse_rlimit,            NULL },
-        { "rlimit-fsize",            parse_rlimit,            NULL },
-        { "rlimit-nofile",           parse_rlimit,            NULL },
-        { "rlimit-stack",            parse_rlimit,            NULL },
+        { "rlimit-as",                  parse_rlimit,             NULL },
+        { "rlimit-core",                parse_rlimit,             NULL },
+        { "rlimit-data",                parse_rlimit,             NULL },
+        { "rlimit-fsize",               parse_rlimit,             NULL },
+        { "rlimit-nofile",              parse_rlimit,             NULL },
+        { "rlimit-stack",               parse_rlimit,             NULL },
 #ifdef RLIMIT_NPROC
-        { "rlimit-nproc",            parse_rlimit,            NULL },
+        { "rlimit-nproc",               parse_rlimit,             NULL },
 #endif
 #ifdef RLIMIT_MEMLOCK
-        { "rlimit-memlock",          parse_rlimit,            NULL },
-#endif
-#endif
-        { NULL,                      NULL,                    NULL },
+        { "rlimit-memlock",             parse_rlimit,             NULL },
+#endif
+#endif
+        { NULL,                         NULL,                     NULL },
     };
 
     table[0].data = &c->daemonize;
@@ -287,24 +395,28 @@
     table[14].data = &c->system_instance;
     table[15].data = &c->no_cpu_limit;
     table[16].data = &c->disable_shm;
+    table[17].data = c;
+    table[18].data = c;
+    table[19].data = c;
+    table[20].data = c;
+    table[21].data = c;
 #ifdef HAVE_SYS_RESOURCE_H
-    table[17].data = &c->rlimit_as;
-    table[18].data = &c->rlimit_core;
-    table[19].data = &c->rlimit_data;
-    table[20].data = &c->rlimit_fsize;
-    table[21].data = &c->rlimit_nofile;
-    table[22].data = &c->rlimit_stack;
+    table[22].data = &c->rlimit_as;
+    table[23].data = &c->rlimit_core;
+    table[24].data = &c->rlimit_data;
+    table[25].data = &c->rlimit_fsize;
+    table[26].data = &c->rlimit_nofile;
+    table[27].data = &c->rlimit_stack;
 #ifdef RLIMIT_NPROC
-    table[23].data = &c->rlimit_nproc;
+    table[28].data = &c->rlimit_nproc;
 #endif
 #ifdef RLIMIT_MEMLOCK
 #ifndef RLIMIT_NPROC
 #error "Houston, we have a numbering problem!"
 #endif
-    table[24].data = &c->rlimit_memlock;
-#endif
-#endif
-
+    table[29].data = &c->rlimit_memlock;
+#endif
+#endif
 
     pa_xfree(c->config_file);
     c->config_file = NULL;
@@ -314,7 +426,7 @@
         pa_open_config_file(DEFAULT_CONFIG_FILE, DEFAULT_CONFIG_FILE_USER, ENV_CONFIG_FILE, &c->config_file, "r");
 
     if (!f && errno != ENOENT) {
-        pa_log("WARNING: failed to open configuration file '%s': %s", c->config_file, pa_cstrerror(errno));
+        pa_log_warn("Failed to open configuration file '%s': %s", c->config_file, pa_cstrerror(errno));
         goto finish;
     }
 
@@ -351,12 +463,16 @@
 };
 
 char *pa_daemon_conf_dump(pa_daemon_conf *c) {
-    pa_strbuf *s = pa_strbuf_new();
+    pa_strbuf *s;
+
+    pa_assert(c);
+
+    s = pa_strbuf_new();
 
     if (c->config_file)
         pa_strbuf_printf(s, "### Read from configuration file: %s ###\n", c->config_file);
 
-    assert(c->log_level <= PA_LOG_LEVEL_MAX);
+    pa_assert(c->log_level <= PA_LOG_LEVEL_MAX);
 
     pa_strbuf_printf(s, "daemonize = %i\n", !!c->daemonize);
     pa_strbuf_printf(s, "fail = %i\n", !!c->fail);
@@ -373,7 +489,12 @@
     pa_strbuf_printf(s, "use-pid-file = %i\n", c->use_pid_file);
     pa_strbuf_printf(s, "system-instance = %i\n", !!c->system_instance);
     pa_strbuf_printf(s, "no-cpu-limit = %i\n", !!c->no_cpu_limit);
-    pa_strbuf_printf(s, "disable_shm = %i\n", !!c->disable_shm);
+    pa_strbuf_printf(s, "disable-shm = %i\n", !!c->disable_shm);
+    pa_strbuf_printf(s, "default-sample-format = %s\n", pa_sample_format_to_string(c->default_sample_spec.format));
+    pa_strbuf_printf(s, "default-sample-rate = %u\n", c->default_sample_spec.rate);
+    pa_strbuf_printf(s, "default-sample-channels = %u\n", c->default_sample_spec.channels);
+    pa_strbuf_printf(s, "default-fragments = %u\n", c->default_n_fragments);
+    pa_strbuf_printf(s, "default-fragment-size-msec = %u\n", c->default_fragment_size_msec);
 #ifdef HAVE_SYS_RESOURCE_H
     pa_strbuf_printf(s, "rlimit-as = %li\n", c->rlimit_as.is_set ? (long int) c->rlimit_as.value : -1);
     pa_strbuf_printf(s, "rlimit-core = %li\n", c->rlimit_core.is_set ? (long int) c->rlimit_core.value : -1);

Modified: trunk/src/daemon/daemon-conf.h
URL: http://0pointer.de/cgi-bin/viewcvs.cgi/trunk/src/daemon/daemon-conf.h?rev=1971&root=pulseaudio&r1=1970&r2=1971&view=diff
==============================================================================
--- trunk/src/daemon/daemon-conf.h (original)
+++ trunk/src/daemon/daemon-conf.h Sun Oct 28 20:13:50 2007
@@ -26,6 +26,7 @@
 ***/
 
 #include <pulsecore/log.h>
+#include <pulse/sample.h>
 
 #ifdef HAVE_SYS_RESOURCE_H
 #include <sys/resource.h>
@@ -39,7 +40,9 @@
     PA_CMD_DUMP_CONF,
     PA_CMD_DUMP_MODULES,
     PA_CMD_KILL,
-    PA_CMD_CHECK
+    PA_CMD_CHECK,
+    PA_CMD_DUMP_RESAMPLE_METHODS,
+    PA_CMD_CLEANUP_SHM
 } pa_daemon_conf_cmd_t;
 
 #ifdef HAVE_SYS_RESOURCE_H
@@ -80,6 +83,8 @@
 #endif
 #endif
 
+    unsigned default_n_fragments, default_fragment_size_msec;
+    pa_sample_spec default_sample_spec;
 } pa_daemon_conf;
 
 /* Allocate a new structure and fill it with sane defaults */

Modified: trunk/src/daemon/daemon.conf.in
URL: http://0pointer.de/cgi-bin/viewcvs.cgi/trunk/src/daemon/daemon.conf.in?rev=1971&root=pulseaudio&r1=1970&r2=1971&view=diff
==============================================================================
--- trunk/src/daemon/daemon.conf.in (original)
+++ trunk/src/daemon/daemon.conf.in Sun Oct 28 20:13:50 2007
@@ -92,10 +92,19 @@
 ; rlimit-core = -1
 ; rlimit-data = -1
 ; rlimit-fsize = -1
-; rlimit-nofile = 200
+; rlimit-nofile = 256
 ; rlimit-stack = -1
 ; rlimit-nproc = -1
-; rlimit-memlock = 25
+; rlimit-memlock = 16384
 
 ## Disable shared memory data transfer 
 ; disable-shm = 0
+
+## Default sample format
+; default-sample-format = s16le
+; default-sample-rate = 44100
+; default-sample-channels = 2
+
+## Default fragment settings, for device drivers that need this
+; default-fragments = 4
+; default-fragment-size-msec = 25

Modified: trunk/src/daemon/default.pa.in
URL: http://0pointer.de/cgi-bin/viewcvs.cgi/trunk/src/daemon/default.pa.in?rev=1971&root=pulseaudio&r1=1970&r2=1971&view=diff
==============================================================================
--- trunk/src/daemon/default.pa.in (original)
+++ trunk/src/daemon/default.pa.in Sun Oct 28 20:13:50 2007
@@ -1,5 +1,4 @@
-#!@PA_BINARY@ -nF 
-
+#!@PA_BINARY@ -nF
 #
 # This file is part of PulseAudio.
 #
@@ -17,8 +16,19 @@
 # along with PulseAudio; if not, write to the Free Software Foundation,
 # Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
 
+.nofail
 
-### Load audio drivers statically
+### Load something into the sample cache
+#load-sample-lazy x11-bell /usr/share/sounds/gtk-events/activate.wav
+load-sample-lazy pulse-hotplug /usr/share/sounds/startup3.wav
+#load-sample-lazy pulse-coldplug /usr/share/sounds/startup3.wav
+#load-sample-lazy pulse-access /usr/share/sounds/generic.wav
+
+.fail
+
+### Load audio drivers statically (it's probably better to not load
+### these drivers manually, but instead use module-hal-detect --
+### see below -- for doing this automatically)
 #load-module module-alsa-sink
 #load-module module-alsa-source device=hw:1,0
 #load-module module-oss device="/dev/dsp" sink_name=output source_name=input
@@ -27,19 +37,13 @@
 #load-module module-pipe-sink
 
 ### Automatically load driver modules depending on the hardware available
- at HAVE_HAL_TRUE@load-module module-hal-detect
-
+.ifexists @PA_DLSEARCHPATH@/module-hal-detect at PA_SOEXT@
+load-module module-hal-detect
+.else
 ### Alternatively use the static hardware detection module (for systems that
-### lack HAL support
- at HAVE_HAL_FALSE@load-module module-detect
-
-### Load audio drivers automatically on access
-#add-autoload-sink output module-oss device="/dev/dsp" sink_name=output source_name=input
-#add-autoload-source input module-oss device="/dev/dsp" sink_name=output source_name=input
-#add-autoload-sink output module-oss-mmap device="/dev/dsp" sink_name=output source_name=input
-#add-autoload-source input module-oss-mmap device="/dev/dsp" sink_name=output source_name=input
-#add-autoload-sink output module-alsa-sink sink_name=output
-#add-autoload-source input module-alsa-source source_name=input
+### lack HAL support)
+load-module module-detect
+.endif
 
 ### Load several protocols
 load-module module-esound-protocol-unix
@@ -61,27 +65,36 @@
 ### Automatically restore the volume of playback streams
 load-module module-volume-restore
 
+### Automatically restore the default sink/source when changed by the user during runtime
+load-module module-default-device-restore
+
 ### Automatically move streams to the default sink if the sink they are
 ### connected to dies, similar for sources
 load-module module-rescue-streams
 
-### Make some devices default
-#set-default-sink output
-#set-default-source input
-
-.nofail
-
-### Load something to the sample cache
-load-sample x11-bell /usr/share/sounds/gtk-events/activate.wav
-#load-sample-dir-lazy /usr/share/sounds/*.wav
+### Automatically suspend sinks/sources that become idle for too long
+load-module module-suspend-on-idle
 
 ### Load X11 bell module
-load-module module-x11-bell sample=x11-bell
+#load-module module-x11-bell sample=x11-bell
 
 ### Publish connection data in the X11 root window
+.ifexists @PA_DLSEARCHPATH@/module-x11-publish at PA_SOEXT@
 load-module module-x11-publish
+.endif
+
+### Register ourselves in the X11 session manager
+# Deactivated by default, to avoid deadlock when PA is started as esd from gnome-session
+# Instead we load this via /etc/xdg/autostart/ and "pactl load-module" now
+# load-module module-x11-xsmp
 
 ### Load additional modules from GConf settings. This can be configured with the paprefs tool.
 ### Please keep in mind that the modules configured by paprefs might conflict with manually
 ### loaded modules.
+.ifexists @PA_DLSEARCHPATH@/module-gconf at PA_SOEXT@
 load-module module-gconf
+.endif
+
+### Make some devices default
+#set-default-sink output
+#set-default-source input

Modified: trunk/src/daemon/dumpmodules.c
URL: http://0pointer.de/cgi-bin/viewcvs.cgi/trunk/src/daemon/dumpmodules.c?rev=1971&root=pulseaudio&r1=1970&r2=1971&view=diff
==============================================================================
--- trunk/src/daemon/dumpmodules.c (original)
+++ trunk/src/daemon/dumpmodules.c Sun Oct 28 20:13:50 2007
@@ -28,26 +28,30 @@
 
 #include <string.h>
 #include <getopt.h>
-#include <assert.h>
 #include <stdio.h>
 #include <ltdl.h>
 
 #include <pulse/util.h>
 
 #include <pulsecore/modinfo.h>
+#include <pulsecore/core-util.h>
+#include <pulsecore/macro.h>
 
 #include "dumpmodules.h"
 
 #define PREFIX "module-"
 
 static void short_info(const char *name, PA_GCC_UNUSED const char *path, pa_modinfo *i) {
-    assert(name && i);
+    pa_assert(name);
+    pa_assert(i);
+
     printf("%-40s%s\n", name, i->description ? i->description : "n/a");
 }
 
 static void long_info(const char *name, const char *path, pa_modinfo *i) {
     static int nl = 0;
-    assert(name && i);
+    pa_assert(name);
+    pa_assert(i);
 
     if (nl)
         printf("\n");
@@ -76,6 +80,8 @@
 static void show_info(const char *name, const char *path, void (*info)(const char *name, const char *path, pa_modinfo*i)) {
     pa_modinfo *i;
 
+    pa_assert(name);
+
     if ((i = pa_modinfo_get_by_name(path ? path : name))) {
         info(name, path, i);
         pa_modinfo_free(i);
@@ -93,7 +99,7 @@
         if (l->address)
             continue;
 
-        snprintf(buf, sizeof(buf), "%s", l->name);
+        pa_snprintf(buf, sizeof(buf), "%s", l->name);
         if ((e = strrchr(buf, '.')))
             *e = 0;
 
@@ -121,6 +127,8 @@
 }
 
 void pa_dump_modules(pa_daemon_conf *c, int argc, char * const argv[]) {
+    pa_assert(c);
+
     if (argc > 0) {
         int i;
         for (i = 0; i < argc; i++)
@@ -137,7 +145,7 @@
             if (strlen(l->name) <= sizeof(PREFIX)-1 || strncmp(l->name, PREFIX, sizeof(PREFIX)-1))
                 continue;
 
-            snprintf(buf, sizeof(buf), "%s", l->name);
+            pa_snprintf(buf, sizeof(buf), "%s", l->name);
             if ((e = strrchr(buf, '.')))
                 *e = 0;
 

Copied: trunk/src/daemon/ltdl-bind-now.c (from r1970, branches/lennart/src/daemon/ltdl-bind-now.c)
URL: http://0pointer.de/cgi-bin/viewcvs.cgi/trunk/src/daemon/ltdl-bind-now.c?p2=trunk/src/daemon/ltdl-bind-now.c&p1=branches/lennart/src/daemon/ltdl-bind-now.c&r1=1970&r2=1971&rev=1971&root=pulseaudio&view=diff
==============================================================================
--- branches/lennart/src/daemon/ltdl-bind-now.c (original)
+++ trunk/src/daemon/ltdl-bind-now.c Sun Oct 28 20:13:50 2007
@@ -115,7 +115,7 @@
 
     pa_assert(m);
     pa_assert(symbol);
-    
+
     if (!(ptr = dlsym(m, symbol))) {
         libtool_set_error(dlerror());
         return NULL;
@@ -136,8 +136,8 @@
         .find_sym = bind_now_find_sym
     };
 #endif
-    
-    pa_assert_se(lt_dlinit() == 0);       
+
+    pa_assert_se(lt_dlinit() == 0);
     pa_assert_se(libtool_mutex = pa_mutex_new(TRUE, FALSE));
     pa_assert_se(lt_dlmutex_register(libtool_lock, libtool_unlock, libtool_set_error, libtool_get_error) == 0);
 
@@ -145,7 +145,7 @@
 
     if (!(place = lt_dlloader_find("dlopen")))
         place = lt_dlloader_next(NULL);
-    
+
     /* Add our BIND_NOW loader as the default module loader. */
     if (lt_dlloader_add(place, &loader, "bind-now-loader") != 0)
         pa_log_warn("Failed to add bind-now-loader.");

Modified: trunk/src/daemon/main.c
URL: http://0pointer.de/cgi-bin/viewcvs.cgi/trunk/src/daemon/main.c?rev=1971&root=pulseaudio&r1=1970&r2=1971&view=diff
==============================================================================
--- trunk/src/daemon/main.c (original)
+++ trunk/src/daemon/main.c Sun Oct 28 20:13:50 2007
@@ -33,7 +33,6 @@
 #include <stdio.h>
 #include <signal.h>
 #include <stddef.h>
-#include <assert.h>
 #include <ltdl.h>
 #include <limits.h>
 #include <fcntl.h>
@@ -59,13 +58,16 @@
 #include <tcpd.h>
 #endif
 
-#include "../pulsecore/winsock.h"
+#ifdef HAVE_DBUS
+#include <dbus/dbus.h>
+#endif
 
 #include <pulse/mainloop.h>
 #include <pulse/mainloop-signal.h>
 #include <pulse/timeval.h>
 #include <pulse/xmalloc.h>
 
+#include <pulsecore/winsock.h>
 #include <pulsecore/core-error.h>
 #include <pulsecore/core.h>
 #include <pulsecore/memblock.h>
@@ -78,12 +80,20 @@
 #include <pulsecore/pid.h>
 #include <pulsecore/namereg.h>
 #include <pulsecore/random.h>
+#include <pulsecore/rtsig.h>
+#include <pulsecore/rtclock.h>
+#include <pulsecore/macro.h>
+#include <pulsecore/mutex.h>
+#include <pulsecore/thread.h>
+#include <pulsecore/once.h>
+#include <pulsecore/shm.h>
 
 #include "cmdline.h"
 #include "cpulimit.h"
 #include "daemon-conf.h"
 #include "dumpmodules.h"
 #include "caps.h"
+#include "ltdl-bind-now.h"
 
 #ifdef HAVE_LIBWRAP
 /* Only one instance of these variables */
@@ -120,7 +130,7 @@
 #endif
 
 static void signal_callback(pa_mainloop_api*m, PA_GCC_UNUSED pa_signal_event *e, int sig, void *userdata) {
-    pa_log_info("Got signal %s.", pa_strsignal(sig));
+    pa_log_info("Got signal %s.", pa_sig2str(sig));
 
     switch (sig) {
 #ifdef SIGUSR1
@@ -151,14 +161,6 @@
             m->quit(m, 1);
             break;
     }
-}
-
-static void close_pipe(int p[2]) {
-    if (p[0] != -1)
-        close(p[0]);
-    if (p[1] != -1)
-        close(p[1]);
-    p[0] = p[1] = -1;
 }
 
 #define set_env(key, value) putenv(pa_sprintf_malloc("%s=%s", (key), (value)))
@@ -281,7 +283,7 @@
 
 static void set_one_rlimit(const pa_rlimit *r, int resource, const char *name) {
     struct rlimit rl;
-    assert(r);
+    pa_assert(r);
 
     if (!r->is_set)
         return;
@@ -313,18 +315,33 @@
     pa_strbuf *buf = NULL;
     pa_daemon_conf *conf = NULL;
     pa_mainloop *mainloop = NULL;
-
     char *s;
-    int r, retval = 1, d = 0;
+    int r = 0, retval = 1, d = 0;
     int daemon_pipe[2] = { -1, -1 };
     int suid_root, real_root;
     int valid_pid_file = 0;
-
     gid_t gid = (gid_t) -1;
 
 #ifdef OS_IS_WIN32
     pa_time_event *timer;
     struct timeval tv;
+#endif
+
+
+#if defined(__linux__) && defined(__OPTIMIZE__)
+    /*
+       Disable lazy relocations to make usage of external libraries
+       more deterministic for our RT threads. We abuse __OPTIMIZE__ as
+       a check whether we are a debug build or not.
+    */
+
+    if (!getenv("LD_BIND_NOW")) {
+        putenv(pa_xstrdup("LD_BIND_NOW=1"));
+
+        /* We have to execute ourselves, because the libc caches the
+         * value of $LD_BIND_NOW on initialization. */
+        pa_assert_se(execv("/proc/self/exe", argv) == 0);
+    }
 #endif
 
 #ifdef HAVE_GETUID
@@ -336,16 +353,26 @@
 #endif
 
     if (suid_root) {
-        if (pa_limit_caps() > 0)
-            /* We managed to drop capabilities except the needed
-             * ones. Hence we can drop the uid. */
-            pa_drop_root();
+        /* Drop all capabilities except CAP_SYS_NICE  */
+        pa_limit_caps();
+
+        /* Drop priviliges, but keep CAP_SYS_NICE */
+        pa_drop_root();
+
+        /* After dropping root, the effective set is reset, hence,
+         * let's raise it again */
+        pa_limit_caps();
+
+        /* When capabilities are not supported we will not be able to
+         * aquire RT sched anymore. But yes, that's the way it is. It
+         * is just too risky tun let PA run as root all the time. */
     }
 
     setlocale(LC_ALL, "");
 
-    if (suid_root && (pa_own_uid_in_group(PA_REALTIME_GROUP, &gid) <= 0 || gid >= 1000)) {
-        pa_log_warn("WARNING: called SUID root, but not in group '"PA_REALTIME_GROUP"'.");
+    if (suid_root && (pa_own_uid_in_group(PA_REALTIME_GROUP, &gid) <= 0)) {
+        pa_log_info("Warning: Called SUID root, but not in group '"PA_REALTIME_GROUP"'. "
+                    "For enabling real-time scheduling please become a member of '"PA_REALTIME_GROUP"' , or increase the RLIMIT_RTPRIO user limit.");
         pa_drop_caps();
         pa_drop_root();
         suid_root = real_root = 0;
@@ -353,8 +380,7 @@
 
     LTDL_SET_PRELOADED_SYMBOLS();
 
-    r = lt_dlinit();
-    assert(r == 0);
+    pa_ltdl_init();
 
 #ifdef OS_IS_WIN32
     {
@@ -386,7 +412,7 @@
     if (conf->high_priority && conf->cmd == PA_CMD_DAEMON)
         pa_raise_priority();
 
-    if (suid_root) {
+    if (suid_root && (conf->cmd != PA_CMD_DAEMON || !conf->high_priority)) {
         pa_drop_caps();
         pa_drop_root();
     }
@@ -405,6 +431,16 @@
             fputs(s, stdout);
             pa_xfree(s);
             retval = 0;
+            goto finish;
+        }
+
+        case PA_CMD_DUMP_RESAMPLE_METHODS: {
+            int i;
+
+            for (i = 0; i < PA_RESAMPLER_MAX; i++)
+                if (pa_resample_method_supported(i))
+                    printf("%s\n", pa_resample_method_to_string(i));
+
             goto finish;
         }
 
@@ -440,8 +476,15 @@
 
             goto finish;
 
+        case PA_CMD_CLEANUP_SHM:
+
+            if (pa_shm_cleanup() >= 0)
+                retval = 0;
+
+            goto finish;
+
         default:
-            assert(conf->cmd == PA_CMD_DAEMON);
+            pa_assert(conf->cmd == PA_CMD_DAEMON);
     }
 
     if (real_root && !conf->system_instance) {
@@ -474,7 +517,7 @@
         if (child != 0) {
             /* Father */
 
-            close(daemon_pipe[1]);
+            pa_assert_se(pa_close(daemon_pipe[1]) == 0);
             daemon_pipe[1] = -1;
 
             if (pa_loop_read(daemon_pipe[0], &retval, sizeof(retval), NULL) != sizeof(retval)) {
@@ -490,7 +533,7 @@
             goto finish;
         }
 
-        close(daemon_pipe[0]);
+        pa_assert_se(pa_close(daemon_pipe[0]) == 0);
         daemon_pipe[0] = -1;
 #endif
 
@@ -505,9 +548,9 @@
 #endif
 
 #ifndef OS_IS_WIN32
-        close(0);
-        close(1);
-        close(2);
+        pa_close(0);
+        pa_close(1);
+        pa_close(2);
 
         open("/dev/null", O_RDONLY);
         open("/dev/null", O_WRONLY);
@@ -529,12 +572,12 @@
 #ifdef TIOCNOTTY
         if ((tty_fd = open("/dev/tty", O_RDWR)) >= 0) {
             ioctl(tty_fd, TIOCNOTTY, (char*) 0);
-            close(tty_fd);
-        }
-#endif
-    }
-
-    chdir("/");
+            pa_assert_se(pa_close(tty_fd) == 0);
+        }
+#endif
+    }
+
+    pa_assert_se(chdir("/") == 0);
     umask(0022);
 
     if (conf->system_instance) {
@@ -564,18 +607,37 @@
     signal(SIGPIPE, SIG_IGN);
 #endif
 
-    mainloop = pa_mainloop_new();
-    assert(mainloop);
+    pa_log_info("Page size is %lu bytes", (unsigned long) PA_PAGE_SIZE);
+
+    if (pa_rtclock_hrtimer())
+        pa_log_info("Fresh high-resolution timers available! Bon appetit!");
+    else
+        pa_log_info("Dude, your kernel stinks! The chef's recommendation today is Linux with high-resolution timers enabled!");
+
+#ifdef SIGRTMIN
+    /* Valgrind uses SIGRTMAX. To easy debugging we don't use it here */
+    pa_rtsig_configure(SIGRTMIN, SIGRTMAX-1);
+#endif
+
+    pa_assert_se(mainloop = pa_mainloop_new());
 
     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;
     }
 
     c->is_system_instance = !!conf->system_instance;
-
-    r = pa_signal_init(pa_mainloop_get_api(mainloop));
-    assert(r == 0);
+    c->high_priority = !!conf->high_priority;
+    c->default_sample_spec = conf->default_sample_spec;
+    c->default_n_fragments = conf->default_n_fragments;
+    c->default_fragment_size_msec = conf->default_fragment_size_msec;
+    c->disallow_module_loading = conf->disallow_module_loading;
+    c->exit_idle_time = conf->exit_idle_time;
+    c->module_idle_time = conf->module_idle_time;
+    c->scache_idle_time = conf->scache_idle_time;
+    c->resample_method = conf->resample_method;
+
+    pa_assert_se(pa_signal_init(pa_mainloop_get_api(mainloop)) == 0);
     pa_signal_new(SIGINT, signal_callback, c);
     pa_signal_new(SIGTERM, signal_callback, c);
 
@@ -590,9 +652,7 @@
 #endif
 
 #ifdef OS_IS_WIN32
-    timer = pa_mainloop_get_api(mainloop)->time_new(
-        pa_mainloop_get_api(mainloop), pa_gettimeofday(&tv), message_cb, NULL);
-    assert(timer);
+    pa_assert_se(timer = pa_mainloop_get_api(mainloop)->time_new(pa_mainloop_get_api(mainloop), pa_gettimeofday(&tv), message_cb, NULL));
 #endif
 
     if (conf->daemonize)
@@ -600,10 +660,8 @@
 
     oil_init();
 
-    if (!conf->no_cpu_limit) {
-        r = pa_cpu_limit_init(pa_mainloop_get_api(mainloop));
-        assert(r == 0);
-    }
+    if (!conf->no_cpu_limit)
+        pa_assert_se(pa_cpu_limit_init(pa_mainloop_get_api(mainloop)) == 0);
 
     buf = pa_strbuf_new();
     if (conf->default_script_file)
@@ -633,12 +691,6 @@
         if (conf->daemonize)
             pa_loop_write(daemon_pipe[1], &retval, sizeof(retval), NULL);
 #endif
-
-        c->disallow_module_loading = conf->disallow_module_loading;
-        c->exit_idle_time = conf->exit_idle_time;
-        c->module_idle_time = conf->module_idle_time;
-        c->scache_idle_time = conf->scache_idle_time;
-        c->resample_method = conf->resample_method;
 
         if (c->default_sink_name &&
             pa_namereg_get(c, c->default_sink_name, PA_NAMEREG_SINK, 1) == NULL) {
@@ -656,7 +708,7 @@
     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();
@@ -676,13 +728,17 @@
     if (valid_pid_file)
         pa_pid_file_remove();
 
-    close_pipe(daemon_pipe);
+    pa_close_pipe(daemon_pipe);
 
 #ifdef OS_IS_WIN32
     WSACleanup();
 #endif
 
-    lt_dlexit();
+    pa_ltdl_done();
+
+#ifdef HAVE_DBUS
+    dbus_shutdown();
+#endif
 
     return retval;
 }

Modified: trunk/src/modules/alsa-util.c
URL: http://0pointer.de/cgi-bin/viewcvs.cgi/trunk/src/modules/alsa-util.c?rev=1971&root=pulseaudio&r1=1970&r2=1971&view=diff
==============================================================================
--- trunk/src/modules/alsa-util.c (original)
+++ trunk/src/modules/alsa-util.c Sun Oct 28 20:13:50 2007
@@ -33,6 +33,7 @@
 #include <pulse/xmalloc.h>
 
 #include <pulsecore/log.h>
+#include <pulsecore/macro.h>
 
 #include "alsa-util.h"
 
@@ -42,7 +43,6 @@
     /* This is a temporary buffer used to avoid lots of mallocs */
     struct pollfd *work_fds;
 
-    snd_pcm_t *pcm;
     snd_mixer_t *mixer;
 
     pa_mainloop_api *m;
@@ -56,11 +56,16 @@
 };
 
 static void io_cb(pa_mainloop_api*a, pa_io_event* e, PA_GCC_UNUSED int fd, pa_io_event_flags_t events, void *userdata) {
-    struct pa_alsa_fdlist *fdl = (struct pa_alsa_fdlist*)userdata;
+
+    struct pa_alsa_fdlist *fdl = userdata;
     int err, i;
     unsigned short revents;
 
-    assert(a && fdl && (fdl->pcm || fdl->mixer) && fdl->fds && fdl->work_fds);
+    pa_assert(a);
+    pa_assert(fdl);
+    pa_assert(fdl->mixer);
+    pa_assert(fdl->fds);
+    pa_assert(fdl->work_fds);
 
     if (fdl->polled)
         return;
@@ -69,7 +74,7 @@
 
     memcpy(fdl->work_fds, fdl->fds, sizeof(struct pollfd) * fdl->num_fds);
 
-    for (i = 0;i < fdl->num_fds;i++) {
+    for (i = 0;i < fdl->num_fds; i++) {
         if (e == fdl->ios[i]) {
             if (events & PA_IO_EVENT_INPUT)
                 fdl->work_fds[i].revents |= POLLIN;
@@ -83,63 +88,46 @@
         }
     }
 
-    assert(i != fdl->num_fds);
-
-    if (fdl->pcm)
-        err = snd_pcm_poll_descriptors_revents(fdl->pcm, fdl->work_fds, fdl->num_fds, &revents);
-    else
-        err = snd_mixer_poll_descriptors_revents(fdl->mixer, fdl->work_fds, fdl->num_fds, &revents);
-
-    if (err < 0) {
-        pa_log_error("Unable to get poll revent: %s",
-            snd_strerror(err));
+    pa_assert(i != fdl->num_fds);
+
+    if ((err = snd_mixer_poll_descriptors_revents(fdl->mixer, fdl->work_fds, fdl->num_fds, &revents)) < 0) {
+        pa_log_error("Unable to get poll revent: %s", snd_strerror(err));
         return;
     }
 
     a->defer_enable(fdl->defer, 1);
 
-    if (revents) {
-        if (fdl->pcm)
-            fdl->cb(fdl->userdata);
-        else
-            snd_mixer_handle_events(fdl->mixer);
-    }
+    if (revents)
+        snd_mixer_handle_events(fdl->mixer);
 }
 
 static void defer_cb(pa_mainloop_api*a, PA_GCC_UNUSED pa_defer_event* e, void *userdata) {
-    struct pa_alsa_fdlist *fdl = (struct pa_alsa_fdlist*)userdata;
+    struct pa_alsa_fdlist *fdl = userdata;
     int num_fds, i, err;
     struct pollfd *temp;
 
-    assert(a && fdl && (fdl->pcm || fdl->mixer));
+    pa_assert(a);
+    pa_assert(fdl);
+    pa_assert(fdl->mixer);
 
     a->defer_enable(fdl->defer, 0);
 
-    if (fdl->pcm)
-        num_fds = snd_pcm_poll_descriptors_count(fdl->pcm);
-    else
-        num_fds = snd_mixer_poll_descriptors_count(fdl->mixer);
-    assert(num_fds > 0);
+    num_fds = snd_mixer_poll_descriptors_count(fdl->mixer);
+    pa_assert(num_fds > 0);
 
     if (num_fds != fdl->num_fds) {
         if (fdl->fds)
             pa_xfree(fdl->fds);
         if (fdl->work_fds)
             pa_xfree(fdl->work_fds);
-        fdl->fds = pa_xmalloc0(sizeof(struct pollfd) * num_fds);
-        fdl->work_fds = pa_xmalloc(sizeof(struct pollfd) * num_fds);
+        fdl->fds = pa_xnew0(struct pollfd, num_fds);
+        fdl->work_fds = pa_xnew(struct pollfd, num_fds);
     }
 
     memset(fdl->work_fds, 0, sizeof(struct pollfd) * num_fds);
 
-    if (fdl->pcm)
-        err = snd_pcm_poll_descriptors(fdl->pcm, fdl->work_fds, num_fds);
-    else
-        err = snd_mixer_poll_descriptors(fdl->mixer, fdl->work_fds, num_fds);
-
-    if (err < 0) {
-        pa_log_error("Unable to get poll descriptors: %s",
-            snd_strerror(err));
+    if ((err = snd_mixer_poll_descriptors(fdl->mixer, fdl->work_fds, num_fds)) < 0) {
+        pa_log_error("Unable to get poll descriptors: %s", snd_strerror(err));
         return;
     }
 
@@ -149,17 +137,17 @@
         return;
 
     if (fdl->ios) {
-        for (i = 0;i < fdl->num_fds;i++)
+        for (i = 0; i < fdl->num_fds; i++)
             a->io_free(fdl->ios[i]);
+
         if (num_fds != fdl->num_fds) {
             pa_xfree(fdl->ios);
-            fdl->ios = pa_xmalloc(sizeof(pa_io_event*) * num_fds);
-            assert(fdl->ios);
+            fdl->ios = NULL;
         }
-    } else {
-        fdl->ios = pa_xmalloc(sizeof(pa_io_event*) * num_fds);
-        assert(fdl->ios);
-    }
+    }
+
+    if (!fdl->ios)
+        fdl->ios = pa_xnew(pa_io_event*, num_fds);
 
     /* Swap pointers */
     temp = fdl->work_fds;
@@ -168,47 +156,41 @@
 
     fdl->num_fds = num_fds;
 
-    for (i = 0;i < num_fds;i++) {
+    for (i = 0;i < num_fds;i++)
         fdl->ios[i] = a->io_new(a, fdl->fds[i].fd,
             ((fdl->fds[i].events & POLLIN) ? PA_IO_EVENT_INPUT : 0) |
             ((fdl->fds[i].events & POLLOUT) ? PA_IO_EVENT_OUTPUT : 0),
             io_cb, fdl);
-        assert(fdl->ios[i]);
-    }
 }
 
 struct pa_alsa_fdlist *pa_alsa_fdlist_new(void) {
     struct pa_alsa_fdlist *fdl;
 
-    fdl = pa_xmalloc(sizeof(struct pa_alsa_fdlist));
+    fdl = pa_xnew0(struct pa_alsa_fdlist, 1);
 
     fdl->num_fds = 0;
     fdl->fds = NULL;
     fdl->work_fds = NULL;
-
-    fdl->pcm = NULL;
     fdl->mixer = NULL;
-
     fdl->m = NULL;
     fdl->defer = NULL;
     fdl->ios = NULL;
-
     fdl->polled = 0;
 
     return fdl;
 }
 
 void pa_alsa_fdlist_free(struct pa_alsa_fdlist *fdl) {
-    assert(fdl);
+    pa_assert(fdl);
 
     if (fdl->defer) {
-        assert(fdl->m);
+        pa_assert(fdl->m);
         fdl->m->defer_free(fdl->defer);
     }
 
     if (fdl->ios) {
         int i;
-        assert(fdl->m);
+        pa_assert(fdl->m);
         for (i = 0;i < fdl->num_fds;i++)
             fdl->m->io_free(fdl->ios[i]);
         pa_xfree(fdl->ios);
@@ -222,29 +204,15 @@
     pa_xfree(fdl);
 }
 
-int pa_alsa_fdlist_init_pcm(struct pa_alsa_fdlist *fdl, snd_pcm_t *pcm_handle, pa_mainloop_api* m, void (*cb)(void *userdata), void *userdata) {
-    assert(fdl && pcm_handle && m && !fdl->m && cb);
-
-    fdl->pcm = pcm_handle;
-    fdl->m = m;
-
-    fdl->defer = m->defer_new(m, defer_cb, fdl);
-    assert(fdl->defer);
-
-    fdl->cb = cb;
-    fdl->userdata = userdata;
-
-    return 0;
-}
-
-int pa_alsa_fdlist_init_mixer(struct pa_alsa_fdlist *fdl, snd_mixer_t *mixer_handle, pa_mainloop_api* m) {
-    assert(fdl && mixer_handle && m && !fdl->m);
+int pa_alsa_fdlist_set_mixer(struct pa_alsa_fdlist *fdl, snd_mixer_t *mixer_handle, pa_mainloop_api* m) {
+    pa_assert(fdl);
+    pa_assert(mixer_handle);
+    pa_assert(m);
+    pa_assert(!fdl->m);
 
     fdl->mixer = mixer_handle;
     fdl->m = m;
-
     fdl->defer = m->defer_new(m, defer_cb, fdl);
-    assert(fdl->defer);
 
     return 0;
 }
@@ -274,8 +242,8 @@
 
     int i, ret;
 
-    assert(pcm_handle);
-    assert(f);
+    pa_assert(pcm_handle);
+    pa_assert(f);
 
     if ((ret = snd_pcm_hw_params_set_format(pcm_handle, hwparams, format_trans[*f])) >= 0)
         return ret;
@@ -308,7 +276,7 @@
 
 /* Set the hardware parameters of the given ALSA device. Returns the
  * selected fragment settings in *period and *period_size */
-int pa_alsa_set_hw_params(snd_pcm_t *pcm_handle, pa_sample_spec *ss, uint32_t *periods, snd_pcm_uframes_t *period_size) {
+int pa_alsa_set_hw_params(snd_pcm_t *pcm_handle, pa_sample_spec *ss, uint32_t *periods, snd_pcm_uframes_t *period_size, int *use_mmap) {
     int ret = -1;
     snd_pcm_uframes_t buffer_size;
     unsigned int r = ss->rate;
@@ -316,17 +284,32 @@
     pa_sample_format_t f = ss->format;
     snd_pcm_hw_params_t *hwparams;
 
-    assert(pcm_handle);
-    assert(ss);
-    assert(periods);
-    assert(period_size);
+    pa_assert(pcm_handle);
+    pa_assert(ss);
+    pa_assert(periods);
+    pa_assert(period_size);
+
+    snd_pcm_hw_params_alloca(&hwparams);
 
     buffer_size = *periods * *period_size;
 
-    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)
+    if ((ret = snd_pcm_hw_params_any(pcm_handle, hwparams)) < 0 ||
+        (ret = snd_pcm_hw_params_set_rate_resample(pcm_handle, hwparams, 0)) < 0)
+        goto finish;
+
+    if (use_mmap && *use_mmap) {
+        if ((ret = snd_pcm_hw_params_set_access(pcm_handle, hwparams, SND_PCM_ACCESS_MMAP_INTERLEAVED)) < 0) {
+
+            /* mmap() didn't work, fall back to interleaved */
+
+            if ((ret = snd_pcm_hw_params_set_access(pcm_handle, hwparams, SND_PCM_ACCESS_RW_INTERLEAVED)) < 0)
+                goto finish;
+
+            if (use_mmap)
+                *use_mmap = 0;
+        }
+
+    } else if ((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)
@@ -346,7 +329,7 @@
         goto finish;
 
     if (ss->rate != r) {
-        pa_log_warn("device doesn't support %u Hz, changed to %u Hz.", ss->rate, r);
+        pa_log_warn("Device %s doesn't support %u Hz, changed to %u Hz.", snd_pcm_name(pcm_handle), ss->rate, r);
 
         /* If the sample rate deviates too much, we need to resample */
         if (r < ss->rate*.95 || r > ss->rate*1.05)
@@ -354,12 +337,12 @@
     }
 
     if (ss->channels != c) {
-        pa_log_warn("device doesn't support %u channels, changed to %u.", ss->channels, c);
+        pa_log_warn("Device %s doesn't support %u channels, changed to %u.", snd_pcm_name(pcm_handle), ss->channels, c);
         ss->channels = c;
     }
 
     if (ss->format != f) {
-        pa_log_warn("device doesn't support sample format %s, changed to %s.", pa_sample_format_to_string(ss->format), pa_sample_format_to_string(f));
+        pa_log_warn("Device %s doesn't support sample format %s, changed to %s.", snd_pcm_name(pcm_handle), pa_sample_format_to_string(ss->format), pa_sample_format_to_string(f));
         ss->format = f;
     }
 
@@ -370,24 +353,54 @@
         (ret = snd_pcm_hw_params_get_period_size(hwparams, period_size, NULL)) < 0)
         goto finish;
 
-    assert(buffer_size > 0);
-    assert(*period_size > 0);
+    pa_assert(buffer_size > 0);
+    pa_assert(*period_size > 0);
     *periods = buffer_size / *period_size;
-    assert(*periods > 0);
+    pa_assert(*periods > 0);
 
     ret = 0;
 
 finish:
-    if (hwparams)
-        snd_pcm_hw_params_free(hwparams);
 
     return ret;
+}
+
+int pa_alsa_set_sw_params(snd_pcm_t *pcm) {
+    snd_pcm_sw_params_t *swparams;
+    int err;
+
+    pa_assert(pcm);
+
+    snd_pcm_sw_params_alloca(&swparams);
+
+    if ((err = snd_pcm_sw_params_current(pcm, swparams) < 0)) {
+        pa_log_warn("Unable to determine current swparams: %s\n", snd_strerror(err));
+        return err;
+    }
+
+    if ((err = snd_pcm_sw_params_set_stop_threshold(pcm, swparams, (snd_pcm_uframes_t) -1)) < 0) {
+        pa_log_warn("Unable to set stop threshold: %s\n", snd_strerror(err));
+        return err;
+    }
+
+    if ((err = snd_pcm_sw_params_set_start_threshold(pcm, swparams, (snd_pcm_uframes_t) -1)) < 0) {
+        pa_log_warn("Unable to set start threshold: %s\n", snd_strerror(err));
+        return err;
+    }
+
+    if ((err = snd_pcm_sw_params(pcm, swparams)) < 0) {
+        pa_log_warn("Unable to set sw params: %s\n", snd_strerror(err));
+        return err;
+    }
+
+    return 0;
 }
 
 int pa_alsa_prepare_mixer(snd_mixer_t *mixer, const char *dev) {
     int err;
 
-    assert(mixer && dev);
+    pa_assert(mixer);
+    pa_assert(dev);
 
     if ((err = snd_mixer_attach(mixer, dev)) < 0) {
         pa_log_warn("Unable to attach to mixer %s: %s", dev, snd_strerror(err));
@@ -410,10 +423,11 @@
 snd_mixer_elem_t *pa_alsa_find_elem(snd_mixer_t *mixer, const char *name, const char *fallback) {
     snd_mixer_elem_t *elem;
     snd_mixer_selem_id_t *sid = NULL;
+
     snd_mixer_selem_id_alloca(&sid);
 
-    assert(mixer);
-    assert(name);
+    pa_assert(mixer);
+    pa_assert(name);
 
     snd_mixer_selem_id_set_name(sid, name);
 

Modified: trunk/src/modules/alsa-util.h
URL: http://0pointer.de/cgi-bin/viewcvs.cgi/trunk/src/modules/alsa-util.h?rev=1971&root=pulseaudio&r1=1970&r2=1971&view=diff
==============================================================================
--- trunk/src/modules/alsa-util.h (original)
+++ trunk/src/modules/alsa-util.h Sun Oct 28 20:13:50 2007
@@ -32,15 +32,14 @@
 
 #include <pulse/channelmap.h>
 
-struct pa_alsa_fdlist;
+typedef struct pa_alsa_fdlist pa_alsa_fdlist;
 
 struct pa_alsa_fdlist *pa_alsa_fdlist_new(void);
 void pa_alsa_fdlist_free(struct pa_alsa_fdlist *fdl);
+int pa_alsa_fdlist_set_mixer(struct pa_alsa_fdlist *fdl, snd_mixer_t *mixer_handle, pa_mainloop_api* m);
 
-int pa_alsa_fdlist_init_pcm(struct pa_alsa_fdlist *fdl, snd_pcm_t *pcm_handle, pa_mainloop_api* m, void (*cb)(void *userdata), void *userdata);
-int pa_alsa_fdlist_init_mixer(struct pa_alsa_fdlist *fdl, snd_mixer_t *mixer_handle, pa_mainloop_api* m);
-
-int pa_alsa_set_hw_params(snd_pcm_t *pcm_handle, pa_sample_spec *ss, uint32_t *periods, snd_pcm_uframes_t *period_size);
+int pa_alsa_set_hw_params(snd_pcm_t *pcm_handle, pa_sample_spec *ss, uint32_t *periods, snd_pcm_uframes_t *period_size, int *use_mmap);
+int pa_alsa_set_sw_params(snd_pcm_t *pcm);
 
 int pa_alsa_prepare_mixer(snd_mixer_t *mixer, const char *dev);
 snd_mixer_elem_t *pa_alsa_find_elem(snd_mixer_t *mixer, const char *name, const char *fallback);

Modified: trunk/src/modules/dbus-util.c
URL: http://0pointer.de/cgi-bin/viewcvs.cgi/trunk/src/modules/dbus-util.c?rev=1971&root=pulseaudio&r1=1970&r2=1971&view=diff
==============================================================================
--- trunk/src/modules/dbus-util.c (original)
+++ trunk/src/modules/dbus-util.c Sun Oct 28 20:13:50 2007
@@ -26,25 +26,25 @@
 #include <config.h>
 #endif
 
-#include <assert.h>
+#include <pulse/xmalloc.h>
+#include <pulse/timeval.h>
 #include <pulsecore/log.h>
 #include <pulsecore/props.h>
-#include <pulse/xmalloc.h>
-#include <pulse/timeval.h>
 
 #include "dbus-util.h"
 
 struct pa_dbus_connection {
-    int refcount;
+    PA_REFCNT_DECLARE;
+
     pa_core *core;
     DBusConnection *connection;
     const char *property_name;
     pa_defer_event* dispatch_event;
 };
 
-static void dispatch_cb(pa_mainloop_api *ea, pa_defer_event *ev, void *userdata)
-{
-    DBusConnection *conn = (DBusConnection *) userdata;
+static void dispatch_cb(pa_mainloop_api *ea, pa_defer_event *ev, void *userdata) {
+    DBusConnection *conn = userdata;
+
     if (dbus_connection_dispatch(conn) == DBUS_DISPATCH_COMPLETE) {
         /* no more data to process, disable the deferred */
         ea->defer_enable(ev, 0);
@@ -52,14 +52,17 @@
 }
 
 /* DBusDispatchStatusFunction callback for the pa mainloop */
-static void dispatch_status(DBusConnection *conn, DBusDispatchStatus status,
-                            void *userdata)
-{
-    pa_dbus_connection *c = (pa_dbus_connection*) userdata;
+static void dispatch_status(DBusConnection *conn, DBusDispatchStatus status, void *userdata) {
+    pa_dbus_connection *c = userdata;
+
+    pa_assert(c);
+
     switch(status) {
+
         case DBUS_DISPATCH_COMPLETE:
             c->core->mainloop->defer_enable(c->dispatch_event, 0);
             break;
+
         case DBUS_DISPATCH_DATA_REMAINS:
         case DBUS_DISPATCH_NEED_MEMORY:
         default:
@@ -68,11 +71,13 @@
     }
 }
 
-static pa_io_event_flags_t
-get_watch_flags(DBusWatch *watch)
-{
-    unsigned int flags = dbus_watch_get_flags(watch);
-    pa_io_event_flags_t events = PA_IO_EVENT_HANGUP | PA_IO_EVENT_ERROR;
+static pa_io_event_flags_t get_watch_flags(DBusWatch *watch) {
+    unsigned int flags;
+    pa_io_event_flags_t events = 0;
+
+    pa_assert(watch);
+
+    flags = dbus_watch_get_flags(watch);
 
     /* no watch flags for disabled watches */
     if (!dbus_watch_get_enabled(watch))
@@ -83,21 +88,22 @@
     if (flags & DBUS_WATCH_WRITABLE)
         events |= PA_IO_EVENT_OUTPUT;
 
-    return events;
+    return events | PA_IO_EVENT_HANGUP | PA_IO_EVENT_ERROR;
 }
 
 /* pa_io_event_cb_t IO event handler */
-static void handle_io_event(PA_GCC_UNUSED pa_mainloop_api *ea, pa_io_event *e,
-                            int fd, pa_io_event_flags_t events, void *userdata)
-{
+static void handle_io_event(PA_GCC_UNUSED pa_mainloop_api *ea, pa_io_event *e, int fd, pa_io_event_flags_t events, void *userdata) {
     unsigned int flags = 0;
-    DBusWatch *watch = (DBusWatch*) userdata;
-
-    assert(fd == dbus_watch_get_fd(watch));
+    DBusWatch *watch = userdata;
+
+#if HAVE_DBUS_WATCH_GET_UNIX_FD
+    pa_assert(fd == dbus_watch_get_unix_fd(watch));
+#else
+    pa_assert(fd == dbus_watch_get_fd(watch));
+#endif
 
     if (!dbus_watch_get_enabled(watch)) {
-        pa_log_warn("Asked to handle disabled watch: %p %i",
-                    (void *) watch, fd);
+        pa_log_warn("Asked to handle disabled watch: %p %i", (void*) watch, fd);
         return;
     }
 
@@ -114,10 +120,8 @@
 }
 
 /* pa_time_event_cb_t timer event handler */
-static void handle_time_event(pa_mainloop_api *ea, pa_time_event* e,
-                              const struct timeval *tv, void *userdata)
-{
-    DBusTimeout *timeout = (DBusTimeout*) userdata;
+static void handle_time_event(pa_mainloop_api *ea, pa_time_event* e, const struct timeval *tv, void *userdata) {
+    DBusTimeout *timeout = userdata;
 
     if (dbus_timeout_get_enabled(timeout)) {
         struct timeval next = *tv;
@@ -130,103 +134,154 @@
 }
 
 /* DBusAddWatchFunction callback for pa mainloop */
-static dbus_bool_t add_watch(DBusWatch *watch, void *data)
-{
+static dbus_bool_t add_watch(DBusWatch *watch, void *data) {
+    pa_core *c = PA_CORE(data);
     pa_io_event *ev;
-    pa_core *c = (pa_core*) data;
-
-    ev = c->mainloop->io_new(c->mainloop, dbus_watch_get_fd(watch),
-                             get_watch_flags(watch),
-                             handle_io_event, (void*) watch);
-    if (NULL == ev)
-        return FALSE;
-
-    /* dbus_watch_set_data(watch, (void*) ev, c->mainloop->io_free); */
-    dbus_watch_set_data(watch, (void*) ev, NULL);
+
+    pa_assert(watch);
+    pa_assert(c);
+
+    ev = c->mainloop->io_new(
+            c->mainloop,
+#if HAVE_DBUS_WATCH_GET_UNIX_FD
+            dbus_watch_get_unix_fd(watch),
+#else
+            dbus_watch_get_fd(watch),
+#endif
+            get_watch_flags(watch), handle_io_event, watch);
+
+    dbus_watch_set_data(watch, ev, NULL);
 
     return TRUE;
 }
 
 /* DBusRemoveWatchFunction callback for pa mainloop */
-static void remove_watch(DBusWatch *watch, void *data)
-{
-    pa_core *c = (pa_core*) data;
-    pa_io_event *ev = (pa_io_event*) dbus_watch_get_data(watch);
-
-    /* free the event */
-    if (NULL != ev)
+static void remove_watch(DBusWatch *watch, void *data) {
+    pa_core *c = PA_CORE(data);
+    pa_io_event *ev;
+
+    pa_assert(watch);
+    pa_assert(c);
+
+    if ((ev = dbus_watch_get_data(watch)))
         c->mainloop->io_free(ev);
 }
 
 /* DBusWatchToggledFunction callback for pa mainloop */
-static void toggle_watch(DBusWatch *watch, void *data)
-{
-    pa_core *c = (pa_core*) data;
-    pa_io_event *ev = (pa_io_event*) dbus_watch_get_data(watch);
+static void toggle_watch(DBusWatch *watch, void *data) {
+    pa_core *c = PA_CORE(data);
+    pa_io_event *ev;
+
+    pa_assert(watch);
+    pa_core_assert_ref(c);
+
+    pa_assert_se(ev = dbus_watch_get_data(watch));
 
     /* get_watch_flags() checks if the watch is enabled */
     c->mainloop->io_enable(ev, get_watch_flags(watch));
 }
 
 /* DBusAddTimeoutFunction callback for pa mainloop */
-static dbus_bool_t add_timeout(DBusTimeout *timeout, void *data)
-{
+static dbus_bool_t add_timeout(DBusTimeout *timeout, void *data) {
+    pa_core *c = PA_CORE(data);
+    pa_time_event *ev;
     struct timeval tv;
-    pa_time_event *ev;
-    pa_core *c = (pa_core*) data;
+
+    pa_assert(timeout);
+    pa_assert(c);
 
     if (!dbus_timeout_get_enabled(timeout))
         return FALSE;
 
-    if (!pa_gettimeofday(&tv))
-        return -1;
-
+    pa_gettimeofday(&tv);
     pa_timeval_add(&tv, dbus_timeout_get_interval(timeout) * 1000);
 
-    ev = c->mainloop->time_new(c->mainloop, &tv, handle_time_event,
-                               (void*) timeout);
-    if (NULL == ev)
-        return FALSE;
-
-    /* dbus_timeout_set_data(timeout, (void*) ev, c->mainloop->time_free); */
-    dbus_timeout_set_data(timeout, (void*) ev, NULL);
+    ev = c->mainloop->time_new(c->mainloop, &tv, handle_time_event, timeout);
+
+    dbus_timeout_set_data(timeout, ev, NULL);
 
     return TRUE;
 }
 
 /* DBusRemoveTimeoutFunction callback for pa mainloop */
-static void remove_timeout(DBusTimeout *timeout, void *data)
-{
-    pa_core *c = (pa_core*) data;
-    pa_time_event *ev = (pa_time_event*) dbus_timeout_get_data(timeout);
-
-    /* free the event */
-    if (NULL != ev)
+static void remove_timeout(DBusTimeout *timeout, void *data) {
+    pa_core *c = PA_CORE(data);
+    pa_time_event *ev;
+
+    pa_assert(timeout);
+    pa_assert(c);
+
+    if ((ev = dbus_timeout_get_data(timeout)))
         c->mainloop->time_free(ev);
 }
 
 /* DBusTimeoutToggledFunction callback for pa mainloop */
-static void toggle_timeout(DBusTimeout *timeout, void *data)
-{
-    struct timeval tv;
-    pa_core *c = (pa_core*) data;
-    pa_time_event *ev = (pa_time_event*) dbus_timeout_get_data(timeout);
+static void toggle_timeout(DBusTimeout *timeout, void *data) {
+    pa_core *c = PA_CORE(data);
+    pa_time_event *ev;
+
+    pa_assert(timeout);
+    pa_assert(c);
+
+    pa_assert_se(ev = dbus_timeout_get_data(timeout));
 
     if (dbus_timeout_get_enabled(timeout)) {
+        struct timeval tv;
+
         pa_gettimeofday(&tv);
         pa_timeval_add(&tv, dbus_timeout_get_interval(timeout) * 1000);
+
         c->mainloop->time_restart(ev, &tv);
-    } else {
-        /* disable the timeout */
+    } else
         c->mainloop->time_restart(ev, NULL);
-    }
-}
-
-static void
-pa_dbus_connection_free(pa_dbus_connection *c)
-{
-    assert(c);
-    assert(!dbus_connection_get_is_connected(c->connection));
+}
+
+static void wakeup_main(void *userdata) {
+    pa_dbus_connection *c = userdata;
+
+    pa_assert(c);
+
+    /* this will wakeup the mainloop and dispatch events, although
+     * it may not be the cleanest way of accomplishing it */
+    c->core->mainloop->defer_enable(c->dispatch_event, 1);
+}
+
+static pa_dbus_connection* pa_dbus_connection_new(pa_core* c, DBusConnection *conn, const char* name) {
+    pa_dbus_connection *pconn;
+
+    pconn = pa_xnew(pa_dbus_connection, 1);
+    PA_REFCNT_INIT(pconn);
+    pconn->core = c;
+    pconn->property_name = name;
+    pconn->connection = conn;
+    pconn->dispatch_event = c->mainloop->defer_new(c->mainloop, dispatch_cb, conn);
+
+    pa_property_set(c, name, pconn);
+
+    return pconn;
+}
+
+DBusConnection* pa_dbus_connection_get(pa_dbus_connection *c){
+    pa_assert(c);
+    pa_assert(PA_REFCNT_VALUE(c) > 0);
+    pa_assert(c->connection);
+
+    return c->connection;
+}
+
+void pa_dbus_connection_unref(pa_dbus_connection *c) {
+    pa_assert(c);
+    pa_assert(PA_REFCNT_VALUE(c) > 0);
+
+    if (PA_REFCNT_DEC(c) > 0)
+        return;
+
+    if (dbus_connection_get_is_connected(c->connection)) {
+        dbus_connection_close(c->connection);
+         /* must process remaining messages, bit of a kludge to handle
+         * both unload and shutdown */
+        while (dbus_connection_read_write_dispatch(c->connection, -1));
+    }
 
     /* already disconnected, just free */
     pa_property_remove(c->core, c->property_name);
@@ -235,113 +290,39 @@
     pa_xfree(c);
 }
 
-static void
-wakeup_main(void *userdata)
-{
-    pa_dbus_connection *c = (pa_dbus_connection*) userdata;
-    /* this will wakeup the mainloop and dispatch events, although
-     * it may not be the cleanest way of accomplishing it */
-    c->core->mainloop->defer_enable(c->dispatch_event, 1);
-}
-
-static pa_dbus_connection* pa_dbus_connection_new(pa_core* c, DBusConnection *conn, const char* name)
-{
-    pa_dbus_connection *pconn = pa_xnew(pa_dbus_connection, 1);
-
-    pconn->refcount = 1;
-    pconn->core = c;
-    pconn->property_name = name;
-    pconn->connection = conn;
-    pconn->dispatch_event = c->mainloop->defer_new(c->mainloop, dispatch_cb,
-                                                   (void*) conn);
-
-    pa_property_set(c, name, pconn);
-
-    return pconn;
-}
-
-DBusConnection* pa_dbus_connection_get(pa_dbus_connection *c)
-{
-    assert(c && c->connection);
-    return c->connection;
-}
-
-void pa_dbus_connection_unref(pa_dbus_connection *c)
-{
-    assert(c);
-
-    /* non-zero refcount, still outstanding refs */
-    if (--(c->refcount))
-        return;
-
-    /* refcount is zero */
-    if (dbus_connection_get_is_connected(c->connection)) {
-        /* disconnect as we have no more internal references */
-        dbus_connection_close(c->connection);
-        /* must process remaining messages, bit of a kludge to
-         * handle both unload and shutdown */
-        while(dbus_connection_read_write_dispatch(c->connection, -1));
-    }
-    pa_dbus_connection_free(c);
-}
-
-pa_dbus_connection* pa_dbus_connection_ref(pa_dbus_connection *c)
-{
-    assert(c);
-
-    ++(c->refcount);
+pa_dbus_connection* pa_dbus_connection_ref(pa_dbus_connection *c) {
+    pa_assert(c);
+    pa_assert(PA_REFCNT_VALUE(c) > 0);
+
+    PA_REFCNT_INC(c);
 
     return c;
 }
 
-pa_dbus_connection* pa_dbus_bus_get(pa_core *c, DBusBusType type,
-                                    DBusError *error)
-{
-    const char* name;
+pa_dbus_connection* pa_dbus_bus_get(pa_core *c, DBusBusType type, DBusError *error) {
+
+    static const char *const prop_name[] = {
+        [DBUS_BUS_SESSION] = "dbus-connection-session",
+        [DBUS_BUS_SYSTEM] = "dbus-connection-system",
+        [DBUS_BUS_STARTER] = "dbus-connection-starter"
+    };
     DBusConnection *conn;
     pa_dbus_connection *pconn;
 
-    switch (type) {
-        case DBUS_BUS_SYSTEM:
-            name = "dbus-connection-system";
-            break;
-        case DBUS_BUS_SESSION:
-            name = "dbus-connection-session";
-            break;
-        case DBUS_BUS_STARTER:
-            name = "dbus-connection-starter";
-            break;
-        default:
-            assert(0); /* never reached */
-            break;
-    }
-
-    if ((pconn = pa_property_get(c, name)))
+    pa_assert(type == DBUS_BUS_SYSTEM || type == DBUS_BUS_SESSION || type == DBUS_BUS_STARTER);
+
+    if ((pconn = pa_property_get(c, prop_name[type])))
         return pa_dbus_connection_ref(pconn);
 
-    /* else */
-    conn = dbus_bus_get_private(type, error);
-    if (conn == NULL || dbus_error_is_set(error)) {
+    if (!(conn = dbus_bus_get_private(type, error)))
         return NULL;
-    }
-
-    pconn = pa_dbus_connection_new(c, conn, name);
-
-    /* don't exit on disconnect */
+
+    pconn = pa_dbus_connection_new(c, conn, prop_name[type]);
+
     dbus_connection_set_exit_on_disconnect(conn, FALSE);
-    /* set up the DBUS call backs */
-    dbus_connection_set_dispatch_status_function(conn, dispatch_status,
-                                                 (void*) pconn, NULL);
-    dbus_connection_set_watch_functions(conn,
-                                        add_watch,
-                                        remove_watch,
-                                        toggle_watch,
-                                        (void*) c, NULL);
-    dbus_connection_set_timeout_functions(conn,
-                                          add_timeout,
-                                          remove_timeout,
-                                          toggle_timeout,
-                                          (void*) c, NULL);
+    dbus_connection_set_dispatch_status_function(conn, dispatch_status, pconn, NULL);
+    dbus_connection_set_watch_functions(conn, add_watch, remove_watch, toggle_watch, c, NULL);
+    dbus_connection_set_timeout_functions(conn, add_timeout, remove_timeout, toggle_timeout, c, NULL);
     dbus_connection_set_wakeup_main_function(conn, wakeup_main, pconn, NULL);
 
     return pconn;

Modified: trunk/src/modules/gconf/gconf-helper.c
URL: http://0pointer.de/cgi-bin/viewcvs.cgi/trunk/src/modules/gconf/gconf-helper.c?rev=1971&root=pulseaudio&r1=1970&r2=1971&view=diff
==============================================================================
--- trunk/src/modules/gconf/gconf-helper.c (original)
+++ trunk/src/modules/gconf/gconf-helper.c Sun Oct 28 20:13:50 2007
@@ -32,6 +32,8 @@
 #include <gconf/gconf-client.h>
 #include <glib.h>
 
+#include <pulsecore/core-util.h>
+
 #define PA_GCONF_ROOT "/system/pulseaudio"
 #define PA_GCONF_PATH_MODULES PA_GCONF_ROOT"/modules"
 
@@ -40,13 +42,13 @@
     gboolean enabled, locked;
     int i;
 
-    snprintf(p, sizeof(p), PA_GCONF_PATH_MODULES"/%s/locked", name);
+    pa_snprintf(p, sizeof(p), PA_GCONF_PATH_MODULES"/%s/locked", name);
     locked = gconf_client_get_bool(client, p, FALSE);
 
     if (locked)
         return;
 
-    snprintf(p, sizeof(p), PA_GCONF_PATH_MODULES"/%s/enabled", name);
+    pa_snprintf(p, sizeof(p), PA_GCONF_PATH_MODULES"/%s/enabled", name);
     enabled = gconf_client_get_bool(client, p, FALSE);
 
     printf("%c%s%c", enabled ? '+' : '-', name, 0);
@@ -56,11 +58,11 @@
         for (i = 0; i < 10; i++) {
             gchar *n, *a;
 
-            snprintf(p, sizeof(p), PA_GCONF_PATH_MODULES"/%s/name%i", name, i);
+            pa_snprintf(p, sizeof(p), PA_GCONF_PATH_MODULES"/%s/name%i", name, i);
             if (!(n = gconf_client_get_string(client, p, NULL)) || !*n)
                 break;
 
-            snprintf(p, sizeof(p), PA_GCONF_PATH_MODULES"/%s/args%i", name, i);
+            pa_snprintf(p, sizeof(p), PA_GCONF_PATH_MODULES"/%s/args%i", name, i);
             a = gconf_client_get_string(client, p, NULL);
 
             printf("%s%c%s%c", n, 0, a ? a : "", 0);

Modified: trunk/src/modules/gconf/module-gconf.c
URL: http://0pointer.de/cgi-bin/viewcvs.cgi/trunk/src/modules/gconf/module-gconf.c?rev=1971&root=pulseaudio&r1=1970&r2=1971&view=diff
==============================================================================
--- trunk/src/modules/gconf/module-gconf.c (original)
+++ trunk/src/modules/gconf/module-gconf.c Sun Oct 28 20:13:50 2007
@@ -25,7 +25,6 @@
 #include <config.h>
 #endif
 
-#include <assert.h>
 #include <string.h>
 #include <unistd.h>
 #include <stdlib.h>
@@ -34,6 +33,7 @@
 #include <sys/types.h>
 #include <sys/wait.h>
 #include <fcntl.h>
+#include <dirent.h>
 
 #ifdef HAVE_SYS_PRCTL_H
 #include <sys/prctl.h>
@@ -95,7 +95,7 @@
 
 static int fill_buf(struct userdata *u) {
     ssize_t r;
-    assert(u);
+    pa_assert(u);
 
     if (u->buf_fill >= BUF_MAX) {
         pa_log("read buffer overflow");
@@ -111,21 +111,21 @@
 
 static int read_byte(struct userdata *u) {
     int ret;
-    assert(u);
+    pa_assert(u);
 
     if (u->buf_fill < 1)
         if (fill_buf(u) < 0)
             return -1;
 
     ret = u->buf[0];
-    assert(u->buf_fill > 0);
+    pa_assert(u->buf_fill > 0);
     u->buf_fill--;
     memmove(u->buf, u->buf+1, u->buf_fill);
     return ret;
 }
 
 static char *read_string(struct userdata *u) {
-    assert(u);
+    pa_assert(u);
 
     for (;;) {
         char *e;
@@ -143,9 +143,9 @@
 }
 
 static void unload_one_module(struct userdata *u, struct module_info*m, unsigned i) {
-    assert(u);
-    assert(m);
-    assert(i < m->n_items);
+    pa_assert(u);
+    pa_assert(m);
+    pa_assert(i < m->n_items);
 
     if (m->items[i].index == PA_INVALID_INDEX)
         return;
@@ -161,8 +161,8 @@
 static void unload_all_modules(struct userdata *u, struct module_info*m) {
     unsigned i;
 
-    assert(u);
-    assert(m);
+    pa_assert(u);
+    pa_assert(m);
 
     for (i = 0; i < m->n_items; i++)
         unload_one_module(u, m, i);
@@ -180,10 +180,10 @@
 
     pa_module *mod;
 
-    assert(u);
-    assert(m);
-    assert(name);
-    assert(args);
+    pa_assert(u);
+    pa_assert(m);
+    pa_assert(name);
+    pa_assert(args);
 
     if (!is_new) {
         if (m->items[i].index != PA_INVALID_INDEX &&
@@ -212,8 +212,8 @@
     struct module_info *m = p;
     struct userdata *u = userdata;
 
-    assert(m);
-    assert(u);
+    pa_assert(m);
+    pa_assert(u);
 
     unload_all_modules(u, m);
     pa_xfree(m->name);
@@ -356,8 +356,10 @@
 
         return pipe_fds[0];
     } else {
+#ifdef __linux__
+        DIR* d;
+#endif
         int max_fd, i;
-
         /* child */
 
         close(pipe_fds[0]);
@@ -372,18 +374,48 @@
         close(2);
         open("/dev/null", O_WRONLY);
 
-        max_fd = 1024;
+#ifdef __linux__
+
+        if ((d = opendir("/proc/self/fd/"))) {
+
+            struct dirent *de;
+
+            while ((de = readdir(d))) {
+                char *e = NULL;
+                int fd;
+
+                if (de->d_name[0] == '.')
+                    continue;
+
+                errno = 0;
+                fd = strtol(de->d_name, &e, 10);
+                pa_assert(errno == 0 && e && *e == 0);
+
+                if (fd >= 3 && dirfd(d) != fd)
+                    close(fd);
+            }
+
+            closedir(d);
+        } else {
+
+#endif
+
+            max_fd = 1024;
 
 #ifdef HAVE_SYS_RESOURCE_H
-        {
-            struct rlimit r;
-            if (getrlimit(RLIMIT_NOFILE, &r) == 0)
-                max_fd = r.rlim_max;
+            {
+                struct rlimit r;
+                if (getrlimit(RLIMIT_NOFILE, &r) == 0)
+                    max_fd = r.rlim_max;
+            }
+#endif
+
+            for (i = 3; i < max_fd; i++)
+                close(i);
+#
+#ifdef __linux__
         }
 #endif
-
-        for (i = 3; i < max_fd; i++)
-            close(i);
 
 #ifdef PR_SET_PDEATHSIG
         /* On Linux we can use PR_SET_PDEATHSIG to have the helper
@@ -413,12 +445,12 @@
     return -1;
 }
 
-int pa__init(pa_core *c, pa_module*m) {
+int pa__init(pa_module*m) {
     struct userdata *u;
     int r;
 
     u = pa_xnew(struct userdata, 1);
-    u->core = c;
+    u->core = m->core;
     u->module = m;
     m->userdata = u;
     u->module_infos = pa_hashmap_new(pa_idxset_string_hash_func, pa_idxset_string_compare_func);
@@ -431,8 +463,8 @@
     if ((u->fd = start_client(PA_GCONF_HELPER, &u->pid)) < 0)
         goto fail;
 
-    u->io_event = c->mainloop->io_new(
-            c->mainloop,
+    u->io_event = m->core->mainloop->io_new(
+            m->core->mainloop,
             u->fd,
             PA_IO_EVENT_INPUT,
             io_event_cb,
@@ -449,21 +481,20 @@
     return 0;
 
 fail:
-    pa__done(c, m);
+    pa__done(m);
     return -1;
 }
 
-void pa__done(pa_core *c, pa_module*m) {
+void pa__done(pa_module*m) {
     struct userdata *u;
 
-    assert(c);
-    assert(m);
+    pa_assert(m);
 
     if (!(u = m->userdata))
         return;
 
     if (u->io_event)
-        c->mainloop->io_free(u->io_event);
+        m->core->mainloop->io_free(u->io_event);
 
     if (u->fd >= 0)
         close(u->fd);

Copied: trunk/src/modules/ladspa.h (from r1970, branches/lennart/src/modules/ladspa.h)
URL: http://0pointer.de/cgi-bin/viewcvs.cgi/trunk/src/modules/ladspa.h?p2=trunk/src/modules/ladspa.h&p1=branches/lennart/src/modules/ladspa.h&r1=1970&r2=1971&rev=1971&root=pulseaudio&view=diff
==============================================================================
--- branches/lennart/src/modules/ladspa.h (original)
+++ trunk/src/modules/ladspa.h Sun Oct 28 20:13:50 2007
@@ -3,17 +3,17 @@
    Linux Audio Developer's Simple Plugin API Version 1.1[LGPL].
    Copyright (C) 2000-2002 Richard W.E. Furse, Paul Barton-Davis,
    Stefan Westerfeld.
-   
+
    This library 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.
-   
+
    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
    Lesser General Public License for more details.
-   
+
    You should have received a copy of the GNU Lesser General Public
    License along with this library; if not, write to the Free Software
    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
@@ -32,7 +32,7 @@
 
 /*****************************************************************************/
 
-/* Overview: 
+/* Overview:
 
    There is a large number of synthesis packages in use or development
    on the Linux platform at this time. This API (`The Linux Audio
@@ -76,7 +76,7 @@
 /* Fundamental data type passed in and out of plugin. This data type
    is used to communicate audio samples and control values. It is
    assumed that the plugin will work sensibly given any numeric input
-   value although it may have a preferred range (see hints below). 
+   value although it may have a preferred range (see hints below).
 
    For audio it is generally assumed that 1.0f is the `0dB' reference
    amplitude and is a `normal' signal level. */
@@ -85,8 +85,8 @@
 
 /*****************************************************************************/
 
-/* Special Plugin Properties: 
- 
+/* Special Plugin Properties:
+
    Optional features of the plugin type are encapsulated in the
    LADSPA_Properties type. This is assembled by ORing individual
    properties together. */
@@ -122,7 +122,7 @@
    (3) The plugin will not access files, devices, pipes, sockets, IPC
    or any other mechanism that might result in process or thread
    blocking.
-      
+
    (4) The plugin will take an amount of time to execute a run() or
    run_adding() call approximately of form (A+B*SampleCount) where A
    and B depend on the machine and host in use. This amount of time
@@ -137,7 +137,7 @@
 
 /*****************************************************************************/
 
-/* Plugin Ports: 
+/* Plugin Ports:
 
    Plugins have `ports' that are inputs or outputs for audio or
    data. Ports can communicate arrays of LADSPA_Data (for audio
@@ -172,23 +172,23 @@
 
 /*****************************************************************************/
 
-/* Plugin Port Range Hints: 
+/* Plugin Port Range Hints:
 
    The host may wish to provide a representation of data entering or
    leaving a plugin (e.g. to generate a GUI automatically). To make
    this more meaningful, the plugin should provide `hints' to the host
    describing the usual values taken by the data.
-   
+
    Note that these are only hints. The host may ignore them and the
    plugin must not assume that data supplied to it is meaningful. If
    the plugin receives invalid input data it is expected to continue
    to run without failure and, where possible, produce a sensible
    output (e.g. a high-pass filter given a negative cutoff frequency
    might switch to an all-pass mode).
-    
+
    Hints are meaningful for all input and output ports but hints for
    input control ports are expected to be particularly useful.
-   
+
    More hint information is encapsulated in the
    LADSPA_PortRangeHintDescriptor type which is assembled by ORing
    individual hint types together. Hints may require further
@@ -353,7 +353,7 @@
 
 /*****************************************************************************/
 
-/* Plugin Handles: 
+/* Plugin Handles:
 
    This plugin handle indicates a particular instance of the plugin
    concerned. It is valid to compare this to NULL (0 for C++) but
@@ -364,13 +364,13 @@
 
 /*****************************************************************************/
 
-/* Descriptor for a Type of Plugin: 
+/* Descriptor for a Type of Plugin:
 
    This structure is used to describe a plugin type. It provides a
    number of functions to examine the type, instantiate it, link it to
    buffers and workspaces and to run it. */
 
-typedef struct _LADSPA_Descriptor { 
+typedef struct _LADSPA_Descriptor {
 
   /* This numeric identifier indicates the plugin type
      uniquely. Plugin programmers may reserve ranges of IDs from a
@@ -430,7 +430,7 @@
      instantiation function accepts a sample rate as a parameter. The
      plugin descriptor from which this instantiate function was found
      must also be passed. This function must return NULL if
-     instantiation fails. 
+     instantiation fails.
 
      Note that instance initialisation should generally occur in
      activate() rather than here. */
@@ -551,7 +551,7 @@
   /* Once an instance of a plugin has been finished with it can be
      deleted using the following function. The instance handle passed
      ceases to be valid after this call.
-  
+
      If activate() was called for a plugin instance then a
      corresponding call to deactivate() must be made before cleanup()
      is called. */
@@ -589,7 +589,7 @@
 const LADSPA_Descriptor * ladspa_descriptor(unsigned long Index);
 
 /* Datatype corresponding to the ladspa_descriptor() function. */
-typedef const LADSPA_Descriptor * 
+typedef const LADSPA_Descriptor *
 (*LADSPA_Descriptor_Function)(unsigned long Index);
 
 /**********************************************************************/

Modified: trunk/src/modules/module-alsa-sink.c
URL: http://0pointer.de/cgi-bin/viewcvs.cgi/trunk/src/modules/module-alsa-sink.c?rev=1971&root=pulseaudio&r1=1970&r2=1971&view=diff
==============================================================================
--- trunk/src/modules/module-alsa-sink.c (original)
+++ trunk/src/modules/module-alsa-sink.c Sun Oct 28 20:13:50 2007
@@ -26,18 +26,12 @@
 #include <config.h>
 #endif
 
-#include <assert.h>
 #include <stdio.h>
 
-#ifdef HAVE_SYS_POLL_H
-#include <sys/poll.h>
-#else
-#include "poll.h"
-#endif
-
 #include <asoundlib.h>
 
 #include <pulse/xmalloc.h>
+#include <pulse/util.h>
 
 #include <pulsecore/core.h>
 #include <pulsecore/module.h>
@@ -47,6 +41,11 @@
 #include <pulsecore/core-util.h>
 #include <pulsecore/sample-util.h>
 #include <pulsecore/log.h>
+#include <pulsecore/macro.h>
+#include <pulsecore/thread.h>
+#include <pulsecore/core-error.h>
+#include <pulsecore/thread-mq.h>
+#include <pulsecore/rtpoll.h>
 
 #include "alsa-util.h"
 #include "module-alsa-sink-symdef.h"
@@ -62,20 +61,38 @@
         "rate=<sample rate> "
         "fragments=<number of fragments> "
         "fragment_size=<fragment size> "
-        "channel_map=<channel map>")
+        "channel_map=<channel map> "
+        "mmap=<enable memory mapping?>")
+
+#define DEFAULT_DEVICE "default"
 
 struct userdata {
+    pa_core *core;
+    pa_module *module;
+    pa_sink *sink;
+
+    pa_thread *thread;
+    pa_thread_mq thread_mq;
+    pa_rtpoll *rtpoll;
+
     snd_pcm_t *pcm_handle;
+
+    pa_alsa_fdlist *mixer_fdl;
     snd_mixer_t *mixer_handle;
     snd_mixer_elem_t *mixer_elem;
-    pa_sink *sink;
-    struct pa_alsa_fdlist *pcm_fdl;
-    struct pa_alsa_fdlist *mixer_fdl;
     long hw_volume_max, hw_volume_min;
 
-    size_t frame_size, fragment_size;
-    pa_memchunk memchunk, silence;
-    pa_module *module;
+    size_t frame_size, fragment_size, hwbuf_size;
+    unsigned nfragments;
+    pa_memchunk memchunk;
+
+    char *device_name;
+
+    int use_mmap;
+
+    int first;
+
+    pa_rtpoll_item *alsa_rtpoll_item;
 };
 
 static const char* const valid_modargs[] = {
@@ -87,260 +104,440 @@
     "fragments",
     "fragment_size",
     "channel_map",
+    "mmap",
     NULL
 };
 
-#define DEFAULT_DEVICE "default"
-
-static void update_usage(struct userdata *u) {
-    pa_module_set_used(u->module, u->sink ? pa_sink_used_by(u->sink) : 0);
-}
-
-static void clear_up(struct userdata *u) {
-    assert(u);
-
-    if (u->sink) {
-        pa_sink_disconnect(u->sink);
-        pa_sink_unref(u->sink);
-        u->sink = NULL;
-    }
-
-    if (u->pcm_fdl)
-        pa_alsa_fdlist_free(u->pcm_fdl);
-    if (u->mixer_fdl)
-        pa_alsa_fdlist_free(u->mixer_fdl);
-
-    u->pcm_fdl = u->mixer_fdl = NULL;
-
-    if (u->mixer_handle) {
-        snd_mixer_close(u->mixer_handle);
-        u->mixer_handle = NULL;
-    }
-
+static int mmap_write(struct userdata *u) {
+    int work_done = 0;
+
+    pa_assert(u);
+    pa_sink_assert_ref(u->sink);
+
+    for (;;) {
+        pa_memchunk chunk;
+        void *p;
+        snd_pcm_sframes_t n;
+        int err;
+        const snd_pcm_channel_area_t *areas;
+        snd_pcm_uframes_t offset, frames;
+
+        if ((n = snd_pcm_avail_update(u->pcm_handle)) < 0) {
+
+            if (n == -EPIPE) {
+                pa_log_debug("snd_pcm_avail_update: Buffer underrun!");
+                u->first = 1;
+            }
+
+            if ((err = snd_pcm_recover(u->pcm_handle, n, 1)) == 0)
+                continue;
+
+            if (err == -EAGAIN)
+                return work_done;
+
+            pa_log("snd_pcm_avail_update: %s", snd_strerror(err));
+            return -1;
+        }
+
+/*         pa_log("Got request for %i samples", (int) n); */
+
+        if (n <= 0)
+            return work_done;
+
+        frames = n;
+
+        if ((err = snd_pcm_mmap_begin(u->pcm_handle, &areas, &offset, &frames)) < 0) {
+
+            if (err == -EPIPE) {
+                pa_log_debug("snd_pcm_mmap_begin: Buffer underrun!");
+                u->first = 1;
+            }
+
+            if ((err = snd_pcm_recover(u->pcm_handle, err, 1)) == 0)
+                continue;
+
+            if (err == -EAGAIN)
+                return work_done;
+
+            pa_log("Failed to write data to DSP: %s", snd_strerror(err));
+            return -1;
+        }
+
+        /* Check these are multiples of 8 bit */
+        pa_assert((areas[0].first & 7) == 0);
+        pa_assert((areas[0].step & 7)== 0);
+
+        /* We assume a single interleaved memory buffer */
+        pa_assert((areas[0].first >> 3) == 0);
+        pa_assert((areas[0].step >> 3) == u->frame_size);
+
+        p = (uint8_t*) areas[0].addr + (offset * u->frame_size);
+
+        chunk.memblock = pa_memblock_new_fixed(u->core->mempool, p, frames * u->frame_size, 1);
+        chunk.length = pa_memblock_get_length(chunk.memblock);
+        chunk.index = 0;
+
+        pa_sink_render_into_full(u->sink, &chunk);
+
+        /* FIXME: Maybe we can do something to keep this memory block
+         * a little bit longer around? */
+        pa_memblock_unref_fixed(chunk.memblock);
+
+        if ((err = snd_pcm_mmap_commit(u->pcm_handle, offset, frames)) < 0) {
+
+            if (err == -EPIPE) {
+                pa_log_debug("snd_pcm_mmap_commit: Buffer underrun!");
+                u->first = 1;
+            }
+
+            if ((err = snd_pcm_recover(u->pcm_handle, err, 1)) == 0)
+                continue;
+
+            if (err == -EAGAIN)
+                return work_done;
+
+            pa_log("Failed to write data to DSP: %s", snd_strerror(err));
+            return -1;
+        }
+
+        work_done = 1;
+
+        if (frames >= (snd_pcm_uframes_t) n)
+            return work_done;
+
+/*         pa_log("wrote %i samples", (int) frames); */
+    }
+}
+
+static int unix_write(struct userdata *u) {
+    snd_pcm_status_t *status;
+    int work_done = 0;
+
+    snd_pcm_status_alloca(&status);
+
+    pa_assert(u);
+    pa_sink_assert_ref(u->sink);
+
+    for (;;) {
+        void *p;
+        snd_pcm_sframes_t t;
+        ssize_t l;
+        int err;
+
+        if ((err = snd_pcm_status(u->pcm_handle, status)) < 0) {
+            pa_log("Failed to query DSP status data: %s", snd_strerror(err));
+            return -1;
+        }
+
+        if (snd_pcm_status_get_avail_max(status)*u->frame_size >= u->hwbuf_size)
+            pa_log_debug("Buffer underrun!");
+
+        l = snd_pcm_status_get_avail(status) * u->frame_size;
+
+/*         pa_log("%u bytes to write", l); */
+
+        if (l <= 0)
+            return work_done;
+
+        if (u->memchunk.length <= 0)
+            pa_sink_render(u->sink, l, &u->memchunk);
+
+        pa_assert(u->memchunk.length > 0);
+
+        p = pa_memblock_acquire(u->memchunk.memblock);
+        t = snd_pcm_writei(u->pcm_handle, (const uint8_t*) p + u->memchunk.index, u->memchunk.length / u->frame_size);
+        pa_memblock_release(u->memchunk.memblock);
+
+/*         pa_log("wrote %i bytes of %u (%u)", t*u->frame_size, u->memchunk.length, l); */
+
+        pa_assert(t != 0);
+
+        if (t < 0) {
+
+            if ((t = snd_pcm_recover(u->pcm_handle, t, 1)) == 0)
+                continue;
+
+            if (t == -EAGAIN) {
+                pa_log_debug("EAGAIN");
+                return work_done;
+            } else {
+                pa_log("Failed to write data to DSP: %s", snd_strerror(t));
+                return -1;
+            }
+        }
+
+        u->memchunk.index += t * u->frame_size;
+        u->memchunk.length -= t * u->frame_size;
+
+        if (u->memchunk.length <= 0) {
+            pa_memblock_unref(u->memchunk.memblock);
+            pa_memchunk_reset(&u->memchunk);
+        }
+
+        work_done = 1;
+
+        if (t * u->frame_size >= (unsigned) l)
+            return work_done;
+    }
+}
+
+static pa_usec_t sink_get_latency(struct userdata *u) {
+    pa_usec_t r = 0;
+    snd_pcm_status_t *status;
+    snd_pcm_sframes_t frames = 0;
+    int err;
+
+    snd_pcm_status_alloca(&status);
+
+    pa_assert(u);
+    pa_assert(u->pcm_handle);
+
+    if ((err = snd_pcm_status(u->pcm_handle, status)) < 0)
+        pa_log("Failed to get delay: %s", snd_strerror(err));
+    else
+        frames = snd_pcm_status_get_delay(status);
+
+    if (frames > 0)
+        r = pa_bytes_to_usec(frames * u->frame_size, &u->sink->sample_spec);
+
+    if (u->memchunk.memblock)
+        r += pa_bytes_to_usec(u->memchunk.length, &u->sink->sample_spec);
+
+    return r;
+}
+
+static int build_pollfd(struct userdata *u) {
+    int err;
+    struct pollfd *pollfd;
+    int n;
+
+    pa_assert(u);
+    pa_assert(u->pcm_handle);
+
+    if ((n = snd_pcm_poll_descriptors_count(u->pcm_handle)) < 0) {
+        pa_log("snd_pcm_poll_descriptors_count() failed: %s", snd_strerror(n));
+        return -1;
+    }
+
+    if (u->alsa_rtpoll_item)
+        pa_rtpoll_item_free(u->alsa_rtpoll_item);
+
+    u->alsa_rtpoll_item = pa_rtpoll_item_new(u->rtpoll, PA_RTPOLL_NEVER, n);
+    pollfd = pa_rtpoll_item_get_pollfd(u->alsa_rtpoll_item, NULL);
+
+    if ((err = snd_pcm_poll_descriptors(u->pcm_handle, pollfd, n)) < 0) {
+        pa_log("snd_pcm_poll_descriptors() failed: %s", snd_strerror(err));
+        return -1;
+    }
+
+    return 0;
+}
+
+static int suspend(struct userdata *u) {
+    pa_assert(u);
+    pa_assert(u->pcm_handle);
+
+    /* Let's suspend */
+    snd_pcm_drain(u->pcm_handle);
+    snd_pcm_close(u->pcm_handle);
+    u->pcm_handle = NULL;
+
+    if (u->alsa_rtpoll_item) {
+        pa_rtpoll_item_free(u->alsa_rtpoll_item);
+        u->alsa_rtpoll_item = NULL;
+    }
+
+    pa_log_info("Device suspended...");
+
+    return 0;
+}
+
+static int unsuspend(struct userdata *u) {
+    pa_sample_spec ss;
+    int err, b;
+    unsigned nfrags;
+    snd_pcm_uframes_t period_size;
+
+    pa_assert(u);
+    pa_assert(!u->pcm_handle);
+
+    pa_log_info("Trying resume...");
+
+    snd_config_update_free_global();
+    if ((err = snd_pcm_open(&u->pcm_handle, u->device_name, SND_PCM_STREAM_PLAYBACK, SND_PCM_NONBLOCK)) < 0) {
+        pa_log("Error opening PCM device %s: %s", u->device_name, snd_strerror(err));
+        goto fail;
+    }
+
+    ss = u->sink->sample_spec;
+    nfrags = u->nfragments;
+    period_size = u->fragment_size / u->frame_size;
+    b = u->use_mmap;
+
+    if ((err = pa_alsa_set_hw_params(u->pcm_handle, &ss, &nfrags, &period_size, &b)) < 0) {
+        pa_log("Failed to set hardware parameters: %s", snd_strerror(err));
+        goto fail;
+    }
+
+    if (b != u->use_mmap) {
+        pa_log_warn("Resume failed, couldn't get original access mode.");
+        goto fail;
+    }
+
+    if (!pa_sample_spec_equal(&ss, &u->sink->sample_spec)) {
+        pa_log_warn("Resume failed, couldn't restore original sample settings.");
+        goto fail;
+    }
+
+    if (nfrags != u->nfragments || period_size*u->frame_size != u->fragment_size) {
+        pa_log_warn("Resume failed, couldn't restore original fragment settings.");
+        goto fail;
+    }
+
+    if ((err = pa_alsa_set_sw_params(u->pcm_handle)) < 0) {
+        pa_log("Failed to set software parameters: %s", snd_strerror(err));
+        goto fail;
+    }
+
+    if (build_pollfd(u) < 0)
+        goto fail;
+
+    /* FIXME: We need to reload the volume somehow */
+
+    u->first = 1;
+
+    pa_log_info("Resumed successfully...");
+
+    return 0;
+
+fail:
     if (u->pcm_handle) {
-        snd_pcm_drop(u->pcm_handle);
         snd_pcm_close(u->pcm_handle);
         u->pcm_handle = NULL;
     }
-}
-
-static int xrun_recovery(struct userdata *u) {
-    int ret;
-    assert(u);
-
-    pa_log_info("*** ALSA-XRUN (playback) ***");
-
-    if ((ret = snd_pcm_prepare(u->pcm_handle)) < 0) {
-        pa_log("snd_pcm_prepare() failed: %s", snd_strerror(-ret));
-
-        clear_up(u);
-        pa_module_unload_request(u->module);
-        return -1;
-    }
-
-    return ret;
-}
-
-static int suspend_recovery(struct userdata *u) {
-    int ret;
-    assert(u);
-
-    pa_log_info("*** ALSA-SUSPEND (playback) ***");
-
-    if ((ret = snd_pcm_resume(u->pcm_handle)) < 0) {
-        if (ret == -EAGAIN)
-            return -1;
-
-        if (ret != -ENOSYS)
-            pa_log("snd_pcm_resume() failed: %s", snd_strerror(-ret));
-        else {
-            if ((ret = snd_pcm_prepare(u->pcm_handle)) < 0)
-                pa_log("snd_pcm_prepare() failed: %s", snd_strerror(-ret));
-        }
-
-        if (ret < 0) {
-            clear_up(u);
-            pa_module_unload_request(u->module);
-            return -1;
-        }
-    }
-
-    return ret;
-}
-
-static void do_write(struct userdata *u) {
-    assert(u);
-
-    update_usage(u);
-
-    for (;;) {
-        pa_memchunk *memchunk = NULL;
-        snd_pcm_sframes_t frames;
-
-        if (u->memchunk.memblock)
-            memchunk = &u->memchunk;
-        else {
-            if (pa_sink_render(u->sink, u->fragment_size, &u->memchunk) < 0)
-                memchunk = &u->silence;
-            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) {
-            if (frames == -EAGAIN)
-                return;
-
-            if (frames == -EPIPE) {
-                if (xrun_recovery(u) < 0)
-                    return;
-
-                continue;
+
+    return -1;
+}
+
+static int sink_process_msg(pa_msgobject *o, int code, void *data, int64_t offset, pa_memchunk *chunk) {
+    struct userdata *u = PA_SINK(o)->userdata;
+
+    switch (code) {
+
+        case PA_SINK_MESSAGE_GET_LATENCY: {
+            pa_usec_t r = 0;
+
+            if (u->pcm_handle)
+                r = sink_get_latency(u);
+
+            *((pa_usec_t*) data) = r;
+
+            return 0;
+        }
+
+        case PA_SINK_MESSAGE_SET_STATE:
+
+            switch ((pa_sink_state_t) PA_PTR_TO_UINT(data)) {
+
+                case PA_SINK_SUSPENDED:
+                    pa_assert(PA_SINK_OPENED(u->sink->thread_info.state));
+
+                    if (suspend(u) < 0)
+                        return -1;
+
+                    break;
+
+                case PA_SINK_IDLE:
+                case PA_SINK_RUNNING:
+
+                    if (u->sink->thread_info.state == PA_SINK_INIT) {
+                        if (build_pollfd(u) < 0)
+                            return -1;
+                    }
+
+                    if (u->sink->thread_info.state == PA_SINK_SUSPENDED) {
+                        if (unsuspend(u) < 0)
+                            return -1;
+                    }
+
+                    break;
+
+                case PA_SINK_UNLINKED:
+                case PA_SINK_INIT:
+                    ;
             }
 
-            if (frames == -ESTRPIPE) {
-                if (suspend_recovery(u) < 0)
-                    return;
-
-                continue;
-            }
-
-            pa_log("snd_pcm_writei() failed: %s", snd_strerror(-frames));
-
-            clear_up(u);
-            pa_module_unload_request(u->module);
-            return;
-        }
-
-        if (memchunk == &u->memchunk) {
-            size_t l = frames * u->frame_size;
-            memchunk->index += l;
-            memchunk->length -= l;
-
-            if (memchunk->length == 0) {
-                pa_memblock_unref(memchunk->memblock);
-                memchunk->memblock = NULL;
-                memchunk->index = memchunk->length = 0;
-            }
-        }
-
-        break;
-    }
-}
-
-static void fdl_callback(void *userdata) {
-    struct userdata *u = userdata;
-    assert(u);
-
-    if (snd_pcm_state(u->pcm_handle) == SND_PCM_STATE_XRUN)
-        if (xrun_recovery(u) < 0)
-            return;
-
-    if (snd_pcm_state(u->pcm_handle) == SND_PCM_STATE_SUSPENDED)
-        if (suspend_recovery(u) < 0)
-            return;
-
-    do_write(u);
+            break;
+    }
+
+    return pa_sink_process_msg(o, code, data, offset, chunk);
 }
 
 static int mixer_callback(snd_mixer_elem_t *elem, unsigned int mask) {
     struct userdata *u = snd_mixer_elem_get_callback_private(elem);
 
-    assert(u && u->mixer_handle);
+    pa_assert(u);
+    pa_assert(u->mixer_handle);
 
     if (mask == SND_CTL_EVENT_MASK_REMOVE)
         return 0;
 
     if (mask & SND_CTL_EVENT_MASK_VALUE) {
-        if (u->sink->get_hw_volume)
-            u->sink->get_hw_volume(u->sink);
-        if (u->sink->get_hw_mute)
-            u->sink->get_hw_mute(u->sink);
-        pa_subscription_post(u->sink->core,
-            PA_SUBSCRIPTION_EVENT_SINK|PA_SUBSCRIPTION_EVENT_CHANGE,
-            u->sink->index);
+        pa_sink_get_volume(u->sink);
+        pa_sink_get_mute(u->sink);
     }
 
     return 0;
 }
 
-static pa_usec_t sink_get_latency_cb(pa_sink *s) {
-    pa_usec_t r = 0;
-    struct userdata *u = s->userdata;
-    snd_pcm_sframes_t frames;
-    int err;
-
-    assert(s && u && u->sink);
-
-    if ((err = snd_pcm_delay(u->pcm_handle, &frames)) < 0) {
-        pa_log("failed to get delay: %s", snd_strerror(err));
-        s->get_latency = NULL;
-        return 0;
-    }
-
-    if (frames < 0)
-        frames = 0;
-
-    r += pa_bytes_to_usec(frames * u->frame_size, &s->sample_spec);
-
-    if (u->memchunk.memblock)
-        r += pa_bytes_to_usec(u->memchunk.length, &s->sample_spec);
-
-    return r;
-}
-
-static int sink_get_hw_volume_cb(pa_sink *s) {
+static int sink_get_volume_cb(pa_sink *s) {
     struct userdata *u = s->userdata;
     int err;
     int i;
 
-    assert(u);
-    assert(u->mixer_elem);
-
-    for (i = 0; i < s->hw_volume.channels; i++) {
+    pa_assert(u);
+    pa_assert(u->mixer_elem);
+
+    for (i = 0; i < s->sample_spec.channels; i++) {
         long set_vol, vol;
 
-        assert(snd_mixer_selem_has_playback_channel(u->mixer_elem, i));
+        pa_assert(snd_mixer_selem_has_playback_channel(u->mixer_elem, i));
 
         if ((err = snd_mixer_selem_get_playback_volume(u->mixer_elem, i, &vol)) < 0)
             goto fail;
 
-        set_vol = (long) roundf(((float) s->hw_volume.values[i] * (u->hw_volume_max - u->hw_volume_min)) / PA_VOLUME_NORM) + u->hw_volume_min;
+        set_vol = (long) roundf(((float) s->volume.values[i] * (u->hw_volume_max - u->hw_volume_min)) / PA_VOLUME_NORM) + u->hw_volume_min;
 
         /* Try to avoid superfluous volume changes */
         if (set_vol != vol)
-            s->hw_volume.values[i] = (pa_volume_t) roundf(((float) (vol - u->hw_volume_min) * PA_VOLUME_NORM) / (u->hw_volume_max - u->hw_volume_min));
+            s->volume.values[i] = (pa_volume_t) roundf(((float) (vol - u->hw_volume_min) * PA_VOLUME_NORM) / (u->hw_volume_max - u->hw_volume_min));
     }
 
     return 0;
 
 fail:
     pa_log_error("Unable to read volume: %s", snd_strerror(err));
-    s->get_hw_volume = NULL;
-    s->set_hw_volume = NULL;
+
+    s->get_volume = NULL;
+    s->set_volume = NULL;
     return -1;
 }
 
-static int sink_set_hw_volume_cb(pa_sink *s) {
+static int sink_set_volume_cb(pa_sink *s) {
     struct userdata *u = s->userdata;
     int err;
     int i;
-    pa_volume_t vol;
-
-    assert(u);
-    assert(u->mixer_elem);
-
-    for (i = 0; i < s->hw_volume.channels; i++) {
+
+    pa_assert(u);
+    pa_assert(u->mixer_elem);
+
+    for (i = 0; i < s->sample_spec.channels; i++) {
         long alsa_vol;
-
-        assert(snd_mixer_selem_has_playback_channel(u->mixer_elem, i));
-
-        vol = s->hw_volume.values[i];
+        pa_volume_t vol;
+
+        pa_assert(snd_mixer_selem_has_playback_channel(u->mixer_elem, i));
+
+        vol = s->volume.values[i];
 
         if (vol > PA_VOLUME_NORM)
             vol = PA_VOLUME_NORM;
@@ -355,55 +552,166 @@
 
 fail:
     pa_log_error("Unable to set volume: %s", snd_strerror(err));
-    s->get_hw_volume = NULL;
-    s->set_hw_volume = NULL;
+
+    s->get_volume = NULL;
+    s->set_volume = NULL;
     return -1;
 }
 
-static int sink_get_hw_mute_cb(pa_sink *s) {
+static int sink_get_mute_cb(pa_sink *s) {
     struct userdata *u = s->userdata;
     int err, sw;
 
-    assert(u && u->mixer_elem);
-
-    err = snd_mixer_selem_get_playback_switch(u->mixer_elem, 0, &sw);
-    if (err) {
+    pa_assert(u);
+    pa_assert(u->mixer_elem);
+
+    if ((err = snd_mixer_selem_get_playback_switch(u->mixer_elem, 0, &sw)) < 0) {
         pa_log_error("Unable to get switch: %s", snd_strerror(err));
-        s->get_hw_mute = NULL;
-        s->set_hw_mute = NULL;
+
+        s->get_mute = NULL;
+        s->set_mute = NULL;
         return -1;
     }
 
-    s->hw_muted = !sw;
+    s->muted = !sw;
 
     return 0;
 }
 
-static int sink_set_hw_mute_cb(pa_sink *s) {
+static int sink_set_mute_cb(pa_sink *s) {
     struct userdata *u = s->userdata;
     int err;
 
-    assert(u && u->mixer_elem);
-
-    err = snd_mixer_selem_set_playback_switch_all(u->mixer_elem, !s->hw_muted);
-    if (err) {
+    pa_assert(u);
+    pa_assert(u->mixer_elem);
+
+    if ((err = snd_mixer_selem_set_playback_switch_all(u->mixer_elem, !s->muted)) < 0) {
         pa_log_error("Unable to set switch: %s", snd_strerror(err));
-        s->get_hw_mute = NULL;
-        s->set_hw_mute = NULL;
+
+        s->get_mute = NULL;
+        s->set_mute = NULL;
         return -1;
     }
 
     return 0;
 }
 
-int pa__init(pa_core *c, pa_module*m) {
+static void thread_func(void *userdata) {
+    struct userdata *u = userdata;
+
+    pa_assert(u);
+
+    pa_log_debug("Thread starting up");
+
+    if (u->core->high_priority)
+        pa_make_realtime();
+
+    pa_thread_mq_install(&u->thread_mq);
+    pa_rtpoll_install(u->rtpoll);
+
+    for (;;) {
+        int ret;
+
+        /* Render some data and write it to the dsp */
+        if (PA_SINK_OPENED(u->sink->thread_info.state)) {
+            int work_done = 0;
+
+            if (u->use_mmap) {
+                if ((work_done = mmap_write(u)) < 0)
+                    goto fail;
+            } else {
+                if ((work_done = unix_write(u)) < 0)
+                    goto fail;
+            }
+
+            if (work_done && u->first) {
+                pa_log_info("Starting playback.");
+                snd_pcm_start(u->pcm_handle);
+                u->first = 0;
+                continue;
+            }
+        }
+
+        /* Hmm, nothing to do. Let's sleep */
+        if ((ret = pa_rtpoll_run(u->rtpoll, 1)) < 0)
+            goto fail;
+
+        if (ret == 0)
+            goto finish;
+
+        /* Tell ALSA about this and process its response */
+        if (PA_SINK_OPENED(u->sink->thread_info.state)) {
+            struct pollfd *pollfd;
+            unsigned short revents = 0;
+            int err;
+            unsigned n;
+
+            pollfd = pa_rtpoll_item_get_pollfd(u->alsa_rtpoll_item, &n);
+
+            if ((err = snd_pcm_poll_descriptors_revents(u->pcm_handle, pollfd, n, &revents)) < 0) {
+                pa_log("snd_pcm_poll_descriptors_revents() failed: %s", snd_strerror(err));
+                goto fail;
+            }
+
+            if (revents & (POLLERR|POLLNVAL|POLLHUP)) {
+
+                if (revents & POLLERR)
+                    pa_log_warn("Got POLLERR from ALSA");
+                if (revents & POLLNVAL)
+                    pa_log_warn("Got POLLNVAL from ALSA");
+                if (revents & POLLHUP)
+                    pa_log_warn("Got POLLHUP from ALSA");
+
+                /* Try to recover from this error */
+
+                switch (snd_pcm_state(u->pcm_handle)) {
+
+                    case SND_PCM_STATE_XRUN:
+                        if ((err = snd_pcm_recover(u->pcm_handle, -EPIPE, 1)) != 0) {
+                            pa_log_warn("Could not recover from POLLERR|POLLNVAL|POLLHUP and XRUN: %s", snd_strerror(err));
+                            goto fail;
+                        }
+                        break;
+
+                    case SND_PCM_STATE_SUSPENDED:
+                        if ((err = snd_pcm_recover(u->pcm_handle, -ESTRPIPE, 1)) != 0) {
+                            pa_log_warn("Could not recover from POLLERR|POLLNVAL|POLLHUP and SUSPENDED: %s", snd_strerror(err));
+                            goto fail;
+                        }
+                        break;
+
+                    default:
+
+                        snd_pcm_drop(u->pcm_handle);
+
+                        if ((err = snd_pcm_prepare(u->pcm_handle)) < 0) {
+                            pa_log_warn("Could not recover from POLLERR|POLLNVAL|POLLHUP with snd_pcm_prepare(): %s", snd_strerror(err));
+                            goto fail;
+                        }
+                        break;
+                }
+            }
+        }
+    }
+
+fail:
+    /* If this was no regular exit from the loop we have to continue
+     * processing messages until we received PA_MESSAGE_SHUTDOWN */
+    pa_asyncmsgq_post(u->thread_mq.outq, PA_MSGOBJECT(u->core), PA_CORE_MESSAGE_UNLOAD_MODULE, u->module, 0, NULL, NULL);
+    pa_asyncmsgq_wait_for(u->thread_mq.inq, PA_MESSAGE_SHUTDOWN);
+
+finish:
+    pa_log_debug("Thread shutting down");
+}
+
+int pa__init(pa_module*m) {
+
     pa_modargs *ma = NULL;
-    int ret = -1;
     struct userdata *u = NULL;
-    const char *dev;
+    char *dev;
     pa_sample_spec ss;
     pa_channel_map map;
-    uint32_t periods, fragsize;
+    uint32_t nfrags, frag_size;
     snd_pcm_uframes_t period_size;
     size_t frame_size;
     snd_pcm_info_t *pcm_info = NULL;
@@ -412,48 +720,107 @@
     const char *name;
     char *name_buf = NULL;
     int namereg_fail;
+    int use_mmap = 1, b;
+
+    snd_pcm_info_alloca(&pcm_info);
+
+    pa_assert(m);
 
     if (!(ma = pa_modargs_new(m->argument, valid_modargs))) {
-        pa_log("failed to parse module arguments");
-        goto fail;
-    }
-
-    ss = c->default_sample_spec;
+        pa_log("Failed to parse module arguments");
+        goto fail;
+    }
+
+    ss = m->core->default_sample_spec;
     if (pa_modargs_get_sample_spec_and_channel_map(ma, &ss, &map, PA_CHANNEL_MAP_ALSA) < 0) {
-        pa_log("failed to parse sample specification and channel map");
+        pa_log("Failed to parse sample specification and channel map");
         goto fail;
     }
 
     frame_size = pa_frame_size(&ss);
 
-    /* Fix latency to 100ms */
-    periods = 8;
-    fragsize = pa_bytes_per_second(&ss)/128;
-
-    if (pa_modargs_get_value_u32(ma, "fragments", &periods) < 0 || pa_modargs_get_value_u32(ma, "fragment_size", &fragsize) < 0) {
-        pa_log("failed to parse buffer metrics");
-        goto fail;
-    }
-    period_size = fragsize/frame_size;
+    nfrags = m->core->default_n_fragments;
+    frag_size = pa_usec_to_bytes(m->core->default_fragment_size_msec*1000, &ss);
+    if (frag_size <= 0)
+        frag_size = frame_size;
+
+    if (pa_modargs_get_value_u32(ma, "fragments", &nfrags) < 0 || pa_modargs_get_value_u32(ma, "fragment_size", &frag_size) < 0) {
+        pa_log("Failed to parse buffer metrics");
+        goto fail;
+    }
+    period_size = frag_size/frame_size;
+
+    if (pa_modargs_get_value_boolean(ma, "mmap", &use_mmap) < 0) {
+        pa_log("Failed to parse mmap argument.");
+        goto fail;
+    }
 
     u = pa_xnew0(struct userdata, 1);
+    u->core = m->core;
+    u->module = m;
     m->userdata = u;
-    u->module = m;
+    u->use_mmap = use_mmap;
+    u->first = 1;
+    pa_thread_mq_init(&u->thread_mq, m->core->mainloop);
+    u->rtpoll = pa_rtpoll_new();
+    u->alsa_rtpoll_item = NULL;
+    pa_rtpoll_item_new_asyncmsgq(u->rtpoll, PA_RTPOLL_EARLY, u->thread_mq.inq);
 
     snd_config_update_free_global();
-    if ((err = snd_pcm_open(&u->pcm_handle, dev = pa_modargs_get_value(ma, "device", DEFAULT_DEVICE), SND_PCM_STREAM_PLAYBACK, SND_PCM_NONBLOCK)) < 0) {
-        pa_log("Error opening PCM device %s: %s", dev, snd_strerror(err));
-        goto fail;
-    }
-
-    if ((err = snd_pcm_info_malloc(&pcm_info)) < 0 ||
-        (err = snd_pcm_info(u->pcm_handle, pcm_info)) < 0) {
+
+    dev = pa_xstrdup(pa_modargs_get_value(ma, "device", DEFAULT_DEVICE));
+
+    for (;;) {
+
+        if ((err = snd_pcm_open(&u->pcm_handle, dev, SND_PCM_STREAM_PLAYBACK, SND_PCM_NONBLOCK)) < 0) {
+            pa_log("Error opening PCM device %s: %s", dev, snd_strerror(err));
+            pa_xfree(dev);
+            goto fail;
+        }
+
+        b = use_mmap;
+        if ((err = pa_alsa_set_hw_params(u->pcm_handle, &ss, &nfrags, &period_size, &b)) < 0) {
+
+            if (err == -EPERM) {
+                /* Hmm, some hw is very exotic, so we retry with plughw, if hw didn't work */
+
+                if (pa_startswith(dev, "hw:")) {
+                    char *d = pa_sprintf_malloc("plughw:%s", dev+3);
+                    pa_log_debug("Opening the device as '%s' didn't work, retrying with '%s'.", dev, d);
+                    pa_xfree(dev);
+                    dev = d;
+
+                    snd_pcm_close(u->pcm_handle);
+                    u->pcm_handle = NULL;
+                    continue;
+                }
+            }
+
+            pa_log("Failed to set hardware parameters: %s", snd_strerror(err));
+            pa_xfree(dev);
+            goto fail;
+        }
+
+        break;
+    }
+
+    u->device_name = dev;
+
+    if (use_mmap && !b) {
+        pa_log_info("Device doesn't support mmap(), falling back to UNIX read/write mode.");
+        u->use_mmap = use_mmap = b;
+    }
+
+    if (u->use_mmap)
+        pa_log_info("Successfully enabled mmap() mode.");
+
+    if ((err = snd_pcm_info(u->pcm_handle, pcm_info)) < 0) {
         pa_log("Error fetching PCM info: %s", snd_strerror(err));
         goto fail;
     }
 
-    if ((err = pa_alsa_set_hw_params(u->pcm_handle, &ss, &periods, &period_size)) < 0) {
-        pa_log("Failed to set hardware parameters: %s", snd_strerror(err));
+    if ((err = pa_alsa_set_sw_params(u->pcm_handle)) < 0) {
+        pa_log("Failed to set software parameters: %s", snd_strerror(err));
         goto fail;
     }
 
@@ -464,15 +831,16 @@
         /* Seems ALSA didn't like the channel number, so let's fix the channel map */
         pa_channel_map_init_auto(&map, ss.channels, PA_CHANNEL_MAP_ALSA);
 
-    if ((err = snd_mixer_open(&u->mixer_handle, 0)) < 0) {
-        pa_log("Error opening mixer: %s", snd_strerror(err));
-        goto fail;
-    }
-
-    if ((pa_alsa_prepare_mixer(u->mixer_handle, dev) < 0) ||
-        !(u->mixer_elem = pa_alsa_find_elem(u->mixer_handle, "PCM", "Master"))) {
-        snd_mixer_close(u->mixer_handle);
-        u->mixer_handle = NULL;
+    if ((err = snd_mixer_open(&u->mixer_handle, 0)) < 0)
+        pa_log_warn("Error opening mixer: %s", snd_strerror(err));
+    else {
+
+        if ((pa_alsa_prepare_mixer(u->mixer_handle, dev) < 0) ||
+            !(u->mixer_elem = pa_alsa_find_elem(u->mixer_handle, "Master", "PCM"))) {
+
+            snd_mixer_close(u->mixer_handle);
+            u->mixer_handle = NULL;
+        }
     }
 
     if ((name = pa_modargs_get_value(ma, "sink_name", NULL)))
@@ -482,114 +850,146 @@
         namereg_fail = 0;
     }
 
-    if (!(u->sink = pa_sink_new(c, __FILE__, name, namereg_fail, &ss, &map))) {
+    u->sink = pa_sink_new(m->core, __FILE__, name, namereg_fail, &ss, &map);
+    pa_xfree(name_buf);
+
+    if (!u->sink) {
         pa_log("Failed to create sink object");
         goto fail;
     }
 
-    u->sink->is_hardware = 1;
-    u->sink->get_latency = sink_get_latency_cb;
+    u->sink->parent.process_msg = sink_process_msg;
+    u->sink->userdata = u;
+
+    pa_sink_set_module(u->sink, m);
+    pa_sink_set_asyncmsgq(u->sink, u->thread_mq.inq);
+    pa_sink_set_rtpoll(u->sink, u->rtpoll);
+    pa_sink_set_description(u->sink, t = pa_sprintf_malloc(
+                                    "ALSA PCM on %s (%s)%s",
+                                    dev,
+                                    snd_pcm_info_get_name(pcm_info),
+                                    use_mmap ? " via DMA" : ""));
+    pa_xfree(t);
+
+    u->sink->flags = PA_SINK_HARDWARE|PA_SINK_HW_VOLUME_CTRL|PA_SINK_LATENCY;
+
+    u->frame_size = frame_size;
+    u->fragment_size = frag_size = period_size * frame_size;
+    u->nfragments = nfrags;
+    u->hwbuf_size = u->fragment_size * nfrags;
+
+    pa_log_info("Using %u fragments of size %lu bytes.", nfrags, (long unsigned) u->fragment_size);
+
+    pa_memchunk_reset(&u->memchunk);
+
     if (u->mixer_handle) {
-        assert(u->mixer_elem);
+        /* Initialize mixer code */
+
+        pa_assert(u->mixer_elem);
+
         if (snd_mixer_selem_has_playback_volume(u->mixer_elem)) {
             int i;
 
-            for (i = 0;i < ss.channels;i++) {
+            for (i = 0; i < ss.channels; i++)
                 if (!snd_mixer_selem_has_playback_channel(u->mixer_elem, i))
                     break;
-            }
 
             if (i == ss.channels) {
-                u->sink->get_hw_volume = sink_get_hw_volume_cb;
-                u->sink->set_hw_volume = sink_set_hw_volume_cb;
-                snd_mixer_selem_get_playback_volume_range(
-                    u->mixer_elem, &u->hw_volume_min, &u->hw_volume_max);
-            }
-        }
+                pa_log_debug("ALSA device has separate volumes controls for all %u channels.", ss.channels);
+                u->sink->get_volume = sink_get_volume_cb;
+                u->sink->set_volume = sink_set_volume_cb;
+                snd_mixer_selem_get_playback_volume_range(u->mixer_elem, &u->hw_volume_min, &u->hw_volume_max);
+            } else
+                pa_log_info("ALSA device lacks separate volumes controls for all %u channels (%u available), falling back to software volume control.", ss.channels, i+1);
+        }
+
         if (snd_mixer_selem_has_playback_switch(u->mixer_elem)) {
-            u->sink->get_hw_mute = sink_get_hw_mute_cb;
-            u->sink->set_hw_mute = sink_set_hw_mute_cb;
-        }
-    }
-    u->sink->userdata = u;
-    pa_sink_set_owner(u->sink, m);
-    pa_sink_set_description(u->sink, t = pa_sprintf_malloc("ALSA PCM on %s (%s)", dev, snd_pcm_info_get_name(pcm_info)));
-    pa_xfree(t);
-
-    u->pcm_fdl = pa_alsa_fdlist_new();
-    assert(u->pcm_fdl);
-    if (pa_alsa_fdlist_init_pcm(u->pcm_fdl, u->pcm_handle, c->mainloop, fdl_callback, u) < 0) {
-        pa_log("failed to initialise file descriptor monitoring");
-        goto fail;
-    }
-
-    if (u->mixer_handle) {
+            u->sink->get_mute = sink_get_mute_cb;
+            u->sink->set_mute = sink_set_mute_cb;
+        }
+
         u->mixer_fdl = pa_alsa_fdlist_new();
-        assert(u->mixer_fdl);
-        if (pa_alsa_fdlist_init_mixer(u->mixer_fdl, u->mixer_handle, c->mainloop) < 0) {
+
+        if (pa_alsa_fdlist_set_mixer(u->mixer_fdl, u->mixer_handle, m->core->mainloop) < 0) {
             pa_log("failed to initialise file descriptor monitoring");
             goto fail;
         }
+
         snd_mixer_elem_set_callback(u->mixer_elem, mixer_callback);
         snd_mixer_elem_set_callback_private(u->mixer_elem, u);
     } else
         u->mixer_fdl = NULL;
 
-    u->frame_size = frame_size;
-    u->fragment_size = period_size * frame_size;
-
-    pa_log_info("using %u fragments of size %lu bytes.", periods, (long unsigned)u->fragment_size);
-
-    u->silence.memblock = pa_memblock_new(c->mempool, u->silence.length = u->fragment_size);
-    assert(u->silence.memblock);
-    pa_silence_memblock(u->silence.memblock, &ss);
-    u->silence.index = 0;
-
-    u->memchunk.memblock = NULL;
-    u->memchunk.index = u->memchunk.length = 0;
-
-    ret = 0;
+    if (!(u->thread = pa_thread_new(thread_func, u))) {
+        pa_log("Failed to create thread.");
+        goto fail;
+    }
 
     /* Get initial mixer settings */
-    if (u->sink->get_hw_volume)
-        u->sink->get_hw_volume(u->sink);
-    if (u->sink->get_hw_mute)
-        u->sink->get_hw_mute(u->sink);
-
-finish:
-
-    pa_xfree(name_buf);
-
-     if (ma)
-         pa_modargs_free(ma);
-
-    if (pcm_info)
-        snd_pcm_info_free(pcm_info);
-
-    return ret;
+    if (u->sink->get_volume)
+        u->sink->get_volume(u->sink);
+    if (u->sink->get_mute)
+        u->sink->get_mute(u->sink);
+
+    pa_sink_put(u->sink);
+
+    pa_modargs_free(ma);
+
+    return 0;
 
 fail:
 
-    if (u)
-        pa__done(c, m);
-
-    goto finish;
-}
-
-void pa__done(pa_core *c, pa_module*m) {
+    if (ma)
+        pa_modargs_free(ma);
+
+    pa__done(m);
+
+    return -1;
+}
+
+void pa__done(pa_module*m) {
     struct userdata *u;
-    assert(c && m);
+
+    pa_assert(m);
 
     if (!(u = m->userdata))
         return;
 
-    clear_up(u);
+    if (u->sink)
+        pa_sink_unlink(u->sink);
+
+    if (u->thread) {
+        pa_asyncmsgq_send(u->thread_mq.inq, NULL, PA_MESSAGE_SHUTDOWN, NULL, 0, NULL);
+        pa_thread_free(u->thread);
+    }
+
+    pa_thread_mq_done(&u->thread_mq);
+
+    if (u->sink)
+        pa_sink_unref(u->sink);
 
     if (u->memchunk.memblock)
         pa_memblock_unref(u->memchunk.memblock);
-    if (u->silence.memblock)
-        pa_memblock_unref(u->silence.memblock);
-
+
+    if (u->alsa_rtpoll_item)
+        pa_rtpoll_item_free(u->alsa_rtpoll_item);
+
+    if (u->rtpoll)
+        pa_rtpoll_free(u->rtpoll);
+
+    if (u->mixer_fdl)
+        pa_alsa_fdlist_free(u->mixer_fdl);
+
+    if (u->mixer_handle)
+        snd_mixer_close(u->mixer_handle);
+
+    if (u->pcm_handle) {
+        snd_pcm_drop(u->pcm_handle);
+        snd_pcm_close(u->pcm_handle);
+    }
+
+    pa_xfree(u->device_name);
     pa_xfree(u);
-}
-
+
+    snd_config_update_free_global();
+}

Modified: trunk/src/modules/module-alsa-source.c
URL: http://0pointer.de/cgi-bin/viewcvs.cgi/trunk/src/modules/module-alsa-source.c?rev=1971&root=pulseaudio&r1=1970&r2=1971&view=diff
==============================================================================
--- trunk/src/modules/module-alsa-source.c (original)
+++ trunk/src/modules/module-alsa-source.c Sun Oct 28 20:13:50 2007
@@ -26,18 +26,12 @@
 #include <config.h>
 #endif
 
-#include <assert.h>
 #include <stdio.h>
 
-#ifdef HAVE_SYS_POLL_H
-#include <sys/poll.h>
-#else
-#include "poll.h"
-#endif
-
 #include <asoundlib.h>
 
 #include <pulse/xmalloc.h>
+#include <pulse/util.h>
 
 #include <pulsecore/core-error.h>
 #include <pulsecore/core.h>
@@ -48,6 +42,11 @@
 #include <pulsecore/core-util.h>
 #include <pulsecore/sample-util.h>
 #include <pulsecore/log.h>
+#include <pulsecore/macro.h>
+#include <pulsecore/thread.h>
+#include <pulsecore/core-error.h>
+#include <pulsecore/thread-mq.h>
+#include <pulsecore/rtpoll.h>
 
 #include "alsa-util.h"
 #include "module-alsa-source-symdef.h"
@@ -63,20 +62,35 @@
         "rate=<sample rate> "
         "fragments=<number of fragments> "
         "fragment_size=<fragment size> "
-        "channel_map=<channel map>")
+        "channel_map=<channel map> "
+        "mmap=<enable memory mapping?>")
+
+#define DEFAULT_DEVICE "default"
 
 struct userdata {
+    pa_core *core;
+    pa_module *module;
+    pa_source *source;
+
+    pa_thread *thread;
+    pa_thread_mq thread_mq;
+    pa_rtpoll *rtpoll;
+
     snd_pcm_t *pcm_handle;
+
+    pa_alsa_fdlist *mixer_fdl;
     snd_mixer_t *mixer_handle;
     snd_mixer_elem_t *mixer_elem;
-    pa_source *source;
-    struct pa_alsa_fdlist *pcm_fdl;
-    struct pa_alsa_fdlist *mixer_fdl;
     long hw_volume_max, hw_volume_min;
 
-    size_t frame_size, fragment_size;
-    pa_memchunk memchunk;
-    pa_module *module;
+    size_t frame_size, fragment_size, hwbuf_size;
+    unsigned nfragments;
+
+    char *device_name;
+
+    int use_mmap;
+
+    pa_rtpoll_item *alsa_rtpoll_item;
 };
 
 static const char* const valid_modargs[] = {
@@ -88,257 +102,438 @@
     "fragments",
     "fragment_size",
     "channel_map",
+    "mmap",
     NULL
 };
 
-#define DEFAULT_DEVICE "default"
-
-static void update_usage(struct userdata *u) {
-   pa_module_set_used(u->module, u->source ? pa_source_used_by(u->source) : 0);
-}
-
-static void clear_up(struct userdata *u) {
-    assert(u);
-
-    if (u->source) {
-        pa_source_disconnect(u->source);
-        pa_source_unref(u->source);
-        u->source = NULL;
-    }
-
-    if (u->pcm_fdl)
-        pa_alsa_fdlist_free(u->pcm_fdl);
-    if (u->mixer_fdl)
-        pa_alsa_fdlist_free(u->mixer_fdl);
-
-    u->pcm_fdl = u->mixer_fdl = NULL;
-
-    if (u->mixer_handle) {
-        snd_mixer_close(u->mixer_handle);
-        u->mixer_handle = NULL;
-    }
-
+static int mmap_read(struct userdata *u) {
+    int work_done = 0;
+
+    pa_assert(u);
+    pa_source_assert_ref(u->source);
+
+    for (;;) {
+        snd_pcm_sframes_t n;
+        int err;
+        const snd_pcm_channel_area_t *areas;
+        snd_pcm_uframes_t offset, frames;
+        pa_memchunk chunk;
+        void *p;
+
+        if ((n = snd_pcm_avail_update(u->pcm_handle)) < 0) {
+
+            if (n == -EPIPE)
+                pa_log_debug("snd_pcm_avail_update: Buffer underrun!");
+
+            if ((err = snd_pcm_recover(u->pcm_handle, n, 1)) == 0)
+                continue;
+
+            if (err == -EAGAIN)
+                return work_done;
+
+            pa_log("snd_pcm_avail_update: %s", snd_strerror(err));
+            return -1;
+        }
+
+/*         pa_log("Got request for %i samples", (int) n); */
+
+        if (n <= 0)
+            return work_done;
+
+        frames = n;
+
+        if ((err = snd_pcm_mmap_begin(u->pcm_handle, &areas, &offset, &frames)) < 0) {
+
+            if (err == -EPIPE)
+                pa_log_debug("snd_pcm_mmap_begin: Buffer underrun!");
+
+            if ((err = snd_pcm_recover(u->pcm_handle, err, 1)) == 0)
+                continue;
+
+            if (err == -EAGAIN)
+                return work_done;
+
+            pa_log("Failed to write data to DSP: %s", snd_strerror(err));
+            return -1;
+        }
+
+        /* Check these are multiples of 8 bit */
+        pa_assert((areas[0].first & 7) == 0);
+        pa_assert((areas[0].step & 7)== 0);
+
+        /* We assume a single interleaved memory buffer */
+        pa_assert((areas[0].first >> 3) == 0);
+        pa_assert((areas[0].step >> 3) == u->frame_size);
+
+        p = (uint8_t*) areas[0].addr + (offset * u->frame_size);
+
+        chunk.memblock = pa_memblock_new_fixed(u->core->mempool, p, frames * u->frame_size, 1);
+        chunk.length = pa_memblock_get_length(chunk.memblock);
+        chunk.index = 0;
+
+        pa_source_post(u->source, &chunk);
+
+        /* FIXME: Maybe we can do something to keep this memory block
+         * a little bit longer around? */
+        pa_memblock_unref_fixed(chunk.memblock);
+
+        if ((err = snd_pcm_mmap_commit(u->pcm_handle, offset, frames)) < 0) {
+
+            if (err == -EPIPE)
+                pa_log_debug("snd_pcm_mmap_commit: Buffer underrun!");
+
+            if ((err = snd_pcm_recover(u->pcm_handle, err, 1)) == 0)
+                continue;
+
+            if (err == -EAGAIN)
+                return work_done;
+
+            pa_log("Failed to write data to DSP: %s", snd_strerror(err));
+            return -1;
+        }
+
+        work_done = 1;
+
+/*         pa_log("wrote %i samples", (int) frames); */
+    }
+}
+
+static int unix_read(struct userdata *u) {
+    snd_pcm_status_t *status;
+    int work_done = 0;
+
+    snd_pcm_status_alloca(&status);
+
+    pa_assert(u);
+    pa_source_assert_ref(u->source);
+
+    for (;;) {
+        void *p;
+        snd_pcm_sframes_t t, k;
+        ssize_t l;
+        int err;
+        pa_memchunk chunk;
+
+        if ((err = snd_pcm_status(u->pcm_handle, status)) < 0) {
+            pa_log("Failed to query DSP status data: %s", snd_strerror(err));
+            return -1;
+        }
+
+        if (snd_pcm_status_get_avail_max(status)*u->frame_size >= u->hwbuf_size)
+            pa_log_debug("Buffer overrun!");
+
+        l = snd_pcm_status_get_avail(status) * u->frame_size;
+
+        if (l <= 0)
+            return work_done;
+
+        chunk.memblock = pa_memblock_new(u->core->mempool, (size_t) -1);
+
+        k = pa_memblock_get_length(chunk.memblock);
+
+        if (k > l)
+            k = l;
+
+        k = (k/u->frame_size)*u->frame_size;
+
+        p = pa_memblock_acquire(chunk.memblock);
+        t = snd_pcm_readi(u->pcm_handle, (uint8_t*) p, k / u->frame_size);
+        pa_memblock_release(chunk.memblock);
+
+/*                     pa_log("wrote %i bytes of %u (%u)", t*u->frame_size, u->memchunk.length, l);   */
+
+        pa_assert(t != 0);
+
+        if (t < 0) {
+            pa_memblock_unref(chunk.memblock);
+
+            if ((t = snd_pcm_recover(u->pcm_handle, t, 1)) == 0)
+                continue;
+
+            if (t == -EAGAIN) {
+                pa_log_debug("EAGAIN");
+                return work_done;
+            } else {
+                pa_log("Failed to read data from DSP: %s", snd_strerror(t));
+                return -1;
+            }
+        }
+
+        chunk.index = 0;
+        chunk.length = t * u->frame_size;
+
+        pa_source_post(u->source, &chunk);
+        pa_memblock_unref(chunk.memblock);
+
+        work_done = 1;
+
+        if (t * u->frame_size >= (unsigned) l)
+            return work_done;
+    }
+}
+
+static pa_usec_t source_get_latency(struct userdata *u) {
+    pa_usec_t r = 0;
+    snd_pcm_status_t *status;
+    snd_pcm_sframes_t frames = 0;
+    int err;
+
+    snd_pcm_status_alloca(&status);
+
+    pa_assert(u);
+    pa_assert(u->pcm_handle);
+
+    if ((err = snd_pcm_status(u->pcm_handle, status)) < 0)
+        pa_log("Failed to get delay: %s", snd_strerror(err));
+    else
+        frames = snd_pcm_status_get_delay(status);
+
+    if (frames > 0)
+        r = pa_bytes_to_usec(frames * u->frame_size, &u->source->sample_spec);
+
+    return r;
+}
+
+static int build_pollfd(struct userdata *u) {
+    int err;
+    struct pollfd *pollfd;
+    int n;
+
+    pa_assert(u);
+    pa_assert(u->pcm_handle);
+
+    if ((n = snd_pcm_poll_descriptors_count(u->pcm_handle)) < 0) {
+        pa_log("snd_pcm_poll_descriptors_count() failed: %s", snd_strerror(n));
+        return -1;
+    }
+
+    if (u->alsa_rtpoll_item)
+        pa_rtpoll_item_free(u->alsa_rtpoll_item);
+
+    u->alsa_rtpoll_item = pa_rtpoll_item_new(u->rtpoll, PA_RTPOLL_NEVER, n);
+    pollfd = pa_rtpoll_item_get_pollfd(u->alsa_rtpoll_item, NULL);
+
+    if ((err = snd_pcm_poll_descriptors(u->pcm_handle, pollfd, n)) < 0) {
+        pa_log("snd_pcm_poll_descriptors() failed: %s", snd_strerror(err));
+        return -1;
+    }
+
+    return 0;
+}
+
+static int suspend(struct userdata *u) {
+    pa_assert(u);
+    pa_assert(u->pcm_handle);
+
+    /* Let's suspend */
+    snd_pcm_close(u->pcm_handle);
+    u->pcm_handle = NULL;
+
+    if (u->alsa_rtpoll_item) {
+        pa_rtpoll_item_free(u->alsa_rtpoll_item);
+        u->alsa_rtpoll_item = NULL;
+    }
+
+    pa_log_info("Device suspended...");
+
+    return 0;
+}
+
+static int unsuspend(struct userdata *u) {
+    pa_sample_spec ss;
+    int err, b;
+    unsigned nfrags;
+    snd_pcm_uframes_t period_size;
+
+    pa_assert(u);
+    pa_assert(!u->pcm_handle);
+
+    pa_log_info("Trying resume...");
+
+    snd_config_update_free_global();
+    if ((err = snd_pcm_open(&u->pcm_handle, u->device_name, SND_PCM_STREAM_CAPTURE, SND_PCM_NONBLOCK)) < 0) {
+        pa_log("Error opening PCM device %s: %s", u->device_name, snd_strerror(err));
+        goto fail;
+    }
+
+    ss = u->source->sample_spec;
+    nfrags = u->nfragments;
+    period_size = u->fragment_size / u->frame_size;
+    b = u->use_mmap;
+
+    if ((err = pa_alsa_set_hw_params(u->pcm_handle, &ss, &nfrags, &period_size, &b)) < 0) {
+        pa_log("Failed to set hardware parameters: %s", snd_strerror(err));
+        goto fail;
+    }
+
+    if (b != u->use_mmap) {
+        pa_log_warn("Resume failed, couldn't get original access mode.");
+        goto fail;
+    }
+
+    if (!pa_sample_spec_equal(&ss, &u->source->sample_spec)) {
+        pa_log_warn("Resume failed, couldn't restore original sample settings.");
+        goto fail;
+    }
+
+    if (nfrags != u->nfragments || period_size*u->frame_size != u->fragment_size) {
+        pa_log_warn("Resume failed, couldn't restore original fragment settings.");
+        goto fail;
+    }
+
+    if ((err = pa_alsa_set_sw_params(u->pcm_handle)) < 0) {
+        pa_log("Failed to set software parameters: %s", snd_strerror(err));
+        goto fail;
+    }
+
+    if (build_pollfd(u) < 0)
+        goto fail;
+
+    snd_pcm_start(u->pcm_handle);
+
+    /* FIXME: We need to reload the volume somehow */
+
+    pa_log_info("Resumed successfully...");
+
+    return 0;
+
+fail:
     if (u->pcm_handle) {
-        snd_pcm_drop(u->pcm_handle);
         snd_pcm_close(u->pcm_handle);
         u->pcm_handle = NULL;
     }
-}
-
-static int xrun_recovery(struct userdata *u) {
-    int ret;
-    assert(u);
-
-    pa_log_info("*** ALSA-XRUN (capture) ***");
-
-    if ((ret = snd_pcm_prepare(u->pcm_handle)) < 0) {
-        pa_log("snd_pcm_prepare() failed: %s", snd_strerror(-ret));
-
-        clear_up(u);
-        pa_module_unload_request(u->module);
-
-        return -1;
-    }
-
-    return 0;
-}
-
-
-static int suspend_recovery(struct userdata *u) {
-    int ret;
-    assert(u);
-
-    pa_log_info("*** ALSA-SUSPEND (capture) ***");
-
-    if ((ret = snd_pcm_resume(u->pcm_handle)) < 0) {
-        if (ret == -EAGAIN)
-            return -1;
-
-        if (ret != -ENOSYS)
-            pa_log("snd_pcm_resume() failed: %s", snd_strerror(-ret));
-        else {
-            if ((ret = snd_pcm_prepare(u->pcm_handle)) < 0)
-                pa_log("snd_pcm_prepare() failed: %s", snd_strerror(-ret));
-        }
-
-        if (ret < 0) {
-            clear_up(u);
-            pa_module_unload_request(u->module);
-            return -1;
-        }
-    }
-
-    return ret;
-}
-
-static void do_read(struct userdata *u) {
-    assert(u);
-
-    update_usage(u);
-
-    for (;;) {
-        pa_memchunk post_memchunk;
-        snd_pcm_sframes_t frames;
-        size_t l;
-
-        if (!u->memchunk.memblock) {
-            u->memchunk.memblock = pa_memblock_new(u->source->core->mempool, u->memchunk.length = u->fragment_size);
-            u->memchunk.index = 0;
-        }
-
-        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) {
-            if (frames == -EAGAIN)
-                return;
-
-            if (frames == -EPIPE) {
-                if (xrun_recovery(u) < 0)
-                    return;
-
-                continue;
+
+    return -1;
+}
+
+static int source_process_msg(pa_msgobject *o, int code, void *data, int64_t offset, pa_memchunk *chunk) {
+    struct userdata *u = PA_SOURCE(o)->userdata;
+
+    switch (code) {
+
+        case PA_SOURCE_MESSAGE_GET_LATENCY: {
+            pa_usec_t r = 0;
+
+            if (u->pcm_handle)
+                r = source_get_latency(u);
+
+            *((pa_usec_t*) data) = r;
+
+            return 0;
+        }
+
+        case PA_SOURCE_MESSAGE_SET_STATE:
+
+            switch ((pa_source_state_t) PA_PTR_TO_UINT(data)) {
+
+                case PA_SOURCE_SUSPENDED:
+                    pa_assert(PA_SOURCE_OPENED(u->source->thread_info.state));
+
+                    if (suspend(u) < 0)
+                        return -1;
+
+                    break;
+
+                case PA_SOURCE_IDLE:
+                case PA_SOURCE_RUNNING:
+
+                    if (u->source->thread_info.state == PA_SOURCE_INIT) {
+                        if (build_pollfd(u) < 0)
+                            return -1;
+
+                        snd_pcm_start(u->pcm_handle);
+                    }
+
+                    if (u->source->thread_info.state == PA_SOURCE_SUSPENDED) {
+                        if (unsuspend(u) < 0)
+                            return -1;
+                    }
+
+                    break;
+
+                case PA_SOURCE_UNLINKED:
+                case PA_SOURCE_INIT:
+                    ;
             }
 
-            if (frames == -ESTRPIPE) {
-                if (suspend_recovery(u) < 0)
-                    return;
-
-                continue;
-            }
-
-            pa_log("snd_pcm_readi() failed: %s", snd_strerror(-frames));
-
-            clear_up(u);
-            pa_module_unload_request(u->module);
-            return;
-        }
-
-        l = frames * u->frame_size;
-
-        post_memchunk = u->memchunk;
-        post_memchunk.length = l;
-
-        pa_source_post(u->source, &post_memchunk);
-
-        u->memchunk.index += l;
-        u->memchunk.length -= l;
-
-        if (u->memchunk.length == 0) {
-            pa_memblock_unref(u->memchunk.memblock);
-            u->memchunk.memblock = NULL;
-            u->memchunk.index = u->memchunk.length = 0;
-        }
-
-        break;
-    }
-}
-
-static void fdl_callback(void *userdata) {
-    struct userdata *u = userdata;
-    assert(u);
-
-    if (snd_pcm_state(u->pcm_handle) == SND_PCM_STATE_XRUN)
-        if (xrun_recovery(u) < 0)
-            return;
-
-    if (snd_pcm_state(u->pcm_handle) == SND_PCM_STATE_SUSPENDED)
-        if (suspend_recovery(u) < 0)
-            return;
-
-    do_read(u);
+            break;
+    }
+
+    return pa_source_process_msg(o, code, data, offset, chunk);
 }
 
 static int mixer_callback(snd_mixer_elem_t *elem, unsigned int mask) {
     struct userdata *u = snd_mixer_elem_get_callback_private(elem);
 
-    assert(u && u->mixer_handle);
+    pa_assert(u);
+    pa_assert(u->mixer_handle);
 
     if (mask == SND_CTL_EVENT_MASK_REMOVE)
         return 0;
 
     if (mask & SND_CTL_EVENT_MASK_VALUE) {
-        if (u->source->get_hw_volume)
-            u->source->get_hw_volume(u->source);
-        if (u->source->get_hw_mute)
-            u->source->get_hw_mute(u->source);
-
-        pa_subscription_post(u->source->core,
-            PA_SUBSCRIPTION_EVENT_SOURCE|PA_SUBSCRIPTION_EVENT_CHANGE,
-            u->source->index);
+        pa_source_get_volume(u->source);
+        pa_source_get_mute(u->source);
     }
 
     return 0;
 }
 
-static pa_usec_t source_get_latency_cb(pa_source *s) {
+static int source_get_volume_cb(pa_source *s) {
     struct userdata *u = s->userdata;
-    snd_pcm_sframes_t frames;
-    assert(s && u && u->source);
-
-    if (snd_pcm_delay(u->pcm_handle, &frames) < 0) {
-        pa_log("failed to get delay");
-        s->get_latency = NULL;
-        return 0;
-    }
-
-    return pa_bytes_to_usec(frames * u->frame_size, &s->sample_spec);
-}
-
-static int source_get_hw_volume_cb(pa_source *s) {
-    struct userdata *u = s->userdata;
-    long vol;
     int err;
     int i;
 
-    assert(u && u->mixer_elem);
-
-    for (i = 0;i < s->hw_volume.channels;i++) {
-        long set_vol;
-
-        assert(snd_mixer_selem_has_capture_channel(u->mixer_elem, i));
+    pa_assert(u);
+    pa_assert(u->mixer_elem);
+
+    for (i = 0; i < s->sample_spec.channels; i++) {
+        long set_vol, vol;
+
+        pa_assert(snd_mixer_selem_has_capture_channel(u->mixer_elem, i));
 
         if ((err = snd_mixer_selem_get_capture_volume(u->mixer_elem, i, &vol)) < 0)
             goto fail;
 
-        set_vol = (long) roundf(((float) s->hw_volume.values[i] * (u->hw_volume_max - u->hw_volume_min)) / PA_VOLUME_NORM) + u->hw_volume_min;
+        set_vol = (long) roundf(((float) s->volume.values[i] * (u->hw_volume_max - u->hw_volume_min)) / PA_VOLUME_NORM) + u->hw_volume_min;
 
         /* Try to avoid superfluous volume changes */
         if (set_vol != vol)
-            s->hw_volume.values[i] = (pa_volume_t) roundf(((float) (vol - u->hw_volume_min) * PA_VOLUME_NORM) / (u->hw_volume_max - u->hw_volume_min));
+            s->volume.values[i] = (pa_volume_t) roundf(((float) (vol - u->hw_volume_min) * PA_VOLUME_NORM) / (u->hw_volume_max - u->hw_volume_min));
     }
 
     return 0;
 
 fail:
     pa_log_error("Unable to read volume: %s", snd_strerror(err));
-    s->get_hw_volume = NULL;
-    s->set_hw_volume = NULL;
+
+    s->get_volume = NULL;
+    s->set_volume = NULL;
     return -1;
 }
 
-static int source_set_hw_volume_cb(pa_source *s) {
+static int source_set_volume_cb(pa_source *s) {
     struct userdata *u = s->userdata;
     int err;
-    pa_volume_t vol;
     int i;
 
-    assert(u && u->mixer_elem);
-
-    for (i = 0;i < s->hw_volume.channels;i++) {
-        assert(snd_mixer_selem_has_capture_channel(u->mixer_elem, i));
-
-        vol = s->hw_volume.values[i];
+    pa_assert(u);
+    pa_assert(u->mixer_elem);
+
+    for (i = 0; i < s->sample_spec.channels; i++) {
+        long alsa_vol;
+        pa_volume_t vol;
+
+        pa_assert(snd_mixer_selem_has_capture_channel(u->mixer_elem, i));
+
+        vol = s->volume.values[i];
 
         if (vol > PA_VOLUME_NORM)
             vol = PA_VOLUME_NORM;
 
-        vol = (long) roundf(((float) vol * (u->hw_volume_max - u->hw_volume_min)) / PA_VOLUME_NORM) + u->hw_volume_min;
-
-        if ((err = snd_mixer_selem_set_capture_volume(u->mixer_elem, i, vol)) < 0)
+        alsa_vol = (long) roundf(((float) vol * (u->hw_volume_max - u->hw_volume_min)) / PA_VOLUME_NORM) + u->hw_volume_min;
+
+        if ((err = snd_mixer_selem_set_capture_volume(u->mixer_elem, i, alsa_vol)) < 0)
             goto fail;
     }
 
@@ -346,55 +541,159 @@
 
 fail:
     pa_log_error("Unable to set volume: %s", snd_strerror(err));
-    s->get_hw_volume = NULL;
-    s->set_hw_volume = NULL;
+
+    s->get_volume = NULL;
+    s->set_volume = NULL;
     return -1;
 }
 
-static int source_get_hw_mute_cb(pa_source *s) {
+static int source_get_mute_cb(pa_source *s) {
     struct userdata *u = s->userdata;
     int err, sw;
 
-    assert(u && u->mixer_elem);
-
-    err = snd_mixer_selem_get_capture_switch(u->mixer_elem, 0, &sw);
-    if (err) {
+    pa_assert(u);
+    pa_assert(u->mixer_elem);
+
+    if ((err = snd_mixer_selem_get_capture_switch(u->mixer_elem, 0, &sw)) < 0) {
         pa_log_error("Unable to get switch: %s", snd_strerror(err));
-        s->get_hw_mute = NULL;
-        s->set_hw_mute = NULL;
+
+        s->get_mute = NULL;
+        s->set_mute = NULL;
         return -1;
     }
 
-    s->hw_muted = !sw;
+    s->muted = !sw;
 
     return 0;
 }
 
-static int source_set_hw_mute_cb(pa_source *s) {
+static int source_set_mute_cb(pa_source *s) {
     struct userdata *u = s->userdata;
     int err;
 
-    assert(u && u->mixer_elem);
-
-    err = snd_mixer_selem_set_capture_switch_all(u->mixer_elem, !s->hw_muted);
-    if (err) {
+    pa_assert(u);
+    pa_assert(u->mixer_elem);
+
+    if ((err = snd_mixer_selem_set_capture_switch_all(u->mixer_elem, !s->muted)) < 0) {
         pa_log_error("Unable to set switch: %s", snd_strerror(err));
-        s->get_hw_mute = NULL;
-        s->set_hw_mute = NULL;
+
+        s->get_mute = NULL;
+        s->set_mute = NULL;
         return -1;
     }
 
     return 0;
 }
 
-int pa__init(pa_core *c, pa_module*m) {
+static void thread_func(void *userdata) {
+    struct userdata *u = userdata;
+
+    pa_assert(u);
+
+    pa_log_debug("Thread starting up");
+
+    if (u->core->high_priority)
+        pa_make_realtime();
+
+    pa_thread_mq_install(&u->thread_mq);
+    pa_rtpoll_install(u->rtpoll);
+
+    for (;;) {
+        int ret;
+
+        /* Read some data and pass it to the sources */
+        if (PA_SOURCE_OPENED(u->source->thread_info.state)) {
+
+            if (u->use_mmap) {
+                if (mmap_read(u) < 0)
+                    goto fail;
+
+            } else {
+                if (unix_read(u) < 0)
+                    goto fail;
+            }
+        }
+
+        /* Hmm, nothing to do. Let's sleep */
+        if ((ret = pa_rtpoll_run(u->rtpoll, 1)) < 0)
+            goto fail;
+
+        if (ret == 0)
+            goto finish;
+
+        /* Tell ALSA about this and process its response */
+        if (PA_SOURCE_OPENED(u->source->thread_info.state)) {
+            struct pollfd *pollfd;
+            unsigned short revents = 0;
+            int err;
+            unsigned n;
+
+            pollfd = pa_rtpoll_item_get_pollfd(u->alsa_rtpoll_item, &n);
+
+            if ((err = snd_pcm_poll_descriptors_revents(u->pcm_handle, pollfd, n, &revents)) < 0) {
+                pa_log("snd_pcm_poll_descriptors_revents() failed: %s", snd_strerror(err));
+                goto fail;
+            }
+
+            if (revents & (POLLERR|POLLNVAL|POLLHUP)) {
+
+                if (revents & POLLERR)
+                    pa_log_warn("Got POLLERR from ALSA");
+                if (revents & POLLNVAL)
+                    pa_log_warn("Got POLLNVAL from ALSA");
+                if (revents & POLLHUP)
+                    pa_log_warn("Got POLLHUP from ALSA");
+
+                /* Try to recover from this error */
+
+                switch (snd_pcm_state(u->pcm_handle)) {
+
+                    case SND_PCM_STATE_XRUN:
+                        if ((err = snd_pcm_recover(u->pcm_handle, -EPIPE, 1)) != 0) {
+                            pa_log_warn("Could not recover from POLLERR|POLLNVAL|POLLHUP and XRUN: %s", snd_strerror(err));
+                            goto fail;
+                        }
+                        break;
+
+                    case SND_PCM_STATE_SUSPENDED:
+                        if ((err = snd_pcm_recover(u->pcm_handle, -ESTRPIPE, 1)) != 0) {
+                            pa_log_warn("Could not recover from POLLERR|POLLNVAL|POLLHUP and SUSPENDED: %s", snd_strerror(err));
+                            goto fail;
+                        }
+                        break;
+
+                    default:
+
+                        snd_pcm_drop(u->pcm_handle);
+
+                        if ((err = snd_pcm_prepare(u->pcm_handle)) < 0) {
+                            pa_log_warn("Could not recover from POLLERR|POLLNVAL|POLLHUP with snd_pcm_prepare(): %s", snd_strerror(err));
+                            goto fail;
+                        }
+                        break;
+                }
+            }
+        }
+    }
+
+fail:
+    /* If this was no regular exit from the loop we have to continue
+     * processing messages until we received PA_MESSAGE_SHUTDOWN */
+    pa_asyncmsgq_post(u->thread_mq.outq, PA_MSGOBJECT(u->core), PA_CORE_MESSAGE_UNLOAD_MODULE, u->module, 0, NULL, NULL);
+    pa_asyncmsgq_wait_for(u->thread_mq.inq, PA_MESSAGE_SHUTDOWN);
+
+finish:
+    pa_log_debug("Thread shutting down");
+}
+
+int pa__init(pa_module*m) {
+
     pa_modargs *ma = NULL;
-    int ret = -1;
     struct userdata *u = NULL;
-    const char *dev;
+    char *dev;
     pa_sample_spec ss;
     pa_channel_map map;
-    unsigned periods, fragsize;
+    unsigned nfrags, frag_size;
     snd_pcm_uframes_t period_size;
     size_t frame_size;
     snd_pcm_info_t *pcm_info = NULL;
@@ -403,64 +702,125 @@
     const char *name;
     char *name_buf = NULL;
     int namereg_fail;
+    int use_mmap = 1, b;
+
+    snd_pcm_info_alloca(&pcm_info);
+
+    pa_assert(m);
 
     if (!(ma = pa_modargs_new(m->argument, valid_modargs))) {
-        pa_log("failed to parse module arguments");
-        goto fail;
-    }
-
-    ss = c->default_sample_spec;
+        pa_log("Failed to parse module arguments");
+        goto fail;
+    }
+
+    ss = m->core->default_sample_spec;
     if (pa_modargs_get_sample_spec_and_channel_map(ma, &ss, &map, PA_CHANNEL_MAP_ALSA) < 0) {
-        pa_log("failed to parse sample specification");
+        pa_log("Failed to parse sample specification");
         goto fail;
     }
 
     frame_size = pa_frame_size(&ss);
 
-    /* Fix latency to 100ms */
-    periods = 12;
-    fragsize = pa_bytes_per_second(&ss)/128;
-
-    if (pa_modargs_get_value_u32(ma, "fragments", &periods) < 0 || pa_modargs_get_value_u32(ma, "fragment_size", &fragsize) < 0) {
-        pa_log("failed to parse buffer metrics");
-        goto fail;
-    }
-    period_size = fragsize/frame_size;
+    nfrags = m->core->default_n_fragments;
+    frag_size = pa_usec_to_bytes(m->core->default_fragment_size_msec*1000, &ss);
+    if (frag_size <= 0)
+        frag_size = frame_size;
+
+    if (pa_modargs_get_value_u32(ma, "fragments", &nfrags) < 0 || pa_modargs_get_value_u32(ma, "fragment_size", &frag_size) < 0) {
+        pa_log("Failed to parse buffer metrics");
+        goto fail;
+    }
+    period_size = frag_size/frame_size;
+
+    if (pa_modargs_get_value_boolean(ma, "mmap", &use_mmap) < 0) {
+        pa_log("Failed to parse mmap argument.");
+        goto fail;
+    }
 
     u = pa_xnew0(struct userdata, 1);
+    u->core = m->core;
+    u->module = m;
     m->userdata = u;
-    u->module = m;
+    u->use_mmap = use_mmap;
+    pa_thread_mq_init(&u->thread_mq, m->core->mainloop);
+    u->rtpoll = pa_rtpoll_new();
+    u->alsa_rtpoll_item = NULL;
+    pa_rtpoll_item_new_asyncmsgq(u->rtpoll, PA_RTPOLL_EARLY, u->thread_mq.inq);
 
     snd_config_update_free_global();
-    if ((err = snd_pcm_open(&u->pcm_handle, dev = pa_modargs_get_value(ma, "device", DEFAULT_DEVICE), SND_PCM_STREAM_CAPTURE, SND_PCM_NONBLOCK)) < 0) {
-        pa_log("Error opening PCM device %s: %s", dev, snd_strerror(err));
-        goto fail;
-    }
-
-    if ((err = snd_pcm_info_malloc(&pcm_info)) < 0 ||
-        (err = snd_pcm_info(u->pcm_handle, pcm_info)) < 0) {
+
+    dev = pa_xstrdup(pa_modargs_get_value(ma, "device", DEFAULT_DEVICE));
+
+    for (;;) {
+
+        if ((err = snd_pcm_open(&u->pcm_handle, dev, SND_PCM_STREAM_CAPTURE, SND_PCM_NONBLOCK)) < 0) {
+            pa_log("Error opening PCM device %s: %s", dev, snd_strerror(err));
+            pa_xfree(dev);
+            goto fail;
+        }
+
+        b = use_mmap;
+        if ((err = pa_alsa_set_hw_params(u->pcm_handle, &ss, &nfrags, &period_size, &b)) < 0) {
+
+            if (err == -EPERM) {
+                /* Hmm, some hw is very exotic, so we retry with plughw, if hw didn't work */
+
+                if (pa_startswith(dev, "hw:")) {
+                    char *d = pa_sprintf_malloc("plughw:%s", dev+3);
+                    pa_log_debug("Opening the device as '%s' didn't work, retrying with '%s'.", dev, d);
+                    pa_xfree(dev);
+                    dev = d;
+
+                    snd_pcm_close(u->pcm_handle);
+                    u->pcm_handle = NULL;
+                    continue;
+                }
+            }
+
+            pa_log("Failed to set hardware parameters: %s", snd_strerror(err));
+            pa_xfree(dev);
+            goto fail;
+        }
+
+        break;
+    }
+
+    u->device_name = dev;
+
+    if (use_mmap && !b) {
+        pa_log_info("Device doesn't support mmap(), falling back to UNIX read/write mode.");
+        u->use_mmap = use_mmap = b;
+    }
+
+    if (u->use_mmap)
+        pa_log_info("Successfully enabled mmap() mode.");
+
+    if ((err = snd_pcm_info(u->pcm_handle, pcm_info)) < 0) {
         pa_log("Error fetching PCM info: %s", snd_strerror(err));
         goto fail;
     }
 
-    if ((err = pa_alsa_set_hw_params(u->pcm_handle, &ss, &periods, &period_size)) < 0) {
-        pa_log("Failed to set hardware parameters: %s", snd_strerror(err));
-        goto fail;
-    }
+    if ((err = pa_alsa_set_sw_params(u->pcm_handle)) < 0) {
+        pa_log("Failed to set software parameters: %s", snd_strerror(err));
+        goto fail;
+    }
+
+    /* ALSA might tweak the sample spec, so recalculate the frame size */
+    frame_size = pa_frame_size(&ss);
 
     if (ss.channels != map.channels)
         /* Seems ALSA didn't like the channel number, so let's fix the channel map */
         pa_channel_map_init_auto(&map, ss.channels, PA_CHANNEL_MAP_ALSA);
 
-    if ((err = snd_mixer_open(&u->mixer_handle, 0)) < 0) {
+    if ((err = snd_mixer_open(&u->mixer_handle, 0)) < 0)
         pa_log("Error opening mixer: %s", snd_strerror(err));
-        goto fail;
-    }
-
-    if ((pa_alsa_prepare_mixer(u->mixer_handle, dev) < 0) ||
-        !(u->mixer_elem = pa_alsa_find_elem(u->mixer_handle, "Capture", "Mic"))) {
-        snd_mixer_close(u->mixer_handle);
-        u->mixer_handle = NULL;
+    else {
+
+        if ((pa_alsa_prepare_mixer(u->mixer_handle, dev) < 0) ||
+            !(u->mixer_elem = pa_alsa_find_elem(u->mixer_handle, "Capture", NULL))) {
+            snd_mixer_close(u->mixer_handle);
+            u->mixer_handle = NULL;
+        }
     }
 
     if ((name = pa_modargs_get_value(ma, "source_name", NULL)))
@@ -470,16 +830,39 @@
         namereg_fail = 0;
     }
 
-    if (!(u->source = pa_source_new(c, __FILE__, name, namereg_fail, &ss, &map))) {
+    u->source = pa_source_new(m->core, __FILE__, name, namereg_fail, &ss, &map);
+    pa_xfree(name_buf);
+
+    if (!u->source) {
         pa_log("Failed to create source object");
         goto fail;
     }
 
-    u->source->is_hardware = 1;
+    u->source->parent.process_msg = source_process_msg;
     u->source->userdata = u;
-    u->source->get_latency = source_get_latency_cb;
+
+    pa_source_set_module(u->source, m);
+    pa_source_set_asyncmsgq(u->source, u->thread_mq.inq);
+    pa_source_set_rtpoll(u->source, u->rtpoll);
+    pa_source_set_description(u->source, t = pa_sprintf_malloc(
+                                      "ALSA PCM on %s (%s)%s",
+                                      dev,
+                                      snd_pcm_info_get_name(pcm_info),
+                                      use_mmap ? " via DMA" : ""));
+    pa_xfree(t);
+
+    u->source->flags = PA_SOURCE_HARDWARE|PA_SOURCE_LATENCY|PA_SOURCE_HW_VOLUME_CTRL;
+
+    u->frame_size = frame_size;
+    u->fragment_size = frag_size = period_size * frame_size;
+    u->nfragments = nfrags;
+    u->hwbuf_size = u->fragment_size * nfrags;
+
+    pa_log_info("Using %u fragments of size %lu bytes.", nfrags, (long unsigned) u->fragment_size);
+
     if (u->mixer_handle) {
-        assert(u->mixer_elem);
+        pa_assert(u->mixer_elem);
+
         if (snd_mixer_selem_has_capture_volume(u->mixer_elem)) {
             int i;
 
@@ -489,89 +872,95 @@
             }
 
             if (i == ss.channels) {
-                u->source->get_hw_volume = source_get_hw_volume_cb;
-                u->source->set_hw_volume = source_set_hw_volume_cb;
-                snd_mixer_selem_get_capture_volume_range(
-                    u->mixer_elem, &u->hw_volume_min, &u->hw_volume_max);
+                u->source->get_volume = source_get_volume_cb;
+                u->source->set_volume = source_set_volume_cb;
+                snd_mixer_selem_get_capture_volume_range(u->mixer_elem, &u->hw_volume_min, &u->hw_volume_max);
             }
         }
+
         if (snd_mixer_selem_has_capture_switch(u->mixer_elem)) {
-            u->source->get_hw_mute = source_get_hw_mute_cb;
-            u->source->set_hw_mute = source_set_hw_mute_cb;
-        }
-    }
-    pa_source_set_owner(u->source, m);
-    pa_source_set_description(u->source, t = pa_sprintf_malloc("ALSA PCM on %s (%s)", dev, snd_pcm_info_get_name(pcm_info)));
-    pa_xfree(t);
-
-    u->pcm_fdl = pa_alsa_fdlist_new();
-    assert(u->pcm_fdl);
-    if (pa_alsa_fdlist_init_pcm(u->pcm_fdl, u->pcm_handle, c->mainloop, fdl_callback, u) < 0) {
-        pa_log("failed to initialise file descriptor monitoring");
-        goto fail;
-    }
-
-    if (u->mixer_handle) {
+            u->source->get_mute = source_get_mute_cb;
+            u->source->set_mute = source_set_mute_cb;
+        }
+
         u->mixer_fdl = pa_alsa_fdlist_new();
-        assert(u->mixer_fdl);
-        if (pa_alsa_fdlist_init_mixer(u->mixer_fdl, u->mixer_handle, c->mainloop) < 0) {
+
+        if (pa_alsa_fdlist_set_mixer(u->mixer_fdl, u->mixer_handle, m->core->mainloop) < 0) {
             pa_log("failed to initialise file descriptor monitoring");
             goto fail;
         }
+
         snd_mixer_elem_set_callback(u->mixer_elem, mixer_callback);
         snd_mixer_elem_set_callback_private(u->mixer_elem, u);
     } else
         u->mixer_fdl = NULL;
 
-    u->frame_size = frame_size;
-    u->fragment_size = period_size * frame_size;
-
-    pa_log_info("using %u fragments of size %lu bytes.", periods, (long unsigned) u->fragment_size);
-
-    u->memchunk.memblock = NULL;
-    u->memchunk.index = u->memchunk.length = 0;
-
-    snd_pcm_start(u->pcm_handle);
-
-    ret = 0;
-
+    if (!(u->thread = pa_thread_new(thread_func, u))) {
+        pa_log("Failed to create thread.");
+        goto fail;
+    }
     /* Get initial mixer settings */
-    if (u->source->get_hw_volume)
-        u->source->get_hw_volume(u->source);
-    if (u->source->get_hw_mute)
-        u->source->get_hw_mute(u->source);
-
-finish:
-    pa_xfree(name_buf);
+    if (u->source->get_volume)
+        u->source->get_volume(u->source);
+    if (u->source->get_mute)
+        u->source->get_mute(u->source);
+
+    pa_source_put(u->source);
+
+    pa_modargs_free(ma);
+
+    return 0;
+
+fail:
 
     if (ma)
-         pa_modargs_free(ma);
-
-    if (pcm_info)
-        snd_pcm_info_free(pcm_info);
-
-    return ret;
-
-fail:
-
-    if (u)
-        pa__done(c, m);
-
-    goto finish;
-}
-
-void pa__done(pa_core *c, pa_module*m) {
+        pa_modargs_free(ma);
+
+    pa__done(m);
+
+    return -1;
+}
+
+void pa__done(pa_module*m) {
     struct userdata *u;
-    assert(c && m);
+
+    pa_assert(m);
 
     if (!(u = m->userdata))
         return;
 
-    clear_up(u);
-
-    if (u->memchunk.memblock)
-        pa_memblock_unref(u->memchunk.memblock);
-
+    if (u->source)
+        pa_source_unlink(u->source);
+
+    if (u->thread) {
+        pa_asyncmsgq_send(u->thread_mq.inq, NULL, PA_MESSAGE_SHUTDOWN, NULL, 0, NULL);
+        pa_thread_free(u->thread);
+    }
+
+    pa_thread_mq_done(&u->thread_mq);
+
+    if (u->source)
+        pa_source_unref(u->source);
+
+    if (u->alsa_rtpoll_item)
+        pa_rtpoll_item_free(u->alsa_rtpoll_item);
+
+    if (u->rtpoll)
+        pa_rtpoll_free(u->rtpoll);
+
+    if (u->mixer_fdl)
+        pa_alsa_fdlist_free(u->mixer_fdl);
+
+    if (u->mixer_handle)
+        snd_mixer_close(u->mixer_handle);
+
+    if (u->pcm_handle) {
+        snd_pcm_drop(u->pcm_handle);
+        snd_pcm_close(u->pcm_handle);
+    }
+
+    pa_xfree(u->device_name);
     pa_xfree(u);
-}
-
+
+    snd_config_update_free_global();
+}

Modified: trunk/src/modules/module-cli.c
URL: http://0pointer.de/cgi-bin/viewcvs.cgi/trunk/src/modules/module-cli.c?rev=1971&root=pulseaudio&r1=1970&r2=1971&view=diff
==============================================================================
--- trunk/src/modules/module-cli.c (original)
+++ trunk/src/modules/module-cli.c Sun Oct 28 20:13:50 2007
@@ -26,7 +26,6 @@
 #endif
 
 #include <stdio.h>
-#include <assert.h>
 #include <unistd.h>
 
 #include <pulsecore/module.h>
@@ -35,6 +34,7 @@
 #include <pulsecore/sioman.h>
 #include <pulsecore/log.h>
 #include <pulsecore/modargs.h>
+#include <pulsecore/macro.h>
 
 #include "module-cli-symdef.h"
 
@@ -51,8 +51,8 @@
 static void eof_and_unload_cb(pa_cli*c, void *userdata) {
     pa_module *m = userdata;
 
-    assert(c);
-    assert(m);
+    pa_assert(c);
+    pa_assert(m);
 
     pa_module_unload_request(m);
 }
@@ -60,21 +60,20 @@
 static void eof_and_exit_cb(pa_cli*c, void *userdata) {
     pa_module *m = userdata;
 
-    assert(c);
-    assert(m);
+    pa_assert(c);
+    pa_assert(m);
 
     m->core->mainloop->quit(m->core->mainloop, 0);
 }
 
-int pa__init(pa_core *c, pa_module*m) {
+int pa__init(pa_module*m) {
     pa_iochannel *io;
     pa_modargs *ma;
     int exit_on_eof = 0;
 
-    assert(c);
-    assert(m);
+    pa_assert(m);
 
-    if (c->running_as_daemon) {
+    if (m->core->running_as_daemon) {
         pa_log_info("Running as daemon, refusing to load this module.");
         return 0;
     }
@@ -94,12 +93,10 @@
         goto fail;
     }
 
-    io = pa_iochannel_new(c->mainloop, STDIN_FILENO, STDOUT_FILENO);
-    assert(io);
+    io = pa_iochannel_new(m->core->mainloop, STDIN_FILENO, STDOUT_FILENO);
     pa_iochannel_set_noclose(io, 1);
 
-    m->userdata = pa_cli_new(c, io, m);
-    assert(m->userdata);
+    m->userdata = pa_cli_new(m->core, io, m);
 
     pa_cli_set_eof_callback(m->userdata, exit_on_eof ? eof_and_exit_cb : eof_and_unload_cb, m);
 
@@ -115,11 +112,10 @@
     return -1;
 }
 
-void pa__done(pa_core *c, pa_module*m) {
-    assert(c);
-    assert(m);
+void pa__done(pa_module*m) {
+    pa_assert(m);
 
-    if (c->running_as_daemon == 0) {
+    if (m->core->running_as_daemon == 0) {
         pa_cli_free(m->userdata);
         pa_stdio_release();
     }

Modified: trunk/src/modules/module-combine.c
URL: http://0pointer.de/cgi-bin/viewcvs.cgi/trunk/src/modules/module-combine.c?rev=1971&root=pulseaudio&r1=1970&r2=1971&view=diff
==============================================================================
--- trunk/src/modules/module-combine.c (original)
+++ trunk/src/modules/module-combine.c Sun Oct 28 20:13:50 2007
@@ -25,12 +25,13 @@
 #include <config.h>
 #endif
 
-#include <assert.h>
 #include <stdio.h>
+#include <errno.h>
 
 #include <pulse/timeval.h>
 #include <pulse/xmalloc.h>
 
+#include <pulsecore/macro.h>
 #include <pulsecore/module.h>
 #include <pulsecore/llist.h>
 #include <pulsecore/sink.h>
@@ -40,6 +41,12 @@
 #include <pulsecore/core-util.h>
 #include <pulsecore/modargs.h>
 #include <pulsecore/namereg.h>
+#include <pulsecore/mutex.h>
+#include <pulsecore/thread.h>
+#include <pulsecore/thread-mq.h>
+#include <pulsecore/rtpoll.h>
+#include <pulsecore/rtclock.h>
+#include <pulsecore/core-error.h>
 
 #include "module-combine-symdef.h"
 
@@ -55,13 +62,12 @@
         "format=<sample format> "
         "channels=<number of channels> "
         "rate=<sample rate> "
-        "channel_map=<channel map> ")
+        "channel_map=<channel map>")
 
 #define DEFAULT_SINK_NAME "combined"
 #define MEMBLOCKQ_MAXLENGTH (1024*170)
-#define RENDER_SIZE (1024*10)
-
-#define DEFAULT_ADJUST_TIME 20
+
+#define DEFAULT_ADJUST_TIME 10
 
 static const char* const valid_modargs[] = {
     "sink_name",
@@ -78,95 +84,140 @@
 
 struct output {
     struct userdata *userdata;
+
+    pa_sink *sink;
     pa_sink_input *sink_input;
-    size_t counter;
+
+    pa_asyncmsgq *inq,    /* Message queue from the sink thread to this sink input */
+                 *outq;   /* Message queue from this sink input to the sink thread */
+    pa_rtpoll_item *inq_rtpoll_item, *outq_rtpoll_item;
+
     pa_memblockq *memblockq;
+
     pa_usec_t total_latency;
+
     PA_LLIST_FIELDS(struct output);
 };
 
 struct userdata {
+    pa_core *core;
     pa_module *module;
-    pa_core *core;
     pa_sink *sink;
-    unsigned n_outputs;
-    struct output *master;
+
+    pa_thread *thread;
+    pa_thread_mq thread_mq;
+    pa_rtpoll *rtpoll;
+
     pa_time_event *time_event;
     uint32_t adjust_time;
 
-    PA_LLIST_HEAD(struct output, outputs);
+    pa_bool_t automatic;
+    size_t block_size;
+
+    pa_hook_slot *sink_new_slot, *sink_unlink_slot, *sink_state_changed_slot;
+
+    pa_resample_method_t resample_method;
+
+    struct timeval adjust_timestamp;
+
+    struct output *master;
+    pa_idxset* outputs; /* managed in main context */
+
+    struct {
+        PA_LLIST_HEAD(struct output, active_outputs); /* managed in IO thread context */
+        pa_atomic_t running;  /* we cache that value here, so that every thread can query it cheaply */
+        struct timeval timestamp;
+        pa_bool_t in_null_mode;
+    } thread_info;
 };
 
+enum {
+    SINK_MESSAGE_ADD_OUTPUT = PA_SINK_MESSAGE_MAX,
+    SINK_MESSAGE_REMOVE_OUTPUT,
+    SINK_MESSAGE_NEED
+};
+
+enum {
+    SINK_INPUT_MESSAGE_POST = PA_SINK_INPUT_MESSAGE_MAX
+};
+
 static void output_free(struct output *o);
-static void clear_up(struct userdata *u);
-
-static void update_usage(struct userdata *u) {
-    pa_module_set_used(u->module, u->sink ? pa_sink_used_by(u->sink) : 0);
-}
+static int output_create_sink_input(struct output *o);
+static void update_master(struct userdata *u, struct output *o);
+static void pick_master(struct userdata *u, struct output *except);
 
 static void adjust_rates(struct userdata *u) {
     struct output *o;
     pa_usec_t max_sink_latency = 0, min_total_latency = (pa_usec_t) -1, target_latency;
     uint32_t base_rate;
-    assert(u && u->sink);
-
-    for (o = u->outputs; o; o = o->next) {
-        uint32_t sink_latency = o->sink_input->sink ? pa_sink_get_latency(o->sink_input->sink) : 0;
-
+    uint32_t idx;
+
+    pa_assert(u);
+    pa_sink_assert_ref(u->sink);
+
+    if (pa_idxset_size(u->outputs) <= 0)
+        return;
+
+    if (!u->master)
+        return;
+
+    if (!PA_SINK_OPENED(pa_sink_get_state(u->sink)))
+        return;
+
+    for (o = pa_idxset_first(u->outputs, &idx); o; o = pa_idxset_next(u->outputs, &idx)) {
+        pa_usec_t sink_latency;
+
+        if (!o->sink_input || !PA_SINK_OPENED(pa_sink_get_state(o->sink)))
+            continue;
+
+        sink_latency = pa_sink_get_latency(o->sink);
         o->total_latency = sink_latency + pa_sink_input_get_latency(o->sink_input);
 
         if (sink_latency > max_sink_latency)
             max_sink_latency = sink_latency;
 
-        if (o->total_latency < min_total_latency)
+        if (min_total_latency == (pa_usec_t) -1 || o->total_latency < min_total_latency)
             min_total_latency = o->total_latency;
     }
 
-    assert(min_total_latency != (pa_usec_t) -1);
+    if (min_total_latency == (pa_usec_t) -1)
+        return;
 
     target_latency = max_sink_latency > min_total_latency ? max_sink_latency : min_total_latency;
 
     pa_log_info("[%s] target latency is %0.0f usec.", u->sink->name, (float) target_latency);
+    pa_log_info("[%s] master %s latency %0.0f usec.", u->sink->name, u->master->sink->name, (float) u->master->total_latency);
 
     base_rate = u->sink->sample_spec.rate;
 
-    for (o = u->outputs; o; o = o->next) {
+    for (o = pa_idxset_first(u->outputs, &idx); o; o = pa_idxset_next(u->outputs, &idx)) {
         uint32_t r = base_rate;
 
+        if (!o->sink_input || !PA_SINK_OPENED(pa_sink_get_state(o->sink)))
+            continue;
+
         if (o->total_latency < target_latency)
-            r -= (uint32_t) (((((double) target_latency - o->total_latency))/u->adjust_time)*r/ 1000000);
+            r -= (uint32_t) (((((double) target_latency - o->total_latency))/u->adjust_time)*r/PA_USEC_PER_SEC);
         else if (o->total_latency > target_latency)
-            r += (uint32_t) (((((double) o->total_latency - target_latency))/u->adjust_time)*r/ 1000000);
-
-        if (r < (uint32_t) (base_rate*0.9) || r > (uint32_t) (base_rate*1.1))
+            r += (uint32_t) (((((double) o->total_latency - target_latency))/u->adjust_time)*r/PA_USEC_PER_SEC);
+
+        if (r < (uint32_t) (base_rate*0.9) || r > (uint32_t) (base_rate*1.1)) {
             pa_log_warn("[%s] sample rates too different, not adjusting (%u vs. %u).", o->sink_input->name, base_rate, r);
-        else {
+            pa_sink_input_set_rate(o->sink_input, base_rate);
+        } else {
             pa_log_info("[%s] new rate is %u Hz; ratio is %0.3f; latency is %0.0f usec.", o->sink_input->name, r, (double) r / base_rate, (float) o->total_latency);
             pa_sink_input_set_rate(o->sink_input, r);
         }
     }
 }
 
-static void request_memblock(struct userdata *u) {
-    pa_memchunk chunk;
-    struct output *o;
-    assert(u && u->sink);
-
-    update_usage(u);
-
-    if (pa_sink_render(u->sink, RENDER_SIZE, &chunk) < 0)
-        return;
-
-    for (o = u->outputs; o; o = o->next)
-        pa_memblockq_push_align(o->memblockq, &chunk);
-
-    pa_memblock_unref(chunk.memblock);
-}
-
-static void time_callback(pa_mainloop_api*a, pa_time_event* e, PA_GCC_UNUSED const struct timeval *tv, void *userdata) {
+static void time_callback(pa_mainloop_api*a, pa_time_event* e, const struct timeval *tv, void *userdata) {
     struct userdata *u = userdata;
     struct timeval n;
-    assert(u && a && u->time_event == e);
+
+    pa_assert(u);
+    pa_assert(a);
+    pa_assert(u->time_event == e);
 
     adjust_rates(u);
 
@@ -175,73 +226,547 @@
     u->sink->core->mainloop->time_restart(e, &n);
 }
 
-static int sink_input_peek_cb(pa_sink_input *i, pa_memchunk *chunk) {
-    struct output *o = i->userdata;
-    assert(i && o && o->sink_input && chunk);
-
-    if (pa_memblockq_peek(o->memblockq, chunk) >= 0)
+static void thread_func(void *userdata) {
+    struct userdata *u = userdata;
+
+    pa_assert(u);
+
+    pa_log_debug("Thread starting up");
+
+    if (u->core->high_priority)
+        pa_make_realtime();
+
+    pa_thread_mq_install(&u->thread_mq);
+    pa_rtpoll_install(u->rtpoll);
+
+    pa_rtclock_get(&u->thread_info.timestamp);
+    u->thread_info.in_null_mode = FALSE;
+
+    for (;;) {
+        int ret;
+
+        /* If no outputs are connected, render some data and drop it immediately. */
+        if (u->sink->thread_info.state == PA_SINK_RUNNING && !u->thread_info.active_outputs) {
+            struct timeval now;
+
+            pa_rtclock_get(&now);
+
+            if (!u->thread_info.in_null_mode || pa_timeval_cmp(&u->thread_info.timestamp, &now) <= 0) {
+                pa_sink_skip(u->sink, u->block_size);
+
+                if (!u->thread_info.in_null_mode)
+                    u->thread_info.timestamp = now;
+
+                pa_timeval_add(&u->thread_info.timestamp, pa_bytes_to_usec(u->block_size, &u->sink->sample_spec));
+            }
+
+            pa_rtpoll_set_timer_absolute(u->rtpoll, &u->thread_info.timestamp);
+            u->thread_info.in_null_mode = TRUE;
+
+        } else {
+            pa_rtpoll_set_timer_disabled(u->rtpoll);
+            u->thread_info.in_null_mode = FALSE;
+        }
+
+        /* Hmm, nothing to do. Let's sleep */
+        if ((ret = pa_rtpoll_run(u->rtpoll, TRUE)) < 0) {
+            pa_log_info("pa_rtpoll_run() = %i", ret);
+            goto fail;
+        }
+
+        if (ret == 0)
+            goto finish;
+    }
+
+fail:
+    /* If this was no regular exit from the loop we have to continue
+     * processing messages until we received PA_MESSAGE_SHUTDOWN */
+    pa_asyncmsgq_post(u->thread_mq.outq, PA_MSGOBJECT(u->core), PA_CORE_MESSAGE_UNLOAD_MODULE, u->module, 0, NULL, NULL);
+    pa_asyncmsgq_wait_for(u->thread_mq.inq, PA_MESSAGE_SHUTDOWN);
+
+finish:
+    pa_log_debug("Thread shutting down");
+}
+
+/* Called from I/O thread context */
+static void render_memblock(struct userdata *u, struct output *o, size_t length) {
+    pa_assert(u);
+    pa_assert(o);
+
+    /* We are run by the sink thread, on behalf of an output (o). The
+     * other output is waiting for us, hence it is safe to access its
+     * mainblockq and asyncmsgq directly. */
+
+    /* If we are not running, we cannot produce any data */
+    if (!pa_atomic_load(&u->thread_info.running))
+        return;
+
+    /* Maybe there's some data in the requesting output's queue
+     * now? */
+    while (pa_asyncmsgq_process_one(o->inq) > 0)
+        ;
+
+    /* Ok, now let's prepare some data if we really have to */
+    while (!pa_memblockq_is_readable(o->memblockq)) {
+        struct output *j;
+        pa_memchunk chunk;
+
+        /* Render data! */
+        pa_sink_render(u->sink, length, &chunk);
+
+        /* OK, let's send this data to the other threads */
+        for (j = u->thread_info.active_outputs; j; j = j->next)
+
+            /* Send to other outputs, which are not the requesting
+             * one */
+
+            if (j != o)
+                pa_asyncmsgq_post(j->inq, PA_MSGOBJECT(j->sink_input), SINK_INPUT_MESSAGE_POST, NULL, 0, &chunk, NULL);
+
+        /* And place it directly into the requesting output's queue */
+        if (o)
+            pa_memblockq_push_align(o->memblockq, &chunk);
+
+        pa_memblock_unref(chunk.memblock);
+    }
+}
+
+/* Called from I/O thread context */
+static void request_memblock(struct output *o, size_t length) {
+    pa_assert(o);
+    pa_sink_input_assert_ref(o->sink_input);
+    pa_sink_assert_ref(o->userdata->sink);
+
+    /* If another thread already prepared some data we received
+     * the data over the asyncmsgq, hence let's first process
+     * it. */
+    while (pa_asyncmsgq_process_one(o->inq) > 0)
+        ;
+
+    /* Check whether we're now readable */
+    if (pa_memblockq_is_readable(o->memblockq))
+        return;
+
+    /* OK, we need to prepare new data, but only if the sink is actually running */
+    if (pa_atomic_load(&o->userdata->thread_info.running))
+        pa_asyncmsgq_send(o->outq, PA_MSGOBJECT(o->userdata->sink), SINK_MESSAGE_NEED, o, length, NULL);
+}
+
+/* Called from I/O thread context */
+static int sink_input_peek_cb(pa_sink_input *i, size_t length, pa_memchunk *chunk) {
+    struct output *o;
+
+    pa_sink_input_assert_ref(i);
+    pa_assert_se(o = i->userdata);
+
+    /* If necessary, get some new data */
+    request_memblock(o, length);
+
+    return pa_memblockq_peek(o->memblockq, chunk);
+}
+
+/* Called from I/O thread context */
+static void sink_input_drop_cb(pa_sink_input *i, size_t length) {
+    struct output *o;
+
+    pa_sink_input_assert_ref(i);
+    pa_assert(length > 0);
+    pa_assert_se(o = i->userdata);
+
+    pa_memblockq_drop(o->memblockq, length);
+}
+
+/* Called from I/O thread context */
+static void sink_input_attach_cb(pa_sink_input *i) {
+    struct output *o;
+
+    pa_sink_input_assert_ref(i);
+    pa_assert_se(o = i->userdata);
+
+    /* Set up the queue from the sink thread to us */
+    pa_assert(!o->inq_rtpoll_item);
+    o->inq_rtpoll_item = pa_rtpoll_item_new_asyncmsgq(
+            i->sink->rtpoll,
+            PA_RTPOLL_LATE,  /* This one is not that important, since we check for data in _peek() anyway. */
+            o->inq);
+}
+
+/* Called from I/O thread context */
+static void sink_input_detach_cb(pa_sink_input *i) {
+    struct output *o;
+
+    pa_sink_input_assert_ref(i);
+    pa_assert_se(o = i->userdata);
+
+    /* Shut down the queue from the sink thread to us */
+    pa_assert(o->inq_rtpoll_item);
+    pa_rtpoll_item_free(o->inq_rtpoll_item);
+    o->inq_rtpoll_item = NULL;
+}
+
+/* Called from main context */
+static void sink_input_kill_cb(pa_sink_input *i) {
+    struct output *o;
+
+    pa_sink_input_assert_ref(i);
+    pa_assert(o = i->userdata);
+
+    pa_module_unload_request(o->userdata->module);
+    output_free(o);
+}
+
+/* Called from thread context */
+static int sink_input_process_msg(pa_msgobject *obj, int code, void *data, int64_t offset, pa_memchunk *chunk) {
+    struct output *o = PA_SINK_INPUT(obj)->userdata;
+
+    switch (code) {
+
+        case PA_SINK_INPUT_MESSAGE_GET_LATENCY: {
+             pa_usec_t *r = data;
+
+            *r = pa_bytes_to_usec(pa_memblockq_get_length(o->memblockq), &o->sink_input->sample_spec);
+
+            /* Fall through, the default handler will add in the extra
+             * latency added by the resampler */
+            break;
+        }
+
+        case SINK_INPUT_MESSAGE_POST:
+
+            if (PA_SINK_OPENED(o->sink_input->sink->thread_info.state))
+                pa_memblockq_push_align(o->memblockq, chunk);
+            else
+                pa_memblockq_flush(o->memblockq);
+
+            break;
+    }
+
+    return pa_sink_input_process_msg(obj, code, data, offset, chunk);
+}
+
+/* Called from main context */
+static void disable_output(struct output *o) {
+    pa_assert(o);
+
+    if (!o->sink_input)
+        return;
+
+    pa_asyncmsgq_send(o->userdata->sink->asyncmsgq, PA_MSGOBJECT(o->userdata->sink), SINK_MESSAGE_REMOVE_OUTPUT, o, 0, NULL);
+    pa_sink_input_unlink(o->sink_input);
+    pa_sink_input_unref(o->sink_input);
+    o->sink_input = NULL;
+
+}
+
+/* Called from main context */
+static void enable_output(struct output *o) {
+    pa_assert(o);
+
+    if (o->sink_input)
+        return;
+
+    if (output_create_sink_input(o) >= 0) {
+
+        pa_memblockq_flush(o->memblockq);
+
+        pa_sink_input_put(o->sink_input);
+
+        if (o->userdata->sink && PA_SINK_LINKED(pa_sink_get_state(o->userdata->sink)))
+            pa_asyncmsgq_send(o->userdata->sink->asyncmsgq, PA_MSGOBJECT(o->userdata->sink), SINK_MESSAGE_ADD_OUTPUT, o, 0, NULL);
+    }
+}
+
+/* Called from main context */
+static void suspend(struct userdata *u) {
+    struct output *o;
+    uint32_t idx;
+
+    pa_assert(u);
+
+    /* Let's suspend by unlinking all streams */
+    for (o = pa_idxset_first(u->outputs, &idx); o; o = pa_idxset_next(u->outputs, &idx))
+        disable_output(o);
+
+    pick_master(u, NULL);
+
+    pa_log_info("Device suspended...");
+}
+
+/* Called from main context */
+static void unsuspend(struct userdata *u) {
+    struct output *o;
+    uint32_t idx;
+
+    pa_assert(u);
+
+    /* Let's resume */
+    for (o = pa_idxset_first(u->outputs, &idx); o; o = pa_idxset_next(u->outputs, &idx)) {
+
+        pa_sink_suspend(o->sink, FALSE);
+
+        if (PA_SINK_OPENED(pa_sink_get_state(o->sink)))
+            enable_output(o);
+    }
+
+    pick_master(u, NULL);
+
+    pa_log_info("Resumed successfully...");
+}
+
+/* Called from main context */
+static int sink_set_state(pa_sink *sink, pa_sink_state_t state) {
+    struct userdata *u;
+
+    pa_sink_assert_ref(sink);
+    pa_assert_se(u = sink->userdata);
+
+    /* Please note that in contrast to the ALSA modules we call
+     * suspend/unsuspend from main context here! */
+
+    switch (state) {
+        case PA_SINK_SUSPENDED:
+            pa_assert(PA_SINK_OPENED(pa_sink_get_state(u->sink)));
+
+            suspend(u);
+            break;
+
+        case PA_SINK_IDLE:
+        case PA_SINK_RUNNING:
+
+            if (pa_sink_get_state(u->sink) == PA_SINK_SUSPENDED)
+                unsuspend(u);
+
+            break;
+
+        case PA_SINK_UNLINKED:
+        case PA_SINK_INIT:
+            ;
+    }
+
+    return 0;
+}
+
+/* Called from thread context of the master */
+static int sink_process_msg(pa_msgobject *o, int code, void *data, int64_t offset, pa_memchunk *chunk) {
+    struct userdata *u = PA_SINK(o)->userdata;
+
+    switch (code) {
+
+        case PA_SINK_MESSAGE_SET_STATE:
+            pa_atomic_store(&u->thread_info.running, PA_PTR_TO_UINT(data) == PA_SINK_RUNNING);
+            break;
+
+        case PA_SINK_MESSAGE_GET_LATENCY:
+
+            /* This code will only be called when running in NULL
+             * mode, i.e. when no output is attached. See
+             * sink_get_latency_cb() below */
+
+            if (u->thread_info.in_null_mode) {
+                struct timeval now;
+
+                if (pa_timeval_cmp(&u->thread_info.timestamp, pa_rtclock_get(&now)) > 0) {
+                    *((pa_usec_t*) data) = pa_timeval_diff(&u->thread_info.timestamp, &now);
+                    break;
+                }
+            }
+
+            *((pa_usec_t*) data) = 0;
+
+            break;
+
+        case SINK_MESSAGE_ADD_OUTPUT: {
+            struct output *op = data;
+
+            PA_LLIST_PREPEND(struct output, u->thread_info.active_outputs, op);
+
+            pa_assert(!op->outq_rtpoll_item);
+
+            /* Create pa_asyncmsgq to the sink thread */
+
+            op->outq_rtpoll_item = pa_rtpoll_item_new_asyncmsgq(
+                    u->rtpoll,
+                    PA_RTPOLL_EARLY-1,  /* This item is very important */
+                    op->outq);
+
+            return 0;
+        }
+
+        case SINK_MESSAGE_REMOVE_OUTPUT: {
+            struct output *op = data;
+
+            PA_LLIST_REMOVE(struct output, u->thread_info.active_outputs, op);
+
+            /* Remove the q that leads from this output to the sink thread */
+
+            pa_assert(op->outq_rtpoll_item);
+            pa_rtpoll_item_free(op->outq_rtpoll_item);
+            op->outq_rtpoll_item = NULL;
+
+            return 0;
+        }
+
+        case SINK_MESSAGE_NEED:
+            render_memblock(u, data, (size_t) offset);
+            return 0;
+    }
+
+    return pa_sink_process_msg(o, code, data, offset, chunk);
+}
+
+/* Called from main context */
+static pa_usec_t sink_get_latency_cb(pa_sink *s) {
+    struct userdata *u;
+
+    pa_sink_assert_ref(s);
+    pa_assert_se(u = s->userdata);
+
+    if (u->master) {
+        /* If we have a master sink, we just return the latency of it
+         * and add our own buffering on top */
+
+        if (!u->master->sink_input)
+            return 0;
+
+        return
+            pa_sink_input_get_latency(u->master->sink_input) +
+            pa_sink_get_latency(u->master->sink);
+
+    } else {
+        pa_usec_t usec = 0;
+
+        /* We have no master, hence let's ask our own thread which
+         * implements the NULL sink */
+
+        if (pa_asyncmsgq_send(s->asyncmsgq, PA_MSGOBJECT(s), PA_SINK_MESSAGE_GET_LATENCY, &usec, 0, NULL) < 0)
+            return 0;
+
+        return usec;
+    }
+}
+
+static void update_description(struct userdata *u) {
+    int first = 1;
+    char *t;
+    struct output *o;
+    uint32_t idx;
+
+    pa_assert(u);
+
+    if (pa_idxset_isempty(u->outputs)) {
+        pa_sink_set_description(u->sink, "Simultaneous output");
+        return;
+    }
+
+    t = pa_xstrdup("Simultaneous output to");
+
+    for (o = pa_idxset_first(u->outputs, &idx); o; o = pa_idxset_next(u->outputs, &idx)) {
+        char *e;
+
+        if (first) {
+            e = pa_sprintf_malloc("%s %s", t, o->sink->description);
+            first = 0;
+        } else
+            e = pa_sprintf_malloc("%s, %s", t, o->sink->description);
+
+        pa_xfree(t);
+        t = e;
+    }
+
+    pa_sink_set_description(u->sink, t);
+    pa_xfree(t);
+}
+
+static void update_master(struct userdata *u, struct output *o) {
+    pa_assert(u);
+
+    if (u->master == o)
+        return;
+
+    if ((u->master = o))
+        pa_log_info("Master sink is now '%s'", o->sink_input->sink->name);
+    else
+        pa_log_info("No master selected, lacking suitable outputs.");
+}
+
+static void pick_master(struct userdata *u, struct output *except) {
+    struct output *o;
+    uint32_t idx;
+    pa_assert(u);
+
+    if (u->master &&
+        u->master != except &&
+        u->master->sink_input &&
+        PA_SINK_OPENED(pa_sink_get_state(u->master->sink))) {
+        update_master(u, u->master);
+        return;
+    }
+
+    for (o = pa_idxset_first(u->outputs, &idx); o; o = pa_idxset_next(u->outputs, &idx))
+        if (o != except &&
+            o->sink_input &&
+            PA_SINK_OPENED(pa_sink_get_state(o->sink))) {
+            update_master(u, o);
+            return;
+        }
+
+    update_master(u, NULL);
+}
+
+static int output_create_sink_input(struct output *o) {
+    pa_sink_input_new_data data;
+    char *t;
+
+    pa_assert(o);
+
+    if (o->sink_input)
         return 0;
 
-    /* Try harder */
-    request_memblock(o->userdata);
-
-    return pa_memblockq_peek(o->memblockq, chunk);
-}
-
-static void sink_input_drop_cb(pa_sink_input *i, const pa_memchunk *chunk, size_t length) {
-    struct output *o = i->userdata;
-    assert(i && o && o->sink_input && chunk && length);
-
-    pa_memblockq_drop(o->memblockq, chunk, length);
-    o->counter += length;
-}
-
-static void sink_input_kill_cb(pa_sink_input *i) {
-    struct output *o = i->userdata;
-    assert(i && o && o->sink_input);
-    pa_module_unload_request(o->userdata->module);
-    clear_up(o->userdata);
-}
-
-static pa_usec_t sink_input_get_latency_cb(pa_sink_input *i) {
-    struct output *o = i->userdata;
-    assert(i && o && o->sink_input);
-
-    return pa_bytes_to_usec(pa_memblockq_get_length(o->memblockq), &i->sample_spec);
-}
-
-static pa_usec_t sink_get_latency_cb(pa_sink *s) {
-    struct userdata *u = s->userdata;
-    assert(s && u && u->sink && u->master);
-
-    return
-        pa_sink_input_get_latency(u->master->sink_input) +
-        pa_sink_get_latency(u->master->sink_input->sink);
-}
-
-static void sink_notify(pa_sink *s) {
-    struct userdata *u;
-    struct output *o;
-
-    assert(s);
-    u = s->userdata;
-    assert(u);
-
-    for (o = u->outputs; o; o = o->next)
-        pa_sink_notify(o->sink_input->sink);
-}
-
-static struct output *output_new(struct userdata *u, pa_sink *sink, int resample_method) {
-    struct output *o = NULL;
-    char t[256];
-    pa_sink_input_new_data data;
-
-    assert(u && sink && u->sink);
-
-    o = pa_xmalloc(sizeof(struct output));
+    t = pa_sprintf_malloc("Simultaneous output on %s", o->sink->description);
+
+    pa_sink_input_new_data_init(&data);
+    data.sink = o->sink;
+    data.driver = __FILE__;
+    data.name = t;
+    pa_sink_input_new_data_set_sample_spec(&data, &o->userdata->sink->sample_spec);
+    pa_sink_input_new_data_set_channel_map(&data, &o->userdata->sink->channel_map);
+    data.module = o->userdata->module;
+    data.resample_method = o->userdata->resample_method;
+
+    o->sink_input = pa_sink_input_new(o->userdata->core, &data, PA_SINK_INPUT_VARIABLE_RATE|PA_SINK_INPUT_DONT_MOVE);
+
+    pa_xfree(t);
+
+    if (!o->sink_input)
+        return -1;
+
+    o->sink_input->parent.process_msg = sink_input_process_msg;
+    o->sink_input->peek = sink_input_peek_cb;
+    o->sink_input->drop = sink_input_drop_cb;
+    o->sink_input->attach = sink_input_attach_cb;
+    o->sink_input->detach = sink_input_detach_cb;
+    o->sink_input->kill = sink_input_kill_cb;
+    o->sink_input->userdata = o;
+
+
+    return 0;
+}
+
+static struct output *output_new(struct userdata *u, pa_sink *sink) {
+    struct output *o;
+
+    pa_assert(u);
+    pa_assert(sink);
+    pa_assert(u->sink);
+
+    o = pa_xnew(struct output, 1);
     o->userdata = u;
-
-    o->counter = 0;
+    o->inq = pa_asyncmsgq_new(0);
+    o->outq = pa_asyncmsgq_new(0);
+    o->inq_rtpoll_item = NULL;
+    o->outq_rtpoll_item = NULL;
+    o->sink = sink;
+    o->sink_input = NULL;
     o->memblockq = pa_memblockq_new(
             0,
             MEMBLOCKQ_MAXLENGTH,
@@ -251,90 +776,151 @@
             0,
             NULL);
 
-    snprintf(t, sizeof(t), "Output stream #%u of sink %s", u->n_outputs+1, u->sink->name);
-
-    pa_sink_input_new_data_init(&data);
-    data.sink = sink;
-    data.driver = __FILE__;
-    data.name = t;
-    pa_sink_input_new_data_set_sample_spec(&data, &u->sink->sample_spec);
-    pa_sink_input_new_data_set_channel_map(&data, &u->sink->channel_map);
-    data.module = u->module;
-
-    if (!(o->sink_input = pa_sink_input_new(u->core, &data, PA_SINK_INPUT_VARIABLE_RATE)))
-        goto fail;
-
-    o->sink_input->get_latency = sink_input_get_latency_cb;
-    o->sink_input->peek = sink_input_peek_cb;
-    o->sink_input->drop = sink_input_drop_cb;
-    o->sink_input->kill = sink_input_kill_cb;
-    o->sink_input->userdata = o;
-
-    PA_LLIST_PREPEND(struct output, u->outputs, o);
-    u->n_outputs++;
+    pa_assert_se(pa_idxset_put(u->outputs, o, NULL) == 0);
+
+    if (u->sink && PA_SINK_LINKED(pa_sink_get_state(u->sink)))
+        pa_asyncmsgq_send(u->sink->asyncmsgq, PA_MSGOBJECT(u->sink), SINK_MESSAGE_ADD_OUTPUT, o, 0, NULL);
+    else {
+        /* If the sink is not yet started, we need to do the activation ourselves */
+        PA_LLIST_PREPEND(struct output, u->thread_info.active_outputs, o);
+
+        o->outq_rtpoll_item = pa_rtpoll_item_new_asyncmsgq(
+                u->rtpoll,
+                PA_RTPOLL_EARLY-1,  /* This item is very important */
+                o->outq);
+    }
+
+    if (PA_SINK_OPENED(pa_sink_get_state(u->sink)) || pa_sink_get_state(u->sink) == PA_SINK_INIT) {
+        pa_sink_suspend(sink, FALSE);
+
+        if (PA_SINK_OPENED(pa_sink_get_state(sink)))
+            if (output_create_sink_input(o) < 0)
+                goto fail;
+    }
+
+
+    update_description(u);
+
     return o;
 
 fail:
 
     if (o) {
+        pa_idxset_remove_by_data(u->outputs, o, NULL);
+
         if (o->sink_input) {
-            pa_sink_input_disconnect(o->sink_input);
+            pa_sink_input_unlink(o->sink_input);
             pa_sink_input_unref(o->sink_input);
         }
 
         if (o->memblockq)
             pa_memblockq_free(o->memblockq);
 
+        if (o->inq)
+            pa_asyncmsgq_unref(o->inq);
+
+        if (o->outq)
+            pa_asyncmsgq_unref(o->outq);
+
         pa_xfree(o);
     }
 
     return NULL;
 }
 
-static void output_free(struct output *o) {
-    assert(o);
-    PA_LLIST_REMOVE(struct output, o->userdata->outputs, o);
-    o->userdata->n_outputs--;
-    pa_memblockq_free(o->memblockq);
-    pa_sink_input_disconnect(o->sink_input);
-    pa_sink_input_unref(o->sink_input);
-    pa_xfree(o);
-}
-
-static void clear_up(struct userdata *u) {
-    struct output *o;
-    assert(u);
-
-    if (u->time_event) {
-        u->core->mainloop->time_free(u->time_event);
-        u->time_event = NULL;
-    }
-
-    while ((o = u->outputs))
-        output_free(o);
-
-    u->master = NULL;
-
-    if (u->sink) {
-        pa_sink_disconnect(u->sink);
-        pa_sink_unref(u->sink);
-        u->sink = NULL;
-    }
-}
-
-int pa__init(pa_core *c, pa_module*m) {
+static pa_hook_result_t sink_new_hook_cb(pa_core *c, pa_sink *s, struct userdata* u) {
+    struct output *o;
+
+    pa_core_assert_ref(c);
+    pa_sink_assert_ref(s);
+    pa_assert(u);
+    pa_assert(u->automatic);
+
+    if (!(s->flags & PA_SINK_HARDWARE) || s == u->sink)
+        return PA_HOOK_OK;
+
+    pa_log_info("Configuring new sink: %s", s->name);
+
+    if (!(o = output_new(u, s))) {
+        pa_log("Failed to create sink input on sink '%s'.", s->name);
+        return PA_HOOK_OK;
+    }
+
+    if (o->sink_input)
+        pa_sink_input_put(o->sink_input);
+
+    pick_master(u, NULL);
+
+    return PA_HOOK_OK;
+}
+
+static pa_hook_result_t sink_unlink_hook_cb(pa_core *c, pa_sink *s, struct userdata* u) {
+    struct output *o;
+    uint32_t idx;
+
+    pa_assert(c);
+    pa_sink_assert_ref(s);
+    pa_assert(u);
+
+    if (s == u->sink)
+        return PA_HOOK_OK;
+
+    for (o = pa_idxset_first(u->outputs, &idx); o; o = pa_idxset_next(u->outputs, &idx))
+        if (o->sink == s)
+            break;
+
+    if (!o)
+        return PA_HOOK_OK;
+
+    pa_log_info("Unconfiguring sink: %s", s->name);
+
+    output_free(o);
+
+    return PA_HOOK_OK;
+}
+
+static pa_hook_result_t sink_state_changed_hook_cb(pa_core *c, pa_sink *s, struct userdata* u) {
+    struct output *o;
+    uint32_t idx;
+    pa_sink_state_t state;
+
+    if (s == u->sink)
+        return PA_HOOK_OK;
+
+    for (o = pa_idxset_first(u->outputs, &idx); o; o = pa_idxset_next(u->outputs, &idx))
+        if (o->sink == s)
+            break;
+
+    if (!o)
+        return PA_HOOK_OK;
+
+    state = pa_sink_get_state(s);
+
+    if (PA_SINK_OPENED(state) && PA_SINK_OPENED(pa_sink_get_state(u->sink)) && !o->sink_input) {
+        enable_output(o);
+        pick_master(u, NULL);
+    }
+
+    if (state == PA_SINK_SUSPENDED && o->sink_input) {
+        disable_output(o);
+        pick_master(u, o);
+    }
+
+    return PA_HOOK_OK;
+}
+
+int pa__init(pa_module*m) {
     struct userdata *u;
     pa_modargs *ma = NULL;
     const char *master_name, *slaves, *rm;
-    pa_sink *master_sink;
-    char *n = NULL;
-    const char*split_state;
-    struct timeval tv;
-    int resample_method = -1;
+    pa_sink *master_sink = NULL;
+    int resample_method = PA_RESAMPLER_TRIVIAL;
     pa_sample_spec ss;
     pa_channel_map map;
-
-    assert(c && m);
+    struct output *o;
+    uint32_t idx;
+
+    pa_assert(m);
 
     if (!(ma = pa_modargs_new(m->argument, valid_modargs))) {
         pa_log("failed to parse module arguments");
@@ -349,116 +935,256 @@
     }
 
     u = pa_xnew(struct userdata, 1);
+    u->core = m->core;
+    u->module = m;
     m->userdata = u;
     u->sink = NULL;
-    u->n_outputs = 0;
     u->master = NULL;
-    u->module = m;
-    u->core = c;
     u->time_event = NULL;
     u->adjust_time = DEFAULT_ADJUST_TIME;
-    PA_LLIST_HEAD_INIT(struct output, u->outputs);
+    pa_thread_mq_init(&u->thread_mq, m->core->mainloop);
+    u->rtpoll = pa_rtpoll_new();
+    u->thread = NULL;
+    u->resample_method = resample_method;
+    u->outputs = pa_idxset_new(NULL, NULL);
+    memset(&u->adjust_timestamp, 0, sizeof(u->adjust_timestamp));
+    u->sink_new_slot = u->sink_unlink_slot = u->sink_state_changed_slot = NULL;
+    PA_LLIST_HEAD_INIT(struct output, u->thread_info.active_outputs);
+    pa_atomic_store(&u->thread_info.running, FALSE);
+    u->thread_info.in_null_mode = FALSE;
+    pa_rtpoll_item_new_asyncmsgq(u->rtpoll, PA_RTPOLL_EARLY, u->thread_mq.inq);
 
     if (pa_modargs_get_value_u32(ma, "adjust_time", &u->adjust_time) < 0) {
-        pa_log("failed to parse adjust_time value");
+        pa_log("Failed to parse adjust_time value");
         goto fail;
     }
 
-    if (!(master_name = pa_modargs_get_value(ma, "master", NULL)) || !(slaves = pa_modargs_get_value(ma, "slaves", NULL))) {
-        pa_log("no master or slave sinks specified");
+    master_name = pa_modargs_get_value(ma, "master", NULL);
+    slaves = pa_modargs_get_value(ma, "slaves", NULL);
+    if (!master_name != !slaves) {
+        pa_log("No master or slave sinks specified");
         goto fail;
     }
 
-    if (!(master_sink = pa_namereg_get(c, master_name, PA_NAMEREG_SINK, 1))) {
-        pa_log("invalid master sink '%s'", master_name);
+    if (master_name) {
+        if (!(master_sink = pa_namereg_get(m->core, master_name, PA_NAMEREG_SINK, 1))) {
+            pa_log("Invalid master sink '%s'", master_name);
+            goto fail;
+        }
+
+        ss = master_sink->sample_spec;
+        u->automatic = FALSE;
+    } else {
+        master_sink = NULL;
+        ss = m->core->default_sample_spec;
+        u->automatic = TRUE;
+    }
+
+    if ((pa_modargs_get_sample_spec(ma, &ss) < 0)) {
+        pa_log("Invalid sample specification.");
         goto fail;
     }
 
-    ss = master_sink->sample_spec;
-    if ((pa_modargs_get_sample_spec(ma, &ss) < 0)) {
-        pa_log("invalid sample specification.");
-        goto fail;
-    }
-
-    if (ss.channels == master_sink->sample_spec.channels)
+    if (master_sink && ss.channels == master_sink->sample_spec.channels)
         map = master_sink->channel_map;
     else
         pa_channel_map_init_auto(&map, ss.channels, PA_CHANNEL_MAP_DEFAULT);
 
-    if ((pa_modargs_get_channel_map(ma, &map) < 0)) {
-        pa_log("invalid channel map.");
+    if ((pa_modargs_get_channel_map(ma, NULL, &map) < 0)) {
+        pa_log("Invalid channel map.");
         goto fail;
     }
 
     if (ss.channels != map.channels) {
-        pa_log("channel map and sample specification don't match.");
+        pa_log("Channel map and sample specification don't match.");
         goto fail;
     }
 
-    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");
+    if (!(u->sink = pa_sink_new(m->core, __FILE__, pa_modargs_get_value(ma, "sink_name", DEFAULT_SINK_NAME), 0, &ss, &map))) {
+        pa_log("Failed to create sink");
         goto fail;
     }
 
-    pa_sink_set_owner(u->sink, m);
-    pa_sink_set_description(u->sink, "Combined Sink");
+    u->sink->parent.process_msg = sink_process_msg;
     u->sink->get_latency = sink_get_latency_cb;
-    u->sink->notify = sink_notify;
+    u->sink->set_state = sink_set_state;
     u->sink->userdata = u;
 
-    if (!(u->master = output_new(u, master_sink, resample_method))) {
-        pa_log("failed to create master sink input on sink '%s'.", u->sink->name);
+    u->sink->flags = PA_SINK_LATENCY;
+    pa_sink_set_module(u->sink, m);
+    pa_sink_set_description(u->sink, "Simultaneous output");
+    pa_sink_set_rtpoll(u->sink, u->rtpoll);
+    pa_sink_set_asyncmsgq(u->sink, u->thread_mq.inq);
+
+    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->automatic) {
+        const char*split_state;
+        char *n = NULL;
+        pa_assert(slaves);
+
+        /* The master and slaves have been specified manually */
+
+        if (!(u->master = output_new(u, master_sink))) {
+            pa_log("Failed to create master sink input on sink '%s'.", master_sink->name);
+            goto fail;
+        }
+
+        split_state = NULL;
+        while ((n = pa_split(slaves, ",", &split_state))) {
+            pa_sink *slave_sink;
+
+            if (!(slave_sink = pa_namereg_get(m->core, n, PA_NAMEREG_SINK, 1)) || slave_sink == u->sink) {
+                pa_log("Invalid slave sink '%s'", n);
+                pa_xfree(n);
+                goto fail;
+            }
+
+            pa_xfree(n);
+
+            if (!output_new(u, slave_sink)) {
+                pa_log("Failed to create slave sink input on sink '%s'.", slave_sink->name);
+                goto fail;
+            }
+        }
+
+        if (pa_idxset_size(u->outputs) <= 1)
+            pa_log_warn("No slave sinks specified.");
+
+        u->sink_new_slot = NULL;
+
+    } else {
+        pa_sink *s;
+
+        /* We're in automatic mode, we elect one hw sink to the master
+         * and attach all other hw sinks as slaves to it */
+
+        for (s = pa_idxset_first(m->core->sinks, &idx); s; s = pa_idxset_next(m->core->sinks, &idx)) {
+
+            if (!(s->flags & PA_SINK_HARDWARE) || s == u->sink)
+                continue;
+
+            if (!output_new(u, s)) {
+                pa_log("Failed to create sink input on sink '%s'.", s->name);
+                goto fail;
+            }
+        }
+
+        u->sink_new_slot = pa_hook_connect(&m->core->hooks[PA_CORE_HOOK_SINK_NEW_POST], (pa_hook_cb_t) sink_new_hook_cb, u);
+    }
+
+    u->sink_unlink_slot = pa_hook_connect(&m->core->hooks[PA_CORE_HOOK_SINK_UNLINK], (pa_hook_cb_t) sink_unlink_hook_cb, u);
+    u->sink_state_changed_slot = pa_hook_connect(&m->core->hooks[PA_CORE_HOOK_SINK_STATE_CHANGED], (pa_hook_cb_t) sink_state_changed_hook_cb, u);
+
+    pick_master(u, NULL);
+
+    if (!(u->thread = pa_thread_new(thread_func, u))) {
+        pa_log("Failed to create thread.");
         goto fail;
     }
 
-    split_state = NULL;
-    while ((n = pa_split(slaves, ",", &split_state))) {
-        pa_sink *slave_sink;
-
-        if (!(slave_sink = pa_namereg_get(c, n, PA_NAMEREG_SINK, 1))) {
-            pa_log("invalid slave sink '%s'", n);
-            goto fail;
-        }
-
-        pa_xfree(n);
-
-        if (!output_new(u, slave_sink, resample_method)) {
-            pa_log("failed to create slave sink input on sink '%s'.", slave_sink->name);
-            goto fail;
-        }
-    }
-
-    if (u->n_outputs <= 1)
-        pa_log_warn("WARNING: no slave sinks specified.");
+    /* Activate the sink and the sink inputs */
+    pa_sink_put(u->sink);
+
+    for (o = pa_idxset_first(u->outputs, &idx); o; o = pa_idxset_next(u->outputs, &idx))
+        if (o->sink_input)
+            pa_sink_input_put(o->sink_input);
 
     if (u->adjust_time > 0) {
+        struct timeval tv;
         pa_gettimeofday(&tv);
         tv.tv_sec += u->adjust_time;
-        u->time_event = c->mainloop->time_new(c->mainloop, &tv, time_callback, u);
+        u->time_event = m->core->mainloop->time_new(m->core->mainloop, &tv, time_callback, u);
     }
 
     pa_modargs_free(ma);
+
     return 0;
 
 fail:
-    pa_xfree(n);
 
     if (ma)
         pa_modargs_free(ma);
 
-    pa__done(c, m);
+    pa__done(m);
+
     return -1;
 }
 
-void pa__done(pa_core *c, pa_module*m) {
+static void output_free(struct output *o) {
+    pa_assert(o);
+
+    pick_master(o->userdata, o);
+
+    disable_output(o);
+
+    pa_assert_se(pa_idxset_remove_by_data(o->userdata->outputs, o, NULL));
+
+    update_description(o->userdata);
+
+    if (o->inq_rtpoll_item)
+        pa_rtpoll_item_free(o->inq_rtpoll_item);
+
+    if (o->outq_rtpoll_item)
+        pa_rtpoll_item_free(o->outq_rtpoll_item);
+
+    if (o->inq)
+        pa_asyncmsgq_unref(o->inq);
+
+    if (o->outq)
+        pa_asyncmsgq_unref(o->outq);
+
+    if (o->memblockq)
+        pa_memblockq_free(o->memblockq);
+
+    pa_xfree(o);
+}
+
+void pa__done(pa_module*m) {
     struct userdata *u;
-    assert(c && m);
+    struct output *o;
+
+    pa_assert(m);
 
     if (!(u = m->userdata))
         return;
 
-    clear_up(u);
+    if (u->sink_new_slot)
+        pa_hook_slot_free(u->sink_new_slot);
+
+    if (u->sink_unlink_slot)
+        pa_hook_slot_free(u->sink_unlink_slot);
+
+    if (u->sink_state_changed_slot)
+        pa_hook_slot_free(u->sink_state_changed_slot);
+
+    if (u->outputs) {
+        while ((o = pa_idxset_first(u->outputs, NULL)))
+            output_free(o);
+
+        pa_idxset_free(u->outputs, NULL, NULL);
+    }
+
+    if (u->sink)
+        pa_sink_unlink(u->sink);
+
+    if (u->thread) {
+        pa_asyncmsgq_send(u->thread_mq.inq, NULL, PA_MESSAGE_SHUTDOWN, NULL, 0, NULL);
+        pa_thread_free(u->thread);
+    }
+
+    pa_thread_mq_done(&u->thread_mq);
+
+    if (u->sink)
+        pa_sink_unref(u->sink);
+
+    if (u->rtpoll)
+        pa_rtpoll_free(u->rtpoll);
+
+    if (u->time_event)
+        u->core->mainloop->time_free(u->time_event);
+
     pa_xfree(u);
 }
-
-

Copied: trunk/src/modules/module-default-device-restore.c (from r1970, branches/lennart/src/modules/module-default-device-restore.c)
URL: http://0pointer.de/cgi-bin/viewcvs.cgi/trunk/src/modules/module-default-device-restore.c?p2=trunk/src/modules/module-default-device-restore.c&p1=branches/lennart/src/modules/module-default-device-restore.c&r1=1970&r2=1971&rev=1971&root=pulseaudio&view=diff
==============================================================================
--- branches/lennart/src/modules/module-default-device-restore.c (original)
+++ trunk/src/modules/module-default-device-restore.c Sun Oct 28 20:13:50 2007
@@ -43,16 +43,16 @@
     FILE *f;
 
     /* We never overwrite manually configured settings */
-    
+
     if (m->core->default_sink_name)
         pa_log_info("Manually configured default sink, not overwriting.");
     else if ((f = pa_open_config_file(NULL, DEFAULT_SINK_FILE, NULL, NULL, "r"))) {
         char ln[256] = "";
-        
+
         fgets(ln, sizeof(ln)-1, f);
         pa_strip_nl(ln);
         fclose(f);
-        
+
         if (!ln[0])
             pa_log_debug("No previous default sink setting, ignoring.");
         else if (pa_namereg_get(m->core, ln, PA_NAMEREG_SINK, 1)) {
@@ -61,12 +61,12 @@
         } else
             pa_log_info("Saved default sink '%s' not existant, not restoring default sink setting.", ln);
     }
-    
+
     if (m->core->default_source_name)
         pa_log_info("Manually configured default source, not overwriting.");
     else if ((f = pa_open_config_file(NULL, DEFAULT_SOURCE_FILE, NULL, NULL, "r"))) {
         char ln[256] = "";
-        
+
         fgets(ln, sizeof(ln)-1, f);
         pa_strip_nl(ln);
         fclose(f);
@@ -90,13 +90,13 @@
         const char *n = pa_namereg_get_default_sink_name(m->core);
         fprintf(f, "%s\n", n ? n : "");
         fclose(f);
-    }    
+    }
 
     if ((f = pa_open_config_file(NULL, DEFAULT_SOURCE_FILE, NULL, NULL, "w"))) {
         const char *n = pa_namereg_get_default_source_name(m->core);
         fprintf(f, "%s\n", n ? n : "");
         fclose(f);
-    }    
+    }
 }
 
 

Modified: trunk/src/modules/module-defs.h.m4
URL: http://0pointer.de/cgi-bin/viewcvs.cgi/trunk/src/modules/module-defs.h.m4?rev=1971&root=pulseaudio&r1=1970&r2=1971&view=diff
==============================================================================
--- trunk/src/modules/module-defs.h.m4 (original)
+++ trunk/src/modules/module-defs.h.m4 Sun Oct 28 20:13:50 2007
@@ -18,8 +18,8 @@
 gen_symbol(pa__get_usage)
 gen_symbol(pa__get_version)
 
-int pa__init(struct pa_core *c, struct pa_module*m);
-void pa__done(struct pa_core *c, struct pa_module*m);
+int pa__init(pa_module*m);
+void pa__done(pa_module*m);
 
 const char* pa__get_author(void);
 const char* pa__get_description(void);

Modified: trunk/src/modules/module-detect.c
URL: http://0pointer.de/cgi-bin/viewcvs.cgi/trunk/src/modules/module-detect.c?rev=1971&root=pulseaudio&r1=1970&r2=1971&view=diff
==============================================================================
--- trunk/src/modules/module-detect.c (original)
+++ trunk/src/modules/module-detect.c Sun Oct 28 20:13:50 2007
@@ -28,7 +28,6 @@
 #endif
 
 #include <stdio.h>
-#include <assert.h>
 #include <unistd.h>
 #include <string.h>
 #include <stdlib.h>
@@ -44,6 +43,7 @@
 #include <pulsecore/modargs.h>
 #include <pulsecore/log.h>
 #include <pulsecore/core-util.h>
+#include <pulsecore/macro.h>
 
 #include "module-detect-symdef.h"
 
@@ -51,6 +51,11 @@
 PA_MODULE_DESCRIPTION("Detect available audio hardware and load matching drivers")
 PA_MODULE_VERSION(PACKAGE_VERSION)
 PA_MODULE_USAGE("just-one=<boolean>")
+
+static const char* const valid_modargs[] = {
+    "just-one",
+    NULL
+};
 
 #ifdef HAVE_ALSA
 
@@ -96,7 +101,7 @@
         if (subdevice != 0)
             continue;
 
-        snprintf(args, sizeof(args), "device=hw:%u", device);
+        pa_snprintf(args, sizeof(args), "device=hw:%u", device);
         if (!pa_module_load(c, is_sink ? "module-alsa-sink" : "module-alsa-source", args))
             continue;
 
@@ -139,7 +144,7 @@
         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;
         }
 
@@ -148,20 +153,20 @@
 
         if (sscanf(line, "%u: ", &device) == 1) {
             if (device == 0)
-                snprintf(args, sizeof(args), "device=/dev/dsp");
+                pa_snprintf(args, sizeof(args), "device=/dev/dsp");
             else
-                snprintf(args, sizeof(args), "device=/dev/dsp%u", device);
+                pa_snprintf(args, sizeof(args), "device=/dev/dsp%u", device);
 
             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);
+            pa_snprintf(args, sizeof(args), "device=/dev/dsp%u.0", device);
 
             if (!pa_module_load(c, "module-oss", args))
                 continue;
-	}
+        }
 
         n++;
 
@@ -193,7 +198,7 @@
     if (!S_ISCHR(s.st_mode))
         return 0;
 
-    snprintf(args, sizeof(args), "device=%s", dev);
+    pa_snprintf(args, sizeof(args), "device=%s", dev);
 
     if (!pa_module_load(c, "module-solaris", args))
         return 0;
@@ -215,17 +220,11 @@
 }
 #endif
 
-int pa__init(pa_core *c, pa_module*m) {
+int pa__init(pa_module*m) {
     int just_one = 0, n = 0;
     pa_modargs *ma;
 
-    static const char* const valid_modargs[] = {
-        "just-one",
-        NULL
-    };
-
-    assert(c);
-    assert(m);
+    pa_assert(m);
 
     if (!(ma = pa_modargs_new(m->argument, valid_modargs))) {
         pa_log("Failed to parse module arguments");
@@ -238,16 +237,16 @@
     }
 
 #if HAVE_ALSA
-    if ((n = detect_alsa(c, just_one)) <= 0)
+    if ((n = detect_alsa(m->core, just_one)) <= 0)
 #endif
 #if HAVE_OSS
-    if ((n = detect_oss(c, just_one)) <= 0)
+    if ((n = detect_oss(m->core, just_one)) <= 0)
 #endif
 #if HAVE_SOLARIS
-    if ((n = detect_solaris(c, just_one)) <= 0)
+    if ((n = detect_solaris(m->core, just_one)) <= 0)
 #endif
 #if OS_IS_WIN32
-    if ((n = detect_waveout(c, just_one)) <= 0)
+    if ((n = detect_waveout(m->core, just_one)) <= 0)
 #endif
     {
         pa_log_warn("failed to detect any sound hardware.");
@@ -269,9 +268,3 @@
 
     return -1;
 }
-
-
-void pa__done(PA_GCC_UNUSED pa_core *c, PA_GCC_UNUSED pa_module*m) {
-    /* NOP */
-}
-

Modified: trunk/src/modules/module-esound-compat-spawnfd.c
URL: http://0pointer.de/cgi-bin/viewcvs.cgi/trunk/src/modules/module-esound-compat-spawnfd.c?rev=1971&root=pulseaudio&r1=1970&r2=1971&view=diff
==============================================================================
--- trunk/src/modules/module-esound-compat-spawnfd.c (original)
+++ trunk/src/modules/module-esound-compat-spawnfd.c Sun Oct 28 20:13:50 2007
@@ -26,7 +26,6 @@
 #endif
 
 #include <unistd.h>
-#include <assert.h>
 #include <string.h>
 #include <errno.h>
 
@@ -48,23 +47,25 @@
     NULL,
 };
 
-int pa__init(pa_core *c, pa_module*m) {
+int pa__init(pa_module*m) {
     pa_modargs *ma = NULL;
     int ret = -1, fd = -1;
     char x = 1;
-    assert(c && m);
+
+    pa_assert(m);
 
     if (!(ma = pa_modargs_new(m->argument, valid_modargs)) ||
         pa_modargs_get_value_s32(ma, "fd", &fd) < 0 ||
         fd < 0) {
+
         pa_log("Failed to parse module arguments");
         goto finish;
     }
 
     if (pa_loop_write(fd, &x, sizeof(x), NULL) != sizeof(x))
-        pa_log("WARNING: write(%u, 1, 1) failed: %s", fd, pa_cstrerror(errno));
+        pa_log_warn("write(%u, 1, 1) failed: %s", fd, pa_cstrerror(errno));
 
-    close(fd);
+    pa_assert_se(pa_close(fd) == 0);
 
     pa_module_unload_request(m);
 
@@ -76,9 +77,3 @@
 
     return ret;
 }
-
-void pa__done(pa_core *c, pa_module*m) {
-    assert(c && m);
-}
-
-

Modified: trunk/src/modules/module-esound-compat-spawnpid.c
URL: http://0pointer.de/cgi-bin/viewcvs.cgi/trunk/src/modules/module-esound-compat-spawnpid.c?rev=1971&root=pulseaudio&r1=1970&r2=1971&view=diff
==============================================================================
--- trunk/src/modules/module-esound-compat-spawnpid.c (original)
+++ trunk/src/modules/module-esound-compat-spawnpid.c Sun Oct 28 20:13:50 2007
@@ -25,7 +25,6 @@
 #endif
 
 #include <unistd.h>
-#include <assert.h>
 #include <string.h>
 #include <errno.h>
 #include <signal.h>
@@ -48,11 +47,12 @@
     NULL,
 };
 
-int pa__init(pa_core *c, pa_module*m) {
+int pa__init(pa_module*m) {
     pa_modargs *ma = NULL;
     int ret = -1;
     uint32_t pid = 0;
-    assert(c && m);
+
+    pa_assert(m);
 
     if (!(ma = pa_modargs_new(m->argument, valid_modargs)) ||
         pa_modargs_get_value_u32(ma, "pid", &pid) < 0 ||
@@ -62,7 +62,7 @@
     }
 
     if (kill(pid, SIGUSR1) < 0)
-        pa_log("WARNING: kill(%u) failed: %s", pid, pa_cstrerror(errno));
+        pa_log_warn("kill(%u) failed: %s", pid, pa_cstrerror(errno));
 
     pa_module_unload_request(m);
 
@@ -74,9 +74,3 @@
 
     return ret;
 }
-
-void pa__done(pa_core *c, pa_module*m) {
-    assert(c && m);
-}
-
-

Modified: trunk/src/modules/module-esound-sink.c
URL: http://0pointer.de/cgi-bin/viewcvs.cgi/trunk/src/modules/module-esound-sink.c?rev=1971&root=pulseaudio&r1=1970&r2=1971&view=diff
==============================================================================
--- trunk/src/modules/module-esound-sink.c (original)
+++ trunk/src/modules/module-esound-sink.c Sun Oct 28 20:13:50 2007
@@ -28,14 +28,23 @@
 #include <stdlib.h>
 #include <sys/stat.h>
 #include <stdio.h>
-#include <assert.h>
 #include <errno.h>
 #include <string.h>
 #include <fcntl.h>
 #include <unistd.h>
 #include <limits.h>
+#include <poll.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <netinet/tcp.h>
+#include <sys/ioctl.h>
+
+#ifdef HAVE_LINUX_SOCKIOS_H
+#include <linux/sockios.h>
+#endif
 
 #include <pulse/xmalloc.h>
+#include <pulse/timeval.h>
 
 #include <pulsecore/core-error.h>
 #include <pulsecore/iochannel.h>
@@ -47,40 +56,66 @@
 #include <pulsecore/socket-client.h>
 #include <pulsecore/esound.h>
 #include <pulsecore/authkey.h>
+#include <pulsecore/thread-mq.h>
+#include <pulsecore/thread.h>
+#include <pulsecore/time-smoother.h>
+#include <pulsecore/rtclock.h>
+#include <pulsecore/socket-util.h>
 
 #include "module-esound-sink-symdef.h"
 
 PA_MODULE_AUTHOR("Lennart Poettering")
 PA_MODULE_DESCRIPTION("ESOUND Sink")
 PA_MODULE_VERSION(PACKAGE_VERSION)
-PA_MODULE_USAGE("sink_name=<name for the sink> server=<address> cookie=<filename>  format=<sample format> channels=<number of channels> rate=<sample rate>")
-
-#define DEFAULT_SINK_NAME "esound_output"
+PA_MODULE_USAGE(
+        "sink_name=<name for the sink> "
+        "server=<address> cookie=<filename>  "
+        "format=<sample format> "
+        "channels=<number of channels> "
+        "rate=<sample rate>")
+
+#define DEFAULT_SINK_NAME "esound_out"
 
 struct userdata {
     pa_core *core;
-
+    pa_module *module;
     pa_sink *sink;
+
+    pa_thread_mq thread_mq;
+    pa_rtpoll *rtpoll;
+    pa_rtpoll_item *rtpoll_item;
+    pa_thread *thread;
+
+    pa_memchunk memchunk;
+
+    void *write_data;
+    size_t write_length, write_index;
+
+    void *read_data;
+    size_t read_length, read_index;
+
+    enum {
+        STATE_AUTH,
+        STATE_LATENCY,
+        STATE_PREPARE,
+        STATE_RUNNING,
+        STATE_DEAD
+    } state;
+
+    pa_usec_t latency;
+
+    esd_format_t format;
+    int32_t rate;
+
+    pa_smoother *smoother;
+    int fd;
+
+    int64_t offset;
+
     pa_iochannel *io;
     pa_socket_client *client;
 
-    pa_defer_event *defer_event;
-
-    pa_memchunk memchunk;
-    pa_module *module;
-
-    void *write_data;
-    size_t write_length, write_index;
-
-    void *read_data;
-    size_t read_length, read_index;
-
-    enum { STATE_AUTH, STATE_LATENCY, STATE_RUNNING, STATE_DEAD } state;
-
-    pa_usec_t latency;
-
-    esd_format_t format;
-    int32_t rate;
+    size_t block_size;
 };
 
 static const char* const valid_modargs[] = {
@@ -93,42 +128,211 @@
     NULL
 };
 
-static void cancel(struct userdata *u) {
-    assert(u);
-
-    u->state = STATE_DEAD;
-
-    if (u->io) {
-        pa_iochannel_free(u->io);
-        u->io = NULL;
-    }
-
-    if (u->defer_event) {
-        u->core->mainloop->defer_free(u->defer_event);
-        u->defer_event = NULL;
-    }
-
-    if (u->sink) {
-        pa_sink_disconnect(u->sink);
-        pa_sink_unref(u->sink);
-        u->sink = NULL;
-    }
-
-    if (u->module) {
-        pa_module_unload_request(u->module);
-        u->module = NULL;
-    }
+enum {
+    SINK_MESSAGE_PASS_SOCKET = PA_SINK_MESSAGE_MAX
+};
+
+static int sink_process_msg(pa_msgobject *o, int code, void *data, int64_t offset, pa_memchunk *chunk) {
+    struct userdata *u = PA_SINK(o)->userdata;
+
+    switch (code) {
+
+        case PA_SINK_MESSAGE_SET_STATE:
+
+            switch ((pa_sink_state_t) PA_PTR_TO_UINT(data)) {
+
+                case PA_SINK_SUSPENDED:
+                    pa_assert(PA_SINK_OPENED(u->sink->thread_info.state));
+
+                    pa_smoother_pause(u->smoother, pa_rtclock_usec());
+                    break;
+
+                case PA_SINK_IDLE:
+                case PA_SINK_RUNNING:
+
+                    if (u->sink->thread_info.state == PA_SINK_SUSPENDED)
+                        pa_smoother_resume(u->smoother, pa_rtclock_usec());
+
+                    break;
+
+                case PA_SINK_UNLINKED:
+                case PA_SINK_INIT:
+                    ;
+            }
+
+            break;
+
+        case PA_SINK_MESSAGE_GET_LATENCY: {
+            pa_usec_t w, r;
+
+            r = pa_smoother_get(u->smoother, pa_rtclock_usec());
+            w = pa_bytes_to_usec(u->offset + u->memchunk.length, &u->sink->sample_spec);
+
+            *((pa_usec_t*) data) = w > r ? w - r : 0;
+            break;
+        }
+
+        case SINK_MESSAGE_PASS_SOCKET: {
+            struct pollfd *pollfd;
+
+            pa_assert(!u->rtpoll_item);
+
+            u->rtpoll_item = pa_rtpoll_item_new(u->rtpoll, PA_RTPOLL_NEVER, 1);
+            pollfd = pa_rtpoll_item_get_pollfd(u->rtpoll_item, NULL);
+            pollfd->fd = u->fd;
+            pollfd->events = pollfd->revents = 0;
+
+            return 0;
+        }
+    }
+
+    return pa_sink_process_msg(o, code, data, offset, chunk);
+}
+
+static void thread_func(void *userdata) {
+    struct userdata *u = userdata;
+    int write_type = 0;
+
+    pa_assert(u);
+
+    pa_log_debug("Thread starting up");
+
+    pa_thread_mq_install(&u->thread_mq);
+    pa_rtpoll_install(u->rtpoll);
+
+    pa_smoother_set_time_offset(u->smoother, pa_rtclock_usec());
+
+    for (;;) {
+        int ret;
+
+        if (u->rtpoll_item) {
+            struct pollfd *pollfd;
+            pollfd = pa_rtpoll_item_get_pollfd(u->rtpoll_item, NULL);
+
+            /* Render some data and write it to the fifo */
+            if (PA_SINK_OPENED(u->sink->thread_info.state) && pollfd->revents) {
+                pa_usec_t usec;
+                int64_t n;
+
+                for (;;) {
+                    ssize_t l;
+                    void *p;
+
+                    if (u->memchunk.length <= 0)
+                        pa_sink_render(u->sink, u->block_size, &u->memchunk);
+
+                    pa_assert(u->memchunk.length > 0);
+
+                    p = pa_memblock_acquire(u->memchunk.memblock);
+                    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)
+                            continue;
+                        else if (errno == EAGAIN) {
+
+                            /* OK, we filled all socket buffers up
+                             * now. */
+                            goto filled_up;
+
+                        } else {
+                            pa_log("Failed to write data to FIFO: %s", pa_cstrerror(errno));
+                            goto fail;
+                        }
+
+                    } else {
+                        u->offset += l;
+
+                        u->memchunk.index += l;
+                        u->memchunk.length -= l;
+
+                        if (u->memchunk.length <= 0) {
+                            pa_memblock_unref(u->memchunk.memblock);
+                            pa_memchunk_reset(&u->memchunk);
+                        }
+
+                        pollfd->revents = 0;
+
+                        if (u->memchunk.length > 0)
+
+                            /* OK, we wrote less that we asked for,
+                             * hence we can assume that the socket
+                             * buffers are full now */
+                            goto filled_up;
+                    }
+                }
+
+            filled_up:
+
+                /* At this spot we know that the socket buffers are
+                 * fully filled up. This is the best time to estimate
+                 * the playback position of the server */
+
+                n = u->offset;
+
+#ifdef SIOCOUTQ
+                {
+                    int l;
+                    if (ioctl(u->fd, SIOCOUTQ, &l) >= 0 && l > 0)
+                        n -= l;
+                }
+#endif
+
+                usec = pa_bytes_to_usec(n, &u->sink->sample_spec);
+
+                if (usec > u->latency)
+                    usec -= u->latency;
+                else
+                    usec = 0;
+
+                pa_smoother_put(u->smoother, pa_rtclock_usec(), usec);
+            }
+
+            /* Hmm, nothing to do. Let's sleep */
+            pollfd->events = PA_SINK_OPENED(u->sink->thread_info.state)  ? POLLOUT : 0;
+        }
+
+        if ((ret = pa_rtpoll_run(u->rtpoll, TRUE)) < 0)
+            goto fail;
+
+        if (ret == 0)
+            goto finish;
+
+        if (u->rtpoll_item) {
+            struct pollfd* pollfd;
+
+            pollfd = pa_rtpoll_item_get_pollfd(u->rtpoll_item, NULL);
+
+            if (pollfd->revents & ~POLLOUT) {
+                pa_log("FIFO shutdown.");
+                goto fail;
+            }
+        }
+    }
+
+fail:
+    /* If this was no regular exit from the loop we have to continue
+     * processing messages until we received PA_MESSAGE_SHUTDOWN */
+    pa_asyncmsgq_post(u->thread_mq.outq, PA_MSGOBJECT(u->core), PA_CORE_MESSAGE_UNLOAD_MODULE, u->module, 0, NULL, NULL);
+    pa_asyncmsgq_wait_for(u->thread_mq.inq, PA_MESSAGE_SHUTDOWN);
+
+finish:
+    pa_log_debug("Thread shutting down");
 }
 
 static int do_write(struct userdata *u) {
     ssize_t r;
-    assert(u);
+    pa_assert(u);
 
     if (!pa_iochannel_is_writable(u->io))
         return 0;
 
     if (u->write_data) {
-        assert(u->write_index < u->write_length);
+        pa_assert(u->write_index < u->write_length);
 
         if ((r = pa_iochannel_write(u->io, (uint8_t*) u->write_data + u->write_index, u->write_length - u->write_index)) <= 0) {
             pa_log("write() failed: %s", pa_cstrerror(errno));
@@ -136,45 +340,44 @@
         }
 
         u->write_index += r;
-        assert(u->write_index <= u->write_length);
+        pa_assert(u->write_index <= u->write_length);
 
         if (u->write_index == u->write_length) {
-            free(u->write_data);
+            pa_xfree(u->write_data);
             u->write_data = NULL;
             u->write_index = u->write_length = 0;
         }
-    } else if (u->state == STATE_RUNNING) {
-        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);
-
-        if ((r = pa_iochannel_write(u->io, (uint8_t*) u->memchunk.memblock->data + u->memchunk.index, u->memchunk.length)) < 0) {
-            pa_log("write() failed: %s", pa_cstrerror(errno));
-            return -1;
-        }
-
-        u->memchunk.index += r;
-        u->memchunk.length -= r;
-
-        if (u->memchunk.length <= 0) {
-            pa_memblock_unref(u->memchunk.memblock);
-            u->memchunk.memblock = NULL;
-        }
+    }
+
+    if (!u->write_data && u->state == STATE_PREPARE) {
+        /* OK, we're done with sending all control data we need to, so
+         * let's hand the socket over to the IO thread now */
+
+        pa_assert(u->fd < 0);
+        u->fd = pa_iochannel_get_send_fd(u->io);
+
+        pa_iochannel_set_noclose(u->io, TRUE);
+        pa_iochannel_free(u->io);
+        u->io = NULL;
+
+        pa_make_tcp_socket_low_delay(u->fd);
+
+        pa_log_info("Connection authenticated, handing fd to IO thread...");
+
+        pa_asyncmsgq_post(u->thread_mq.inq, PA_MSGOBJECT(u->sink), SINK_MESSAGE_PASS_SOCKET, NULL, 0, NULL, NULL);
+        u->state = STATE_RUNNING;
     }
 
     return 0;
 }
 
 static int handle_response(struct userdata *u) {
-    assert(u);
+    pa_assert(u);
 
     switch (u->state) {
+
         case STATE_AUTH:
-            assert(u->read_length == sizeof(int32_t));
+            pa_assert(u->read_length == sizeof(int32_t));
 
             /* Process auth data */
             if (!*(int32_t*) u->read_data) {
@@ -183,14 +386,14 @@
             }
 
             /* Request latency data */
-            assert(!u->write_data);
+            pa_assert(!u->write_data);
             *(int32_t*) (u->write_data = pa_xmalloc(u->write_length = sizeof(int32_t))) = ESD_PROTO_LATENCY;
 
             u->write_index = 0;
             u->state = STATE_LATENCY;
 
             /* Space for next response */
-            assert(u->read_length >= sizeof(int32_t));
+            pa_assert(u->read_length >= sizeof(int32_t));
             u->read_index = 0;
             u->read_length = sizeof(int32_t);
 
@@ -198,17 +401,17 @@
 
         case STATE_LATENCY: {
             int32_t *p;
-            assert(u->read_length == sizeof(int32_t));
+            pa_assert(u->read_length == sizeof(int32_t));
 
             /* Process latency info */
             u->latency = (pa_usec_t) ((double) (*(int32_t*) u->read_data) * 1000000 / 44100);
             if (u->latency > 10000000) {
-                pa_log("WARNING! Invalid latency information received from server");
+                pa_log_warn("Invalid latency information received from server");
                 u->latency = 0;
             }
 
             /* Create stream */
-            assert(!u->write_data);
+            pa_assert(!u->write_data);
             p = u->write_data = pa_xmalloc0(u->write_length = sizeof(int32_t)*3+ESD_NAME_MAX);
             *(p++) = ESD_PROTO_STREAM_PLAY;
             *(p++) = u->format;
@@ -216,7 +419,7 @@
             pa_strlcpy((char*) p, "PulseAudio Tunnel", ESD_NAME_MAX);
 
             u->write_index = 0;
-            u->state = STATE_RUNNING;
+            u->state = STATE_PREPARE;
 
             /* Don't read any further */
             pa_xfree(u->read_data);
@@ -227,14 +430,14 @@
         }
 
         default:
-            abort();
+            pa_assert_not_reached();
     }
 
     return 0;
 }
 
 static int do_read(struct userdata *u) {
-    assert(u);
+    pa_assert(u);
 
     if (!pa_iochannel_is_readable(u->io))
         return 0;
@@ -245,16 +448,15 @@
         if (!u->read_data)
             return 0;
 
-        assert(u->read_index < u->read_length);
+        pa_assert(u->read_index < u->read_length);
 
         if ((r = pa_iochannel_read(u->io, (uint8_t*) u->read_data + u->read_index, u->read_length - u->read_index)) <= 0) {
             pa_log("read() failed: %s", r < 0 ? pa_cstrerror(errno) : "EOF");
-            cancel(u);
             return -1;
         }
 
         u->read_index += r;
-        assert(u->read_index <= u->read_length);
+        pa_assert(u->read_index <= u->read_length);
 
         if (u->read_index == u->read_length)
             return handle_response(u);
@@ -263,42 +465,19 @@
     return 0;
 }
 
-static void do_work(struct userdata *u) {
-    assert(u);
-
-    u->core->mainloop->defer_enable(u->defer_event, 0);
-
-    if (do_read(u) < 0 || do_write(u) < 0)
-        cancel(u);
-}
-
-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->latency +
-        (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_work(u);
-}
-
 static void io_callback(PA_GCC_UNUSED pa_iochannel *io, void*userdata) {
     struct userdata *u = userdata;
-    assert(u);
-    do_work(u);
+    pa_assert(u);
+
+    if (do_read(u) < 0 || do_write(u) < 0) {
+
+        if (u->io) {
+            pa_iochannel_free(u->io);
+            u->io = NULL;
+        }
+
+       pa_module_unload_request(u->module);
+    }
 }
 
 static void on_connection(PA_GCC_UNUSED pa_socket_client *c, pa_iochannel*io, void *userdata) {
@@ -308,30 +487,34 @@
     u->client = NULL;
 
     if (!io) {
-        pa_log("connection failed: %s", pa_cstrerror(errno));
-        cancel(u);
+        pa_log("Connection failed: %s", pa_cstrerror(errno));
+        pa_module_unload_request(u->module);
         return;
     }
 
+    pa_assert(!u->io);
     u->io = io;
     pa_iochannel_set_callback(u->io, io_callback, u);
-}
-
-int pa__init(pa_core *c, pa_module*m) {
+
+    pa_log_info("Connection established, authenticating ...");
+}
+
+int pa__init(pa_module*m) {
     struct userdata *u = NULL;
     const char *p;
     pa_sample_spec ss;
     pa_modargs *ma = NULL;
     char *t;
-
-    assert(c && m);
+    const char *espeaker;
+
+    pa_assert(m);
 
     if (!(ma = pa_modargs_new(m->argument, valid_modargs))) {
         pa_log("failed to parse module arguments");
         goto fail;
     }
 
-    ss = c->default_sample_spec;
+    ss = m->core->default_sample_spec;
     if (pa_modargs_get_sample_spec(ma, &ss) < 0) {
         pa_log("invalid sample format specification");
         goto fail;
@@ -343,37 +526,62 @@
         goto fail;
     }
 
-    u = pa_xmalloc0(sizeof(struct userdata));
-    u->core = c;
+    u = pa_xnew0(struct userdata, 1);
+    u->core = m->core;
     u->module = m;
     m->userdata = u;
+    u->fd = -1;
+    u->smoother = pa_smoother_new(PA_USEC_PER_SEC, PA_USEC_PER_SEC*2, TRUE);
+    pa_memchunk_reset(&u->memchunk);
+    u->offset = 0;
+
+    pa_thread_mq_init(&u->thread_mq, m->core->mainloop);
+    u->rtpoll = pa_rtpoll_new();
+    pa_rtpoll_item_new_asyncmsgq(u->rtpoll, PA_RTPOLL_EARLY, u->thread_mq.inq);
+    u->rtpoll_item = NULL;
+
     u->format =
         (ss.format == PA_SAMPLE_U8 ? ESD_BITS8 : ESD_BITS16) |
         (ss.channels == 2 ? ESD_STEREO : ESD_MONO);
     u->rate = ss.rate;
-    u->sink = NULL;
-    u->client = NULL;
-    u->io = NULL;
+    u->block_size = pa_usec_to_bytes(PA_USEC_PER_SEC/20, &ss);
+
     u->read_data = u->write_data = NULL;
     u->read_index = u->write_index = u->read_length = u->write_length = 0;
+
     u->state = STATE_AUTH;
     u->latency = 0;
 
-    if (!(u->sink = pa_sink_new(c, __FILE__, pa_modargs_get_value(ma, "sink_name", DEFAULT_SINK_NAME), 0, &ss, NULL))) {
+    if (!(u->sink = pa_sink_new(m->core, __FILE__, pa_modargs_get_value(ma, "sink_name", DEFAULT_SINK_NAME), 0, &ss, NULL))) {
         pa_log("failed to create sink.");
         goto fail;
     }
 
-    if (!(u->client = pa_socket_client_new_string(u->core->mainloop, p = pa_modargs_get_value(ma, "server", ESD_UNIX_SOCKET_NAME), ESD_DEFAULT_PORT))) {
-        pa_log("failed to connect to server.");
+    u->sink->parent.process_msg = sink_process_msg;
+    u->sink->userdata = u;
+    u->sink->flags = PA_SINK_LATENCY;
+
+    pa_sink_set_module(u->sink, m);
+    pa_sink_set_asyncmsgq(u->sink, u->thread_mq.inq);
+    pa_sink_set_rtpoll(u->sink, u->rtpoll);
+
+    if (!(espeaker = getenv("ESPEAKER")))
+        espeaker = ESD_UNIX_SOCKET_NAME;
+
+    if (!(u->client = pa_socket_client_new_string(u->core->mainloop, p = pa_modargs_get_value(ma, "server", espeaker), ESD_DEFAULT_PORT))) {
+        pa_log("Failed to connect to server.");
         goto fail;
     }
+
+    pa_sink_set_description(u->sink, t = pa_sprintf_malloc("Esound sink '%s'", p));
+    pa_xfree(t);
+
     pa_socket_client_set_callback(u->client, on_connection, u);
 
     /* Prepare the initial request */
     u->write_data = pa_xmalloc(u->write_length = ESD_KEY_LEN + sizeof(int32_t));
     if (pa_authkey_load_auto(pa_modargs_get_value(ma, "cookie", ".esd_auth"), u->write_data, ESD_KEY_LEN) < 0) {
-        pa_log("failed to load cookie");
+        pa_log("Failed to load cookie");
         goto fail;
     }
     *(int32_t*) ((uint8_t*) u->write_data + ESD_KEY_LEN) = ESD_ENDIAN_KEY;
@@ -381,19 +589,12 @@
     /* Reserve space for the response */
     u->read_data = pa_xmalloc(u->read_length = sizeof(int32_t));
 
-    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("Esound sink '%s'", p));
-    pa_xfree(t);
-
-    u->memchunk.memblock = NULL;
-    u->memchunk.length = 0;
-
-    u->defer_event = c->mainloop->defer_new(c->mainloop, defer_callback, u);
-    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_sink_put(u->sink);
 
     pa_modargs_free(ma);
 
@@ -403,20 +604,39 @@
     if (ma)
         pa_modargs_free(ma);
 
-    pa__done(c, m);
+    pa__done(m);
 
     return -1;
 }
 
-void pa__done(pa_core *c, pa_module*m) {
+void pa__done(pa_module*m) {
     struct userdata *u;
-    assert(c && m);
+    pa_assert(m);
 
     if (!(u = m->userdata))
         return;
 
-    u->module = NULL;
-    cancel(u);
+    if (u->sink)
+        pa_sink_unlink(u->sink);
+
+    if (u->thread) {
+        pa_asyncmsgq_send(u->thread_mq.inq, NULL, PA_MESSAGE_SHUTDOWN, NULL, 0, NULL);
+        pa_thread_free(u->thread);
+    }
+
+    pa_thread_mq_done(&u->thread_mq);
+
+    if (u->sink)
+        pa_sink_unref(u->sink);
+
+    if (u->io)
+        pa_iochannel_free(u->io);
+
+    if (u->rtpoll_item)
+        pa_rtpoll_item_free(u->rtpoll_item);
+
+    if (u->rtpoll)
+        pa_rtpoll_free(u->rtpoll);
 
     if (u->memchunk.memblock)
         pa_memblock_unref(u->memchunk.memblock);
@@ -427,8 +647,11 @@
     pa_xfree(u->read_data);
     pa_xfree(u->write_data);
 
+    if (u->smoother)
+        pa_smoother_free(u->smoother);
+
+    if (u->fd >= 0)
+        pa_close(u->fd);
+
     pa_xfree(u);
 }
-
-
-

Modified: trunk/src/modules/module-hal-detect.c
URL: http://0pointer.de/cgi-bin/viewcvs.cgi/trunk/src/modules/module-hal-detect.c?rev=1971&root=pulseaudio&r1=1970&r2=1971&view=diff
==============================================================================
--- trunk/src/modules/module-hal-detect.c (original)
+++ trunk/src/modules/module-hal-detect.c Sun Oct 28 20:13:50 2007
@@ -1,25 +1,25 @@
 /* $Id$ */
 
 /***
-  This file is part of PulseAudio.
-
-  Copyright 2006 Lennart Poettering
-  Copyright 2006 Shams E. King
-
-  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.
+    This file is part of PulseAudio.
+
+    Copyright 2006 Lennart Poettering
+    Copyright 2006 Shams E. King
+
+    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
@@ -27,7 +27,6 @@
 #endif
 
 #include <stdio.h>
-#include <assert.h>
 #include <unistd.h>
 #include <string.h>
 #include <stdlib.h>
@@ -45,6 +44,9 @@
 #include <pulsecore/hashmap.h>
 #include <pulsecore/idxset.h>
 #include <pulsecore/core-util.h>
+#include <pulsecore/namereg.h>
+#include <pulsecore/core-scache.h>
+#include <pulsecore/modargs.h>
 
 #include <hal/libhal.h>
 
@@ -54,40 +56,27 @@
 PA_MODULE_AUTHOR("Shahms King")
 PA_MODULE_DESCRIPTION("Detect available audio hardware and load matching drivers")
 PA_MODULE_VERSION(PACKAGE_VERSION)
-
-typedef enum {
-#ifdef HAVE_ALSA
-    CAP_ALSA,
-#endif
-#ifdef HAVE_OSS
-    CAP_OSS,
-#endif
-    CAP_MAX
-} capability_t;
-
-static const char* const capabilities[CAP_MAX] = {
-#ifdef HAVE_ALSA
-    [CAP_ALSA] = "alsa",
-#endif
-#ifdef HAVE_OSS
-    [CAP_OSS] = "oss",
-#endif
-};
+#if defined(HAVE_ALSA) && defined(HAVE_OSS)
+PA_MODULE_USAGE("api=<alsa or oss>")
+#elif defined(HAVE_ALSA)
+PA_MODULE_USAGE("api=<alsa>")
+#elif defined(HAVE_OSS)
+PA_MODULE_USAGE("api=<oss>")
+#endif
 
 struct device {
     uint32_t index;
     char *udi;
+    char *sink_name, *source_name;
+    int acl_race_fix;
 };
 
 struct userdata {
     pa_core *core;
-    LibHalContext *ctx;
-    capability_t capability;
-    pa_dbus_connection *conn;
+    LibHalContext *context;
+    pa_dbus_connection *connection;
     pa_hashmap *devices;
-#if defined(HAVE_ALSA) && defined(HAVE_OSS)
-    int use_oss;
-#endif
+    const char *capability;
 };
 
 struct timerdata {
@@ -95,23 +84,30 @@
     char *udi;
 };
 
-static const char* get_capability_name(capability_t cap) {
-    if (cap >= CAP_MAX)
-        return NULL;
-    return capabilities[cap];
-}
+#define CAPABILITY_ALSA "alsa"
+#define CAPABILITY_OSS "oss"
+
+static const char* const valid_modargs[] = {
+    "api",
+    NULL
+};
 
 static void hal_device_free(struct device* d) {
+    pa_assert(d);
+
     pa_xfree(d->udi);
+    pa_xfree(d->sink_name);
+    pa_xfree(d->source_name);
     pa_xfree(d);
 }
 
 static void hal_device_free_cb(void *d, PA_GCC_UNUSED void *data) {
-    hal_device_free((struct device*) d);
+    hal_device_free(d);
 }
 
 static const char *strip_udi(const char *udi) {
     const char *slash;
+
     if ((slash = strrchr(udi, '/')))
         return slash+1;
 
@@ -119,6 +115,7 @@
 }
 
 #ifdef HAVE_ALSA
+
 typedef enum {
     ALSA_TYPE_SINK,
     ALSA_TYPE_SOURCE,
@@ -126,234 +123,297 @@
     ALSA_TYPE_MAX
 } alsa_type_t;
 
-static alsa_type_t hal_device_get_alsa_type(LibHalContext *ctx, const char *udi,
-                                            DBusError *error)
-{
+static alsa_type_t hal_alsa_device_get_type(LibHalContext *context, const char *udi, DBusError *error) {
     char *type;
     alsa_type_t t;
 
-    type = libhal_device_get_property_string(ctx, udi, "alsa.type", error);
-    if (!type || dbus_error_is_set(error))
-        return FALSE;
-
-    if (!strcmp(type, "playback")) {
+    if (!(type = libhal_device_get_property_string(context, udi, "alsa.type", error)))
+        return ALSA_TYPE_OTHER;
+
+    if (!strcmp(type, "playback"))
         t = ALSA_TYPE_SINK;
-    } else if (!strcmp(type, "capture")) {
+    else if (!strcmp(type, "capture"))
         t = ALSA_TYPE_SOURCE;
-    } else {
+    else
         t = ALSA_TYPE_OTHER;
-    }
+
     libhal_free_string(type);
 
     return t;
 }
 
-static int hal_device_get_alsa_card(LibHalContext *ctx, const char *udi,
-                                    DBusError *error)
-{
-    return libhal_device_get_property_int(ctx, udi, "alsa.card", error);
-}
-
-static int hal_device_get_alsa_device(LibHalContext *ctx, const char *udi,
-                                      DBusError *error)
-{
-    return libhal_device_get_property_int(ctx, udi, "alsa.device", error);
-}
-
-static pa_module* hal_device_load_alsa(struct userdata *u, const char *udi,
-                                       DBusError  *error)
-{
-    char args[128];
+static int hal_alsa_device_is_modem(LibHalContext *context, const char *udi, DBusError *error) {
+    char *class;
+    int r;
+
+    if (!(class = libhal_device_get_property_string(context, udi, "alsa.pcm_class", error)))
+        return 0;
+
+    r = strcmp(class, "modem") == 0;
+    pa_xfree(class);
+
+    return r;
+}
+
+static pa_module* hal_device_load_alsa(struct userdata *u, const char *udi, char **sink_name, char **source_name) {
+    char *args;
     alsa_type_t type;
     int device, card;
     const char *module_name;
-
-    type = hal_device_get_alsa_type(u->ctx, udi, error);
-    if (dbus_error_is_set(error) || type == ALSA_TYPE_OTHER)
-        return NULL;
-
-    device = hal_device_get_alsa_device(u->ctx, udi, error);
+    DBusError error;
+    pa_module *m;
+
+    dbus_error_init(&error);
+
+    pa_assert(u);
+    pa_assert(sink_name);
+    pa_assert(source_name);
+
+    *sink_name = *source_name = NULL;
+
+    type = hal_alsa_device_get_type(u->context, udi, &error);
+    if (dbus_error_is_set(&error) || type == ALSA_TYPE_OTHER)
+        goto fail;
+
+    device = libhal_device_get_property_int(u->context, udi, "alsa.device", &error);
+    if (dbus_error_is_set(&error) || device != 0)
+        goto fail;
+
+    card = libhal_device_get_property_int(u->context, udi, "alsa.card", &error);
+    if (dbus_error_is_set(&error))
+        goto fail;
+
+    if (hal_alsa_device_is_modem(u->context, udi, &error))
+        goto fail;
+
+    if (type == ALSA_TYPE_SINK) {
+        *sink_name = pa_sprintf_malloc("alsa_output.%s", strip_udi(udi));
+
+        module_name = "module-alsa-sink";
+        args = pa_sprintf_malloc("device=hw:%u sink_name=%s", card, *sink_name);
+    } else {
+        *source_name = pa_sprintf_malloc("alsa_input.%s", strip_udi(udi));
+
+        module_name = "module-alsa-source";
+        args = pa_sprintf_malloc("device=hw:%u source_name=%s", card, *source_name);
+    }
+
+    pa_log_debug("Loading %s with arguments '%s'", module_name, args);
+
+    m = pa_module_load(u->core, module_name, args);
+
+    pa_xfree(args);
+
+    if (!m) {
+        pa_xfree(*sink_name);
+        pa_xfree(*source_name);
+        *sink_name = *source_name = NULL;
+    }
+
+    return m;
+
+fail:
+    if (dbus_error_is_set(&error)) {
+        pa_log_error("D-Bus error while parsing ALSA data: %s: %s", error.name, error.message);
+        dbus_error_free(&error);
+    }
+
+    return NULL;
+}
+
+#endif
+
+#ifdef HAVE_OSS
+
+static int hal_oss_device_is_pcm(LibHalContext *context, const char *udi, DBusError *error) {
+    char *class = NULL, *dev = NULL, *e;
+    int device;
+    int r = 0;
+
+    class = libhal_device_get_property_string(context, udi, "oss.type", error);
+    if (dbus_error_is_set(error) || !class)
+        goto finish;
+
+    if (strcmp(class, "pcm"))
+        goto finish;
+
+    dev = libhal_device_get_property_string(context, udi, "oss.device_file", error);
+    if (dbus_error_is_set(error) || !dev)
+        goto finish;
+
+    if ((e = strrchr(dev, '/')))
+        if (pa_startswith(e + 1, "audio"))
+            goto finish;
+
+    device = libhal_device_get_property_int(context, udi, "oss.device", error);
     if (dbus_error_is_set(error) || device != 0)
-        return NULL;
-
-    card = hal_device_get_alsa_card(u->ctx, udi, error);
-    if (dbus_error_is_set(error))
-        return NULL;
-
-    if (type == ALSA_TYPE_SINK) {
-        module_name = "module-alsa-sink";
-        snprintf(args, sizeof(args), "device=hw:%u sink_name=alsa_output.%s", card, strip_udi(udi));
-    } else {
-        module_name = "module-alsa-source";
-        snprintf(args, sizeof(args), "device=hw:%u source_name=alsa_input.%s", card, strip_udi(udi));
-    }
-
-    pa_log_debug("Loading %s with arguments '%s'", module_name, args);
-
-    return pa_module_load(u->core, module_name, args);
-}
-
-#endif
-
-#ifdef HAVE_OSS
-static dbus_bool_t hal_device_is_oss_pcm(LibHalContext *ctx, const char *udi,
-                                         DBusError *error)
-{
-    dbus_bool_t rv = FALSE;
-    char* type, *device_file = NULL;
-    int device;
-
-    type = libhal_device_get_property_string(ctx, udi, "oss.type", error);
-    if (!type || dbus_error_is_set(error))
-        return FALSE;
-
-    if (!strcmp(type, "pcm")) {
-        char *e;
-
-        device = libhal_device_get_property_int(ctx, udi, "oss.device", error);
-        if (dbus_error_is_set(error) || device != 0)
-            goto exit;
-
-        device_file = libhal_device_get_property_string(ctx, udi, "oss.device_file",
-                                                   error);
-        if (!device_file || dbus_error_is_set(error))
-            goto exit;
-
-        /* hack to ignore /dev/audio style devices */
-        if ((e = strrchr(device_file, '/')))
-            rv = !pa_startswith(e + 1, "audio");
-    }
-
-exit:
-    libhal_free_string(type);
-    libhal_free_string(device_file);
-    return rv;
-}
-
-static pa_module* hal_device_load_oss(struct userdata *u, const char *udi,
-                                      DBusError  *error)
-{
-    char args[256];
+        goto finish;
+
+    r = 1;
+
+finish:
+
+    libhal_free_string(class);
+    libhal_free_string(dev);
+
+    return r;
+}
+
+static pa_module* hal_device_load_oss(struct userdata *u, const char *udi, char **sink_name, char **source_name) {
+    char* args;
     char* device;
-
-    if (!hal_device_is_oss_pcm(u->ctx, udi, error) || dbus_error_is_set(error))
-        return NULL;
-
-    device = libhal_device_get_property_string(u->ctx, udi, "oss.device_file",
-                                               error);
-    if (!device || dbus_error_is_set(error))
-        return NULL;
-
-    snprintf(args, sizeof(args), "device=%s sink_name=oss_output.%s source_name=oss_input.%s", device, strip_udi(udi), strip_udi(udi));
+    DBusError error;
+    pa_module *m;
+
+    dbus_error_init(&error);
+
+    pa_assert(u);
+    pa_assert(sink_name);
+    pa_assert(source_name);
+
+    *sink_name = *source_name = NULL;
+
+    if (!hal_oss_device_is_pcm(u->context, udi, &error) || dbus_error_is_set(&error))
+        goto fail;
+
+    device = libhal_device_get_property_string(u->context, udi, "oss.device_file", &error);
+    if (!device || dbus_error_is_set(&error))
+        goto fail;
+
+    *sink_name = pa_sprintf_malloc("oss_output.%s", strip_udi(udi));
+    *source_name = pa_sprintf_malloc("oss_input.%s", strip_udi(udi));
+
+    args = pa_sprintf_malloc("device=%s sink_name=%s source_name=%s", device, *sink_name, *source_name);
     libhal_free_string(device);
 
     pa_log_debug("Loading module-oss with arguments '%s'", args);
-
-    return pa_module_load(u->core, "module-oss", args);
-}
-#endif
-
-static dbus_bool_t hal_device_add(struct userdata *u, const char *udi,
-                                  DBusError *error)
-{
+    m = pa_module_load(u->core, "module-oss", args);
+    pa_xfree(args);
+
+    if (!m) {
+        pa_xfree(*sink_name);
+        pa_xfree(*source_name);
+        *sink_name = *source_name = NULL;
+    }
+
+    return m;
+
+fail:
+    if (dbus_error_is_set(&error)) {
+        pa_log_error("D-Bus error while parsing OSS data: %s: %s", error.name, error.message);
+        dbus_error_free(&error);
+    }
+
+    return NULL;
+}
+#endif
+
+static struct device* hal_device_add(struct userdata *u, const char *udi) {
     pa_module* m = NULL;
     struct device *d;
-
-    switch(u->capability) {
+    char *sink_name = NULL, *source_name = NULL;
+
+    pa_assert(u);
+    pa_assert(u->capability);
+    pa_assert(!pa_hashmap_get(u->devices, udi));
+
 #ifdef HAVE_ALSA
-        case CAP_ALSA:
-            m = hal_device_load_alsa(u, udi, error);
-            break;
+    if (strcmp(u->capability, CAPABILITY_ALSA) == 0)
+        m = hal_device_load_alsa(u, udi, &sink_name, &source_name);
 #endif
 #ifdef HAVE_OSS
-        case CAP_OSS:
-#ifdef HAVE_ALSA
-            if (u->use_oss)
-#endif
-                m = hal_device_load_oss(u, udi, error);
-            break;
-#endif
-        default:
-            assert(FALSE); /* never reached */
-            break;
-    }
-
-    if (!m || dbus_error_is_set(error))
-        return FALSE;
+    if (strcmp(u->capability, CAPABILITY_OSS) == 0)
+        m = hal_device_load_oss(u, udi, &sink_name, &source_name);
+#endif
+
+    if (!m)
+        return NULL;
 
     d = pa_xnew(struct device, 1);
+    d->acl_race_fix = 0;
     d->udi = pa_xstrdup(udi);
     d->index = m->index;
-
+    d->sink_name = sink_name;
+    d->source_name = source_name;
     pa_hashmap_put(u->devices, d->udi, d);
 
-    return TRUE;
-}
-
-static int hal_device_add_all(struct userdata *u, capability_t capability)
-{
+    return d;
+}
+
+static int hal_device_add_all(struct userdata *u, const char *capability) {
     DBusError error;
-    int i,n,count;
-    dbus_bool_t r;
+    int i, n, count = 0;
     char** udis;
-    const char* cap = get_capability_name(capability);
-
-    assert(capability < CAP_MAX);
-
-    pa_log_info("Trying capability %u (%s)", capability, cap);
+
+    pa_assert(u);
+
     dbus_error_init(&error);
-    udis = libhal_find_device_by_capability(u->ctx, cap, &n, &error);
+
+    if (u->capability && strcmp(u->capability, capability) != 0)
+        return 0;
+
+    pa_log_info("Trying capability %s", capability);
+
+    udis = libhal_find_device_by_capability(u->context, capability, &n, &error);
     if (dbus_error_is_set(&error)) {
-        pa_log_error("Error finding devices: %s: %s", error.name,
-                     error.message);
+        pa_log_error("Error finding devices: %s: %s", error.name, error.message);
         dbus_error_free(&error);
         return -1;
     }
-    count = 0;
-    u->capability = capability;
-    for (i = 0; i < n; ++i) {
-        r = hal_device_add(u, udis[i], &error);
-        if (dbus_error_is_set(&error)) {
-            pa_log_error("Error adding device: %s: %s", error.name,
-                         error.message);
-            dbus_error_free(&error);
-            count = -1;
-            break;
-        }
-        if (r)
-            ++count;
+
+    if (n > 0) {
+        u->capability = capability;
+
+        for (i = 0; i < n; i++) {
+            struct device *d;
+
+            if (!(d = hal_device_add(u, udis[i])))
+                pa_log_debug("Not loaded device %s", udis[i]);
+            else {
+                if (d->sink_name)
+                    pa_scache_play_item_by_name(u->core, "pulse-coldplug", d->sink_name, PA_VOLUME_NORM, 0);
+                count++;
+            }
+        }
     }
 
     libhal_free_string_array(udis);
     return count;
 }
 
-static dbus_bool_t device_has_capability(LibHalContext *ctx, const char *udi,
-                                         const char* cap, DBusError *error)
-{
+static dbus_bool_t device_has_capability(LibHalContext *context, const char *udi, const char* cap, DBusError *error){
     dbus_bool_t has_prop;
-    has_prop = libhal_device_property_exists(ctx, udi, "info.capabilities",
-                                             error);
+
+    has_prop = libhal_device_property_exists(context, udi, "info.capabilities", error);
     if (!has_prop || dbus_error_is_set(error))
         return FALSE;
 
-    return libhal_device_query_capability(ctx, udi, cap, error);
-}
-
-static void device_added_time_cb(pa_mainloop_api *ea, pa_time_event *ev,
-                                 const struct timeval *tv, void *userdata)
-{
+    return libhal_device_query_capability(context, udi, cap, error);
+}
+
+static void device_added_time_cb(pa_mainloop_api *ea, pa_time_event *ev, const struct timeval *tv, void *userdata) {
     DBusError error;
-    struct timerdata *td = (struct timerdata*) userdata;
+    struct timerdata *td = userdata;
 
     dbus_error_init(&error);
-    if (libhal_device_exists(td->u->ctx, td->udi, &error))
-        hal_device_add(td->u, td->udi, &error);
-
-    if (dbus_error_is_set(&error)) {
-        pa_log_error("Error adding device: %s: %s", error.name,
-                     error.message);
-        dbus_error_free(&error);
+
+    if (!pa_hashmap_get(td->u->devices, td->udi)) {
+        int b;
+        struct device *d;
+
+        b = libhal_device_exists(td->u->context, td->udi, &error);
+
+        if (dbus_error_is_set(&error)) {
+            pa_log_error("Error adding device: %s: %s", error.name, error.message);
+            dbus_error_free(&error);
+        } else if (b) {
+            if (!(d = hal_device_add(td->u, td->udi)))
+                pa_log_debug("Not loaded device %s", td->udi);
+            else {
+                if (d->sink_name)
+                    pa_scache_play_item_by_name(td->u->core, "pulse-hotplug", d->sink_name, PA_VOLUME_NORM, 0);
+            }
+        }
     }
 
     pa_xfree(td->udi);
@@ -361,28 +421,68 @@
     ea->time_free(ev);
 }
 
-static void device_added_cb(LibHalContext *ctx, const char *udi)
-{
+static void device_added_cb(LibHalContext *context, const char *udi) {
     DBusError error;
     struct timeval tv;
-    dbus_bool_t has_cap;
     struct timerdata *t;
-    struct userdata *u = (struct userdata*) libhal_ctx_get_user_data(ctx);
-    const char* cap = get_capability_name(u->capability);
+    struct userdata *u;
+    int good = 0;
+
+    pa_assert_se(u = libhal_ctx_get_user_data(context));
+
+    if (pa_hashmap_get(u->devices, udi))
+        return;
 
     pa_log_debug("HAL Device added: %s", udi);
 
     dbus_error_init(&error);
-    has_cap = device_has_capability(ctx, udi, cap, &error);
-    if (dbus_error_is_set(&error)) {
-        pa_log_error("Error getting capability: %s: %s", error.name,
-                     error.message);
-        dbus_error_free(&error);
-        return;
-    }
-
-    /* skip it */
-    if (!has_cap)
+
+    if (u->capability) {
+
+        good = device_has_capability(context, udi, u->capability, &error);
+
+        if (dbus_error_is_set(&error)) {
+            pa_log_error("Error getting capability: %s: %s", error.name, error.message);
+            dbus_error_free(&error);
+            return;
+        }
+
+    } else {
+
+#ifdef HAVE_ALSA
+        good = device_has_capability(context, udi, CAPABILITY_ALSA, &error);
+
+        if (dbus_error_is_set(&error)) {
+            pa_log_error("Error getting capability: %s: %s", error.name, error.message);
+            dbus_error_free(&error);
+            return;
+        }
+
+        if (good)
+            u->capability = CAPABILITY_ALSA;
+#endif
+#if defined(HAVE_OSS) && defined(HAVE_ALSA)
+        if (!good) {
+#endif
+#ifdef HAS_OSS
+            good = device_has_capability(context, udi, CAPABILITY_OSS, &error);
+
+            if (dbus_error_is_set(&error)) {
+                pa_log_error("Error getting capability: %s: %s", error.name, error.message);
+                dbus_error_free(&error);
+                return;
+            }
+
+            if (good)
+                u->capability = CAPABILITY_OSS;
+
+#endif
+#if defined(HAVE_OSS) && defined(HAVE_ALSA)
+        }
+#endif
+    }
+
+    if (!good)
         return;
 
     /* actually add the device 1/2 second later */
@@ -392,187 +492,359 @@
 
     pa_gettimeofday(&tv);
     pa_timeval_add(&tv, 500000);
-    u->core->mainloop->time_new(u->core->mainloop, &tv,
-                                device_added_time_cb, t);
-}
-
-static void device_removed_cb(LibHalContext* ctx, const char *udi)
-{
+    u->core->mainloop->time_new(u->core->mainloop, &tv, device_added_time_cb, t);
+}
+
+static void device_removed_cb(LibHalContext* context, const char *udi) {
     struct device *d;
-    struct userdata *u = (struct userdata*) libhal_ctx_get_user_data(ctx);
+    struct userdata *u;
+
+    pa_assert_se(u = libhal_ctx_get_user_data(context));
 
     pa_log_debug("Device removed: %s", udi);
+
     if ((d = pa_hashmap_remove(u->devices, udi))) {
         pa_module_unload_by_index(u->core, d->index);
         hal_device_free(d);
     }
 }
 
-static void new_capability_cb(LibHalContext *ctx, const char *udi,
-                              const char* capability)
-{
-    struct userdata *u = (struct userdata*) libhal_ctx_get_user_data(ctx);
-    const char* capname = get_capability_name(u->capability);
-
-    if (capname && !strcmp(capname, capability)) {
+static void new_capability_cb(LibHalContext *context, const char *udi, const char* capability) {
+    struct userdata *u;
+
+    pa_assert_se(u = libhal_ctx_get_user_data(context));
+
+    if (!u->capability || strcmp(u->capability, capability) == 0)
         /* capability we care about, pretend it's a new device */
-        device_added_cb(ctx, udi);
-    }
-}
-
-static void lost_capability_cb(LibHalContext *ctx, const char *udi,
-                               const char* capability)
-{
-    struct userdata *u = (struct userdata*) libhal_ctx_get_user_data(ctx);
-    const char* capname = get_capability_name(u->capability);
-
-    if (capname && !strcmp(capname, capability)) {
+        device_added_cb(context, udi);
+}
+
+static void lost_capability_cb(LibHalContext *context, const char *udi, const char* capability) {
+    struct userdata *u;
+
+    pa_assert_se(u = libhal_ctx_get_user_data(context));
+
+    if (u->capability && strcmp(u->capability, capability) == 0)
         /* capability we care about, pretend it was removed */
-        device_removed_cb(ctx, udi);
-    }
-}
-
-#if 0
-static void property_modified_cb(LibHalContext *ctx, const char *udi,
-                                 const char* key,
-                                 dbus_bool_t is_removed,
-                                 dbus_bool_t is_added)
-{
-}
-#endif
-
-static void pa_hal_context_free(LibHalContext* hal_ctx)
-{
+        device_removed_cb(context, udi);
+}
+
+static DBusHandlerResult filter_cb(DBusConnection *bus, DBusMessage *message, void *userdata) {
+    struct userdata*u = userdata;
     DBusError error;
 
+    pa_assert(bus);
+    pa_assert(message);
+    pa_assert(u);
+
     dbus_error_init(&error);
-    libhal_ctx_shutdown(hal_ctx, &error);
-    libhal_ctx_free(hal_ctx);
-
-    if (dbus_error_is_set(&error)) {
-        dbus_error_free(&error);
-    }
-}
-
-static void userdata_free(struct userdata *u) {
-    pa_hal_context_free(u->ctx);
-    /* free the devices with the hashmap */
-    pa_hashmap_free(u->devices, hal_device_free_cb, NULL);
-    pa_dbus_connection_unref(u->conn);
-    pa_xfree(u);
-}
-
-static LibHalContext* pa_hal_context_new(pa_core* c, DBusConnection *conn)
-{
+
+    pa_log_debug("dbus: interface=%s, path=%s, member=%s\n",
+                 dbus_message_get_interface(message),
+                 dbus_message_get_path(message),
+                 dbus_message_get_member(message));
+
+    if (dbus_message_is_signal(message, "org.freedesktop.Hal.Device.AccessControl", "ACLAdded") ||
+        dbus_message_is_signal(message, "org.freedesktop.Hal.Device.AccessControl", "ACLRemoved")) {
+        uint32_t uid;
+        int suspend = strcmp(dbus_message_get_member(message), "ACLRemoved") == 0;
+
+        if (!dbus_message_get_args(message, &error, DBUS_TYPE_UINT32, &uid, DBUS_TYPE_INVALID) || dbus_error_is_set(&error)) {
+            pa_log_error("Failed to parse ACL message: %s: %s", error.name, error.message);
+            goto finish;
+        }
+
+        if (uid == getuid() || uid == geteuid()) {
+            struct device *d;
+            const char *udi;
+
+            udi = dbus_message_get_path(message);
+
+            if ((d = pa_hashmap_get(u->devices, udi))) {
+                int send_acl_race_fix_message = 0;
+
+                d->acl_race_fix = 0;
+
+                if (d->sink_name) {
+                    pa_sink *sink;
+
+                    if ((sink = pa_namereg_get(u->core, d->sink_name, PA_NAMEREG_SINK, 0))) {
+                        int prev_suspended = pa_sink_get_state(sink) == PA_SINK_SUSPENDED;
+
+                        if (prev_suspended && !suspend) {
+                            /* resume */
+                            if (pa_sink_suspend(sink, 0) >= 0)
+                                pa_scache_play_item_by_name(u->core, "pulse-access", d->sink_name, PA_VOLUME_NORM, 0);
+                            else
+                                d->acl_race_fix = 1;
+
+                        } else if (!prev_suspended && suspend) {
+                            /* suspend */
+                            if (pa_sink_suspend(sink, 1) >= 0)
+                                send_acl_race_fix_message = 1;
+                        }
+                    }
+                }
+
+                if (d->source_name) {
+                    pa_source *source;
+
+                    if ((source = pa_namereg_get(u->core, d->source_name, PA_NAMEREG_SOURCE, 0))) {
+                        int prev_suspended = pa_source_get_state(source) == PA_SOURCE_SUSPENDED;
+
+                        if (prev_suspended && !suspend) {
+                            /* resume */
+                            if (pa_source_suspend(source, 0) < 0)
+                                d->acl_race_fix = 1;
+
+                        } else if (!prev_suspended && suspend) {
+                            /* suspend */
+                            if (pa_source_suspend(source, 0) >= 0)
+                                send_acl_race_fix_message = 1;
+                        }
+                    }
+                }
+
+                if (send_acl_race_fix_message) {
+                    DBusMessage *msg;
+                    msg = dbus_message_new_signal(udi, "org.pulseaudio.Server", "DirtyGiveUpMessage");
+                    dbus_connection_send(pa_dbus_connection_get(u->connection), msg, NULL);
+                    dbus_message_unref(msg);
+                }
+
+            } else if (!suspend)
+                device_added_cb(u->context, udi);
+        }
+
+    } else if (dbus_message_is_signal(message, "org.pulseaudio.Server", "DirtyGiveUpMessage")) {
+        /* We use this message to avoid a dirty race condition when we
+           get an ACLAdded message before the previously owning PA
+           sever has closed the device. We can remove this as
+           soon as HAL learns frevoke() */
+
+        const char *udi;
+        struct device *d;
+
+        udi = dbus_message_get_path(message);
+
+        if ((d = pa_hashmap_get(u->devices, udi)) && d->acl_race_fix) {
+            pa_log_debug("Got dirty give up message for '%s', trying resume ...", udi);
+
+            d->acl_race_fix = 0;
+
+            if (d->sink_name) {
+                pa_sink *sink;
+
+                if ((sink = pa_namereg_get(u->core, d->sink_name, PA_NAMEREG_SINK, 0))) {
+
+                    int prev_suspended = pa_sink_get_state(sink) == PA_SINK_SUSPENDED;
+
+                    if (prev_suspended) {
+                        /* resume */
+                        if (pa_sink_suspend(sink, 0) >= 0)
+                            pa_scache_play_item_by_name(u->core, "pulse-access", d->sink_name, PA_VOLUME_NORM, 0);
+                    }
+                }
+            }
+
+            if (d->source_name) {
+                pa_source *source;
+
+                if ((source = pa_namereg_get(u->core, d->source_name, PA_NAMEREG_SOURCE, 0))) {
+
+                    int prev_suspended = pa_source_get_state(source) == PA_SOURCE_SUSPENDED;
+
+                    if (prev_suspended)
+                        pa_source_suspend(source, 0);
+                }
+            }
+
+        } else
+            /* Yes, we don't check the UDI for validity, but hopefully HAL will */
+            device_added_cb(u->context, udi);
+    }
+
+finish:
+    dbus_error_free(&error);
+
+    return DBUS_HANDLER_RESULT_HANDLED;
+}
+
+static void hal_context_free(LibHalContext* hal_context) {
     DBusError error;
-    LibHalContext *hal_ctx = NULL;
 
     dbus_error_init(&error);
-    if (!(hal_ctx = libhal_ctx_new())) {
+
+    libhal_ctx_shutdown(hal_context, &error);
+    libhal_ctx_free(hal_context);
+
+    dbus_error_free(&error);
+}
+
+static LibHalContext* hal_context_new(pa_core* c, DBusConnection *conn) {
+    DBusError error;
+    LibHalContext *hal_context = NULL;
+
+    dbus_error_init(&error);
+
+    if (!(hal_context = libhal_ctx_new())) {
         pa_log_error("libhal_ctx_new() failed");
         goto fail;
     }
 
-    if (!libhal_ctx_set_dbus_connection(hal_ctx, conn)) {
-        pa_log_error("Error establishing DBUS connection: %s: %s",
-                     error.name, error.message);
-        goto fail;
-    }
-
-    if (!libhal_ctx_init(hal_ctx, &error)) {
-        pa_log_error("Couldn't connect to hald: %s: %s",
-                     error.name, error.message);
-        goto fail;
-    }
-
-    return hal_ctx;
+    if (!libhal_ctx_set_dbus_connection(hal_context, conn)) {
+        pa_log_error("Error establishing DBUS connection: %s: %s", error.name, error.message);
+        goto fail;
+    }
+
+    if (!libhal_ctx_init(hal_context, &error)) {
+        pa_log_error("Couldn't connect to hald: %s: %s", error.name, error.message);
+        goto fail;
+    }
+
+    return hal_context;
 
 fail:
-    if (hal_ctx)
-        pa_hal_context_free(hal_ctx);
-
-    if (dbus_error_is_set(&error))
-        dbus_error_free(&error);
+    if (hal_context)
+        hal_context_free(hal_context);
+
+    dbus_error_free(&error);
 
     return NULL;
 }
 
-int pa__init(pa_core *c, pa_module*m) {
+int pa__init(pa_module*m) {
     DBusError error;
     pa_dbus_connection *conn;
     struct userdata *u = NULL;
-    LibHalContext *hal_ctx = NULL;
+    LibHalContext *hal_context = NULL;
     int n = 0;
-
-    assert(c);
-    assert(m);
+    pa_modargs *ma;
+    const char *api;
+
+    pa_assert(m);
 
     dbus_error_init(&error);
-    if (!(conn = pa_dbus_bus_get(c, DBUS_BUS_SYSTEM, &error))) {
-        pa_log_error("Unable to contact DBUS system bus: %s: %s",
-                     error.name, error.message);
-        dbus_error_free(&error);
-        return -1;
-    }
-
-    if (!(hal_ctx = pa_hal_context_new(c, pa_dbus_connection_get(conn)))) {
+
+    if (!(ma = pa_modargs_new(m->argument, valid_modargs))) {
+        pa_log("Failed to parse module arguments");
+        goto fail;
+    }
+
+    if ((api = pa_modargs_get_value(ma, "api", NULL))) {
+        int good = 0;
+
+#ifdef HAVE_ALSA
+        if (strcmp(api, CAPABILITY_ALSA) == 0) {
+            good = 1;
+            api = CAPABILITY_ALSA;
+        }
+#endif
+#ifdef HAVE_OSS
+        if (strcmp(api, CAPABILITY_OSS) == 0) {
+            good = 1;
+            api = CAPABILITY_OSS;
+        }
+#endif
+
+        if (!good) {
+            pa_log_error("Invalid API specification.");
+            goto fail;
+        }
+    }
+
+    if (!(conn = pa_dbus_bus_get(m->core, DBUS_BUS_SYSTEM, &error)) || dbus_error_is_set(&error)) {
+        if (conn)
+            pa_dbus_connection_unref(conn);
+        pa_log_error("Unable to contact DBUS system bus: %s: %s", error.name, error.message);
+        goto fail;
+    }
+
+    if (!(hal_context = hal_context_new(m->core, pa_dbus_connection_get(conn)))) {
         /* pa_hal_context_new() logs appropriate errors */
-        return -1;
+        pa_dbus_connection_unref(conn);
+        goto fail;
     }
 
     u = pa_xnew(struct userdata, 1);
-    u->core = c;
-    u->ctx = hal_ctx;
-    u->conn = conn;
-    u->devices = pa_hashmap_new(pa_idxset_string_hash_func,
-                                pa_idxset_string_compare_func);
-    m->userdata = (void*) u;
+    u->core = m->core;
+    u->context = hal_context;
+    u->connection = conn;
+    u->devices = pa_hashmap_new(pa_idxset_string_hash_func, pa_idxset_string_compare_func);
+    u->capability = api;
+    m->userdata = u;
 
 #ifdef HAVE_ALSA
-    n = hal_device_add_all(u, CAP_ALSA);
+    n = hal_device_add_all(u, CAPABILITY_ALSA);
 #endif
 #if defined(HAVE_ALSA) && defined(HAVE_OSS)
-    u->use_oss = 0;
-
-    if (n <= 0) {
+    if (n <= 0)
 #endif
 #ifdef HAVE_OSS
-        n += hal_device_add_all(u, CAP_OSS);
-#endif
-#if defined(HAVE_ALSA) && defined(HAVE_OSS)
-
-        /* We found something with OSS, but didn't find anything with
-         * ALSA. Then let's use only OSS from now on. */
-        if (n > 0)
-            u->use_oss = 1;
-    }
-#endif
-
-    libhal_ctx_set_user_data(hal_ctx, u);
-    libhal_ctx_set_device_added(hal_ctx, device_added_cb);
-    libhal_ctx_set_device_removed(hal_ctx, device_removed_cb);
-    libhal_ctx_set_device_new_capability(hal_ctx, new_capability_cb);
-    libhal_ctx_set_device_lost_capability(hal_ctx, lost_capability_cb);
-    /*libhal_ctx_set_device_property_modified(hal_ctx, property_modified_cb);*/
-
-    dbus_error_init(&error);
-    if (!libhal_device_property_watch_all(hal_ctx, &error)) {
-        pa_log_error("error monitoring device list: %s: %s",
-                     error.name, error.message);
-        dbus_error_free(&error);
-        userdata_free(u);
-        return -1;
-    }
-
-    pa_log_info("loaded %i modules.", n);
+        n += hal_device_add_all(u, CAPABILITY_OSS);
+#endif
+
+    libhal_ctx_set_user_data(hal_context, u);
+    libhal_ctx_set_device_added(hal_context, device_added_cb);
+    libhal_ctx_set_device_removed(hal_context, device_removed_cb);
+    libhal_ctx_set_device_new_capability(hal_context, new_capability_cb);
+    libhal_ctx_set_device_lost_capability(hal_context, lost_capability_cb);
+
+    if (!libhal_device_property_watch_all(hal_context, &error)) {
+        pa_log_error("Error monitoring device list: %s: %s", error.name, error.message);
+        goto fail;
+    }
+
+    if (!dbus_connection_add_filter(pa_dbus_connection_get(conn), filter_cb, u, NULL)) {
+        pa_log_error("Failed to add filter function");
+        goto fail;
+    }
+
+    dbus_bus_add_match(pa_dbus_connection_get(conn), "type='signal',sender='org.freedesktop.Hal', interface='org.freedesktop.Hal.Device.AccessControl'", &error);
+    if (dbus_error_is_set(&error)) {
+        pa_log_error("Unable to subscribe to HAL ACL signals: %s: %s", error.name, error.message);
+        goto fail;
+    }
+
+    dbus_bus_add_match(pa_dbus_connection_get(conn), "type='signal',interface='org.pulseaudio.Server'", &error);
+    if (dbus_error_is_set(&error)) {
+        pa_log_error("Unable to subscribe to PulseAudio signals: %s: %s", error.name, error.message);
+        goto fail;
+    }
+
+    pa_log_info("Loaded %i modules.", n);
+
+    pa_modargs_free(ma);
 
     return 0;
-}
-
-
-void pa__done(PA_GCC_UNUSED pa_core *c, pa_module *m) {
-    assert (c && m);
-
-    /* free the user data */
-    userdata_free(m->userdata);
-}
+
+fail:
+    if (ma)
+        pa_modargs_free(ma);
+
+    dbus_error_free(&error);
+    pa__done(m);
+
+    return -1;
+}
+
+
+void pa__done(pa_module *m) {
+    struct userdata *u;
+
+    pa_assert(m);
+
+    if (!(u = m->userdata))
+        return;
+
+    if (u->context)
+        hal_context_free(u->context);
+
+    if (u->devices)
+        pa_hashmap_free(u->devices, hal_device_free_cb, NULL);
+
+    if (u->connection)
+        pa_dbus_connection_unref(u->connection);
+
+    pa_xfree(u);
+}

Modified: trunk/src/modules/module-jack-sink.c
URL: http://0pointer.de/cgi-bin/viewcvs.cgi/trunk/src/modules/module-jack-sink.c?rev=1971&root=pulseaudio&r1=1970&r2=1971&view=diff
==============================================================================
--- trunk/src/modules/module-jack-sink.c (original)
+++ trunk/src/modules/module-jack-sink.c Sun Oct 28 20:13:50 2007
@@ -3,7 +3,7 @@
 /***
   This file is part of PulseAudio.
 
-  Copyright 2006, 2007 Lennart Poettering and Tanu Kaskinen
+  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
@@ -25,105 +25,82 @@
 #include <config.h>
 #endif
 
-#include <pthread.h>
+#include <stdlib.h>
+#include <sys/stat.h>
+#include <stdio.h>
 #include <assert.h>
 #include <errno.h>
+#include <string.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <limits.h>
 
 #include <jack/jack.h>
-#include <jack/ringbuffer.h>
-#include <jack/types.h>
-
-#include <pulse/mainloop-api.h>
-#include <pulse/sample.h>
-#include <pulse/channelmap.h>
+
 #include <pulse/xmalloc.h>
 
+#include <pulsecore/core-error.h>
 #include <pulsecore/sink.h>
 #include <pulsecore/module.h>
-#include <pulsecore/core.h>
+#include <pulsecore/core-util.h>
+#include <pulsecore/modargs.h>
 #include <pulsecore/log.h>
-#include <pulsecore/core-util.h>
-#include <pulsecore/core-error.h>
-#include <pulsecore/pipe.h>
-#include <pulsecore/modargs.h>
-#include <pulsecore/strbuf.h>
+#include <pulsecore/thread.h>
+#include <pulsecore/thread-mq.h>
+#include <pulsecore/rtpoll.h>
+#include <pulsecore/sample-util.h>
 
 #include "module-jack-sink-symdef.h"
 
-PA_MODULE_AUTHOR("Lennart Poettering & Tanu Kaskinen")
-PA_MODULE_DESCRIPTION("Jack Sink")
+/* General overview:
+ *
+ * Because JACK has a very unflexible event loop management, which
+ * doesn't allow us to add our own event sources to the event thread
+ * we cannot use the JACK real-time thread for dispatching our PA
+ * work. Instead, we run an additional RT thread which does most of
+ * the PA handling, and have the JACK RT thread request data from it
+ * via pa_asyncmsgq. The cost is an additional context switch which
+ * should hopefully not be that expensive if RT scheduling is
+ * enabled. A better fix would only be possible with additional event
+ * source support in JACK.
+ */
+
+PA_MODULE_AUTHOR("Lennart Poettering")
+PA_MODULE_DESCRIPTION("JACK Sink")
 PA_MODULE_VERSION(PACKAGE_VERSION)
 PA_MODULE_USAGE(
         "sink_name=<name of sink> "
         "server_name=<jack server name> "
         "client_name=<jack client name> "
         "channels=<number of channels> "
-        "connect=<connect ports automatically?> "
-        "buffersize=<intermediate buffering in frames> "
+        "connect=<connect ports?> "
         "channel_map=<channel map>")
 
 #define DEFAULT_SINK_NAME "jack_out"
-#define DEFAULT_CLIENT_NAME "PulseAudio(output)"
-#define DEFAULT_RINGBUFFER_SIZE 4096
-
 
 struct userdata {
+    pa_core *core;
+    pa_module *module;
     pa_sink *sink;
 
     unsigned channels;
-    unsigned frame_size;
-
-    jack_port_t* j_ports[PA_CHANNELS_MAX];
-    jack_client_t *j_client;
-
-    jack_nframes_t j_buffersize;
-
-    /* For avoiding j_buffersize changes at a wrong moment. */
-    pthread_mutex_t buffersize_mutex;
-
-    /* The intermediate store where the pulse side writes to and the jack side
-       reads from. */
-    jack_ringbuffer_t* ringbuffer;
-    
-    /* For signaling when there's room in the ringbuffer. */
-    pthread_mutex_t cond_mutex;
-    pthread_cond_t ringbuffer_cond;
-
-    pthread_t filler_thread; /* Keeps the ringbuffer filled. */
-
-    int ringbuffer_is_full;
-    int filler_thread_is_running;
-    int quit_requested;
-
-    int pipe_fd_type;
-    int pipe_fds[2];
-    pa_io_event *io_event;
+
+    jack_port_t* port[PA_CHANNELS_MAX];
+    jack_client_t *client;
+
+    void *buffer[PA_CHANNELS_MAX];
+
+    pa_thread_mq thread_mq;
+    pa_asyncmsgq *jack_msgq;
+    pa_rtpoll *rtpoll;
+    pa_rtpoll_item *rtpoll_item;
+
+    pa_thread *thread;
+
+    jack_nframes_t frames_in_buffer;
+    jack_nframes_t saved_frame_time;
+    pa_bool_t saved_frame_time_valid;
 };
-
-
-struct options {
-    char* sink_name;
-    int sink_name_given;
-
-    char* server_name; /* May be NULL */
-    int server_name_given;
-
-    char* client_name;
-    int client_name_given;
-
-    unsigned channels;
-    int channels_given;
-
-    int connect;
-    int connect_given;
-
-    unsigned buffersize;
-    int buffersize_given;
-
-    pa_channel_map map;
-    int map_given;
-};
-
 
 static const char* const valid_modargs[] = {
     "sink_name",
@@ -131,752 +108,348 @@
     "client_name",
     "channels",
     "connect",
-    "buffersize",
     "channel_map",
     NULL
 };
 
-
-/* Initialization functions. */
-static int parse_options(struct options* o, const char* argument);
-static void set_default_channels(pa_module* self, struct options* o);
-static int create_sink(pa_module* self, struct options *o);
-static void connect_ports(pa_module* self);
-static int start_filling_ringbuffer(pa_module* self);
-
-/* Various callbacks. */
-static void jack_error_func(const char* t);
-static pa_usec_t sink_get_latency_cb(pa_sink* s);
-static int jack_process(jack_nframes_t nframes, void* arg);
-static int jack_blocksize_cb(jack_nframes_t nframes, void* arg);
-static void jack_shutdown(void* arg);
-static void io_event_cb(pa_mainloop_api* m, pa_io_event* e, int fd,
-                        pa_io_event_flags_t flags, void* userdata);
-
-/* The ringbuffer filler thread runs in this function. */
-static void* fill_ringbuffer(void* arg);
-
-/* request_render asks asynchronously the mainloop to call io_event_cb. */
-static void request_render(struct userdata* u);
-
-
-int pa__init(pa_core* c, pa_module* self) {
-    struct userdata* u = NULL;
-    struct options o;
+enum {
+    SINK_MESSAGE_RENDER = PA_SINK_MESSAGE_MAX,
+    SINK_MESSAGE_ON_SHUTDOWN
+};
+
+static int sink_process_msg(pa_msgobject *o, int code, void *data, int64_t offset, pa_memchunk *memchunk) {
+    struct userdata *u = PA_SINK(o)->userdata;
+
+    switch (code) {
+
+        case SINK_MESSAGE_RENDER:
+
+            /* Handle the request from the JACK thread */
+
+            if (u->sink->thread_info.state == PA_SINK_RUNNING) {
+                pa_memchunk chunk;
+                size_t nbytes;
+                void *p;
+
+                pa_assert(offset > 0);
+                nbytes = offset * pa_frame_size(&u->sink->sample_spec);
+
+                pa_sink_render_full(u->sink, nbytes, &chunk);
+
+                p = (uint8_t*) pa_memblock_acquire(chunk.memblock) + chunk.index;
+                pa_deinterleave(p, u->buffer, u->channels, sizeof(float), offset);
+                pa_memblock_release(chunk.memblock);
+
+                pa_memblock_unref(chunk.memblock);
+            } else {
+                unsigned c;
+                pa_sample_spec ss;
+
+                /* Humm, we're not RUNNING, hence let's write some silence */
+
+                ss = u->sink->sample_spec;
+                ss.channels = 1;
+
+                for (c = 0; c < u->channels; c++)
+                    pa_silence_memory(u->buffer[c], offset * pa_sample_size(&ss), &ss);
+            }
+
+            u->frames_in_buffer = offset;
+            u->saved_frame_time = * (jack_nframes_t*) data;
+            u->saved_frame_time_valid = TRUE;
+
+            return 0;
+
+        case SINK_MESSAGE_ON_SHUTDOWN:
+            pa_asyncmsgq_post(u->thread_mq.outq, PA_MSGOBJECT(u->core), PA_CORE_MESSAGE_UNLOAD_MODULE, u->module, 0, NULL, NULL);
+            return 0;
+
+        case PA_SINK_MESSAGE_GET_LATENCY: {
+            jack_nframes_t l, ft, d;
+            size_t n;
+
+            /* This is the "worst-case" latency */
+            l = jack_port_get_total_latency(u->client, u->port[0]) + u->frames_in_buffer;
+
+            if (u->saved_frame_time_valid) {
+                /* Adjust the worst case latency by the time that
+                 * passed since we last handed data to JACK */
+
+                ft = jack_frame_time(u->client);
+                d = ft > u->saved_frame_time ? ft - u->saved_frame_time : 0;
+                l = l > d ? l - d : 0;
+            }
+
+            /* Convert it to usec */
+            n = l * pa_frame_size(&u->sink->sample_spec);
+            *((pa_usec_t*) data) = pa_bytes_to_usec(n, &u->sink->sample_spec);
+
+            return 0;
+        }
+    }
+
+    return pa_sink_process_msg(o, code, data, offset, memchunk);
+}
+
+static int jack_process(jack_nframes_t nframes, void *arg) {
+    struct userdata *u = arg;
+    unsigned c;
+    jack_nframes_t frame_time;
+    pa_assert(u);
+
+    /* We just forward the request to our other RT thread */
+
+    for (c = 0; c < u->channels; c++)
+        pa_assert_se(u->buffer[c] = jack_port_get_buffer(u->port[c], nframes));
+
+    frame_time = jack_frame_time(u->client);
+
+    pa_assert_se(pa_asyncmsgq_send(u->jack_msgq, PA_MSGOBJECT(u->sink), SINK_MESSAGE_RENDER, &frame_time, nframes, NULL) == 0);
+    return 0;
+}
+
+static void thread_func(void *userdata) {
+    struct userdata *u = userdata;
+
+    pa_assert(u);
+
+    pa_log_debug("Thread starting up");
+
+    if (u->core->high_priority)
+        pa_make_realtime();
+
+    pa_thread_mq_install(&u->thread_mq);
+    pa_rtpoll_install(u->rtpoll);
+
+    for (;;) {
+        int ret;
+
+        if ((ret = pa_rtpoll_run(u->rtpoll, TRUE)) < 0)
+            goto fail;
+
+        if (ret == 0)
+            goto finish;
+    }
+
+fail:
+    /* If this was no regular exit from the loop we have to continue
+     * processing messages until we received PA_MESSAGE_SHUTDOWN */
+    pa_asyncmsgq_post(u->thread_mq.outq, PA_MSGOBJECT(u->core), PA_CORE_MESSAGE_UNLOAD_MODULE, u->module, 0, NULL, NULL);
+    pa_asyncmsgq_wait_for(u->thread_mq.inq, PA_MESSAGE_SHUTDOWN);
+
+finish:
+    pa_log_debug("Thread shutting down");
+}
+
+static void jack_error_func(const char*t) {
+    char *s;
+
+    s = pa_xstrndup(t, strcspn(t, "\n\r"));
+    pa_log_warn("JACK error >%s<", s);
+    pa_xfree(s);
+}
+
+static void jack_init(void *arg) {
+    struct userdata *u = arg;
+
+    pa_log_info("JACK thread starting up.");
+
+    if (u->core->high_priority)
+        pa_make_realtime();
+}
+
+static void jack_shutdown(void* arg) {
+    struct userdata *u = arg;
+
+    pa_log_info("JACK thread shutting down..");
+    pa_asyncmsgq_post(u->jack_msgq, PA_MSGOBJECT(u->sink), SINK_MESSAGE_ON_SHUTDOWN, NULL, 0, NULL, NULL);
+}
+
+int pa__init(pa_module*m) {
+    struct userdata *u = NULL;
+    pa_sample_spec ss;
+    pa_channel_map map;
+    pa_modargs *ma = NULL;
+    jack_status_t status;
+    const char *server_name, *client_name;
+    uint32_t channels = 0;
+    int do_connect = 1;
     unsigned i;
-    
-    assert(c);
-    assert(self);
-
-    o.sink_name = NULL;
-    o.server_name = NULL;
-    o.client_name = NULL;
-    
-    self->userdata = pa_xnew0(struct userdata, 1);
-    u = self->userdata;
-    
-    u->pipe_fds[0] = u->pipe_fds[1] = -1;
-    u->pipe_fd_type = 0;
-    u->ringbuffer_is_full = 0;
-    u->filler_thread_is_running = 0;
-    u->quit_requested = 0;
-    pthread_mutex_init(&u->buffersize_mutex, NULL);
-    pthread_mutex_init(&u->cond_mutex, NULL);
-    pthread_cond_init(&u->ringbuffer_cond, NULL);
-    
-    if (parse_options(&o, self->argument) != 0)
-        goto fail;
-    
+    const char **ports = NULL, **p;
+    char *t;
+
+    pa_assert(m);
+
     jack_set_error_function(jack_error_func);
-    
-    if (!(u->j_client = jack_client_open(
-                          o.client_name,
-                          o.server_name ? JackServerName : JackNullOption,
-                          NULL, o.server_name))) {
-        pa_log_error("jack_client_open() failed.");
-        goto fail;
-    }
-    pa_log_info("Successfully connected as '%s'",
-                jack_get_client_name(u->j_client));
-    
-    if (!o.channels_given)
-        set_default_channels(self, &o);
-    
-    u->channels = o.channels;
-    
-    if (!o.map_given)
-        pa_channel_map_init_auto(&o.map, u->channels, PA_CHANNEL_MAP_ALSA);
-    
-    for (i = 0; i < u->channels; i++) {
-        char* port_name = pa_sprintf_malloc(
-                              "out_%i:%s", i+1,
-                              pa_channel_position_to_string(o.map.map[i]));
-        
-        if (!(u->j_ports[i] = jack_port_register(
-                                  u->j_client, port_name,
-                                  JACK_DEFAULT_AUDIO_TYPE,
-                                  JackPortIsOutput|JackPortIsTerminal, 0))) {
+
+    if (!(ma = pa_modargs_new(m->argument, valid_modargs))) {
+        pa_log("Failed to parse module arguments.");
+        goto fail;
+    }
+
+    if (pa_modargs_get_value_boolean(ma, "connect", &do_connect) < 0) {
+        pa_log("Failed to parse connect= argument.");
+        goto fail;
+    }
+
+    server_name = pa_modargs_get_value(ma, "server_name", NULL);
+    client_name = pa_modargs_get_value(ma, "client_name", "PulseAudio JACK Sink");
+
+    u = pa_xnew0(struct userdata, 1);
+    u->core = m->core;
+    u->module = m;
+    m->userdata = u;
+    u->saved_frame_time_valid = FALSE;
+    pa_thread_mq_init(&u->thread_mq, m->core->mainloop);
+    u->rtpoll = pa_rtpoll_new();
+    pa_rtpoll_item_new_asyncmsgq(u->rtpoll, PA_RTPOLL_EARLY, u->thread_mq.inq);
+
+    /* The queue linking the JACK thread and our RT thread */
+    u->jack_msgq = pa_asyncmsgq_new(0);
+
+    /* The msgq from the JACK RT thread should have an even higher
+     * priority than the normal message queues, to match the guarantee
+     * all other drivers make: supplying the audio device with data is
+     * the top priority -- and as long as that is possible we don't do
+     * anything else */
+    u->rtpoll_item = pa_rtpoll_item_new_asyncmsgq(u->rtpoll, PA_RTPOLL_EARLY-1, u->jack_msgq);
+
+    if (!(u->client = jack_client_open(client_name, server_name ? JackServerName : JackNullOption, &status, server_name))) {
+        pa_log("jack_client_open() failed.");
+        goto fail;
+    }
+
+    ports = jack_get_ports(u->client, NULL, NULL, JackPortIsPhysical|JackPortIsInput);
+
+    channels = 0;
+    for (p = ports; *p; p++)
+        channels++;
+
+    if (!channels)
+        channels = m->core->default_sample_spec.channels;
+
+    if (pa_modargs_get_value_u32(ma, "channels", &channels) < 0 || channels <= 0 || channels >= PA_CHANNELS_MAX) {
+        pa_log("Failed to parse channels= argument.");
+        goto fail;
+    }
+
+    pa_channel_map_init_auto(&map, channels, PA_CHANNEL_MAP_ALSA);
+    if (pa_modargs_get_channel_map(ma, NULL, &map) < 0 || map.channels != channels) {
+        pa_log("Failed to parse channel_map= argument.");
+        goto fail;
+    }
+
+    pa_log_info("Successfully connected as '%s'", jack_get_client_name(u->client));
+
+    ss.channels = u->channels = channels;
+    ss.rate = jack_get_sample_rate(u->client);
+    ss.format = PA_SAMPLE_FLOAT32NE;
+
+    pa_assert(pa_sample_spec_valid(&ss));
+
+    for (i = 0; i < ss.channels; i++) {
+        if (!(u->port[i] = jack_port_register(u->client, pa_channel_position_to_string(map.map[i]), JACK_DEFAULT_AUDIO_TYPE, JackPortIsOutput|JackPortIsTerminal, 0))) {
             pa_log("jack_port_register() failed.");
             goto fail;
         }
-        
-        pa_xfree(port_name);
-    }
-    
-    if (pipe(u->pipe_fds) < 0) {
-        pa_log("pipe() failed: %s", pa_cstrerror(errno));
-        goto fail;
-    }
-    pa_make_nonblock_fd(u->pipe_fds[1]);
-    
-    if (create_sink(self, &o) != 0)
-        goto fail;
-
-    u->frame_size = pa_frame_size(&u->sink->sample_spec);
-    u->j_buffersize = jack_get_buffer_size(u->j_client);
-    
-    /* If the ringbuffer size were equal to the jack buffer size, a full block
-       would never fit in the ringbuffer, because the ringbuffer can never be
-       totally full: one slot is always wasted. */
-    if (o.buffersize <= u->j_buffersize) {
-        o.buffersize = u->j_buffersize + 1;
-    }
-    /* The actual ringbuffer size will be rounded up to the nearest power of
-       two. */
-    if (!(u->ringbuffer = jack_ringbuffer_create(
-                              o.buffersize * u->frame_size))) {
-        pa_log("jack_ringbuffer_create() failed.");
-        goto fail;
-    }
-    assert((u->ringbuffer->size % sizeof(float)) == 0);
-    pa_log_info("buffersize is %u frames (%u samples, %u bytes).",
-                u->ringbuffer->size / u->frame_size,
-                u->ringbuffer->size / sizeof(float),
-                u->ringbuffer->size);
-    
-    jack_set_process_callback(u->j_client, jack_process, u);
-    jack_set_buffer_size_callback(u->j_client, jack_blocksize_cb, u);
-    jack_on_shutdown(u->j_client, jack_shutdown, u);
-    
-    if (jack_activate(u->j_client)) {
-        pa_log("jack_activate() failed.");
-        goto fail;
-    }
-
-    if (o.connect)
-        connect_ports(self);
-
-    u->io_event = c->mainloop->io_new(c->mainloop, u->pipe_fds[0],
-                                      PA_IO_EVENT_INPUT, io_event_cb, self);
-    
-    if (start_filling_ringbuffer(self) != 0)
-        goto fail;
-
-    pa_xfree(o.sink_name);
-    pa_xfree(o.server_name);
-    pa_xfree(o.client_name);
-    
-    return 0;
-
-fail:
-    pa_xfree(o.sink_name);
-    pa_xfree(o.server_name);
-    pa_xfree(o.client_name);
-    pa__done(c, self);
-
-    return -1;
-}
-
-
-static int parse_options(struct options* o, const char* argument) {
-    pa_modargs *ma = NULL;
-    const char* arg_val;
-    pa_strbuf* strbuf;
-    
-    assert(o);
-
-    if (!(ma = pa_modargs_new(argument, valid_modargs))) {
-        pa_log_error("Failed to parse module arguments.");
-        goto fail;
-    }
-
-    strbuf = pa_strbuf_new();
-    if ((arg_val = pa_modargs_get_value(ma, "sink_name", NULL))) {
-        pa_strbuf_puts(strbuf, arg_val);
-        o->sink_name = pa_strbuf_tostring(strbuf);
-        o->sink_name_given = 1;
-    } else {
-        pa_strbuf_puts(strbuf, DEFAULT_SINK_NAME);
-        o->sink_name = pa_strbuf_tostring(strbuf);
-        o->sink_name_given = 0;
-    }
-    pa_strbuf_free(strbuf);
-
-    strbuf = pa_strbuf_new();
-    if ((arg_val = pa_modargs_get_value(ma, "server_name", NULL))) {
-        pa_strbuf_puts(strbuf, arg_val);
-        o->server_name = pa_strbuf_tostring(strbuf);
-        o->server_name_given = 1;
-    } else {
-        o->server_name = NULL;
-        o->server_name_given = 0;
-    }
-    pa_strbuf_free(strbuf);
-
-    strbuf = pa_strbuf_new();
-    if ((arg_val = pa_modargs_get_value(ma, "client_name", NULL))) {
-        pa_strbuf_puts(strbuf, arg_val);
-        o->client_name = pa_strbuf_tostring(strbuf);
-        o->client_name_given = 1;
-    } else {
-        pa_strbuf_puts(strbuf, DEFAULT_CLIENT_NAME);
-        o->client_name = pa_strbuf_tostring(strbuf);
-        o->client_name_given = 1;
-    }
-    pa_strbuf_free(strbuf);
-
-    if (pa_modargs_get_value(ma, "channels", NULL)) {
-        o->channels_given = 1;
-        if (pa_modargs_get_value_u32(ma, "channels", &o->channels) < 0 ||
-            o->channels == 0 ||
-            o->channels >= PA_CHANNELS_MAX) {
-            pa_log_error("Failed to parse the \"channels\" argument.");
-            goto fail;
+    }
+
+    if (!(u->sink = pa_sink_new(m->core, __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;
+    u->sink->flags = PA_SINK_LATENCY;
+
+    pa_sink_set_module(u->sink, m);
+    pa_sink_set_asyncmsgq(u->sink, u->thread_mq.inq);
+    pa_sink_set_rtpoll(u->sink, u->rtpoll);
+    pa_sink_set_description(u->sink, t = pa_sprintf_malloc("Jack sink (%s)", jack_get_client_name(u->client)));
+    pa_xfree(t);
+
+    jack_set_process_callback(u->client, jack_process, u);
+    jack_on_shutdown(u->client, jack_shutdown, u);
+    jack_set_thread_init_callback(u->client, jack_init, u);
+
+    if (!(u->thread = pa_thread_new(thread_func, u))) {
+        pa_log("Failed to create thread.");
+        goto fail;
+    }
+
+    if (jack_activate(u->client)) {
+        pa_log("jack_activate() failed");
+        goto fail;
+    }
+
+    if (do_connect) {
+        for (i = 0, p = ports; i < ss.channels; i++, p++) {
+
+            if (!*p) {
+                pa_log("Not enough physical output ports, leaving unconnected.");
+                break;
+            }
+
+            pa_log_info("Connecting %s to %s", jack_port_name(u->port[i]), *p);
+
+            if (jack_connect(u->client, jack_port_name(u->port[i]), *p)) {
+                pa_log("Failed to connect %s to %s, leaving unconnected.", jack_port_name(u->port[i]), *p);
+                break;
+            }
         }
-    } else {
-        o->channels = 0; /* The actual default value is the number of physical
-                            input ports in jack (unknown at the moment), or if
-                            that's zero, then the default_sample_spec.channels
-                            of the core. */
-        o->channels_given = 0;
-    }
-
-    if (pa_modargs_get_value(ma, "connect", NULL)) {
-        o->connect_given = 1;
-        if (pa_modargs_get_value_boolean(ma, "connect", &o->connect) < 0) {
-            pa_log_error("Failed to parse the \"connect\" argument.");
-            goto fail;
-        }
-    } else {
-        o->connect = 1;
-        o->connect_given = 0;
-    }
-
-    if (pa_modargs_get_value(ma, "buffersize", NULL)) {
-        o->buffersize_given = 1;
-        if (pa_modargs_get_value_u32(ma, "buffersize", &o->buffersize) < 0) {
-            pa_log_error("Failed to parse the \"buffersize\" argument.");
-            goto fail;
-        }
-    } else {
-        o->buffersize = DEFAULT_RINGBUFFER_SIZE;
-        o->buffersize_given = 0;
-    }
-
-    if (pa_modargs_get_value(ma, "channel_map", NULL)) {
-        o->map_given = 1;
-        if (pa_modargs_get_channel_map(ma, &o->map) < 0) {
-            pa_log_error("Failed to parse the \"channel_map\" argument.");
-            goto fail;
-        }
-
-        /* channel_map specifies the channel count too. */
-        if (o->channels_given && (o->channels != o->map.channels)) {
-            pa_log_error(
-                "\"channels\" and \"channel_map\" arguments conficted. If you "
-                "use the \"channel_map\" argument, you can omit the "
-                "\"channels\" argument.");
-            goto fail;
-        } else {
-            o->channels = o->map.channels;
-            o->channels_given = 1;
-        }
-    } else {
-        /* The actual default value is the default alsa mappings, but that
-           can't be set until the channel count is known. Here we initialize
-           the map to some valid value, although the value won't be used. */
-        pa_channel_map_init_stereo(&o->map);
-        o->map_given = 0;
-    }
-
+    }
+
+    pa_sink_put(u->sink);
+
+    free(ports);
     pa_modargs_free(ma);
 
     return 0;
 
 fail:
     if (ma)
-      pa_modargs_free(ma);
+        pa_modargs_free(ma);
+
+    free(ports);
+
+    pa__done(m);
 
     return -1;
 }
 
-
-static void set_default_channels(pa_module* self, struct options* o) {
-    struct userdata* u;
-    const char **ports, **p;
-    
-    assert(self);
-    assert(o);
-    assert(self->userdata);
-
-    u = self->userdata;
-    
-    assert(u->j_client);
-    assert(self->core);
-    
-    o->channels = 0;
-    
-    ports = jack_get_ports(u->j_client, NULL, JACK_DEFAULT_AUDIO_TYPE,
-                           JackPortIsPhysical|JackPortIsInput);
-    
-    for (p = ports; *p; p++)
-        o->channels++;
-    
-    free(ports);
-    
-    if (o->channels >= PA_CHANNELS_MAX)
-        o->channels = PA_CHANNELS_MAX - 1;
-    
-    if (o->channels == 0)
-        o->channels = self->core->default_sample_spec.channels;
-}
-
-
-static int create_sink(pa_module* self, struct options* o) {
-    struct userdata* u;
-    pa_sample_spec ss;
-    char *t;
-    
-    assert(self);
-    assert(o);
-    assert(self->userdata);
-
-    u = self->userdata;
-    
-    assert(u->j_client);
-    
-    ss.channels = u->channels;
-    ss.rate = jack_get_sample_rate(u->j_client);
-    ss.format = PA_SAMPLE_FLOAT32NE;
-    assert(pa_sample_spec_valid(&ss));
-
-    if (!(u->sink = pa_sink_new(self->core, __FILE__, o->sink_name, 0, &ss,
-                                &o->map))) {
-        pa_log("failed to create sink.");
-        return -1;
-    }
-    
-    u->sink->userdata = u;
-    pa_sink_set_owner(u->sink, self);
-    
-    pa_sink_set_description(
-        u->sink,
-        t = pa_sprintf_malloc("Jack sink (%s)",
-                              jack_get_client_name(u->j_client)));
-    pa_xfree(t);
-    
-    u->sink->get_latency = sink_get_latency_cb;
-    
-    return 0;
-}
-
-
-static void connect_ports(pa_module* self) {
-    struct userdata* u;
-    unsigned i;
-    const char **ports, **p;
-    
-    assert(self);
-    assert(self->userdata);
-
-    u = self->userdata;
-    
-    assert(u->j_client);
-    
-    ports = jack_get_ports(u->j_client, NULL, JACK_DEFAULT_AUDIO_TYPE,
-                           JackPortIsPhysical|JackPortIsInput);
-    
-    for (i = 0, p = ports; i < u->channels; i++, p++) {
-        assert(u->j_ports[i]);
-        
-        if (!*p) {
-            pa_log("Not enough physical output ports, leaving unconnected.");
-            break;
-        }
-        
-        pa_log_info("connecting %s to %s",
-                    jack_port_name(u->j_ports[i]), *p);
-        
-        if (jack_connect(u->j_client, jack_port_name(u->j_ports[i]), *p)) {
-            pa_log("Failed to connect %s to %s, leaving unconnected.",
-                   jack_port_name(u->j_ports[i]), *p);
-            break;
-        }
-    }
-    
-    free(ports);
-}
-
-
-static int start_filling_ringbuffer(pa_module* self) {
-    struct userdata* u;
-    pthread_attr_t thread_attributes;
-
-    assert(self);
-    assert(self->userdata);
-
-    u = self->userdata;
-    
-    pthread_attr_init(&thread_attributes);
-    
-    if (pthread_attr_setinheritsched(&thread_attributes,
-                                     PTHREAD_INHERIT_SCHED) != 0) {
-        pa_log("pthread_attr_setinheritsched() failed.");
-        goto fail;
-    }
-    else if (pthread_create(&u->filler_thread, &thread_attributes,
-                            fill_ringbuffer, u) != 0) {
-        pa_log("pthread_create() failed.");
-        goto fail;
-    }
-    
-    u->filler_thread_is_running = 1;
-    
-    pthread_attr_destroy(&thread_attributes);
-
-    return 0;
-    
-fail:
-    pthread_attr_destroy(&thread_attributes);
-    return -1;
-}
-
-
-static void jack_error_func(const char* t) {
-    pa_log_warn("JACK error >%s<", t);
-}
-
-
-static pa_usec_t sink_get_latency_cb(pa_sink* s) {
-    /* The latency is approximately the sum of the first port's latency,
-       buffersize of jack and the ringbuffer size. Maybe instead of using just
-       the first port, the max of all ports' latencies should be used? */
-    struct userdata* u;
-    jack_nframes_t l;
-    
-    assert(s);
-    assert(s->userdata);
-
-    u = s->userdata;
-    
-    l = jack_port_get_total_latency(u->j_client, u->j_ports[0]) +
-        u->j_buffersize + u->ringbuffer->size / u->frame_size;
-    
-    return pa_bytes_to_usec(l * u->frame_size, &s->sample_spec);
-}
-
-
-static int jack_process(jack_nframes_t nframes, void* arg) {
-    struct userdata* u = arg;
-    float* j_buffers[PA_CHANNELS_MAX];
-    unsigned nsamples = u->channels * nframes;
-    unsigned sample_idx_part1, sample_idx_part2;
-    jack_nframes_t frame_idx;
-    jack_ringbuffer_data_t data[2]; /* In case the readable area in the
-                                       ringbuffer is non-continuous, the data
-                                       will be split in two parts. */
-    unsigned chan;
-    unsigned samples_left_over;
-    
-    for (chan = 0; chan < u->channels; chan++) {
-        j_buffers[chan] = jack_port_get_buffer(u->j_ports[chan], nframes);
-    }
-    
-    jack_ringbuffer_get_read_vector(u->ringbuffer, data);
-    
-    /* We assume that the possible discontinuity doesn't happen in the middle
-     * of a sample. Should be a safe assumption. */
-    assert(((data[0].len % sizeof(float)) == 0) ||
-           (data[1].len == 0));
-    
-    /* Copy from the first part of data until enough samples are copied or the
-       first part ends. */
-    sample_idx_part1 = 0;
-    chan = 0;
-    frame_idx = 0;
-    while (sample_idx_part1 < nsamples &&
-           ((sample_idx_part1 + 1) * sizeof(float)) <= data[0].len) {
-        float *s = ((float*) data[0].buf) + sample_idx_part1;
-        float *d = j_buffers[chan] + frame_idx;
-        *d = *s;
-
-        sample_idx_part1++;
-        chan = (chan + 1) % u->channels;
-        frame_idx = sample_idx_part1 / u->channels;
-    }
-    
-    samples_left_over = nsamples - sample_idx_part1;
-    
-    /* Copy from the second part of data until enough samples are copied or the
-       second part ends. */
-    sample_idx_part2 = 0;
-    while (sample_idx_part2 < samples_left_over &&
-           ((sample_idx_part2 + 1) * sizeof(float)) <= data[1].len) {
-        float *s = ((float*) data[1].buf) + sample_idx_part2;
-        float *d = j_buffers[chan] + frame_idx;
-        *d = *s;
-
-        sample_idx_part2++;
-        chan = (chan + 1) % u->channels;
-        frame_idx = (sample_idx_part1 + sample_idx_part2) / u->channels;
-    }
-    
-    samples_left_over -= sample_idx_part2;
-    
-    /* If there's still samples left, fill the buffers with zeros. */
-    while (samples_left_over > 0) {
-        float *d = j_buffers[chan] + frame_idx;
-        *d = 0.0;
-
-        samples_left_over--;
-        chan = (chan + 1) % u->channels;
-        frame_idx = (nsamples - samples_left_over) / u->channels;
-    }
-    
-    jack_ringbuffer_read_advance(
-        u->ringbuffer, (sample_idx_part1 + sample_idx_part2) * sizeof(float));
-    
-    /* Tell the rendering part that there is room in the ringbuffer. */
-    u->ringbuffer_is_full = 0;
-    pthread_cond_signal(&u->ringbuffer_cond);
-    
-    return 0;
-}
-
-
-static int jack_blocksize_cb(jack_nframes_t nframes, void* arg) {
-    /* This gets called in the processing thread, so do we have to be realtime
-       safe? No, we can do whatever we want. User gets silence while we do it.
-       
-       In addition to just updating the j_buffersize field in userdata, we have
-       to create a new ringbuffer, if the new buffer size is bigger or equal to
-       the old ringbuffer size. */
-    struct userdata* u = arg;
-    
-    assert(u);
-    
-    /* We don't want to change the blocksize and the ringbuffer while rendering
-       is going on. */
-    pthread_mutex_lock(&u->buffersize_mutex);
-    
-    u->j_buffersize = nframes;
-    
-    if ((u->ringbuffer->size / u->frame_size) <= nframes) {
-        /* We have to create a new ringbuffer. What are we going to do with the
-           old data in the old buffer? We throw it away, because we're lazy
-           coders. The listening experience is likely to get ruined anyway
-           during the blocksize change. */
-        jack_ringbuffer_free(u->ringbuffer);
-        
-        /* The actual ringbuffer size will be rounded up to the nearest power
-           of two. */
-        if (!(u->ringbuffer =
-                  jack_ringbuffer_create((nframes + 1) * u->frame_size))) {
-            pa_log_error(
-                "jack_ringbuffer_create() failed while changing jack's buffer "
-                "size, module exiting.");
-            jack_client_close(u->j_client);
-            u->quit_requested = 1;
-        }
-        assert((u->ringbuffer->size % sizeof(float)) == 0);
-        pa_log_info("buffersize is %u frames (%u samples, %u bytes).",
-                    u->ringbuffer->size / u->frame_size,
-                    u->ringbuffer->size / sizeof(float),
-                    u->ringbuffer->size);
-    }
-    
-    pthread_mutex_unlock(&u->buffersize_mutex);
-    
-    return 0;
-}
-
-
-static void jack_shutdown(void* arg) {
-    struct userdata* u = arg;
-    assert(u);
-
-    u->quit_requested = 1;
-    request_render(u);
-}
-
-
-static void io_event_cb(pa_mainloop_api* m, pa_io_event* e, int fd,
-                        pa_io_event_flags_t flags, void* userdata) {
-    pa_module* self = userdata;
-    struct userdata* u;
-    char x;
-    jack_ringbuffer_data_t buffer[2]; /* The write area in the ringbuffer may
-                                         be split in two parts. */
-    pa_memchunk chunk; /* This is the data source. */
-    unsigned part1_length, part2_length;
-    unsigned sample_idx_part1, sample_idx_part2;
-    unsigned chan;
-    unsigned frame_size;
-    int rem;
-    
-    assert(m);
-    assert(e);
-    assert(flags == PA_IO_EVENT_INPUT);
-    assert(self);
-    assert(self->userdata);
-
-    u = self->userdata;
-    
-    assert(u->pipe_fds[0] == fd);
-
-    pa_read(fd, &x, 1, &u->pipe_fd_type);
-
-    if (u->quit_requested) {
-        pa_module_unload_request(self);
+void pa__done(pa_module*m) {
+    struct userdata *u;
+
+    pa_assert(m);
+
+    if (!(u = m->userdata))
         return;
-    }
-
-    frame_size = u->frame_size;
-    
-    /* No blocksize changes during rendering, please. */
-    pthread_mutex_lock(&u->buffersize_mutex);
-    
-    jack_ringbuffer_get_write_vector(u->ringbuffer, buffer);
-    assert(((buffer[0].len % sizeof(float)) == 0) || (buffer[1].len == 0));
-    
-    part1_length = buffer[0].len / sizeof(float);
-    part2_length = buffer[1].len / sizeof(float);
-
-    /* If the amount of free space is not a multiple of the frame size, we have
-       to truncate the lengths so that we process only complete frames. */
-    if ((rem = (part1_length + part2_length) % u->channels) != 0) {
-        if (part2_length >= rem) {
-            part2_length -= rem;
-        } else {
-            part1_length -= rem - part2_length;
-            part2_length = 0;
-        }
-    }
-    
-    /* pa_sink_render_full doesn't accept zero length, so we have do the
-       copying only if there's data to copy, which actually makes a kind of
-       sense. */
-    if (part1_length > 0 || part2_length > 0) {
-        pa_sink_render_full(u->sink,
-                            (part1_length + part2_length) * sizeof(float),
-                            &chunk);
-        
-        /* Write to the first part of the buffer. */
-        for (sample_idx_part1 = 0;
-             sample_idx_part1 < part1_length;
-             sample_idx_part1++) {
-            float *s =
-                ((float*) ((uint8_t*) chunk.memblock->data + chunk.index)) +
-                sample_idx_part1;
-            float *d = ((float*) buffer[0].buf) + sample_idx_part1;
-            *d = *s;
-        }
-        
-        /* Write to the second part of the buffer. */
-        for (sample_idx_part2 = 0;
-             sample_idx_part2 < part2_length;
-             sample_idx_part2++) {
-            float *s =
-                ((float*) ((uint8_t*) chunk.memblock->data + chunk.index)) +
-                sample_idx_part1 + sample_idx_part2;
-            float *d = ((float*) buffer[1].buf) + sample_idx_part2;
-            *d = *s;
-        }
-        
-        pa_memblock_unref(chunk.memblock);
-        
-        jack_ringbuffer_write_advance(
-            u->ringbuffer, (part1_length + part2_length) * sizeof(float));
-    }
-    
-    /* Blocksize can be changed again. */
-    pthread_mutex_unlock(&u->buffersize_mutex);
-}
-
-
-static void* fill_ringbuffer(void* arg) {
-    struct userdata* u = arg;
-    
-    assert(u);
-    
-    while (!u->quit_requested) {
-        if (u->ringbuffer_is_full) {
-            pthread_mutex_lock(&u->cond_mutex);
-            pthread_cond_wait(&u->ringbuffer_cond,
-                              &u->cond_mutex);
-            pthread_mutex_unlock(&u->cond_mutex);
-        }
-        /* No, it's not full yet, but this must be set to one as soon as
-           possible, because if the jack thread manages to process another
-           block before we set this to one, we may end up waiting without
-           a reason. */
-        u->ringbuffer_is_full = 1;
-
-        request_render(u);
-    }
-    
-    return NULL;
-}
-
-
-static void request_render(struct userdata* u) {
-    char c = 'x';
-    
-    assert(u);
-    
-    assert(u->pipe_fds[1] >= 0);
-    pa_write(u->pipe_fds[1], &c, 1, &u->pipe_fd_type);
-}
-
-void pa__done(pa_core* c, pa_module* self) {
-    struct userdata* u;
-    
-    assert(c);
-    assert(self);
-
-    if (!self->userdata)
-        return;
-
-    u = self->userdata;
-    
-    if (u->filler_thread_is_running) {
-        u->quit_requested = 1;
-        pthread_cond_signal(&u->ringbuffer_cond);
-        pthread_join(u->filler_thread, NULL);
-    }
-    
-    if (u->j_client)
-        jack_client_close(u->j_client);
-
-    if (u->io_event)
-        c->mainloop->io_free(u->io_event);
-
-    if (u->sink) {
-        pa_sink_disconnect(u->sink);
+
+    if (u->client)
+        jack_client_close(u->client);
+
+    if (u->sink)
+        pa_sink_unlink(u->sink);
+
+    if (u->thread) {
+        pa_asyncmsgq_send(u->thread_mq.inq, NULL, PA_MESSAGE_SHUTDOWN, NULL, 0, NULL);
+        pa_thread_free(u->thread);
+    }
+
+    pa_thread_mq_done(&u->thread_mq);
+
+    if (u->sink)
         pa_sink_unref(u->sink);
-    }
-    
-    if (u->ringbuffer)
-        jack_ringbuffer_free(u->ringbuffer);
-
-    if (u->pipe_fds[0] >= 0)
-        pa_close(u->pipe_fds[0]);
-    if (u->pipe_fds[1] >= 0)
-        pa_close(u->pipe_fds[1]);
-    
-    pthread_mutex_destroy(&u->buffersize_mutex);
-    pthread_cond_destroy(&u->ringbuffer_cond);
-    pthread_mutex_destroy(&u->cond_mutex);
-    pa_xfree(self->userdata);
-    self->userdata = NULL;
-}
+
+    if (u->rtpoll_item)
+        pa_rtpoll_item_free(u->rtpoll_item);
+
+    if (u->jack_msgq)
+        pa_asyncmsgq_unref(u->jack_msgq);
+
+    if (u->rtpoll)
+        pa_rtpoll_free(u->rtpoll);
+
+    pa_xfree(u);
+}

Modified: trunk/src/modules/module-jack-source.c
URL: http://0pointer.de/cgi-bin/viewcvs.cgi/trunk/src/modules/module-jack-source.c?rev=1971&root=pulseaudio&r1=1970&r2=1971&view=diff
==============================================================================
--- trunk/src/modules/module-jack-source.c (original)
+++ trunk/src/modules/module-jack-source.c Sun Oct 28 20:13:50 2007
@@ -28,31 +28,34 @@
 #include <stdlib.h>
 #include <sys/stat.h>
 #include <stdio.h>
-#include <assert.h>
 #include <errno.h>
 #include <string.h>
 #include <fcntl.h>
 #include <unistd.h>
 #include <limits.h>
-#include <pthread.h>
 
 #include <jack/jack.h>
 
 #include <pulse/xmalloc.h>
 
 #include <pulsecore/core-error.h>
-#include <pulsecore/iochannel.h>
 #include <pulsecore/source.h>
 #include <pulsecore/module.h>
 #include <pulsecore/core-util.h>
 #include <pulsecore/modargs.h>
 #include <pulsecore/log.h>
-#include <pulse/mainloop-api.h>
+#include <pulsecore/thread.h>
+#include <pulsecore/thread-mq.h>
+#include <pulsecore/rtpoll.h>
+#include <pulsecore/sample-util.h>
 
 #include "module-jack-source-symdef.h"
 
+/* See module-jack-sink for a few comments how this module basically
+ * works */
+
 PA_MODULE_AUTHOR("Lennart Poettering")
-PA_MODULE_DESCRIPTION("Jack Source")
+PA_MODULE_DESCRIPTION("JACK Source")
 PA_MODULE_VERSION(PACKAGE_VERSION)
 PA_MODULE_USAGE(
         "source_name=<name of source> "
@@ -67,7 +70,6 @@
 struct userdata {
     pa_core *core;
     pa_module *module;
-
     pa_source *source;
 
     unsigned channels;
@@ -75,19 +77,15 @@
     jack_port_t* port[PA_CHANNELS_MAX];
     jack_client_t *client;
 
-    pthread_mutex_t mutex;
-    pthread_cond_t cond;
-
-    void * buffer[PA_CHANNELS_MAX];
-    jack_nframes_t frames_posted;
-    int quit_requested;
-
-    int pipe_fds[2];
-    int pipe_fd_type;
-    pa_io_event *io_event;
-
-    jack_nframes_t frames_in_buffer;
-    jack_nframes_t timestamp;
+    pa_thread_mq thread_mq;
+    pa_asyncmsgq *jack_msgq;
+    pa_rtpoll *rtpoll;
+    pa_rtpoll_item *rtpoll_item;
+
+    pa_thread *thread;
+
+    jack_nframes_t saved_frame_time;
+    pa_bool_t saved_frame_time_valid;
 };
 
 static const char* const valid_modargs[] = {
@@ -100,141 +98,150 @@
     NULL
 };
 
-static void stop_source(struct userdata *u) {
-    assert (u);
-
-    jack_client_close(u->client);
-    u->client = NULL;
-    u->core->mainloop->io_free(u->io_event);
-    u->io_event = NULL;
-    pa_source_disconnect(u->source);
-    pa_source_unref(u->source);
-    u->source = NULL;
-    pa_module_unload_request(u->module);
-}
-
-static void io_event_cb(pa_mainloop_api *m, pa_io_event *e, int fd, pa_io_event_flags_t flags, void *userdata) {
+enum {
+    SOURCE_MESSAGE_POST = PA_SOURCE_MESSAGE_MAX,
+    SOURCE_MESSAGE_ON_SHUTDOWN
+};
+
+static int source_process_msg(pa_msgobject *o, int code, void *data, int64_t offset, pa_memchunk *chunk) {
+    struct userdata *u = PA_SOURCE(o)->userdata;
+
+    switch (code) {
+
+        case SOURCE_MESSAGE_POST:
+
+            /* Handle the new block from the JACK thread */
+            pa_assert(chunk);
+            pa_assert(chunk->length > 0);
+
+            if (u->source->thread_info.state == PA_SOURCE_RUNNING)
+                pa_source_post(u->source, chunk);
+
+            u->saved_frame_time = offset;
+            u->saved_frame_time_valid = TRUE;
+
+            return 0;
+
+        case SOURCE_MESSAGE_ON_SHUTDOWN:
+            pa_asyncmsgq_post(u->thread_mq.outq, PA_MSGOBJECT(u->core), PA_CORE_MESSAGE_UNLOAD_MODULE, u->module, 0, NULL, NULL);
+            return 0;
+
+        case PA_SOURCE_MESSAGE_GET_LATENCY: {
+            jack_nframes_t l, ft, d;
+            size_t n;
+
+            /* This is the "worst-case" latency */
+            l = jack_port_get_total_latency(u->client, u->port[0]);
+
+            if (u->saved_frame_time_valid) {
+                /* Adjust the worst case latency by the time that
+                 * passed since we last handed data to JACK */
+
+                ft = jack_frame_time(u->client);
+                d = ft > u->saved_frame_time ? ft - u->saved_frame_time : 0;
+                l += d;
+            }
+
+            /* Convert it to usec */
+            n = l * pa_frame_size(&u->source->sample_spec);
+            *((pa_usec_t*) data) = pa_bytes_to_usec(n, &u->source->sample_spec);
+
+            return 0;
+        }
+    }
+
+    return pa_source_process_msg(o, code, data, offset, chunk);
+}
+
+static int jack_process(jack_nframes_t nframes, void *arg) {
+    unsigned c;
+    struct userdata *u = arg;
+    const void *buffer[PA_CHANNELS_MAX];
+    void *p;
+    jack_nframes_t frame_time;
+    pa_memchunk chunk;
+
+    pa_assert(u);
+
+    for (c = 0; c < u->channels; c++)
+        pa_assert(buffer[c] = jack_port_get_buffer(u->port[c], nframes));
+
+    /* We interleave the data and pass it on to the other RT thread */
+
+    pa_memchunk_reset(&chunk);
+    chunk.length = nframes * pa_frame_size(&u->source->sample_spec);
+    chunk.memblock = pa_memblock_new(u->core->mempool, chunk.length);
+    p = pa_memblock_acquire(chunk.memblock);
+    pa_interleave(buffer, u->channels, p, sizeof(float), nframes);
+    pa_memblock_release(chunk.memblock);
+
+    frame_time = jack_frame_time(u->client);
+
+    pa_asyncmsgq_post(u->jack_msgq, PA_MSGOBJECT(u->source), SOURCE_MESSAGE_POST, NULL, frame_time, &chunk, NULL);
+
+    pa_memblock_unref(chunk.memblock);
+
+    return 0;
+}
+
+static void thread_func(void *userdata) {
     struct userdata *u = userdata;
-    char x;
-
-    assert(m);
-    assert(flags == PA_IO_EVENT_INPUT);
-    assert(u);
-    assert(u->pipe_fds[0] == fd);
-
-    pa_read(fd, &x, 1, &u->pipe_fd_type);
-
-    if (u->quit_requested) {
-        stop_source(u);
-        u->quit_requested = 0;
-        return;
-    }
-
-    pthread_mutex_lock(&u->mutex);
-
-    if (u->frames_posted > 0) {
-        unsigned fs;
-        jack_nframes_t frame_idx;
-        pa_memchunk chunk;
-
-        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;
-
-        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;
-
-                *d = *s;
-            }
-        }
-
-        pa_source_post(u->source, &chunk);
-        pa_memblock_unref(chunk.memblock);
-
-        u->frames_posted = 0;
-
-        pthread_cond_signal(&u->cond);
-    }
-
-    pthread_mutex_unlock(&u->mutex);
-}
-
-static void request_post(struct userdata *u) {
-    char c = 'x';
-    assert(u);
-
-    assert(u->pipe_fds[1] >= 0);
-    pa_write(u->pipe_fds[1], &c, 1, &u->pipe_fd_type);
-}
-
-static void jack_shutdown(void *arg) {
+
+    pa_assert(u);
+
+    pa_log_debug("Thread starting up");
+
+    if (u->core->high_priority)
+        pa_make_realtime();
+
+    pa_thread_mq_install(&u->thread_mq);
+    pa_rtpoll_install(u->rtpoll);
+
+    for (;;) {
+        int ret;
+
+        if ((ret = pa_rtpoll_run(u->rtpoll, TRUE)) < 0)
+            goto fail;
+
+        if (ret == 0)
+            goto finish;
+    }
+
+fail:
+    /* If this was no regular exit from the loop we have to continue
+     * processing messages until we received PA_MESSAGE_SHUTDOWN */
+    pa_asyncmsgq_post(u->thread_mq.outq, PA_MSGOBJECT(u->core), PA_CORE_MESSAGE_UNLOAD_MODULE, u->module, 0, NULL, NULL);
+    pa_asyncmsgq_wait_for(u->thread_mq.inq, PA_MESSAGE_SHUTDOWN);
+
+finish:
+    pa_log_debug("Thread shutting down");
+}
+
+static void jack_error_func(const char*t) {
+    char *s;
+
+    s = pa_xstrndup(t, strcspn(t, "\n\r"));
+    pa_log_warn("JACK error >%s<", s);
+    pa_xfree(s);
+}
+
+static void jack_init(void *arg) {
     struct userdata *u = arg;
-    assert(u);
-
-    u->quit_requested = 1;
-    request_post(u);
-}
-
-static int jack_process(jack_nframes_t nframes, void *arg) {
+
+    pa_log_info("JACK thread starting up.");
+
+    if (u->core->high_priority)
+        pa_make_realtime();
+}
+
+static void jack_shutdown(void* arg) {
     struct userdata *u = arg;
-    assert(u);
-
-    if (jack_transport_query(u->client, NULL) == JackTransportRolling) {
-        unsigned c;
-
-        pthread_mutex_lock(&u->mutex);
-
-        u->frames_posted = nframes;
-
-        for (c = 0; c < u->channels; c++) {
-            u->buffer[c] = jack_port_get_buffer(u->port[c], nframes);
-            assert(u->buffer[c]);
-        }
-
-        request_post(u);
-
-        pthread_cond_wait(&u->cond, &u->mutex);
-
-        u->frames_in_buffer = nframes;
-        u->timestamp = jack_get_current_transport_frame(u->client);
-
-        pthread_mutex_unlock(&u->mutex);
-    }
-
-    return 0;
-}
-
-static pa_usec_t source_get_latency_cb(pa_source *s) {
-    struct userdata *u;
-    jack_nframes_t n, l, d;
-
-    assert(s);
-    u = s->userdata;
-
-    if (jack_transport_query(u->client, NULL) != JackTransportRolling)
-        return 0;
-
-    n = jack_get_current_transport_frame(u->client);
-
-    if (n < u->timestamp)
-        return 0;
-
-    d = n - u->timestamp;
-    l = jack_port_get_total_latency(u->client, u->port[0]);
-
-    return pa_bytes_to_usec((l + d) * pa_frame_size(&s->sample_spec), &s->sample_spec);
-}
-
-static void jack_error_func(const char*t) {
-    pa_log_warn("JACK error >%s<", t);
-}
-
-int pa__init(pa_core *c, pa_module*m) {
+
+    pa_log_info("JACK thread shutting down..");
+    pa_asyncmsgq_post(u->jack_msgq, PA_MSGOBJECT(u->source), SOURCE_MESSAGE_ON_SHUTDOWN, NULL, 0, NULL, NULL);
+}
+
+int pa__init(pa_module*m) {
     struct userdata *u = NULL;
     pa_sample_spec ss;
     pa_channel_map map;
@@ -247,40 +254,35 @@
     const char **ports = NULL, **p;
     char *t;
 
-    assert(c);
-    assert(m);
+    pa_assert(m);
 
     jack_set_error_function(jack_error_func);
 
     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;
     }
 
     if (pa_modargs_get_value_boolean(ma, "connect", &do_connect) < 0) {
-        pa_log("failed to parse connect= argument.");
+        pa_log("Failed to parse connect= argument.");
         goto fail;
     }
 
     server_name = pa_modargs_get_value(ma, "server_name", NULL);
-    client_name = pa_modargs_get_value(ma, "client_name", "PulseAudio");
+    client_name = pa_modargs_get_value(ma, "client_name", "PulseAudio JACK Source");
 
     u = pa_xnew0(struct userdata, 1);
+    u->core = m->core;
+    u->module = m;
     m->userdata = u;
-    u->core = c;
-    u->module = m;
-    u->pipe_fds[0] = u->pipe_fds[1] = -1;
-    u->pipe_fd_type = 0;
-
-    pthread_mutex_init(&u->mutex, NULL);
-    pthread_cond_init(&u->cond, NULL);
-
-    if (pipe(u->pipe_fds) < 0) {
-        pa_log("pipe() failed: %s", pa_cstrerror(errno));
-        goto fail;
-    }
-
-    pa_make_nonblock_fd(u->pipe_fds[1]);
+    u->saved_frame_time_valid = FALSE;
+
+    pa_thread_mq_init(&u->thread_mq, m->core->mainloop);
+    u->rtpoll = pa_rtpoll_new();
+    pa_rtpoll_item_new_asyncmsgq(u->rtpoll, PA_RTPOLL_EARLY, u->thread_mq.inq);
+
+    u->jack_msgq = pa_asyncmsgq_new(0);
+    u->rtpoll_item = pa_rtpoll_item_new_asyncmsgq(u->rtpoll, PA_RTPOLL_EARLY-1, u->jack_msgq);
 
     if (!(u->client = jack_client_open(client_name, server_name ? JackServerName : JackNullOption, &status, server_name))) {
         pa_log("jack_client_open() failed.");
@@ -294,7 +296,7 @@
         channels++;
 
     if (!channels)
-        channels = c->default_sample_spec.channels;
+        channels = m->core->default_sample_spec.channels;
 
     if (pa_modargs_get_value_u32(ma, "channels", &channels) < 0 || channels <= 0 || channels >= PA_CHANNELS_MAX) {
         pa_log("failed to parse channels= argument.");
@@ -302,7 +304,7 @@
     }
 
     pa_channel_map_init_auto(&map, channels, PA_CHANNEL_MAP_ALSA);
-    if (pa_modargs_get_channel_map(ma, &map) < 0 || map.channels != channels) {
+    if (pa_modargs_get_channel_map(ma, NULL, &map) < 0 || map.channels != channels) {
         pa_log("failed to parse channel_map= argument.");
         goto fail;
     }
@@ -313,7 +315,7 @@
     ss.rate = jack_get_sample_rate(u->client);
     ss.format = PA_SAMPLE_FLOAT32NE;
 
-    assert(pa_sample_spec_valid(&ss));
+    pa_assert(pa_sample_spec_valid(&ss));
 
     for (i = 0; i < ss.channels; i++) {
         if (!(u->port[i] = jack_port_register(u->client, pa_channel_position_to_string(map.map[i]), JACK_DEFAULT_AUDIO_TYPE, JackPortIsInput|JackPortIsTerminal, 0))) {
@@ -322,19 +324,29 @@
         }
     }
 
-    if (!(u->source = pa_source_new(c, __FILE__, pa_modargs_get_value(ma, "source_name", DEFAULT_SOURCE_NAME), 0, &ss, &map))) {
+    if (!(u->source = pa_source_new(m->core, __FILE__, pa_modargs_get_value(ma, "source_name", DEFAULT_SOURCE_NAME), 0, &ss, &map))) {
         pa_log("failed to create source.");
         goto fail;
     }
 
+    u->source->parent.process_msg = source_process_msg;
     u->source->userdata = u;
-    pa_source_set_owner(u->source, m);
+    u->source->flags = PA_SOURCE_LATENCY;
+
+    pa_source_set_module(u->source, m);
+    pa_source_set_asyncmsgq(u->source, u->thread_mq.inq);
+    pa_source_set_rtpoll(u->source, u->rtpoll);
     pa_source_set_description(u->source, t = pa_sprintf_malloc("Jack source (%s)", jack_get_client_name(u->client)));
     pa_xfree(t);
-    u->source->get_latency = source_get_latency_cb;
 
     jack_set_process_callback(u->client, jack_process, u);
     jack_on_shutdown(u->client, jack_shutdown, u);
+    jack_set_thread_init_callback(u->client, jack_init, u);
+
+    if (!(u->thread = pa_thread_new(thread_func, u))) {
+        pa_log("Failed to create thread.");
+        goto fail;
+    }
 
     if (jack_activate(u->client)) {
         pa_log("jack_activate() failed");
@@ -359,7 +371,7 @@
 
     }
 
-    u->io_event = c->mainloop->io_new(c->mainloop, u->pipe_fds[0], PA_IO_EVENT_INPUT, io_event_cb, u);
+    pa_source_put(u->source);
 
     free(ports);
     pa_modargs_free(ma);
@@ -372,14 +384,14 @@
 
     free(ports);
 
-    pa__done(c, m);
+    pa__done(m);
 
     return -1;
 }
 
-void pa__done(pa_core *c, pa_module*m) {
+void pa__done(pa_module*m) {
     struct userdata *u;
-    assert(c && m);
+    pa_assert(m);
 
     if (!(u = m->userdata))
         return;
@@ -387,20 +399,27 @@
     if (u->client)
         jack_client_close(u->client);
 
-    if (u->io_event)
-        c->mainloop->io_free(u->io_event);
-
-    if (u->source) {
-        pa_source_disconnect(u->source);
+    if (u->source)
+        pa_source_unlink(u->source);
+
+    if (u->thread) {
+        pa_asyncmsgq_send(u->thread_mq.inq, NULL, PA_MESSAGE_SHUTDOWN, NULL, 0, NULL);
+        pa_thread_free(u->thread);
+    }
+
+    pa_thread_mq_done(&u->thread_mq);
+
+    if (u->source)
         pa_source_unref(u->source);
-    }
-
-    if (u->pipe_fds[0] >= 0)
-        close(u->pipe_fds[0]);
-    if (u->pipe_fds[1] >= 0)
-        close(u->pipe_fds[1]);
-
-    pthread_mutex_destroy(&u->mutex);
-    pthread_cond_destroy(&u->cond);
+
+    if (u->rtpoll_item)
+        pa_rtpoll_item_free(u->rtpoll_item);
+
+    if (u->jack_msgq)
+        pa_asyncmsgq_unref(u->jack_msgq);
+
+    if (u->rtpoll)
+        pa_rtpoll_free(u->rtpoll);
+
     pa_xfree(u);
 }

Modified: trunk/src/modules/module-lirc.c
URL: http://0pointer.de/cgi-bin/viewcvs.cgi/trunk/src/modules/module-lirc.c?rev=1971&root=pulseaudio&r1=1970&r2=1971&view=diff
==============================================================================
--- trunk/src/modules/module-lirc.c (original)
+++ trunk/src/modules/module-lirc.c Sun Oct 28 20:13:50 2007
@@ -26,11 +26,11 @@
 #endif
 
 #include <stdio.h>
-#include <assert.h>
 #include <unistd.h>
 #include <string.h>
+#include <stdlib.h>
+
 #include <lirc/lirc_client.h>
-#include <stdlib.h>
 
 #include <pulse/xmalloc.h>
 
@@ -39,6 +39,7 @@
 #include <pulsecore/namereg.h>
 #include <pulsecore/sink.h>
 #include <pulsecore/modargs.h>
+#include <pulsecore/macro.h>
 
 #include "module-lirc-symdef.h"
 
@@ -68,11 +69,12 @@
 static void io_callback(pa_mainloop_api *io, PA_GCC_UNUSED pa_io_event *e, PA_GCC_UNUSED int fd, pa_io_event_flags_t events, void*userdata) {
     struct userdata *u = userdata;
     char *name = NULL, *code = NULL;
-    assert(io);
-    assert(u);
+
+    pa_assert(io);
+    pa_assert(u);
 
     if (events & (PA_IO_EVENT_HANGUP|PA_IO_EVENT_ERROR)) {
-        pa_log("lost connection to LIRC daemon.");
+        pa_log("Lost connection to LIRC daemon.");
         goto fail;
     }
 
@@ -86,7 +88,7 @@
 
         c = pa_xstrdup(code);
         c[strcspn(c, "\n\r")] = 0;
-        pa_log_debug("raw IR code '%s'", c);
+        pa_log_debug("Raw IR code '%s'", c);
         pa_xfree(c);
 
         while (lirc_code2char(u->config, code, &name) == 0 && name) {
@@ -99,7 +101,7 @@
                 MUTE_TOGGLE
             } volchange = INVALID;
 
-            pa_log_info("translated IR code '%s'", name);
+            pa_log_info("Translated IR code '%s'", name);
 
             if (strcasecmp(name, "volume-up") == 0)
                 volchange = UP;
@@ -113,15 +115,15 @@
                 volchange = RESET;
 
             if (volchange == INVALID)
-                pa_log_warn("recieved unknown IR code '%s'", name);
+                pa_log_warn("Recieved unknown IR code '%s'", name);
             else {
                 pa_sink *s;
 
                 if (!(s = pa_namereg_get(u->module->core, u->sink_name, PA_NAMEREG_SINK, 1)))
-                    pa_log("failed to get sink '%s'", u->sink_name);
+                    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 +136,7 @@
                                     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 +147,20 @@
                                     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:
@@ -179,13 +181,14 @@
 
     pa_module_unload_request(u->module);
 
-    free(code);
+    pa_xfree(code);
 }
 
-int pa__init(pa_core *c, pa_module*m) {
+int pa__init(pa_module*m) {
     pa_modargs *ma = NULL;
     struct userdata *u;
-    assert(c && m);
+
+    pa_assert(m);
 
     if (lirc_in_use) {
         pa_log("module-lirc may no be loaded twice.");
@@ -197,7 +200,7 @@
         goto fail;
     }
 
-    m->userdata = u = pa_xmalloc(sizeof(struct userdata));
+    m->userdata = u = pa_xnew(struct userdata, 1);
     u->module = m;
     u->io = NULL;
     u->config = NULL;
@@ -215,7 +218,7 @@
         goto fail;
     }
 
-    u->io = c->mainloop->io_new(c->mainloop, u->lirc_fd, PA_IO_EVENT_INPUT|PA_IO_EVENT_HANGUP, io_callback, u);
+    u->io = m->core->mainloop->io_new(m->core->mainloop, u->lirc_fd, PA_IO_EVENT_INPUT|PA_IO_EVENT_HANGUP, io_callback, u);
 
     lirc_in_use = 1;
 
@@ -228,14 +231,13 @@
     if (ma)
         pa_modargs_free(ma);
 
-    pa__done(c, m);
+    pa__done(m);
     return -1;
 }
 
-void pa__done(pa_core *c, pa_module*m) {
+void pa__done(pa_module*m) {
     struct userdata *u;
-    assert(c);
-    assert(m);
+    pa_assert(m);
 
     if (!(u = m->userdata))
         return;

Modified: trunk/src/modules/module-match.c
URL: http://0pointer.de/cgi-bin/viewcvs.cgi/trunk/src/modules/module-match.c?rev=1971&root=pulseaudio&r1=1970&r2=1971&view=diff
==============================================================================
--- trunk/src/modules/module-match.c (original)
+++ trunk/src/modules/module-match.c Sun Oct 28 20:13:50 2007
@@ -26,7 +26,6 @@
 #endif
 
 #include <unistd.h>
-#include <assert.h>
 #include <string.h>
 #include <errno.h>
 #include <sys/types.h>
@@ -80,6 +79,8 @@
     struct rule *end = NULL;
     char *fn = NULL;
 
+    pa_assert(u);
+
     f = filename ?
         fopen(fn = pa_xstrdup(filename), "r") :
         pa_open_config_file(DEFAULT_MATCH_TABLE_FILE, DEFAULT_MATCH_TABLE_FILE_USER, NULL, &fn, "r");
@@ -132,7 +133,7 @@
             goto finish;
         }
 
-        rule = pa_xmalloc(sizeof(struct rule));
+        rule = pa_xnew(struct rule, 1);
         rule->regex = regex;
         rule->volume = volume;
         rule->next = NULL;
@@ -164,7 +165,9 @@
     struct userdata *u =  userdata;
     pa_sink_input *si;
     struct rule *r;
-    assert(c && u);
+
+    pa_assert(c);
+    pa_assert(u);
 
     if (t != (PA_SUBSCRIPTION_EVENT_SINK_INPUT|PA_SUBSCRIPTION_EVENT_NEW))
         return;
@@ -179,23 +182,24 @@
         if (!regexec(&r->regex, si->name, 0, NULL, 0)) {
             pa_cvolume cv;
             pa_log_debug("changing volume of sink input '%s' to 0x%03x", si->name, r->volume);
-            pa_cvolume_set(&cv, r->volume, si->sample_spec.channels);
+            pa_cvolume_set(&cv, si->sample_spec.channels, r->volume);
             pa_sink_input_set_volume(si, &cv);
         }
     }
 }
 
-int pa__init(pa_core *c, pa_module*m) {
+int pa__init(pa_module*m) {
     pa_modargs *ma = NULL;
     struct userdata *u;
-    assert(c && m);
+
+    pa_assert(m);
 
     if (!(ma = pa_modargs_new(m->argument, valid_modargs))) {
         pa_log("Failed to parse module arguments");
         goto fail;
     }
 
-    u = pa_xmalloc(sizeof(struct userdata));
+    u = pa_xnew(struct userdata, 1);
     u->rules = NULL;
     u->subscription = NULL;
     m->userdata = u;
@@ -203,23 +207,24 @@
     if (load_rules(u, pa_modargs_get_value(ma, "table", NULL)) < 0)
         goto fail;
 
-    u->subscription = pa_subscription_new(c, PA_SUBSCRIPTION_MASK_SINK_INPUT, callback, u);
+    u->subscription = pa_subscription_new(m->core, PA_SUBSCRIPTION_MASK_SINK_INPUT, callback, u);
 
     pa_modargs_free(ma);
     return 0;
 
 fail:
-    pa__done(c, m);
+    pa__done(m);
 
     if (ma)
         pa_modargs_free(ma);
     return  -1;
 }
 
-void pa__done(pa_core *c, pa_module*m) {
+void pa__done(pa_module*m) {
     struct userdata* u;
     struct rule *r, *n;
-    assert(c && m);
+
+    pa_assert(m);
 
     if (!(u = m->userdata))
         return;

Modified: trunk/src/modules/module-mmkbd-evdev.c
URL: http://0pointer.de/cgi-bin/viewcvs.cgi/trunk/src/modules/module-mmkbd-evdev.c?rev=1971&root=pulseaudio&r1=1970&r2=1971&view=diff
==============================================================================
--- trunk/src/modules/module-mmkbd-evdev.c (original)
+++ trunk/src/modules/module-mmkbd-evdev.c Sun Oct 28 20:13:50 2007
@@ -26,7 +26,6 @@
 #endif
 
 #include <stdio.h>
-#include <assert.h>
 #include <unistd.h>
 #include <string.h>
 #include <stdlib.h>
@@ -80,11 +79,12 @@
 
 static void io_callback(pa_mainloop_api *io, PA_GCC_UNUSED pa_io_event *e, PA_GCC_UNUSED int fd, pa_io_event_flags_t events, void*userdata) {
     struct userdata *u = userdata;
-    assert(io);
-    assert(u);
+
+    pa_assert(io);
+    pa_assert(u);
 
     if (events & (PA_IO_EVENT_HANGUP|PA_IO_EVENT_ERROR)) {
-        pa_log("lost connection to evdev device.");
+        pa_log("Lost connection to evdev device.");
         goto fail;
     }
 
@@ -92,14 +92,14 @@
         struct input_event ev;
 
         if (pa_loop_read(u->fd, &ev, sizeof(ev), &u->fd_type) <= 0) {
-            pa_log("failed to read from event device: %s", pa_cstrerror(errno));
+            pa_log("Failed to read from event device: %s", pa_cstrerror(errno));
             goto fail;
         }
 
         if (ev.type == EV_KEY && (ev.value == 1 || ev.value == 2)) {
             enum { INVALID, UP, DOWN, MUTE_TOGGLE } volchange = INVALID;
 
-            pa_log_debug("key code=%u, value=%u", ev.code, ev.value);
+            pa_log_debug("Key code=%u, value=%u", ev.code, ev.value);
 
             switch (ev.code) {
                 case KEY_VOLUMEDOWN:  volchange = DOWN; break;
@@ -111,10 +111,10 @@
                 pa_sink *s;
 
                 if (!(s = pa_namereg_get(u->module->core, u->sink_name, PA_NAMEREG_SINK, 1)))
-                    pa_log("failed to get sink '%s'", u->sink_name);
+                    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 @@
                                     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 @@
                                     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:
@@ -165,21 +165,23 @@
 
 #define test_bit(bit, array) (array[bit/8] & (1<<(bit%8)))
 
-int pa__init(pa_core *c, pa_module*m) {
+int pa__init(pa_module*m) {
+
     pa_modargs *ma = NULL;
     struct userdata *u;
     int version;
     struct _input_id input_id;
     char name[256];
     uint8_t evtype_bitmask[EV_MAX/8 + 1];
-    assert(c && m);
+
+    pa_assert(m);
 
     if (!(ma = pa_modargs_new(m->argument, valid_modargs))) {
         pa_log("Failed to parse module arguments");
         goto fail;
     }
 
-    m->userdata = u = pa_xmalloc(sizeof(struct userdata));
+    m->userdata = u = pa_xnew(struct userdata,1);
     u->module = m;
     u->io = NULL;
     u->sink_name = pa_xstrdup(pa_modargs_get_value(ma, "sink", NULL));
@@ -221,11 +223,11 @@
     }
 
     if (!test_bit(EV_KEY, evtype_bitmask)) {
-        pa_log("device has no keys.");
-        goto fail;
-    }
-
-    u->io = c->mainloop->io_new(c->mainloop, u->fd, PA_IO_EVENT_INPUT|PA_IO_EVENT_HANGUP, io_callback, u);
+        pa_log("Device has no keys.");
+        goto fail;
+    }
+
+    u->io = m->core->mainloop->io_new(m->core->mainloop, u->fd, PA_IO_EVENT_INPUT|PA_IO_EVENT_HANGUP, io_callback, u);
 
     pa_modargs_free(ma);
 
@@ -236,14 +238,14 @@
     if (ma)
         pa_modargs_free(ma);
 
-    pa__done(c, m);
+    pa__done(m);
     return -1;
 }
 
-void pa__done(pa_core *c, pa_module*m) {
+void pa__done(pa_module*m) {
     struct userdata *u;
-    assert(c);
-    assert(m);
+
+    pa_assert(m);
 
     if (!(u = m->userdata))
         return;
@@ -252,7 +254,7 @@
         m->core->mainloop->io_free(u->io);
 
     if (u->fd >= 0)
-        close(u->fd);
+        pa_assert_se(pa_close(u->fd) == 0);
 
     pa_xfree(u->sink_name);
     pa_xfree(u);

Modified: trunk/src/modules/module-native-protocol-fd.c
URL: http://0pointer.de/cgi-bin/viewcvs.cgi/trunk/src/modules/module-native-protocol-fd.c?rev=1971&root=pulseaudio&r1=1970&r2=1971&view=diff
==============================================================================
--- trunk/src/modules/module-native-protocol-fd.c (original)
+++ trunk/src/modules/module-native-protocol-fd.c Sun Oct 28 20:13:50 2007
@@ -26,10 +26,10 @@
 #endif
 
 #include <stdio.h>
-#include <assert.h>
 #include <unistd.h>
 
 #include <pulsecore/module.h>
+#include <pulsecore/macro.h>
 #include <pulsecore/iochannel.h>
 #include <pulsecore/modargs.h>
 #include <pulsecore/protocol-native.h>
@@ -48,25 +48,26 @@
     NULL,
 };
 
-int pa__init(pa_core *c, pa_module*m) {
+int pa__init(pa_module*m) {
     pa_iochannel *io;
     pa_modargs *ma;
     int fd, r = -1;
-    assert(c && m);
+
+    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 finish;
     }
 
     if (pa_modargs_get_value_s32(ma, "fd", &fd) < 0) {
-        pa_log("invalid file descriptor.");
+        pa_log("Invalid file descriptor.");
         goto finish;
     }
 
-    io = pa_iochannel_new(c->mainloop, fd, fd);
+    io = pa_iochannel_new(m->core->mainloop, fd, fd);
 
-    if (!(m->userdata = pa_protocol_native_new_iochannel(c, io, m, ma))) {
+    if (!(m->userdata = pa_protocol_native_new_iochannel(m->core, io, m, ma))) {
         pa_iochannel_free(io);
         goto finish;
     }
@@ -80,8 +81,8 @@
     return r;
 }
 
-void pa__done(pa_core *c, pa_module*m) {
-    assert(c && m);
+void pa__done(pa_module*m) {
+    pa_assert(m);
 
     pa_protocol_native_free(m->userdata);
 }

Modified: trunk/src/modules/module-null-sink.c
URL: http://0pointer.de/cgi-bin/viewcvs.cgi/trunk/src/modules/module-null-sink.c?rev=1971&root=pulseaudio&r1=1970&r2=1971&view=diff
==============================================================================
--- trunk/src/modules/module-null-sink.c (original)
+++ trunk/src/modules/module-null-sink.c Sun Oct 28 20:13:50 2007
@@ -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,12 +37,17 @@
 #include <pulse/timeval.h>
 #include <pulse/xmalloc.h>
 
-#include <pulsecore/iochannel.h>
+#include <pulsecore/macro.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 <pulsecore/thread-mq.h>
+#include <pulsecore/rtpoll.h>
+#include <pulsecore/rtclock.h>
 
 #include "module-null-sink-symdef.h"
 
@@ -64,11 +68,14 @@
     pa_core *core;
     pa_module *module;
     pa_sink *sink;
-    pa_time_event *time_event;
+
+    pa_thread *thread;
+    pa_thread_mq thread_mq;
+    pa_rtpoll *rtpoll;
+
     size_t block_size;
 
-    uint64_t n_bytes;
-    struct timeval start_time;
+    struct timeval timestamp;
 };
 
 static const char* const valid_modargs[] = {
@@ -81,78 +88,132 @@
     NULL
 };
 
-static void time_callback(pa_mainloop_api *m, pa_time_event*e, const struct timeval *tv, void *userdata) {
+static int sink_process_msg(pa_msgobject *o, int code, void *data, int64_t offset, 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_rtclock_get(&u->timestamp);
+
+            break;
+
+        case PA_SINK_MESSAGE_GET_LATENCY: {
+            struct timeval now;
+
+            pa_rtclock_get(&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, offset, chunk);
+}
+
+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;
-
-    a = pa_timeval_diff(pa_gettimeofday(&now), &u->start_time);
-    b = pa_bytes_to_usec(u->n_bytes, &s->sample_spec);
-
-    return b > a ? b - a : 0;
-}
-
-int pa__init(pa_core *c, pa_module*m) {
+
+    pa_assert(u);
+
+    pa_log_debug("Thread starting up");
+
+    pa_thread_mq_install(&u->thread_mq);
+    pa_rtpoll_install(u->rtpoll);
+
+    pa_rtclock_get(&u->timestamp);
+
+    for (;;) {
+        int ret;
+
+        /* Render some data and drop it immediately */
+        if (u->sink->thread_info.state == PA_SINK_RUNNING) {
+            struct timeval now;
+
+            pa_rtclock_get(&now);
+
+            if (pa_timeval_cmp(&u->timestamp, &now) <= 0) {
+                pa_sink_skip(u->sink, u->block_size);
+                pa_timeval_add(&u->timestamp, pa_bytes_to_usec(u->block_size, &u->sink->sample_spec));
+            }
+
+            pa_rtpoll_set_timer_absolute(u->rtpoll, &u->timestamp);
+        } else
+            pa_rtpoll_set_timer_disabled(u->rtpoll);
+
+        /* Hmm, nothing to do. Let's sleep */
+        if ((ret = pa_rtpoll_run(u->rtpoll, 1)) < 0)
+            goto fail;
+
+        if (ret == 0)
+            goto finish;
+    }
+
+fail:
+    /* If this was no regular exit from the loop we have to continue
+     * processing messages until we received PA_MESSAGE_SHUTDOWN */
+    pa_asyncmsgq_post(u->thread_mq.outq, PA_MSGOBJECT(u->core), PA_CORE_MESSAGE_UNLOAD_MODULE, u->module, 0, NULL, NULL);
+    pa_asyncmsgq_wait_for(u->thread_mq.inq, PA_MESSAGE_SHUTDOWN);
+
+finish:
+    pa_log_debug("Thread shutting down");
+}
+
+int pa__init(pa_module*m) {
     struct userdata *u = NULL;
     pa_sample_spec ss;
     pa_channel_map map;
     pa_modargs *ma = NULL;
 
-    assert(c);
-    assert(m);
+    pa_assert(m);
 
     if (!(ma = pa_modargs_new(m->argument, valid_modargs))) {
-        pa_log("failed to parse module arguments.");
-        goto fail;
-    }
-
-    ss = c->default_sample_spec;
+        pa_log("Failed to parse module arguments.");
+        goto fail;
+    }
+
+    ss = m->core->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;
     }
 
     u = pa_xnew0(struct userdata, 1);
-    u->core = c;
+    u->core = m->core;
     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.");
-        goto fail;
-    }
-
-    u->sink->get_latency = get_latency;
+    pa_thread_mq_init(&u->thread_mq, m->core->mainloop);
+    u->rtpoll = pa_rtpoll_new();
+    pa_rtpoll_item_new_asyncmsgq(u->rtpoll, PA_RTPOLL_EARLY, u->thread_mq.inq);
+
+    if (!(u->sink = pa_sink_new(m->core, __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);
+    u->sink->flags = PA_SINK_LATENCY;
+
+    pa_sink_set_module(u->sink, m);
+    pa_sink_set_asyncmsgq(u->sink, u->thread_mq.inq);
+    pa_sink_set_rtpoll(u->sink, u->rtpoll);
     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_sink_put(u->sink);
 
     pa_modargs_free(ma);
 
@@ -162,22 +223,34 @@
     if (ma)
         pa_modargs_free(ma);
 
-    pa__done(c, m);
+    pa__done(m);
 
     return -1;
 }
 
-void pa__done(pa_core *c, pa_module*m) {
+void pa__done(pa_module*m) {
     struct userdata *u;
-    assert(c && m);
+
+    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->sink)
+        pa_sink_unlink(u->sink);
+
+    if (u->thread) {
+        pa_asyncmsgq_send(u->thread_mq.inq, NULL, PA_MESSAGE_SHUTDOWN, NULL, 0, NULL);
+        pa_thread_free(u->thread);
+    }
+
+    pa_thread_mq_done(&u->thread_mq);
+
+    if (u->sink)
+        pa_sink_unref(u->sink);
+
+    if (u->rtpoll)
+        pa_rtpoll_free(u->rtpoll);
 
     pa_xfree(u);
 }

Modified: trunk/src/modules/module-oss.c
URL: http://0pointer.de/cgi-bin/viewcvs.cgi/trunk/src/modules/module-oss.c?rev=1971&root=pulseaudio&r1=1970&r2=1971&view=diff
==============================================================================
--- trunk/src/modules/module-oss.c (original)
+++ trunk/src/modules/module-oss.c Sun Oct 28 20:13:50 2007
@@ -22,8 +22,26 @@
   USA.
 ***/
 
+/* General power management rules:
+ *
+ *   When SUSPENDED we close the audio device.
+ *
+ *   We make no difference between IDLE and RUNNING in our handling.
+ *
+ *   As long as we are in RUNNING/IDLE state we will *always* write data to
+ *   the device. If none is avilable from the inputs, we write silence
+ *   instead.
+ *
+ *   If power should be saved on IDLE module-suspend-on-idle should be used.
+ *
+ */
+
 #ifdef HAVE_CONFIG_H
 #include <config.h>
+#endif
+
+#ifdef HAVE_SYS_MMAN_H
+#include <sys/mman.h>
 #endif
 
 #include <sys/soundcard.h>
@@ -31,18 +49,19 @@
 #include <stdlib.h>
 #include <sys/stat.h>
 #include <stdio.h>
-#include <assert.h>
 #include <errno.h>
 #include <string.h>
 #include <fcntl.h>
 #include <unistd.h>
 #include <limits.h>
+#include <signal.h>
+#include <poll.h>
 
 #include <pulse/xmalloc.h>
 #include <pulse/util.h>
 
 #include <pulsecore/core-error.h>
-#include <pulsecore/iochannel.h>
+#include <pulsecore/thread.h>
 #include <pulsecore/sink.h>
 #include <pulsecore/source.h>
 #include <pulsecore/module.h>
@@ -50,6 +69,9 @@
 #include <pulsecore/core-util.h>
 #include <pulsecore/modargs.h>
 #include <pulsecore/log.h>
+#include <pulsecore/macro.h>
+#include <pulsecore/thread-mq.h>
+#include <pulsecore/rtpoll.h>
 
 #include "oss-util.h"
 #include "module-oss-symdef.h"
@@ -68,21 +90,48 @@
         "rate=<sample rate> "
         "fragments=<number of fragments> "
         "fragment_size=<fragment size> "
-        "channel_map=<channel map>")
+        "channel_map=<channel map> "
+        "mmap=<enable memory mapping?>")
+
+#define DEFAULT_DEVICE "/dev/dsp"
 
 struct userdata {
+    pa_core *core;
+    pa_module *module;
     pa_sink *sink;
     pa_source *source;
-    pa_iochannel *io;
-    pa_core *core;
-
-    pa_memchunk memchunk, silence;
-
-    uint32_t in_fragment_size, out_fragment_size, sample_size;
-    int use_getospace, use_getispace;
+
+    pa_thread *thread;
+    pa_thread_mq thread_mq;
+    pa_rtpoll *rtpoll;
+
+    char *device_name;
+
+    pa_memchunk memchunk;
+
+    size_t frame_size;
+    uint32_t in_fragment_size, out_fragment_size, in_nfrags, out_nfrags, in_hwbuf_size, out_hwbuf_size;
+    pa_bool_t use_getospace, use_getispace;
+    pa_bool_t use_getodelay;
+
+    pa_bool_t sink_suspended, source_suspended;
 
     int fd;
-    pa_module *module;
+    int mode;
+
+    int mixer_fd;
+    int mixer_devmask;
+
+    int nfrags, frag_size;
+
+    pa_bool_t use_mmap;
+    unsigned out_mmap_current, in_mmap_current;
+    void *in_mmap, *out_mmap;
+    pa_memblock **in_mmap_memblocks, **out_mmap_memblocks;
+
+    int in_mmap_saved_nfrags, out_mmap_saved_nfrags;
+
+    pa_rtpoll_item *rtpoll_item;
 };
 
 static const char* const valid_modargs[] = {
@@ -97,280 +146,1010 @@
     "rate",
     "channels",
     "channel_map",
+    "mmap",
     NULL
 };
 
-#define DEFAULT_DEVICE "/dev/dsp"
-
-static void update_usage(struct userdata *u) {
-   pa_module_set_used(u->module,
-                      (u->sink ? pa_sink_used_by(u->sink) : 0) +
-                      (u->source ? pa_source_used_by(u->source) : 0));
-}
-
-static void clear_up(struct userdata *u) {
-    assert(u);
-
-    if (u->sink) {
-        pa_sink_disconnect(u->sink);
-        pa_sink_unref(u->sink);
-        u->sink = NULL;
-    }
-
-    if (u->source) {
-        pa_source_disconnect(u->source);
-        pa_source_unref(u->source);
-        u->source = NULL;
-    }
-
-    if (u->io) {
-        pa_iochannel_free(u->io);
-        u->io = NULL;
-    }
-}
-
-static void do_write(struct userdata *u) {
-    pa_memchunk *memchunk;
-    ssize_t r;
-    size_t l;
-    int loop = 0;
-
-    assert(u);
-
-    if (!u->sink || !pa_iochannel_is_writable(u->io))
+static void trigger(struct userdata *u, pa_bool_t quick) {
+    int enable_bits = 0, zero = 0;
+
+    pa_assert(u);
+
+    if (u->fd < 0)
         return;
 
-    update_usage(u);
-
-    l = u->out_fragment_size;
-
-    if (u->use_getospace) {
-        audio_buf_info info;
-
-        if (ioctl(u->fd, SNDCTL_DSP_GETOSPACE, &info) < 0)
+     pa_log_debug("trigger");
+
+    if (u->source && PA_SOURCE_OPENED(u->source->thread_info.state))
+        enable_bits |= PCM_ENABLE_INPUT;
+
+    if (u->sink && PA_SINK_OPENED(u->sink->thread_info.state))
+        enable_bits |= PCM_ENABLE_OUTPUT;
+
+    pa_log_debug("trigger: %i", enable_bits);
+
+
+    if (u->use_mmap) {
+
+        if (!quick)
+            ioctl(u->fd, SNDCTL_DSP_SETTRIGGER, &zero);
+
+#ifdef SNDCTL_DSP_HALT
+        if (enable_bits == 0)
+            if (ioctl(u->fd, SNDCTL_DSP_HALT, NULL) < 0)
+                pa_log_warn("SNDCTL_DSP_HALT: %s", pa_cstrerror(errno));
+#endif
+
+        if (ioctl(u->fd, SNDCTL_DSP_SETTRIGGER, &enable_bits) < 0)
+            pa_log_warn("SNDCTL_DSP_SETTRIGGER: %s", pa_cstrerror(errno));
+
+        if (u->sink && !(enable_bits & PCM_ENABLE_OUTPUT)) {
+            pa_log_debug("clearing playback buffer");
+            pa_silence_memory(u->out_mmap, u->out_hwbuf_size, &u->sink->sample_spec);
+        }
+
+    } else {
+
+        if (enable_bits)
+            if (ioctl(u->fd, SNDCTL_DSP_POST, NULL) < 0)
+                pa_log_warn("SNDCTL_DSP_POST: %s", pa_cstrerror(errno));
+
+        if (!quick) {
+            /*
+             * Some crappy drivers do not start the recording until we
+             * read something.  Without this snippet, poll will never
+             * register the fd as ready.
+             */
+
+            if (u->source && PA_SOURCE_OPENED(u->source->thread_info.state)) {
+                uint8_t *buf = pa_xnew(uint8_t, u->in_fragment_size);
+                pa_read(u->fd, buf, u->in_fragment_size, NULL);
+                pa_xfree(buf);
+            }
+        }
+    }
+}
+
+static void mmap_fill_memblocks(struct userdata *u, unsigned n) {
+    pa_assert(u);
+    pa_assert(u->out_mmap_memblocks);
+
+/*     pa_log("Mmmap writing %u blocks", n); */
+
+    while (n > 0) {
+        pa_memchunk chunk;
+
+        if (u->out_mmap_memblocks[u->out_mmap_current])
+            pa_memblock_unref_fixed(u->out_mmap_memblocks[u->out_mmap_current]);
+
+        chunk.memblock = u->out_mmap_memblocks[u->out_mmap_current] =
+            pa_memblock_new_fixed(
+                    u->core->mempool,
+                    (uint8_t*) u->out_mmap + u->out_fragment_size * u->out_mmap_current,
+                    u->out_fragment_size,
+                    1);
+
+        chunk.length = pa_memblock_get_length(chunk.memblock);
+        chunk.index = 0;
+
+        pa_sink_render_into_full(u->sink, &chunk);
+
+        u->out_mmap_current++;
+        while (u->out_mmap_current >= u->out_nfrags)
+            u->out_mmap_current -= u->out_nfrags;
+
+        n--;
+    }
+}
+
+static int mmap_write(struct userdata *u) {
+    struct count_info info;
+
+    pa_assert(u);
+    pa_assert(u->sink);
+
+/*     pa_log("Mmmap writing..."); */
+
+    if (ioctl(u->fd, SNDCTL_DSP_GETOPTR, &info) < 0) {
+        pa_log("SNDCTL_DSP_GETOPTR: %s", pa_cstrerror(errno));
+        return -1;
+    }
+
+    info.blocks += u->out_mmap_saved_nfrags;
+    u->out_mmap_saved_nfrags = 0;
+
+    if (info.blocks > 0)
+        mmap_fill_memblocks(u, info.blocks);
+
+    return info.blocks;
+}
+
+static void mmap_post_memblocks(struct userdata *u, unsigned n) {
+    pa_assert(u);
+    pa_assert(u->in_mmap_memblocks);
+
+/*     pa_log("Mmmap reading %u blocks", n); */
+
+    while (n > 0) {
+        pa_memchunk chunk;
+
+        if (!u->in_mmap_memblocks[u->in_mmap_current]) {
+
+            chunk.memblock = u->in_mmap_memblocks[u->in_mmap_current] =
+                pa_memblock_new_fixed(
+                        u->core->mempool,
+                        (uint8_t*) u->in_mmap + u->in_fragment_size*u->in_mmap_current,
+                        u->in_fragment_size,
+                        1);
+
+            chunk.length = pa_memblock_get_length(chunk.memblock);
+            chunk.index = 0;
+
+            pa_source_post(u->source, &chunk);
+        }
+
+        u->in_mmap_current++;
+        while (u->in_mmap_current >= u->in_nfrags)
+            u->in_mmap_current -= u->in_nfrags;
+
+        n--;
+    }
+}
+
+static void mmap_clear_memblocks(struct userdata*u, unsigned n) {
+    unsigned i = u->in_mmap_current;
+
+    pa_assert(u);
+    pa_assert(u->in_mmap_memblocks);
+
+    if (n > u->in_nfrags)
+        n = u->in_nfrags;
+
+    while (n > 0) {
+        if (u->in_mmap_memblocks[i]) {
+            pa_memblock_unref_fixed(u->in_mmap_memblocks[i]);
+            u->in_mmap_memblocks[i] = NULL;
+        }
+
+        i++;
+        while (i >= u->in_nfrags)
+            i -= u->in_nfrags;
+
+        n--;
+    }
+}
+
+static int mmap_read(struct userdata *u) {
+    struct count_info info;
+    pa_assert(u);
+    pa_assert(u->source);
+
+/*     pa_log("Mmmap reading..."); */
+
+    if (ioctl(u->fd, SNDCTL_DSP_GETIPTR, &info) < 0) {
+        pa_log("SNDCTL_DSP_GETIPTR: %s", pa_cstrerror(errno));
+        return -1;
+    }
+
+/*     pa_log("... %i", info.blocks); */
+
+    info.blocks += u->in_mmap_saved_nfrags;
+    u->in_mmap_saved_nfrags = 0;
+
+    if (info.blocks > 0) {
+        mmap_post_memblocks(u, info.blocks);
+        mmap_clear_memblocks(u, u->in_nfrags/2);
+    }
+
+    return info.blocks;
+}
+
+static pa_usec_t mmap_sink_get_latency(struct userdata *u) {
+    struct count_info info;
+    size_t bpos, n;
+
+    pa_assert(u);
+
+    if (ioctl(u->fd, SNDCTL_DSP_GETOPTR, &info) < 0) {
+        pa_log("SNDCTL_DSP_GETOPTR: %s", pa_cstrerror(errno));
+        return 0;
+    }
+
+    u->out_mmap_saved_nfrags += info.blocks;
+
+    bpos = ((u->out_mmap_current + u->out_mmap_saved_nfrags) * u->out_fragment_size) % u->out_hwbuf_size;
+
+    if (bpos <= (size_t) info.ptr)
+        n = u->out_hwbuf_size - (info.ptr - bpos);
+    else
+        n = bpos - info.ptr;
+
+/*     pa_log("n = %u, bpos = %u, ptr = %u, total=%u, fragsize = %u, n_frags = %u\n", n, bpos, (unsigned) info.ptr, total, u->out_fragment_size, u->out_fragments); */
+
+    return pa_bytes_to_usec(n, &u->sink->sample_spec);
+}
+
+static pa_usec_t mmap_source_get_latency(struct userdata *u) {
+    struct count_info info;
+    size_t bpos, n;
+
+    pa_assert(u);
+
+    if (ioctl(u->fd, SNDCTL_DSP_GETIPTR, &info) < 0) {
+        pa_log("SNDCTL_DSP_GETIPTR: %s", pa_cstrerror(errno));
+        return 0;
+    }
+
+    u->in_mmap_saved_nfrags += info.blocks;
+    bpos = ((u->in_mmap_current + u->in_mmap_saved_nfrags) * u->in_fragment_size) % u->in_hwbuf_size;
+
+    if (bpos <= (size_t) info.ptr)
+        n = info.ptr - bpos;
+    else
+        n = u->in_hwbuf_size - bpos + info.ptr;
+
+/*     pa_log("n = %u, bpos = %u, ptr = %u, total=%u, fragsize = %u, n_frags = %u\n", n, bpos, (unsigned) info.ptr, total, u->in_fragment_size, u->in_fragments);  */
+
+    return pa_bytes_to_usec(n, &u->source->sample_spec);
+}
+
+static pa_usec_t io_sink_get_latency(struct userdata *u) {
+    pa_usec_t r = 0;
+
+    pa_assert(u);
+
+    if (u->use_getodelay) {
+        int arg;
+
+        if (ioctl(u->fd, SNDCTL_DSP_GETODELAY, &arg) < 0) {
+            pa_log_info("Device doesn't support SNDCTL_DSP_GETODELAY: %s", pa_cstrerror(errno));
+            u->use_getodelay = 0;
+        } else
+            r = pa_bytes_to_usec(arg, &u->sink->sample_spec);
+
+    }
+
+    if (!u->use_getodelay && u->use_getospace) {
+        struct audio_buf_info info;
+
+        if (ioctl(u->fd, SNDCTL_DSP_GETOSPACE, &info) < 0) {
+            pa_log_info("Device doesn't support SNDCTL_DSP_GETOSPACE: %s", pa_cstrerror(errno));
             u->use_getospace = 0;
-        else {
-            if (info.bytes/l > 0) {
-                l = (info.bytes/l)*l;
-                loop = 1;
+        } else
+            r = pa_bytes_to_usec(info.bytes, &u->sink->sample_spec);
+    }
+
+    if (u->memchunk.memblock)
+        r += pa_bytes_to_usec(u->memchunk.length, &u->sink->sample_spec);
+
+    return r;
+}
+
+
+static pa_usec_t io_source_get_latency(struct userdata *u) {
+    pa_usec_t r = 0;
+
+    pa_assert(u);
+
+    if (u->use_getispace) {
+        struct audio_buf_info info;
+
+        if (ioctl(u->fd, SNDCTL_DSP_GETISPACE, &info) < 0) {
+            pa_log_info("Device doesn't support SNDCTL_DSP_GETISPACE: %s", pa_cstrerror(errno));
+            u->use_getispace = 0;
+        } else
+            r = pa_bytes_to_usec(info.bytes, &u->source->sample_spec);
+    }
+
+    return r;
+}
+
+static void build_pollfd(struct userdata *u) {
+    struct pollfd *pollfd;
+
+    pa_assert(u);
+    pa_assert(u->fd >= 0);
+
+    if (u->rtpoll_item)
+        pa_rtpoll_item_free(u->rtpoll_item);
+
+    u->rtpoll_item = pa_rtpoll_item_new(u->rtpoll, PA_RTPOLL_NEVER, 1);
+    pollfd = pa_rtpoll_item_get_pollfd(u->rtpoll_item, NULL);
+    pollfd->fd = u->fd;
+    pollfd->events = 0;
+    pollfd->revents = 0;
+}
+
+static int suspend(struct userdata *u) {
+    pa_assert(u);
+    pa_assert(u->fd >= 0);
+
+    pa_log_info("Suspending...");
+
+    if (u->out_mmap_memblocks) {
+        unsigned i;
+        for (i = 0; i < u->out_nfrags; i++)
+            if (u->out_mmap_memblocks[i]) {
+                pa_memblock_unref_fixed(u->out_mmap_memblocks[i]);
+                u->out_mmap_memblocks[i] = NULL;
             }
-        }
-    }
-
-    do {
-        memchunk = &u->memchunk;
-
-        if (!memchunk->length)
-            if (pa_sink_render(u->sink, l, 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) {
-
-            if (errno != EAGAIN) {
-                pa_log("write() failed: %s", pa_cstrerror(errno));
-
-                clear_up(u);
-                pa_module_unload_request(u->module);
+    }
+
+    if (u->in_mmap_memblocks) {
+        unsigned i;
+        for (i = 0; i < u->in_nfrags; i++)
+            if (u->in_mmap_memblocks[i]) {
+                pa_memblock_unref_fixed(u->in_mmap_memblocks[i]);
+                u->in_mmap_memblocks[i] = NULL;
             }
+    }
+
+    if (u->in_mmap && u->in_mmap != MAP_FAILED) {
+        munmap(u->in_mmap, u->in_hwbuf_size);
+        u->in_mmap = NULL;
+    }
+
+    if (u->out_mmap && u->out_mmap != MAP_FAILED) {
+        munmap(u->out_mmap, u->out_hwbuf_size);
+        u->out_mmap = NULL;
+    }
+
+    /* Let's suspend */
+    ioctl(u->fd, SNDCTL_DSP_SYNC, NULL);
+    pa_close(u->fd);
+    u->fd = -1;
+
+    if (u->rtpoll_item) {
+        pa_rtpoll_item_free(u->rtpoll_item);
+        u->rtpoll_item = NULL;
+    }
+
+    pa_log_info("Device suspended...");
+
+    return 0;
+}
+
+static int unsuspend(struct userdata *u) {
+    int m;
+    pa_sample_spec ss, *ss_original;
+    int frag_size, in_frag_size, out_frag_size;
+    int in_nfrags, out_nfrags;
+    struct audio_buf_info info;
+
+    pa_assert(u);
+    pa_assert(u->fd < 0);
+
+    m = u->mode;
+
+    pa_log_info("Trying resume...");
+
+    if ((u->fd = pa_oss_open(u->device_name, &m, NULL)) < 0) {
+        pa_log_warn("Resume failed, device busy (%s)", pa_cstrerror(errno));
+        return -1;
+
+    if (m != u->mode)
+        pa_log_warn("Resume failed, couldn't open device with original access mode.");
+        goto fail;
+    }
+
+    if (u->nfrags >= 2 && u->frag_size >= 1)
+        if (pa_oss_set_fragments(u->fd, u->nfrags, u->frag_size) < 0) {
+            pa_log_warn("Resume failed, couldn't set original fragment settings.");
+            goto fail;
+        }
+
+    ss = *(ss_original = u->sink ? &u->sink->sample_spec : &u->source->sample_spec);
+    if (pa_oss_auto_format(u->fd, &ss) < 0 || !pa_sample_spec_equal(&ss, ss_original)) {
+        pa_log_warn("Resume failed, couldn't set original sample format settings.");
+        goto fail;
+    }
+
+    if (ioctl(u->fd, SNDCTL_DSP_GETBLKSIZE, &frag_size) < 0) {
+        pa_log_warn("SNDCTL_DSP_GETBLKSIZE: %s", pa_cstrerror(errno));
+        goto fail;
+    }
+
+    in_frag_size = out_frag_size = frag_size;
+    in_nfrags = out_nfrags = u->nfrags;
+
+    if (ioctl(u->fd, SNDCTL_DSP_GETISPACE, &info) >= 0) {
+        in_frag_size = info.fragsize;
+        in_nfrags = info.fragstotal;
+    }
+
+    if (ioctl(u->fd, SNDCTL_DSP_GETOSPACE, &info) >= 0) {
+        out_frag_size = info.fragsize;
+        out_nfrags = info.fragstotal;
+    }
+
+    if ((u->source && (in_frag_size != (int) u->in_fragment_size || in_nfrags != (int) u->in_nfrags)) ||
+        (u->sink && (out_frag_size != (int) u->out_fragment_size || out_nfrags != (int) u->out_nfrags))) {
+        pa_log_warn("Resume failed, input fragment settings don't match.");
+        goto fail;
+    }
+
+    if (u->use_mmap) {
+        if (u->source) {
+            if ((u->in_mmap = mmap(NULL, u->in_hwbuf_size, PROT_READ, MAP_SHARED, u->fd, 0)) == MAP_FAILED) {
+                pa_log("Resume failed, mmap(): %s", pa_cstrerror(errno));
+                goto fail;
+            }
+        }
+
+        if (u->sink) {
+            if ((u->out_mmap = mmap(NULL, u->out_hwbuf_size, PROT_WRITE, MAP_SHARED, u->fd, 0)) == MAP_FAILED) {
+                pa_log("Resume failed, mmap(): %s", pa_cstrerror(errno));
+                if (u->in_mmap && u->in_mmap != MAP_FAILED) {
+                    munmap(u->in_mmap, u->in_hwbuf_size);
+                    u->in_mmap = NULL;
+                }
+
+                goto fail;
+            }
+
+            pa_silence_memory(u->out_mmap, u->out_hwbuf_size, &ss);
+        }
+    }
+
+    u->out_mmap_current = u->in_mmap_current = 0;
+    u->out_mmap_saved_nfrags = u->in_mmap_saved_nfrags = 0;
+
+    pa_assert(!u->rtpoll_item);
+
+    build_pollfd(u);
+
+    if (u->sink)
+        pa_sink_get_volume(u->sink);
+    if (u->source)
+        pa_source_get_volume(u->source);
+
+    pa_log_info("Resumed successfully...");
+
+    return 0;
+
+fail:
+    pa_close(u->fd);
+    u->fd = -1;
+    return -1;
+}
+
+static int sink_process_msg(pa_msgobject *o, int code, void *data, int64_t offset, pa_memchunk *chunk) {
+    struct userdata *u = PA_SINK(o)->userdata;
+    int ret;
+    pa_bool_t do_trigger = FALSE, quick = TRUE;
+
+    switch (code) {
+
+        case PA_SINK_MESSAGE_GET_LATENCY: {
+            pa_usec_t r = 0;
+
+            if (u->fd >= 0) {
+                if (u->use_mmap)
+                    r = mmap_sink_get_latency(u);
+                else
+                    r = io_sink_get_latency(u);
+            }
+
+            *((pa_usec_t*) data) = r;
+
+            return 0;
+        }
+
+        case PA_SINK_MESSAGE_SET_STATE:
+
+            switch ((pa_sink_state_t) PA_PTR_TO_UINT(data)) {
+
+                case PA_SINK_SUSPENDED:
+                    pa_assert(PA_SINK_OPENED(u->sink->thread_info.state));
+
+                    if (!u->source || u->source_suspended) {
+                        if (suspend(u) < 0)
+                            return -1;
+                    }
+
+                    do_trigger = TRUE;
+
+                    u->sink_suspended = TRUE;
+                    break;
+
+                case PA_SINK_IDLE:
+                case PA_SINK_RUNNING:
+
+                    if (u->sink->thread_info.state == PA_SINK_INIT) {
+                        do_trigger = TRUE;
+                        quick = u->source && PA_SOURCE_OPENED(u->source->thread_info.state);
+                    }
+
+                    if (u->sink->thread_info.state == PA_SINK_SUSPENDED) {
+
+                        if (!u->source || u->source_suspended) {
+                            if (unsuspend(u) < 0)
+                                return -1;
+                            quick = FALSE;
+                        }
+
+                        do_trigger = TRUE;
+
+                        u->out_mmap_current = 0;
+                        u->out_mmap_saved_nfrags = 0;
+
+                        u->sink_suspended = FALSE;
+                    }
+
+                    break;
+
+                case PA_SINK_UNLINKED:
+                case PA_SINK_INIT:
+                    ;
+            }
 
             break;
-        }
-
-        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;
+
+    }
+
+    ret = pa_sink_process_msg(o, code, data, offset, chunk);
+
+    if (do_trigger)
+        trigger(u, quick);
+
+    return ret;
+}
+
+static int source_process_msg(pa_msgobject *o, int code, void *data, int64_t offset, pa_memchunk *chunk) {
+    struct userdata *u = PA_SOURCE(o)->userdata;
+    int ret;
+    int do_trigger = FALSE, quick = TRUE;
+
+    switch (code) {
+
+        case PA_SOURCE_MESSAGE_GET_LATENCY: {
+            pa_usec_t r = 0;
+
+            if (u->fd >= 0) {
+                if (u->use_mmap)
+                    r = mmap_source_get_latency(u);
+                else
+                    r = io_source_get_latency(u);
             }
-        }
-
-        l = l > (size_t) r ? l - r : 0;
-    } while (loop && l > 0);
-}
-
-static void do_read(struct userdata *u) {
-    pa_memchunk memchunk;
-    ssize_t r;
-    size_t l;
-    int loop = 0;
-    assert(u);
-
-    if (!u->source || !pa_iochannel_is_readable(u->io) || !pa_idxset_size(u->source->outputs))
-        return;
-
-    update_usage(u);
-
-    l = u->in_fragment_size;
-
-    if (u->use_getispace) {
-        audio_buf_info info;
-
-        if (ioctl(u->fd, SNDCTL_DSP_GETISPACE, &info) < 0)
-            u->use_getispace = 0;
-        else {
-            if (info.bytes/l > 0) {
-                l = (info.bytes/l)*l;
-                loop = 1;
+
+            *((pa_usec_t*) data) = r;
+            return 0;
+        }
+
+        case PA_SOURCE_MESSAGE_SET_STATE:
+
+            switch ((pa_source_state_t) PA_PTR_TO_UINT(data)) {
+                case PA_SOURCE_SUSPENDED:
+                    pa_assert(PA_SOURCE_OPENED(u->source->thread_info.state));
+
+                    if (!u->sink || u->sink_suspended) {
+                        if (suspend(u) < 0)
+                            return -1;
+                    }
+
+                    do_trigger = TRUE;
+
+                    u->source_suspended = TRUE;
+                    break;
+
+                case PA_SOURCE_IDLE:
+                case PA_SOURCE_RUNNING:
+
+                    if (u->source->thread_info.state == PA_SOURCE_INIT) {
+                        do_trigger = TRUE;
+                        quick = u->sink && PA_SINK_OPENED(u->sink->thread_info.state);
+                    }
+
+                    if (u->source->thread_info.state == PA_SOURCE_SUSPENDED) {
+
+                        if (!u->sink || u->sink_suspended) {
+                            if (unsuspend(u) < 0)
+                                return -1;
+                            quick = FALSE;
+                        }
+
+                        do_trigger = TRUE;
+
+                        u->in_mmap_current = 0;
+                        u->in_mmap_saved_nfrags = 0;
+
+                        u->source_suspended = FALSE;
+                    }
+                    break;
+
+                case PA_SOURCE_UNLINKED:
+                case PA_SOURCE_INIT:
+                    ;
+
             }
-        }
-    }
-
-    do {
-        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) {
-            pa_memblock_unref(memchunk.memblock);
-
-            if (errno != EAGAIN) {
-                pa_log("read() failed: %s", pa_cstrerror(errno));
-
-                clear_up(u);
-                pa_module_unload_request(u->module);
+            break;
+
+    }
+
+    ret = pa_source_process_msg(o, code, data, offset, chunk);
+
+    if (do_trigger)
+        trigger(u, quick);
+
+    return ret;
+}
+
+static int sink_get_volume(pa_sink *s) {
+    struct userdata *u;
+    int r;
+
+    pa_assert_se(u = s->userdata);
+
+    pa_assert(u->mixer_devmask & (SOUND_MASK_VOLUME|SOUND_MASK_PCM));
+
+    if (u->mixer_devmask & SOUND_MASK_VOLUME)
+        if ((r = pa_oss_get_volume(u->mixer_fd, SOUND_MIXER_READ_VOLUME, &s->sample_spec, &s->volume)) >= 0)
+            return r;
+
+    if (u->mixer_devmask & SOUND_MASK_PCM)
+        if ((r = pa_oss_get_volume(u->mixer_fd, SOUND_MIXER_READ_PCM, &s->sample_spec, &s->volume)) >= 0)
+            return r;
+
+    pa_log_info("Device doesn't support reading mixer settings: %s", pa_cstrerror(errno));
+    return -1;
+}
+
+static int sink_set_volume(pa_sink *s) {
+    struct userdata *u;
+    int r;
+
+    pa_assert_se(u = s->userdata);
+
+    pa_assert(u->mixer_devmask & (SOUND_MASK_VOLUME|SOUND_MASK_PCM));
+
+    if (u->mixer_devmask & SOUND_MASK_VOLUME)
+        if ((r = pa_oss_set_volume(u->mixer_fd, SOUND_MIXER_WRITE_VOLUME, &s->sample_spec, &s->volume)) >= 0)
+            return r;
+
+    if (u->mixer_devmask & SOUND_MASK_PCM)
+        if ((r = pa_oss_get_volume(u->mixer_fd, SOUND_MIXER_WRITE_PCM, &s->sample_spec, &s->volume)) >= 0)
+            return r;
+
+    pa_log_info("Device doesn't support writing mixer settings: %s", pa_cstrerror(errno));
+    return -1;
+}
+
+static int source_get_volume(pa_source *s) {
+    struct userdata *u;
+    int r;
+
+    pa_assert_se(u = s->userdata);
+
+    pa_assert(u->mixer_devmask & (SOUND_MASK_IGAIN|SOUND_MASK_RECLEV));
+
+    if (u->mixer_devmask & SOUND_MASK_IGAIN)
+        if ((r = pa_oss_get_volume(u->mixer_fd, SOUND_MIXER_READ_IGAIN, &s->sample_spec, &s->volume)) >= 0)
+            return r;
+
+    if (u->mixer_devmask & SOUND_MASK_RECLEV)
+        if ((r = pa_oss_get_volume(u->mixer_fd, SOUND_MIXER_READ_RECLEV, &s->sample_spec, &s->volume)) >= 0)
+            return r;
+
+    pa_log_info("Device doesn't support reading mixer settings: %s", pa_cstrerror(errno));
+    return -1;
+}
+
+static int source_set_volume(pa_source *s) {
+    struct userdata *u;
+    int r;
+
+    pa_assert_se(u = s->userdata);
+
+    pa_assert(u->mixer_devmask & (SOUND_MASK_IGAIN|SOUND_MASK_RECLEV));
+
+    if (u->mixer_devmask & SOUND_MASK_IGAIN)
+        if ((r = pa_oss_set_volume(u->mixer_fd, SOUND_MIXER_WRITE_IGAIN, &s->sample_spec, &s->volume)) >= 0)
+            return r;
+
+    if (u->mixer_devmask & SOUND_MASK_RECLEV)
+        if ((r = pa_oss_get_volume(u->mixer_fd, SOUND_MIXER_WRITE_RECLEV, &s->sample_spec, &s->volume)) >= 0)
+            return r;
+
+    pa_log_info("Device doesn't support writing mixer settings: %s", pa_cstrerror(errno));
+    return -1;
+}
+
+static void thread_func(void *userdata) {
+    struct userdata *u = userdata;
+    int write_type = 0, read_type = 0;
+    unsigned short revents = 0;
+
+    pa_assert(u);
+
+    pa_log_debug("Thread starting up");
+
+    if (u->core->high_priority)
+        pa_make_realtime();
+
+    pa_thread_mq_install(&u->thread_mq);
+    pa_rtpoll_install(u->rtpoll);
+
+    for (;;) {
+        int ret;
+
+/*        pa_log("loop");    */
+
+        /* Render some data and write it to the dsp */
+
+        if (u->sink && PA_SINK_OPENED(u->sink->thread_info.state) && ((revents & POLLOUT) || u->use_mmap || u->use_getospace)) {
+
+            if (u->use_mmap) {
+
+                if ((ret = mmap_write(u)) < 0)
+                    goto fail;
+
+                revents &= ~POLLOUT;
+
+                if (ret > 0)
+                    continue;
+
+            } else {
+                ssize_t l;
+                pa_bool_t loop = FALSE, work_done = FALSE;
+
+                l = u->out_fragment_size;
+
+                if (u->use_getospace) {
+                    audio_buf_info info;
+
+                    if (ioctl(u->fd, SNDCTL_DSP_GETOSPACE, &info) < 0) {
+                        pa_log_info("Device doesn't support SNDCTL_DSP_GETOSPACE: %s", pa_cstrerror(errno));
+                        u->use_getospace = FALSE;
+                    } else {
+                        l = info.bytes;
+
+                        /* We loop only if GETOSPACE worked and we
+                         * actually *know* that we can write more than
+                         * one fragment at a time */
+                        loop = TRUE;
+                    }
+                }
+
+                /* Round down to multiples of the fragment size,
+                 * because OSS needs that (at least some versions
+                 * do) */
+                l = (l/u->out_fragment_size) * u->out_fragment_size;
+
+                /* Hmm, so poll() signalled us that we can read
+                 * something, but GETOSPACE told us there was nothing?
+                 * Hmm, make the best of it, try to read some data, to
+                 * avoid spinning forever. */
+                if (l <= 0 && (revents & POLLOUT)) {
+                    l = u->out_fragment_size;
+                    loop = FALSE;
+                }
+
+                while (l > 0) {
+                    void *p;
+                    ssize_t t;
+
+                    if (u->memchunk.length <= 0)
+                        pa_sink_render(u->sink, l, &u->memchunk);
+
+                    pa_assert(u->memchunk.length > 0);
+
+                    p = pa_memblock_acquire(u->memchunk.memblock);
+                    t = pa_write(u->fd, (uint8_t*) p + u->memchunk.index, u->memchunk.length, &write_type);
+                    pa_memblock_release(u->memchunk.memblock);
+
+/*                     pa_log("wrote %i bytes of %u", t, l); */
+
+                    pa_assert(t != 0);
+
+                    if (t < 0) {
+
+                        if (errno == EINTR)
+                            continue;
+
+                        else if (errno == EAGAIN) {
+                            pa_log_debug("EAGAIN");
+
+                            revents &= ~POLLOUT;
+                            break;
+
+                        } else {
+                            pa_log("Failed to write data to DSP: %s", pa_cstrerror(errno));
+                            goto fail;
+                        }
+
+                    } else {
+
+                        u->memchunk.index += t;
+                        u->memchunk.length -= t;
+
+                        if (u->memchunk.length <= 0) {
+                            pa_memblock_unref(u->memchunk.memblock);
+                            pa_memchunk_reset(&u->memchunk);
+                        }
+
+                        l -= t;
+
+                        revents &= ~POLLOUT;
+                        work_done = TRUE;
+                    }
+
+                    if (!loop)
+                        break;
+                }
+
+                if (work_done)
+                    continue;
             }
-
-            break;
-        }
-
-        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);
-
-        l = l > (size_t) r ? l - r : 0;
-    } while (loop && l > 0);
-}
-
-static void io_callback(PA_GCC_UNUSED pa_iochannel *io, void*userdata) {
-    struct userdata *u = userdata;
-    assert(u);
-    do_write(u);
-    do_read(u);
-}
-
-static void source_notify_cb(pa_source *s) {
-    struct userdata *u = s->userdata;
-    assert(u);
-    do_read(u);
-}
-
-static pa_usec_t sink_get_latency_cb(pa_sink *s) {
-    pa_usec_t r = 0;
-    int arg;
-    struct userdata *u = s->userdata;
-    assert(s && u && u->sink);
-
-    if (ioctl(u->fd, SNDCTL_DSP_GETODELAY, &arg) < 0) {
-        pa_log_info("device doesn't support SNDCTL_DSP_GETODELAY: %s", pa_cstrerror(errno));
-        s->get_latency = NULL;
-        return 0;
-    }
-
-    r += pa_bytes_to_usec(arg, &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(pa_source *s) {
-    struct userdata *u = s->userdata;
-    audio_buf_info info;
-    assert(s && u && u->source);
-
-    if (!u->use_getispace)
-        return 0;
-
-    if (ioctl(u->fd, SNDCTL_DSP_GETISPACE, &info) < 0) {
-        u->use_getispace = 0;
-        return 0;
-    }
-
-    if (info.bytes <= 0)
-        return 0;
-
-    return pa_bytes_to_usec(info.bytes, &s->sample_spec);
-}
-
-static int sink_get_hw_volume(pa_sink *s) {
-    struct userdata *u = s->userdata;
-
-    if (pa_oss_get_pcm_volume(u->fd, &s->sample_spec, &s->hw_volume) < 0) {
-        pa_log_info("device doesn't support reading mixer settings: %s", pa_cstrerror(errno));
-        s->get_hw_volume = NULL;
-        return -1;
-    }
-
-    return 0;
-}
-
-static int sink_set_hw_volume(pa_sink *s) {
-    struct userdata *u = s->userdata;
-
-    if (pa_oss_set_pcm_volume(u->fd, &s->sample_spec, &s->hw_volume) < 0) {
-        pa_log_info("device doesn't support writing mixer settings: %s", pa_cstrerror(errno));
-        s->set_hw_volume = NULL;
-        return -1;
-    }
-
-    return 0;
-}
-
-static int source_get_hw_volume(pa_source *s) {
-    struct userdata *u = s->userdata;
-
-    if (pa_oss_get_input_volume(u->fd, &s->sample_spec, &s->hw_volume) < 0) {
-        pa_log_info("device doesn't support reading mixer settings: %s", pa_cstrerror(errno));
-        s->get_hw_volume = NULL;
-        return -1;
-    }
-
-    return 0;
-}
-
-static int source_set_hw_volume(pa_source *s) {
-    struct userdata *u = s->userdata;
-
-    if (pa_oss_set_input_volume(u->fd, &s->sample_spec, &s->hw_volume) < 0) {
-        pa_log_info("device doesn't support writing mixer settings: %s", pa_cstrerror(errno));
-        s->set_hw_volume = NULL;
-        return -1;
-    }
-
-    return 0;
-}
-
-int pa__init(pa_core *c, pa_module*m) {
+        }
+
+        /* Try to read some data and pass it on to the source driver. */
+
+        if (u->source && PA_SOURCE_OPENED(u->source->thread_info.state) && ((revents & POLLIN) || u->use_mmap || u->use_getispace)) {
+
+            if (u->use_mmap) {
+
+                if ((ret = mmap_read(u)) < 0)
+                    goto fail;
+
+                revents &= ~POLLIN;
+
+                if (ret > 0)
+                    continue;
+
+            } else {
+
+                void *p;
+                ssize_t l;
+                pa_memchunk memchunk;
+                pa_bool_t loop = FALSE, work_done = FALSE;
+
+                l = u->in_fragment_size;
+
+                if (u->use_getispace) {
+                    audio_buf_info info;
+
+                    if (ioctl(u->fd, SNDCTL_DSP_GETISPACE, &info) < 0) {
+                        pa_log_info("Device doesn't support SNDCTL_DSP_GETISPACE: %s", pa_cstrerror(errno));
+                        u->use_getispace = FALSE;
+                    } else {
+                        l = info.bytes;
+                        loop = TRUE;
+                    }
+                }
+
+                l = (l/u->in_fragment_size) * u->in_fragment_size;
+
+                if (l <= 0 && (revents & POLLIN)) {
+                    l = u->in_fragment_size;
+                    loop = FALSE;
+                }
+
+                while (l > 0) {
+                    ssize_t t, k;
+
+                    pa_assert(l > 0);
+
+                    memchunk.memblock = pa_memblock_new(u->core->mempool, (size_t) -1);
+
+                    k = pa_memblock_get_length(memchunk.memblock);
+
+                    if (k > l)
+                        k = l;
+
+                    k = (k/u->frame_size)*u->frame_size;
+
+                    p = pa_memblock_acquire(memchunk.memblock);
+                    t = pa_read(u->fd, p, k, &read_type);
+                    pa_memblock_release(memchunk.memblock);
+
+                    pa_assert(t != 0); /* EOF cannot happen */
+
+/*                     pa_log("read %i bytes of %u", t, l); */
+
+                    if (t < 0) {
+                        pa_memblock_unref(memchunk.memblock);
+
+                        if (errno == EINTR)
+                            continue;
+
+                        else if (errno == EAGAIN) {
+                            pa_log_debug("EAGAIN");
+
+                            revents &= ~POLLIN;
+                            break;
+
+                        } else {
+                            pa_log("Failed to read data from DSP: %s", pa_cstrerror(errno));
+                            goto fail;
+                        }
+
+                    } else {
+                        memchunk.index = 0;
+                        memchunk.length = t;
+
+                        pa_source_post(u->source, &memchunk);
+                        pa_memblock_unref(memchunk.memblock);
+
+                        l -= t;
+
+                        revents &= ~POLLIN;
+                        work_done = TRUE;
+                    }
+
+                    if (!loop)
+                        break;
+                }
+
+                if (work_done)
+                    continue;
+            }
+        }
+
+/*         pa_log("loop2 revents=%i", revents); */
+
+        if (u->rtpoll_item) {
+            struct pollfd *pollfd;
+
+            pa_assert(u->fd >= 0);
+
+            pollfd = pa_rtpoll_item_get_pollfd(u->rtpoll_item, NULL);
+            pollfd->events =
+                ((u->source && PA_SOURCE_OPENED(u->source->thread_info.state)) ? POLLIN : 0) |
+                ((u->sink && PA_SINK_OPENED(u->sink->thread_info.state)) ? POLLOUT : 0);
+        }
+
+        /* Hmm, nothing to do. Let's sleep */
+        if ((ret = pa_rtpoll_run(u->rtpoll, TRUE)) < 0)
+            goto fail;
+
+        if (ret == 0)
+            goto finish;
+
+        if (u->rtpoll_item) {
+            struct pollfd *pollfd;
+
+            pollfd = pa_rtpoll_item_get_pollfd(u->rtpoll_item, NULL);
+
+            if (pollfd->revents & ~(POLLOUT|POLLIN)) {
+                pa_log("DSP shutdown.");
+                goto fail;
+            }
+
+            revents = pollfd->revents;
+        } else
+            revents = 0;
+    }
+
+fail:
+    /* If this was no regular exit from the loop we have to continue
+     * processing messages until we received PA_MESSAGE_SHUTDOWN */
+    pa_asyncmsgq_post(u->thread_mq.outq, PA_MSGOBJECT(u->core), PA_CORE_MESSAGE_UNLOAD_MODULE, u->module, 0, NULL, NULL);
+    pa_asyncmsgq_wait_for(u->thread_mq.inq, PA_MESSAGE_SHUTDOWN);
+
+finish:
+    pa_log_debug("Thread shutting down");
+}
+
+int pa__init(pa_module*m) {
+
     struct audio_buf_info info;
     struct userdata *u = NULL;
-    const char *p;
+    const char *dev;
     int fd = -1;
-    int nfrags, frag_size, in_frag_size, out_frag_size;
-    int mode;
-    int record = 1, playback = 1;
+    int nfrags, frag_size;
+    int mode, caps;
+    int record = 1, playback = 1, use_mmap = 1;
     pa_sample_spec ss;
     pa_channel_map map;
     pa_modargs *ma = NULL;
     char hwdesc[64], *t;
     const char *name;
-    char *name_buf = NULL;
     int namereg_fail;
 
-    assert(c);
-    assert(m);
+    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;
     }
 
@@ -380,36 +1159,52 @@
     }
 
     if (!playback && !record) {
-        pa_log("neither playback nor record enabled for device.");
+        pa_log("Neither playback nor record enabled for device.");
         goto fail;
     }
 
-    mode = (playback&&record) ? O_RDWR : (playback ? O_WRONLY : (record ? O_RDONLY : 0));
-
-    ss = c->default_sample_spec;
+    mode = (playback && record) ? O_RDWR : (playback ? O_WRONLY : (record ? O_RDONLY : 0));
+
+    ss = m->core->default_sample_spec;
     if (pa_modargs_get_sample_spec_and_channel_map(ma, &ss, &map, PA_CHANNEL_MAP_OSS) < 0) {
-        pa_log("failed to parse sample specification or channel map");
+        pa_log("Failed to parse sample specification or channel map");
         goto fail;
     }
 
-    /* Fix latency to 100ms */
-    nfrags = 12;
-    frag_size = pa_bytes_per_second(&ss)/128;
+    nfrags = m->core->default_n_fragments;
+    frag_size = pa_usec_to_bytes(m->core->default_fragment_size_msec*1000, &ss);
+    if (frag_size <= 0)
+        frag_size = pa_frame_size(&ss);
 
     if (pa_modargs_get_value_s32(ma, "fragments", &nfrags) < 0 || pa_modargs_get_value_s32(ma, "fragment_size", &frag_size) < 0) {
-        pa_log("failed to parse fragments arguments");
+        pa_log("Failed to parse fragments arguments");
         goto fail;
     }
 
-    if ((fd = pa_oss_open(p = pa_modargs_get_value(ma, "device", DEFAULT_DEVICE), &mode, NULL)) < 0)
+    if (pa_modargs_get_value_boolean(ma, "mmap", &use_mmap) < 0) {
+        pa_log("Failed to parse mmap argument.");
         goto fail;
-
-    if (pa_oss_get_hw_description(p, hwdesc, sizeof(hwdesc)) >= 0)
-        pa_log_info("hardware name is '%s'.", hwdesc);
+    }
+
+    if ((fd = pa_oss_open(dev = pa_modargs_get_value(ma, "device", DEFAULT_DEVICE), &mode, &caps)) < 0)
+        goto fail;
+
+    if (use_mmap && (!(caps & DSP_CAP_MMAP) || !(caps & DSP_CAP_TRIGGER))) {
+        pa_log_info("OSS device not mmap capable, falling back to UNIX read/write mode.");
+        use_mmap = 0;
+    }
+
+    if (use_mmap && mode == O_WRONLY) {
+        pa_log_info("Device opened for playback only, cannot do memory mapping, falling back to UNIX write() mode.");
+        use_mmap = 0;
+    }
+
+    if (pa_oss_get_hw_description(dev, hwdesc, sizeof(hwdesc)) >= 0)
+        pa_log_info("Hardware name is '%s'.", hwdesc);
     else
         hwdesc[0] = 0;
 
-    pa_log_info("device opened in %s mode.", mode == O_WRONLY ? "O_WRONLY" : (mode == O_RDONLY ? "O_RDONLY" : "O_RDWR"));
+    pa_log_info("Device opened in %s mode.", mode == O_WRONLY ? "O_WRONLY" : (mode == O_RDONLY ? "O_RDONLY" : "O_RDWR"));
 
     if (nfrags >= 2 && frag_size >= 1)
         if (pa_oss_set_fragments(fd, nfrags, frag_size) < 0)
@@ -422,152 +1217,282 @@
         pa_log("SNDCTL_DSP_GETBLKSIZE: %s", pa_cstrerror(errno));
         goto fail;
     }
-    assert(frag_size);
-    in_frag_size = out_frag_size = frag_size;
-
-    u = pa_xmalloc(sizeof(struct userdata));
-    u->core = c;
-    u->use_getospace = u->use_getispace = 0;
+    pa_assert(frag_size > 0);
+
+    u = pa_xnew0(struct userdata, 1);
+    u->core = m->core;
+    u->module = m;
+    m->userdata = u;
+    u->fd = fd;
+    u->mixer_fd = -1;
+    u->use_getospace = u->use_getispace = 1;
+    u->use_getodelay = 1;
+    u->mode = mode;
+    u->frame_size = pa_frame_size(&ss);
+    u->device_name = pa_xstrdup(dev);
+    u->in_nfrags = u->out_nfrags = u->nfrags = nfrags;
+    u->out_fragment_size = u->in_fragment_size = u->frag_size = frag_size;
+    u->use_mmap = use_mmap;
+    pa_thread_mq_init(&u->thread_mq, m->core->mainloop);
+    u->rtpoll = pa_rtpoll_new();
+    pa_rtpoll_item_new_asyncmsgq(u->rtpoll, PA_RTPOLL_EARLY, u->thread_mq.inq);
+    u->rtpoll_item = NULL;
+    build_pollfd(u);
 
     if (ioctl(fd, SNDCTL_DSP_GETISPACE, &info) >= 0) {
-        pa_log_info("input -- %u fragments of size %u.", info.fragstotal, info.fragsize);
-        in_frag_size = info.fragsize;
+        pa_log_info("Input -- %u fragments of size %u.", info.fragstotal, info.fragsize);
+        u->in_fragment_size = info.fragsize;
+        u->in_nfrags = info.fragstotal;
         u->use_getispace = 1;
     }
 
     if (ioctl(fd, SNDCTL_DSP_GETOSPACE, &info) >= 0) {
-        pa_log_info("output -- %u fragments of size %u.", info.fragstotal, info.fragsize);
-        out_frag_size = info.fragsize;
+        pa_log_info("Output -- %u fragments of size %u.", info.fragstotal, info.fragsize);
+        u->out_fragment_size = info.fragsize;
+        u->out_nfrags = info.fragstotal;
         u->use_getospace = 1;
     }
 
+    u->in_hwbuf_size = u->in_nfrags * u->in_fragment_size;
+    u->out_hwbuf_size = u->out_nfrags * u->out_fragment_size;
+
     if (mode != O_WRONLY) {
+        char *name_buf = NULL;
+
+        if (use_mmap) {
+            if ((u->in_mmap = mmap(NULL, u->in_hwbuf_size, PROT_READ, MAP_SHARED, fd, 0)) == MAP_FAILED) {
+                pa_log_warn("mmap(PROT_READ) failed, reverting to non-mmap mode: %s", pa_cstrerror(errno));
+                use_mmap = u->use_mmap = 0;
+                u->in_mmap = NULL;
+            } else
+                pa_log_debug("Successfully mmap()ed input buffer.");
+        }
+
         if ((name = pa_modargs_get_value(ma, "source_name", NULL)))
             namereg_fail = 1;
         else {
-            name = name_buf = pa_sprintf_malloc("oss_input.%s", pa_path_get_filename(p));
+            name = name_buf = pa_sprintf_malloc("oss_input.%s", pa_path_get_filename(dev));
             namereg_fail = 0;
         }
 
-        if (!(u->source = pa_source_new(c, __FILE__, name, namereg_fail, &ss, &map)))
+        u->source = pa_source_new(m->core, __FILE__, name, namereg_fail, &ss, &map);
+        pa_xfree(name_buf);
+        if (!u->source) {
+            pa_log("Failed to create source object");
             goto fail;
-
+        }
+
+        u->source->parent.process_msg = source_process_msg;
         u->source->userdata = u;
-        u->source->notify = source_notify_cb;
-        u->source->get_latency = source_get_latency_cb;
-        u->source->get_hw_volume = source_get_hw_volume;
-        u->source->set_hw_volume = source_set_hw_volume;
-        pa_source_set_owner(u->source, m);
-        pa_source_set_description(u->source, t = pa_sprintf_malloc("OSS PCM on %s%s%s%s",
-                                                                 p,
-                                                                 hwdesc[0] ? " (" : "",
-                                                                 hwdesc[0] ? hwdesc : "",
-                                                                 hwdesc[0] ? ")" : ""));
+
+        pa_source_set_module(u->source, m);
+        pa_source_set_asyncmsgq(u->source, u->thread_mq.inq);
+        pa_source_set_rtpoll(u->source, u->rtpoll);
+        pa_source_set_description(u->source, t = pa_sprintf_malloc(
+                                          "OSS PCM on %s%s%s%s%s",
+                                          dev,
+                                          hwdesc[0] ? " (" : "",
+                                          hwdesc[0] ? hwdesc : "",
+                                          hwdesc[0] ? ")" : "",
+                                          use_mmap ? " via DMA" : ""));
         pa_xfree(t);
-        u->source->is_hardware = 1;
-    } else
-        u->source = NULL;
-
-    pa_xfree(name_buf);
-    name_buf = NULL;
+        u->source->flags = PA_SOURCE_HARDWARE|PA_SOURCE_LATENCY;
+        u->source->refresh_volume = TRUE;
+
+        if (use_mmap)
+            u->in_mmap_memblocks = pa_xnew0(pa_memblock*, u->in_nfrags);
+    }
 
     if (mode != O_RDONLY) {
+        char *name_buf = NULL;
+
+        if (use_mmap) {
+            if ((u->out_mmap = mmap(NULL, u->out_hwbuf_size, PROT_WRITE, MAP_SHARED, fd, 0)) == MAP_FAILED) {
+                if (mode == O_RDWR) {
+                    pa_log_debug("mmap() failed for input. Changing to O_WRONLY mode.");
+                    mode = O_WRONLY;
+                    goto go_on;
+                } else {
+                    pa_log_warn("mmap(PROT_WRITE) failed, reverting to non-mmap mode: %s", pa_cstrerror(errno));
+                    u->use_mmap = (use_mmap = FALSE);
+                    u->out_mmap = NULL;
+                }
+            } else {
+                pa_log_debug("Successfully mmap()ed output buffer.");
+                pa_silence_memory(u->out_mmap, u->out_hwbuf_size, &ss);
+            }
+        }
+
         if ((name = pa_modargs_get_value(ma, "sink_name", NULL)))
             namereg_fail = 1;
         else {
-            name = name_buf = pa_sprintf_malloc("oss_output.%s", pa_path_get_filename(p));
+            name = name_buf = pa_sprintf_malloc("oss_output.%s", pa_path_get_filename(dev));
             namereg_fail = 0;
         }
 
-        if (!(u->sink = pa_sink_new(c, __FILE__, name, namereg_fail, &ss, &map)))
+        u->sink = pa_sink_new(m->core, __FILE__, name, namereg_fail, &ss, &map);
+        pa_xfree(name_buf);
+        if (!u->sink) {
+            pa_log("Failed to create sink object");
             goto fail;
-
-        u->sink->get_latency = sink_get_latency_cb;
-        u->sink->get_hw_volume = sink_get_hw_volume;
-        u->sink->set_hw_volume = sink_set_hw_volume;
+        }
+
+        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("OSS PCM on %s%s%s%s",
-                                                           p,
-                                                           hwdesc[0] ? " (" : "",
-                                                           hwdesc[0] ? hwdesc : "",
-                                                           hwdesc[0] ? ")" : ""));
+
+        pa_sink_set_module(u->sink, m);
+        pa_sink_set_asyncmsgq(u->sink, u->thread_mq.inq);
+        pa_sink_set_rtpoll(u->sink, u->rtpoll);
+        pa_sink_set_description(u->sink, t = pa_sprintf_malloc(
+                                        "OSS PCM on %s%s%s%s%s",
+                                        dev,
+                                        hwdesc[0] ? " (" : "",
+                                        hwdesc[0] ? hwdesc : "",
+                                        hwdesc[0] ? ")" : "",
+                                        use_mmap ? " via DMA" : ""));
         pa_xfree(t);
-        u->sink->is_hardware = 1;
-    } else
-        u->sink = NULL;
-
-    pa_xfree(name_buf);
-    name_buf = NULL;
-
-    assert(u->source || u->sink);
-
-    u->io = pa_iochannel_new(c->mainloop, u->source ? fd : -1, u->sink ? fd : -1);
-    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->out_fragment_size = out_frag_size;
-    u->in_fragment_size = in_frag_size;
-    u->silence.memblock = pa_memblock_new(u->core->mempool, u->silence.length = u->out_fragment_size);
-    assert(u->silence.memblock);
-    pa_silence_memblock(u->silence.memblock, &ss);
-    u->silence.index = 0;
-
-    u->module = m;
-    m->userdata = u;
+        u->sink->flags = PA_SINK_HARDWARE|PA_SINK_LATENCY;
+        u->sink->refresh_volume = TRUE;
+
+        if (use_mmap)
+            u->out_mmap_memblocks = pa_xnew0(pa_memblock*, u->out_nfrags);
+    }
+
+    if ((u->mixer_fd = pa_oss_open_mixer_for_device(u->device_name)) >= 0) {
+        int do_close = 1;
+        u->mixer_devmask = 0;
+
+        if (ioctl(fd, SOUND_MIXER_READ_DEVMASK, &u->mixer_devmask) < 0)
+            pa_log_warn("SOUND_MIXER_READ_DEVMASK failed: %s", pa_cstrerror(errno));
+
+        else {
+            if (u->sink && (u->mixer_devmask & (SOUND_MASK_VOLUME|SOUND_MASK_PCM))) {
+                pa_log_debug("Found hardware mixer track for playback.");
+                u->sink->flags |= PA_SINK_HW_VOLUME_CTRL;
+                u->sink->get_volume = sink_get_volume;
+                u->sink->set_volume = sink_set_volume;
+                do_close = 0;
+            }
+
+            if (u->source && (u->mixer_devmask & (SOUND_MASK_RECLEV|SOUND_MASK_IGAIN))) {
+                pa_log_debug("Found hardware mixer track for recording.");
+                u->source->flags |= PA_SOURCE_HW_VOLUME_CTRL;
+                u->source->get_volume = source_get_volume;
+                u->source->set_volume = source_set_volume;
+                do_close = 0;
+            }
+        }
+
+        if (do_close) {
+            pa_close(u->mixer_fd);
+            u->mixer_fd = -1;
+        }
+    }
+
+go_on:
+
+    pa_assert(u->source || u->sink);
+
+    pa_memchunk_reset(&u->memchunk);
+
+    if (!(u->thread = pa_thread_new(thread_func, u))) {
+        pa_log("Failed to create thread.");
+        goto fail;
+    }
+
+    /* Read mixer settings */
+    if (u->sink && u->sink->get_volume)
+        sink_get_volume(u->sink);
+    if (u->source && u->source->get_volume)
+        source_get_volume(u->source);
+
+    if (u->sink)
+        pa_sink_put(u->sink);
+    if (u->source)
+        pa_source_put(u->source);
 
     pa_modargs_free(ma);
 
-    /*
-     * Some crappy drivers do not start the recording until we read something.
-     * Without this snippet, poll will never register the fd as ready.
-     */
-    if (u->source) {
-        char *buf = pa_xnew(char, u->sample_size);
-        pa_read(u->fd, buf, u->sample_size, NULL);
-        pa_xfree(buf);
-    }
-
-    /* Read mixer settings */
-    if (u->source)
-        source_get_hw_volume(u->source);
-    if (u->sink)
-        sink_get_hw_volume(u->sink);
-
     return 0;
 
 fail:
-    if (fd >= 0)
-        close(fd);
+
+    if (u)
+        pa__done(m);
+    else if (fd >= 0)
+        pa_close(fd);
 
     if (ma)
         pa_modargs_free(ma);
 
-    pa_xfree(name_buf);
-
     return -1;
 }
 
-void pa__done(pa_core *c, pa_module*m) {
+void pa__done(pa_module*m) {
     struct userdata *u;
 
-    assert(c);
-    assert(m);
+    pa_assert(m);
 
     if (!(u = m->userdata))
         return;
 
-    clear_up(u);
+    if (u->sink)
+        pa_sink_unlink(u->sink);
+
+    if (u->source)
+        pa_source_unlink(u->source);
+
+    if (u->thread) {
+        pa_asyncmsgq_send(u->thread_mq.inq, NULL, PA_MESSAGE_SHUTDOWN, NULL, 0, NULL);
+        pa_thread_free(u->thread);
+    }
+
+    pa_thread_mq_done(&u->thread_mq);
+
+    if (u->sink)
+        pa_sink_unref(u->sink);
+
+    if (u->source)
+        pa_source_unref(u->source);
 
     if (u->memchunk.memblock)
         pa_memblock_unref(u->memchunk.memblock);
-    if (u->silence.memblock)
-        pa_memblock_unref(u->silence.memblock);
+
+    if (u->rtpoll_item)
+        pa_rtpoll_item_free(u->rtpoll_item);
+
+    if (u->rtpoll)
+        pa_rtpoll_free(u->rtpoll);
+
+    if (u->out_mmap_memblocks) {
+        unsigned i;
+        for (i = 0; i < u->out_nfrags; i++)
+            if (u->out_mmap_memblocks[i])
+                pa_memblock_unref_fixed(u->out_mmap_memblocks[i]);
+        pa_xfree(u->out_mmap_memblocks);
+    }
+
+    if (u->in_mmap_memblocks) {
+        unsigned i;
+        for (i = 0; i < u->in_nfrags; i++)
+            if (u->in_mmap_memblocks[i])
+                pa_memblock_unref_fixed(u->in_mmap_memblocks[i]);
+        pa_xfree(u->in_mmap_memblocks);
+    }
+
+    if (u->in_mmap && u->in_mmap != MAP_FAILED)
+        munmap(u->in_mmap, u->in_hwbuf_size);
+
+    if (u->out_mmap && u->out_mmap != MAP_FAILED)
+        munmap(u->out_mmap, u->out_hwbuf_size);
+
+    if (u->fd >= 0)
+        pa_close(u->fd);
+
+    if (u->mixer_fd >= 0)
+        pa_close(u->mixer_fd);
+
+    pa_xfree(u->device_name);
 
     pa_xfree(u);
 }

Modified: trunk/src/modules/module-pipe-sink.c
URL: http://0pointer.de/cgi-bin/viewcvs.cgi/trunk/src/modules/module-pipe-sink.c?rev=1971&root=pulseaudio&r1=1970&r2=1971&view=diff
==============================================================================
--- trunk/src/modules/module-pipe-sink.c (original)
+++ trunk/src/modules/module-pipe-sink.c Sun Oct 28 20:13:50 2007
@@ -28,22 +28,25 @@
 #include <stdlib.h>
 #include <sys/stat.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 <poll.h>
 
 #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>
 #include <pulsecore/modargs.h>
 #include <pulsecore/log.h>
+#include <pulsecore/thread.h>
+#include <pulsecore/thread-mq.h>
+#include <pulsecore/rtpoll.h>
 
 #include "module-pipe-sink-symdef.h"
 
@@ -58,20 +61,24 @@
         "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;
+    pa_module *module;
+    pa_sink *sink;
+
+    pa_thread *thread;
+    pa_thread_mq thread_mq;
+    pa_rtpoll *rtpoll;
 
     char *filename;
-
-    pa_sink *sink;
-    pa_iochannel *io;
-    pa_defer_event *defer_event;
+    int fd;
 
     pa_memchunk memchunk;
-    pa_module *module;
+
+    pa_rtpoll_item *rtpoll_item;
 };
 
 static const char* const valid_modargs[] = {
@@ -84,133 +91,191 @@
     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;
-    }
-
-    u->memchunk.index += r;
-    u->memchunk.length -= r;
-
-    if (u->memchunk.length <= 0) {
-        pa_memblock_unref(u->memchunk.memblock);
-        u->memchunk.memblock = NULL;
-    }
+static int sink_process_msg(pa_msgobject *o, int code, void *data, int64_t offset, pa_memchunk *chunk) {
+    struct userdata *u = PA_SINK(o)->userdata;
+
+    switch (code) {
+
+        case PA_SINK_MESSAGE_GET_LATENCY: {
+            size_t n = 0;
+            int l;
+
+#ifdef TIOCINQ
+            if (ioctl(u->fd, TIOCINQ, &l) >= 0 && l > 0)
+                n = (size_t) l;
+#endif
+
+            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, offset, chunk);
 }
 
-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 void thread_func(void *userdata) {
+    struct userdata *u = userdata;
+    int write_type = 0;
+
+    pa_assert(u);
+
+    pa_log_debug("Thread starting up");
+
+    pa_thread_mq_install(&u->thread_mq);
+    pa_rtpoll_install(u->rtpoll);
+
+    for (;;) {
+        struct pollfd *pollfd;
+        int ret;
+
+        pollfd = pa_rtpoll_item_get_pollfd(u->rtpoll_item, NULL);
+
+        /* Render some data and write it to the fifo */
+        if (u->sink->thread_info.state == PA_SINK_RUNNING && pollfd->revents) {
+            ssize_t l;
+            void *p;
+
+            if (u->memchunk.length <= 0)
+                pa_sink_render(u->sink, PIPE_BUF, &u->memchunk);
+
+            pa_assert(u->memchunk.length > 0);
+
+            p = pa_memblock_acquire(u->memchunk.memblock);
+            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)
+                    continue;
+                else if (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);
+                    pa_memchunk_reset(&u->memchunk);
+                }
+
+                pollfd->revents = 0;
+            }
+        }
+
+        /* Hmm, nothing to do. Let's sleep */
+        pollfd->events = u->sink->thread_info.state == PA_SINK_RUNNING ? POLLOUT : 0;
+
+        if ((ret = pa_rtpoll_run(u->rtpoll, TRUE)) < 0)
+            goto fail;
+
+        if (ret == 0)
+            goto finish;
+
+        pollfd = pa_rtpoll_item_get_pollfd(u->rtpoll_item, NULL);
+
+        if (pollfd->revents & ~POLLOUT) {
+            pa_log("FIFO shutdown.");
+            goto fail;
+        }
+    }
+
+fail:
+    /* If this was no regular exit from the loop we have to continue
+     * processing messages until we received PA_MESSAGE_SHUTDOWN */
+    pa_asyncmsgq_post(u->thread_mq.outq, PA_MSGOBJECT(u->core), PA_CORE_MESSAGE_UNLOAD_MODULE, u->module, 0, NULL, NULL);
+    pa_asyncmsgq_wait_for(u->thread_mq.inq, PA_MESSAGE_SHUTDOWN);
+
+finish:
+    pa_log_debug("Thread shutting down");
 }
 
-static 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);
-}
-
-static void io_callback(PA_GCC_UNUSED pa_iochannel *io, void*userdata) {
-    struct userdata *u = userdata;
-    assert(u);
-    do_write(u);
-}
-
-int pa__init(pa_core *c, pa_module*m) {
-    struct userdata *u = NULL;
+int pa__init(pa_module*m) {
+    struct userdata *u;
     struct stat st;
-    const char *p;
-    int fd = -1;
     pa_sample_spec ss;
     pa_channel_map map;
-    pa_modargs *ma = NULL;
+    pa_modargs *ma;
     char *t;
-
-    assert(c && m);
+    struct pollfd *pollfd;
+
+    pa_assert(m);
 
     if (!(ma = pa_modargs_new(m->argument, valid_modargs))) {
-        pa_log("failed to parse module arguments");
-        goto fail;
-    }
-
-    ss = c->default_sample_spec;
+        pa_log("Failed to parse module arguments.");
+        goto fail;
+    }
+
+    ss = m->core->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");
-        goto fail;
-    }
-
-    mkfifo(p = pa_modargs_get_value(ma, "file", DEFAULT_FIFO_NAME), 0777);
-
-    if ((fd = open(p, O_RDWR)) < 0) {
-        pa_log("open('%s'): %s", p, pa_cstrerror(errno));
-        goto fail;
-    }
-
-    pa_fd_set_cloexec(fd, 1);
-
-    if (fstat(fd, &st) < 0) {
-        pa_log("fstat('%s'): %s", p, pa_cstrerror(errno));
-        goto fail;
-    }
-
-    if (!S_ISFIFO(st.st_mode)) {
-        pa_log("'%s' is not a FIFO.", p);
-        goto fail;
-    }
-
-    u = pa_xmalloc0(sizeof(struct userdata));
-    u->filename = pa_xstrdup(p);
-    u->core = c;
+        pa_log("Invalid sample format specification or channel map");
+        goto fail;
+    }
+
+    u = pa_xnew0(struct userdata, 1);
+    u->core = m->core;
     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.");
-        goto fail;
-    }
-    u->sink->notify = notify_cb;
-    u->sink->get_latency = get_latency_cb;
+    pa_memchunk_reset(&u->memchunk);
+    pa_thread_mq_init(&u->thread_mq, m->core->mainloop);
+    u->rtpoll = pa_rtpoll_new();
+    pa_rtpoll_item_new_asyncmsgq(u->rtpoll, PA_RTPOLL_EARLY, u->thread_mq.inq);
+
+    u->filename = pa_xstrdup(pa_modargs_get_value(ma, "file", DEFAULT_FILE_NAME));
+
+    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;
+    }
+
+    pa_make_fd_cloexec(u->fd);
+    pa_make_fd_nonblock(u->fd);
+
+    if (fstat(u->fd, &st) < 0) {
+        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.", u->filename);
+        goto fail;
+    }
+
+    if (!(u->sink = pa_sink_new(m->core, __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_description(u->sink, t = pa_sprintf_malloc("Unix FIFO sink '%s'", p));
+    u->sink->flags = PA_SINK_LATENCY;
+
+    pa_sink_set_module(u->sink, m);
+    pa_sink_set_asyncmsgq(u->sink, u->thread_mq.inq);
+    pa_sink_set_rtpoll(u->sink, u->rtpoll);
+    pa_sink_set_description(u->sink, t = pa_sprintf_malloc("Unix FIFO sink '%s'", u->filename));
     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);
+    u->rtpoll_item = pa_rtpoll_item_new(u->rtpoll, PA_RTPOLL_NEVER, 1);
+    pollfd = pa_rtpoll_item_get_pollfd(u->rtpoll_item, NULL);
+    pollfd->fd = u->fd;
+    pollfd->events = pollfd->revents = 0;
+
+    if (!(u->thread = pa_thread_new(thread_func, u))) {
+        pa_log("Failed to create thread.");
+        goto fail;
+    }
+
+    pa_sink_put(u->sink);
 
     pa_modargs_free(ma);
 
@@ -220,32 +285,48 @@
     if (ma)
         pa_modargs_free(ma);
 
-    if (fd >= 0)
-        close(fd);
-
-    pa__done(c, m);
+    pa__done(m);
 
     return -1;
 }
 
-void pa__done(pa_core *c, pa_module*m) {
+void pa__done(pa_module*m) {
     struct userdata *u;
-    assert(c && m);
+
+    pa_assert(m);
 
     if (!(u = m->userdata))
         return;
 
+    if (u->sink)
+        pa_sink_unlink(u->sink);
+
+    if (u->thread) {
+        pa_asyncmsgq_send(u->thread_mq.inq, NULL, PA_MESSAGE_SHUTDOWN, NULL, 0, NULL);
+        pa_thread_free(u->thread);
+    }
+
+    pa_thread_mq_done(&u->thread_mq);
+
+    if (u->sink)
+        pa_sink_unref(u->sink);
+
     if (u->memchunk.memblock)
-        pa_memblock_unref(u->memchunk.memblock);
-
-    pa_sink_disconnect(u->sink);
-    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);
+       pa_memblock_unref(u->memchunk.memblock);
+
+    if (u->rtpoll_item)
+        pa_rtpoll_item_free(u->rtpoll_item);
+
+    if (u->rtpoll)
+        pa_rtpoll_free(u->rtpoll);
+
+    if (u->filename) {
+        unlink(u->filename);
+        pa_xfree(u->filename);
+    }
+
+    if (u->fd >= 0)
+        pa_assert_se(pa_close(u->fd) == 0);
 
     pa_xfree(u);
 }

Modified: trunk/src/modules/module-pipe-source.c
URL: http://0pointer.de/cgi-bin/viewcvs.cgi/trunk/src/modules/module-pipe-source.c?rev=1971&root=pulseaudio&r1=1970&r2=1971&view=diff
==============================================================================
--- trunk/src/modules/module-pipe-source.c (original)
+++ trunk/src/modules/module-pipe-source.c Sun Oct 28 20:13:50 2007
@@ -28,22 +28,24 @@
 #include <stdlib.h>
 #include <sys/stat.h>
 #include <stdio.h>
-#include <assert.h>
 #include <errno.h>
 #include <string.h>
 #include <fcntl.h>
 #include <unistd.h>
 #include <limits.h>
+#include <sys/poll.h>
 
 #include <pulse/xmalloc.h>
 
 #include <pulsecore/core-error.h>
-#include <pulsecore/iochannel.h>
 #include <pulsecore/source.h>
 #include <pulsecore/module.h>
 #include <pulsecore/core-util.h>
 #include <pulsecore/modargs.h>
 #include <pulsecore/log.h>
+#include <pulsecore/thread.h>
+#include <pulsecore/thread-mq.h>
+#include <pulsecore/rtpoll.h>
 
 #include "module-pipe-source-symdef.h"
 
@@ -58,18 +60,24 @@
         "rate=<sample rate> "
         "channel_map=<channel map>")
 
-#define DEFAULT_FIFO_NAME "/tmp/music.input"
+#define DEFAULT_FILE_NAME "/tmp/music.input"
 #define DEFAULT_SOURCE_NAME "fifo_input"
 
 struct userdata {
     pa_core *core;
+    pa_module *module;
+    pa_source *source;
+
+    pa_thread *thread;
+    pa_thread_mq thread_mq;
+    pa_rtpoll *rtpoll;
 
     char *filename;
-
-    pa_source *source;
-    pa_iochannel *io;
-    pa_module *module;
-    pa_memchunk chunk;
+    int fd;
+
+    pa_memchunk memchunk;
+
+    pa_rtpoll_item *rtpoll_item;
 };
 
 static const char* const valid_modargs[] = {
@@ -82,109 +90,168 @@
     NULL
 };
 
-static void do_read(struct userdata *u) {
-    ssize_t r;
-    pa_memchunk chunk;
-    assert(u);
-
-    if (!pa_iochannel_is_readable(u->io))
-        return;
-
-    pa_module_set_used(u->module, pa_idxset_size(u->source->outputs));
-
-    if (!u->chunk.memblock) {
-        u->chunk.memblock = pa_memblock_new(u->core->mempool, PIPE_BUF);
-        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) {
-        pa_log("read(): %s", pa_cstrerror(errno));
-        return;
-    }
-
-    u->chunk.length = r;
-    pa_source_post(u->source, &u->chunk);
-    u->chunk.index += r;
-
-    if (u->chunk.index >= u->chunk.memblock->length) {
-        u->chunk.index = u->chunk.length = 0;
-        pa_memblock_unref(u->chunk.memblock);
-        u->chunk.memblock = NULL;
-    }
+static void thread_func(void *userdata) {
+    struct userdata *u = userdata;
+    int read_type = 0;
+
+    pa_assert(u);
+
+    pa_log_debug("Thread starting up");
+
+    pa_thread_mq_install(&u->thread_mq);
+    pa_rtpoll_install(u->rtpoll);
+
+    for (;;) {
+        int ret;
+        struct pollfd *pollfd;
+
+        pollfd = pa_rtpoll_item_get_pollfd(u->rtpoll_item, NULL);
+
+        /* Try to read some data and pass it on to the source driver */
+        if (u->source->thread_info.state == PA_SOURCE_RUNNING && pollfd->revents) {
+            ssize_t l;
+            void *p;
+
+            if (!u->memchunk.memblock) {
+                u->memchunk.memblock = pa_memblock_new(u->core->mempool, PIPE_BUF);
+                u->memchunk.index = u->memchunk.length = 0;
+            }
+
+            pa_assert(pa_memblock_get_length(u->memchunk.memblock) > u->memchunk.index);
+
+            p = pa_memblock_acquire(u->memchunk.memblock);
+            l = pa_read(u->fd, (uint8_t*) p + u->memchunk.index, pa_memblock_get_length(u->memchunk.memblock) - u->memchunk.index, &read_type);
+            pa_memblock_release(u->memchunk.memblock);
+
+            pa_assert(l != 0); /* EOF cannot happen, since we opened the fifo for both reading and writing */
+
+            if (l < 0) {
+
+                if (errno == EINTR)
+                    continue;
+                else if (errno != EAGAIN) {
+                    pa_log("Faile to read data from FIFO: %s", pa_cstrerror(errno));
+                    goto fail;
+                }
+
+            } else {
+
+                u->memchunk.length = l;
+                pa_source_post(u->source, &u->memchunk);
+                u->memchunk.index += l;
+
+                if (u->memchunk.index >= pa_memblock_get_length(u->memchunk.memblock)) {
+                    pa_memblock_unref(u->memchunk.memblock);
+                    pa_memchunk_reset(&u->memchunk);
+                }
+
+                pollfd->revents = 0;
+            }
+        }
+
+        /* Hmm, nothing to do. Let's sleep */
+        pollfd->events = u->source->thread_info.state == PA_SOURCE_RUNNING ? POLLIN : 0;
+
+        if ((ret = pa_rtpoll_run(u->rtpoll, 1)) < 0)
+            goto fail;
+
+        if (ret == 0)
+            goto finish;
+
+        pollfd = pa_rtpoll_item_get_pollfd(u->rtpoll_item, NULL);
+        if (pollfd->revents & ~POLLIN) {
+            pa_log("FIFO shutdown.");
+            goto fail;
+        }
+    }
+
+fail:
+    /* If this was no regular exit from the loop we have to continue
+     * processing messages until we received PA_MESSAGE_SHUTDOWN */
+    pa_asyncmsgq_post(u->thread_mq.outq, PA_MSGOBJECT(u->core), PA_CORE_MESSAGE_UNLOAD_MODULE, u->module, 0, NULL, NULL);
+    pa_asyncmsgq_wait_for(u->thread_mq.inq, PA_MESSAGE_SHUTDOWN);
+
+finish:
+    pa_log_debug("Thread shutting down");
 }
 
-static void io_callback(PA_GCC_UNUSED pa_iochannel *io, void*userdata) {
-    struct userdata *u = userdata;
-    assert(u);
-    do_read(u);
-}
-
-int pa__init(pa_core *c, pa_module*m) {
-    struct userdata *u = NULL;
+int pa__init(pa_module*m) {
+    struct userdata *u;
     struct stat st;
-    const char *p;
-    int fd = -1;
     pa_sample_spec ss;
     pa_channel_map map;
-    pa_modargs *ma = NULL;
+    pa_modargs *ma;
     char *t;
-
-    assert(c && m);
+    struct pollfd *pollfd;
+
+    pa_assert(m);
 
     if (!(ma = pa_modargs_new(m->argument, valid_modargs))) {
-        pa_log("failed to parse module arguments");
-        goto fail;
-    }
-
-    ss = c->default_sample_spec;
+        pa_log("failed to parse module arguments.");
+        goto fail;
+    }
+
+    ss = m->core->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");
         goto fail;
     }
 
-    mkfifo(p = pa_modargs_get_value(ma, "file", DEFAULT_FIFO_NAME), 0777);
-
-    if ((fd = open(p, O_RDWR)) < 0) {
-        pa_log("open('%s'): %s", p, pa_cstrerror(errno));
-        goto fail;
-    }
-
-    pa_fd_set_cloexec(fd, 1);
-
-    if (fstat(fd, &st) < 0) {
-        pa_log("fstat('%s'): %s", p, pa_cstrerror(errno));
-        goto fail;
-    }
-
-    if (!S_ISFIFO(st.st_mode)) {
-        pa_log("'%s' is not a FIFO.", p);
-        goto fail;
-    }
-
-    u = pa_xmalloc0(sizeof(struct userdata));
-
-    u->filename = pa_xstrdup(p);
-    u->core = c;
-
-    if (!(u->source = pa_source_new(c, __FILE__, pa_modargs_get_value(ma, "source_name", DEFAULT_SOURCE_NAME), 0, &ss, &map))) {
-        pa_log("failed to create source.");
-        goto fail;
-    }
-    u->source->userdata = u;
-    pa_source_set_owner(u->source, m);
-    pa_source_set_description(u->source, t = pa_sprintf_malloc("Unix FIFO source '%s'", p));
-    pa_xfree(t);
-
-    u->io = pa_iochannel_new(c->mainloop, fd, -1);
-    assert(u->io);
-    pa_iochannel_set_callback(u->io, io_callback, u);
-
-    u->chunk.memblock = NULL;
-    u->chunk.index = u->chunk.length = 0;
-
+    u = pa_xnew0(struct userdata, 1);
+    u->core = m->core;
     u->module = m;
     m->userdata = u;
+    pa_memchunk_reset(&u->memchunk);
+    pa_thread_mq_init(&u->thread_mq, m->core->mainloop);
+    u->rtpoll = pa_rtpoll_new();
+    pa_rtpoll_item_new_asyncmsgq(u->rtpoll, PA_RTPOLL_EARLY, u->thread_mq.inq);
+
+    u->filename = pa_xstrdup(pa_modargs_get_value(ma, "file", DEFAULT_FILE_NAME));
+
+    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;
+    }
+
+    pa_make_fd_cloexec(u->fd);
+    pa_make_fd_nonblock(u->fd);
+
+    if (fstat(u->fd, &st) < 0) {
+        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.", u->filename);
+        goto fail;
+    }
+
+    if (!(u->source = pa_source_new(m->core, __FILE__, pa_modargs_get_value(ma, "source_name", DEFAULT_SOURCE_NAME), 0, &ss, &map))) {
+        pa_log("Failed to create source.");
+        goto fail;
+    }
+
+    u->source->userdata = u;
+    u->source->flags = 0;
+
+    pa_source_set_module(u->source, m);
+    pa_source_set_asyncmsgq(u->source, u->thread_mq.inq);
+    pa_source_set_rtpoll(u->source, u->rtpoll);
+    pa_source_set_description(u->source, t = pa_sprintf_malloc("Unix FIFO source '%s'", u->filename));
+    pa_xfree(t);
+
+    u->rtpoll_item = pa_rtpoll_item_new(u->rtpoll, PA_RTPOLL_NEVER, 1);
+    pollfd = pa_rtpoll_item_get_pollfd(u->rtpoll_item, NULL);
+    pollfd->fd = u->fd;
+    pollfd->events = pollfd->revents = 0;
+
+    if (!(u->thread = pa_thread_new(thread_func, u))) {
+        pa_log("Failed to create thread.");
+        goto fail;
+    }
+
+    pa_source_put(u->source);
 
     pa_modargs_free(ma);
 
@@ -194,31 +261,48 @@
     if (ma)
         pa_modargs_free(ma);
 
-    if (fd >= 0)
-        close(fd);
-
-    pa__done(c, m);
+    pa__done(m);
 
     return -1;
 }
 
-void pa__done(pa_core *c, pa_module*m) {
+void pa__done(pa_module*m) {
     struct userdata *u;
-    assert(c && m);
+
+    pa_assert(m);
 
     if (!(u = m->userdata))
         return;
 
-    if (u->chunk.memblock)
-        pa_memblock_unref(u->chunk.memblock);
-
-    pa_source_disconnect(u->source);
-    pa_source_unref(u->source);
-    pa_iochannel_free(u->io);
-
-    assert(u->filename);
-    unlink(u->filename);
-    pa_xfree(u->filename);
+    if (u->source)
+        pa_source_unlink(u->source);
+
+    if (u->thread) {
+        pa_asyncmsgq_send(u->thread_mq.inq, NULL, PA_MESSAGE_SHUTDOWN, NULL, 0, NULL);
+        pa_thread_free(u->thread);
+    }
+
+    pa_thread_mq_done(&u->thread_mq);
+
+    if (u->source)
+        pa_source_unref(u->source);
+
+    if (u->memchunk.memblock)
+        pa_memblock_unref(u->memchunk.memblock);
+
+    if (u->rtpoll_item)
+        pa_rtpoll_item_free(u->rtpoll_item);
+
+    if (u->rtpoll)
+        pa_rtpoll_free(u->rtpoll);
+
+    if (u->filename) {
+        unlink(u->filename);
+        pa_xfree(u->filename);
+    }
+
+    if (u->fd >= 0)
+        pa_assert_se(pa_close(u->fd) == 0);
 
     pa_xfree(u);
 }

Modified: trunk/src/modules/module-protocol-stub.c
URL: http://0pointer.de/cgi-bin/viewcvs.cgi/trunk/src/modules/module-protocol-stub.c?rev=1971&root=pulseaudio&r1=1970&r2=1971&view=diff
==============================================================================
--- trunk/src/modules/module-protocol-stub.c (original)
+++ trunk/src/modules/module-protocol-stub.c Sun Oct 28 20:13:50 2007
@@ -29,7 +29,6 @@
 #include <string.h>
 #include <errno.h>
 #include <stdio.h>
-#include <assert.h>
 #include <unistd.h>
 #include <limits.h>
 
@@ -43,10 +42,9 @@
 #include <netinet/in.h>
 #endif
 
-#include "../pulsecore/winsock.h"
-
 #include <pulse/xmalloc.h>
 
+#include <pulsecore/winsock.h>
 #include <pulsecore/core-error.h>
 #include <pulsecore/module.h>
 #include <pulsecore/socket-server.h>
@@ -154,7 +152,6 @@
   #define protocol_free pa_protocol_esound_free
   #define TCPWRAP_SERVICE "esound"
   #define IPV4_PORT ESD_DEFAULT_PORT
-  #define UNIX_SOCKET ESD_UNIX_SOCKET_NAME
   #define MODULE_ARGUMENTS_COMMON "sink", "source", "auth-anonymous", "cookie",
   #ifdef USE_TCP_SOCKETS
     #include "module-esound-protocol-tcp-symdef.h"
@@ -205,10 +202,9 @@
 #endif
 };
 
-int pa__init(pa_core *c, pa_module*m) {
+int pa__init(pa_module*m) {
     pa_modargs *ma = NULL;
     int ret = -1;
-
     struct userdata *u = NULL;
 
 #if defined(USE_TCP_SOCKETS)
@@ -219,9 +215,13 @@
     pa_socket_server *s;
     int r;
     char tmp[PATH_MAX];
-#endif
-
-    assert(c && m);
+
+#if defined(USE_PROTOCOL_ESOUND)
+    char tmp2[PATH_MAX];
+#endif
+#endif
+
+    pa_assert(m);
 
     if (!(ma = pa_modargs_new(m->argument, valid_modargs))) {
         pa_log("Failed to parse module arguments");
@@ -239,22 +239,22 @@
     listen_on = pa_modargs_get_value(ma, "listen", NULL);
 
     if (listen_on) {
-        s_ipv6 = pa_socket_server_new_ipv6_string(c->mainloop, listen_on, port, TCPWRAP_SERVICE);
-        s_ipv4 = pa_socket_server_new_ipv4_string(c->mainloop, listen_on, port, TCPWRAP_SERVICE);
+        s_ipv6 = pa_socket_server_new_ipv6_string(m->core->mainloop, listen_on, port, TCPWRAP_SERVICE);
+        s_ipv4 = pa_socket_server_new_ipv4_string(m->core->mainloop, listen_on, port, TCPWRAP_SERVICE);
     } else {
-        s_ipv6 = pa_socket_server_new_ipv6_any(c->mainloop, port, TCPWRAP_SERVICE);
-        s_ipv4 = pa_socket_server_new_ipv4_any(c->mainloop, port, TCPWRAP_SERVICE);
+        s_ipv6 = pa_socket_server_new_ipv6_any(m->core->mainloop, port, TCPWRAP_SERVICE);
+        s_ipv4 = pa_socket_server_new_ipv4_any(m->core->mainloop, port, TCPWRAP_SERVICE);
     }
 
     if (!s_ipv4 && !s_ipv6)
         goto fail;
 
     if (s_ipv4)
-        if (!(u->protocol_ipv4 = protocol_new(c, s_ipv4, m, ma)))
+        if (!(u->protocol_ipv4 = protocol_new(m->core, s_ipv4, m, ma)))
             pa_socket_server_unref(s_ipv4);
 
     if (s_ipv6)
-        if (!(u->protocol_ipv6 = protocol_new(c, s_ipv6, m, ma)))
+        if (!(u->protocol_ipv6 = protocol_new(m->core, s_ipv6, m, ma)))
             pa_socket_server_unref(s_ipv6);
 
     if (!u->protocol_ipv4 && !u->protocol_ipv6)
@@ -262,18 +262,23 @@
 
 #else
 
+#if defined(USE_PROTOCOL_ESOUND)
+
+    snprintf(tmp2, sizeof(tmp2), "/tmp/.esd-%lu/socket", (unsigned long) getuid());
+    pa_runtime_path(pa_modargs_get_value(ma, "socket", tmp2), tmp, sizeof(tmp));
+    u->socket_path = pa_xstrdup(tmp);
+
+    /* This socket doesn't reside in our own runtime dir but in
+     * /tmp/.esd/, hence we have to create the dir first */
+
+    if (pa_make_secure_parent_dir(u->socket_path, m->core->is_system_instance ? 0755 : 0700, (uid_t)-1, (gid_t)-1) < 0) {
+        pa_log("Failed to create socket directory '%s': %s\n", u->socket_path, pa_cstrerror(errno));
+        goto fail;
+    }
+
+#else
     pa_runtime_path(pa_modargs_get_value(ma, "socket", UNIX_SOCKET), tmp, sizeof(tmp));
     u->socket_path = pa_xstrdup(tmp);
-
-#if defined(USE_PROTOCOL_ESOUND)
-
-    /* This socket doesn't reside in our own runtime dir but in
-     * /tmp/.esd/, hence we have to create the dir first */
-
-    if (pa_make_secure_parent_dir(u->socket_path, c->is_system_instance ? 0755 : 0700, (uid_t)-1, (gid_t)-1) < 0) {
-        pa_log("Failed to create socket directory '%s': %s\n", u->socket_path, pa_cstrerror(errno));
-        goto fail;
-    }
 #endif
 
     if ((r = pa_unix_socket_remove_stale(tmp)) < 0) {
@@ -284,10 +289,10 @@
     if (r)
         pa_log("Removed stale UNIX socket '%s'.", tmp);
 
-    if (!(s = pa_socket_server_new_unix(c->mainloop, tmp)))
-        goto fail;
-
-    if (!(u->protocol_unix = protocol_new(c, s, m, ma)))
+    if (!(s = pa_socket_server_new_unix(m->core->mainloop, tmp)))
+        goto fail;
+
+    if (!(u->protocol_unix = protocol_new(m->core, s, m, ma)))
         goto fail;
 
 #endif
@@ -333,11 +338,10 @@
     goto finish;
 }
 
-void pa__done(pa_core *c, pa_module*m) {
+void pa__done(pa_module*m) {
     struct userdata *u;
 
-    assert(c);
-    assert(m);
+    pa_assert(m);
 
     u = m->userdata;
 
@@ -358,7 +362,6 @@
     }
 #endif
 
-
     pa_xfree(u->socket_path);
 #endif
 

Modified: trunk/src/modules/module-rescue-streams.c
URL: http://0pointer.de/cgi-bin/viewcvs.cgi/trunk/src/modules/module-rescue-streams.c?rev=1971&root=pulseaudio&r1=1970&r2=1971&view=diff
==============================================================================
--- trunk/src/modules/module-rescue-streams.c (original)
+++ trunk/src/modules/module-rescue-streams.c Sun Oct 28 20:13:50 2007
@@ -52,20 +52,26 @@
     pa_sink_input *i;
     pa_sink *target;
 
-    assert(c);
-    assert(sink);
+    pa_assert(c);
+    pa_assert(sink);
 
     if (!pa_idxset_size(sink->inputs)) {
         pa_log_debug("No sink inputs to move away.");
         return PA_HOOK_OK;
     }
 
-    if (!(target = pa_namereg_get(c, NULL, PA_NAMEREG_SINK, 0))) {
-        pa_log_info("No evacuation sink found.");
-        return PA_HOOK_OK;
+    if (!(target = pa_namereg_get(c, NULL, PA_NAMEREG_SINK, 0)) || target == sink) {
+        uint32_t idx;
+
+        for (target = pa_idxset_first(c->sinks, &idx); target; target = pa_idxset_next(c->sinks, &idx))
+            if (target != sink)
+                break;
+
+        if (!target) {
+            pa_log_info("No evacuation sink found.");
+            return PA_HOOK_OK;
+        }
     }
-
-    assert(target != sink);
 
     while ((i = pa_idxset_first(sink->inputs, NULL))) {
         if (pa_sink_input_move_to(i, target, 1) < 0) {
@@ -84,20 +90,28 @@
     pa_source_output *o;
     pa_source *target;
 
-    assert(c);
-    assert(source);
+    pa_assert(c);
+    pa_assert(source);
 
     if (!pa_idxset_size(source->outputs)) {
         pa_log_debug("No source outputs to move away.");
         return PA_HOOK_OK;
     }
 
-    if (!(target = pa_namereg_get(c, NULL, PA_NAMEREG_SOURCE, 0))) {
-        pa_log_info("No evacuation source found.");
-        return PA_HOOK_OK;
+    if (!(target = pa_namereg_get(c, NULL, PA_NAMEREG_SOURCE, 0)) || target == source) {
+        uint32_t idx;
+
+        for (target = pa_idxset_first(c->sources, &idx); target; target = pa_idxset_next(c->sources, &idx))
+            if (target != source && !target->monitor_of == !source->monitor_of)
+                break;
+
+        if (!target) {
+            pa_log_info("No evacuation source found.");
+            return PA_HOOK_OK;
+        }
     }
 
-    assert(target != source);
+    pa_assert(target != source);
 
     while ((o = pa_idxset_first(source->outputs, NULL))) {
         if (pa_source_output_move_to(o, target) < 0) {
@@ -112,12 +126,11 @@
     return PA_HOOK_OK;
 }
 
-int pa__init(pa_core *c, pa_module*m) {
+int pa__init(pa_module*m) {
     pa_modargs *ma = NULL;
     struct userdata *u;
 
-    assert(c);
-    assert(m);
+    pa_assert(m);
 
     if (!(ma = pa_modargs_new(m->argument, valid_modargs))) {
         pa_log("Failed to parse module arguments");
@@ -125,18 +138,17 @@
     }
 
     m->userdata = u = pa_xnew(struct userdata, 1);
-    u->sink_slot = pa_hook_connect(&c->hook_sink_disconnect, (pa_hook_cb_t) sink_hook_callback, NULL);
-    u->source_slot = pa_hook_connect(&c->hook_source_disconnect, (pa_hook_cb_t) source_hook_callback, NULL);
+    u->sink_slot = pa_hook_connect(&m->core->hooks[PA_CORE_HOOK_SINK_UNLINK], (pa_hook_cb_t) sink_hook_callback, NULL);
+    u->source_slot = pa_hook_connect(&m->core->hooks[PA_CORE_HOOK_SOURCE_UNLINK], (pa_hook_cb_t) source_hook_callback, NULL);
 
     pa_modargs_free(ma);
     return 0;
 }
 
-void pa__done(pa_core *c, pa_module*m) {
+void pa__done(pa_module*m) {
     struct userdata *u;
 
-    assert(c);
-    assert(m);
+    pa_assert(m);
 
     if (!m->userdata)
         return;

Modified: trunk/src/modules/module-sine.c
URL: http://0pointer.de/cgi-bin/viewcvs.cgi/trunk/src/modules/module-sine.c?rev=1971&root=pulseaudio&r1=1970&r2=1971&view=diff
==============================================================================
--- trunk/src/modules/module-sine.c (original)
+++ trunk/src/modules/module-sine.c Sun Oct 28 20:13:50 2007
@@ -26,7 +26,6 @@
 #endif
 
 #include <stdio.h>
-#include <assert.h>
 #include <math.h>
 
 #include <pulse/xmalloc.h>
@@ -36,6 +35,7 @@
 #include <pulsecore/modargs.h>
 #include <pulsecore/namereg.h>
 #include <pulsecore/log.h>
+#include <pulsecore/core-util.h>
 
 #include "module-sine-symdef.h"
 
@@ -58,36 +58,46 @@
     NULL,
 };
 
-static int sink_input_peek(pa_sink_input *i, pa_memchunk *chunk) {
-    struct userdata *u;
-    assert(i && chunk && i->userdata);
+static int sink_input_peek_cb(pa_sink_input *i, size_t length, pa_memchunk *chunk) {
+    struct userdata *u;
+
+    pa_assert(i);
     u = i->userdata;
+    pa_assert(u);
+    pa_assert(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;
 }
 
-static void sink_input_drop(pa_sink_input *i, const pa_memchunk *chunk, size_t length) {
-    struct userdata *u;
-    assert(i && chunk && length && i->userdata);
+static void sink_input_drop_cb(pa_sink_input *i, size_t length) {
+    struct userdata *u;
+    size_t l;
+
+    pa_assert(i);
     u = i->userdata;
-
-    assert(chunk->memblock == u->memblock && length <= u->memblock->length-u->peek_index);
+    pa_assert(u);
+    pa_assert(length > 0);
 
     u->peek_index += length;
 
-    if (u->peek_index >= u->memblock->length)
-        u->peek_index = 0;
-}
-
-static void sink_input_kill(pa_sink_input *i) {
-    struct userdata *u;
-    assert(i && i->userdata);
+    l = pa_memblock_get_length(u->memblock);
+
+    while (u->peek_index >= l)
+        u->peek_index -= l;
+}
+
+static void sink_input_kill_cb(pa_sink_input *i) {
+    struct userdata *u;
+
+    pa_assert(i);
     u = i->userdata;
-
-    pa_sink_input_disconnect(u->sink_input);
+    pa_assert(u);
+
+    pa_sink_input_unlink(u->sink_input);
     pa_sink_input_unref(u->sink_input);
     u->sink_input = NULL;
 
@@ -103,14 +113,14 @@
         f[i] = (float) sin((double) i/l*M_PI*2*freq)/2;
 }
 
-int pa__init(pa_core *c, pa_module*m) {
+int pa__init(pa_module*m) {
     pa_modargs *ma = NULL;
     struct userdata *u;
     pa_sink *sink;
-    const char *sink_name;
     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))) {
@@ -118,15 +128,14 @@
         goto fail;
     }
 
-    m->userdata = u = pa_xmalloc(sizeof(struct userdata));
-    u->core = c;
+    m->userdata = u = pa_xnew0(struct userdata, 1);
+    u->core = m->core;
     u->module = m;
     u->sink_input = NULL;
     u->memblock = NULL;
-
-    sink_name = pa_modargs_get_value(ma, "sink", NULL);
-
-    if (!(sink = pa_namereg_get(c, sink_name, PA_NAMEREG_SINK, 1))) {
+    u->peek_index = 0;
+
+    if (!(sink = pa_namereg_get(m->core, pa_modargs_get_value(ma, "sink", NULL), PA_NAMEREG_SINK, 1))) {
         pa_log("No such sink.");
         goto fail;
     }
@@ -141,10 +150,12 @@
         goto fail;
     }
 
-    u->memblock = pa_memblock_new(c->mempool, pa_bytes_per_second(&ss));
-    calc_sine(u->memblock->data, u->memblock->length, frequency);
-
-    snprintf(t, sizeof(t), "Sine Generator at %u Hz", frequency);
+    u->memblock = pa_memblock_new(m->core->mempool, pa_bytes_per_second(&ss));
+    p = pa_memblock_acquire(u->memblock);
+    calc_sine(p, pa_memblock_get_length(u->memblock), frequency);
+    pa_memblock_release(u->memblock);
+
+    pa_snprintf(t, sizeof(t), "Sine Generator at %u Hz", frequency);
 
     pa_sink_input_new_data_init(&data);
     data.sink = sink;
@@ -153,15 +164,15 @@
     pa_sink_input_new_data_set_sample_spec(&data, &ss);
     data.module = m;
 
-    if (!(u->sink_input = pa_sink_input_new(c, &data, 0)))
-        goto fail;
-
-    u->sink_input->peek = sink_input_peek;
-    u->sink_input->drop = sink_input_drop;
-    u->sink_input->kill = sink_input_kill;
+    if (!(u->sink_input = pa_sink_input_new(m->core, &data, 0)))
+        goto fail;
+
+    u->sink_input->peek = sink_input_peek_cb;
+    u->sink_input->drop = sink_input_drop_cb;
+    u->sink_input->kill = sink_input_kill_cb;
     u->sink_input->userdata = u;
 
-    u->peek_index = 0;
+    pa_sink_input_put(u->sink_input);
 
     pa_modargs_free(ma);
     return 0;
@@ -170,24 +181,26 @@
     if (ma)
         pa_modargs_free(ma);
 
-    pa__done(c, m);
+    pa__done(m);
     return -1;
 }
 
-void pa__done(pa_core *c, pa_module*m) {
-    struct userdata *u = m->userdata;
-    assert(c && m);
-
-    if (!u)
+void pa__done(pa_module*m) {
+    struct userdata *u;
+
+    pa_assert(m);
+
+    if (!(u = m->userdata))
         return;
 
     if (u->sink_input) {
-        pa_sink_input_disconnect(u->sink_input);
+        pa_sink_input_unlink(u->sink_input);
         pa_sink_input_unref(u->sink_input);
     }
 
     if (u->memblock)
         pa_memblock_unref(u->memblock);
+
     pa_xfree(u);
 }
 

Modified: trunk/src/modules/module-solaris.c
URL: http://0pointer.de/cgi-bin/viewcvs.cgi/trunk/src/modules/module-solaris.c?rev=1971&root=pulseaudio&r1=1970&r2=1971&view=diff
==============================================================================
--- trunk/src/modules/module-solaris.c (original)
+++ trunk/src/modules/module-solaris.c Sun Oct 28 20:13:50 2007
@@ -4,7 +4,7 @@
   This file is part of PulseAudio.
 
   Copyright 2006 Lennart Poettering
-  Copyright 2006 Pierre Ossman <ossman at cendio.se> for Cendio AB
+  Copyright 2006-2007 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
@@ -57,6 +57,9 @@
 #include <pulsecore/modargs.h>
 #include <pulsecore/log.h>
 #include <pulsecore/core-error.h>
+#include <pulsecore/thread-mq.h>
+#include <pulsecore/rtpoll.h>
+#include <pulsecore/thread.h>
 
 #include "module-solaris-symdef.h"
 
@@ -75,12 +78,14 @@
     "channel_map=<channel map>")
 
 struct userdata {
+    pa_core *core;
     pa_sink *sink;
     pa_source *source;
-    pa_iochannel *io;
-    pa_core *core;
-    pa_time_event *timer;
-    pa_usec_t poll_timeout;
+
+    pa_thread *thread;
+    pa_thread_mq thread_mq;
+    pa_rtpoll *rtpoll;
+
     pa_signal_event *sig;
 
     pa_memchunk memchunk;
@@ -90,9 +95,9 @@
     uint32_t frame_size;
     uint32_t buffer_size;
     unsigned int written_bytes, read_bytes;
-    int sink_underflow;
 
     int fd;
+    pa_rtpoll_item *rtpoll_item;
     pa_module *module;
 };
 
@@ -114,309 +119,357 @@
 #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_sink_used_by(u->sink) : 0) +
-                      (u->source ? pa_source_used_by(u->source) : 0));
-}
-
-static void do_write(struct userdata *u) {
+static int sink_process_msg(pa_msgobject *o, int code, void *data, int64_t offset, pa_memchunk *chunk) {
+    struct userdata *u = PA_SINK(o)->userdata;
+    int err;
     audio_info_t info;
+
+    switch (code) {
+    case PA_SINK_MESSAGE_GET_LATENCY: {
+        pa_usec_t r = 0;
+
+        if (u->fd >= 0) {
+
+            err = ioctl(u->fd, AUDIO_GETINFO, &info);
+            pa_assert(err >= 0);
+
+            r += pa_bytes_to_usec(u->written_bytes, &PA_SINK(o)->sample_spec);
+            r -= pa_bytes_to_usec(info.play.samples * u->frame_size, &PA_SINK(o)->sample_spec);
+
+            if (u->memchunk.memblock)
+                r += pa_bytes_to_usec(u->memchunk.length, &PA_SINK(o)->sample_spec);
+        }
+
+        *((pa_usec_t*) data) = r;
+
+        return 0;
+    }
+
+    case PA_SINK_MESSAGE_SET_VOLUME:
+        if (u->fd >= 0) {
+            AUDIO_INITINFO(&info);
+
+            info.play.gain = pa_cvolume_avg((pa_cvolume*)data) * AUDIO_MAX_GAIN / PA_VOLUME_NORM;
+            assert(info.play.gain <= AUDIO_MAX_GAIN);
+
+            if (ioctl(u->fd, AUDIO_SETINFO, &info) < 0) {
+                if (errno == EINVAL)
+                    pa_log("AUDIO_SETINFO: Unsupported volume.");
+                else
+                    pa_log("AUDIO_SETINFO: %s", pa_cstrerror(errno));
+            } else {
+                return 0;
+            }
+        }
+        break;
+
+    case PA_SINK_MESSAGE_GET_VOLUME:
+        if (u->fd >= 0) {
+            err = ioctl(u->fd, AUDIO_GETINFO, &info);
+            assert(err >= 0);
+
+            pa_cvolume_set((pa_cvolume*) data, ((pa_cvolume*) data)->channels,
+                info.play.gain * PA_VOLUME_NORM / AUDIO_MAX_GAIN);
+
+            return 0;
+        }
+        break;
+
+    case PA_SINK_MESSAGE_SET_MUTE:
+        if (u->fd >= 0) {
+            AUDIO_INITINFO(&info);
+
+            info.output_muted = !!PA_PTR_TO_UINT(data);
+
+            if (ioctl(u->fd, AUDIO_SETINFO, &info) < 0)
+                pa_log("AUDIO_SETINFO: %s", pa_cstrerror(errno));
+            else
+                return 0;
+        }
+        break;
+
+    case PA_SINK_MESSAGE_GET_MUTE:
+        if (u->fd >= 0) {
+            err = ioctl(u->fd, AUDIO_GETINFO, &info);
+            pa_assert(err >= 0);
+
+            *(int*)data = !!info.output_muted;
+
+            return 0;
+        }
+        break;
+    }
+
+    return pa_sink_process_msg(o, code, data, offset, chunk);
+}
+
+static int source_process_msg(pa_msgobject *o, int code, void *data, int64_t offset, pa_memchunk *chunk) {
+    struct userdata *u = PA_SOURCE(o)->userdata;
     int err;
-    size_t len;
-    ssize_t r;
-
-    assert(u);
-
-    /* We cannot check pa_iochannel_is_writable() because of our buffer hack */
-    if (!u->sink)
-        return;
-
-    update_usage(u);
-
-    err = ioctl(u->fd, AUDIO_GETINFO, &info);
-    assert(err >= 0);
-
-    /*
-     * Since we cannot modify the size of the output buffer we fake it
-     * by not filling it more than u->buffer_size.
-     */
-    len = u->buffer_size;
-    len -= u->written_bytes - (info.play.samples * u->frame_size);
-
-    /* The sample counter can sometimes go backwards :( */
-    if (len > u->buffer_size)
-        len = 0;
-
-    if (!u->sink_underflow && (len == u->buffer_size))
-        pa_log_debug("Solaris buffer underflow!");
-
-    len -= len % u->frame_size;
-
-    if (len == 0)
-        return;
-
-    if (!u->memchunk.length) {
-        if (pa_sink_render(u->sink, len, &u->memchunk) < 0) {
-            u->sink_underflow = 1;
-            return;
-        }
-    }
-
-    u->sink_underflow = 0;
-
-    assert(u->memchunk.memblock);
-    assert(u->memchunk.memblock->data);
-    assert(u->memchunk.length);
-
-    if (u->memchunk.length < len) {
-        len = u->memchunk.length;
-        len -= len % u->frame_size;
-        assert(len);
-    }
-
-    if ((r = pa_iochannel_write(u->io,
-        (uint8_t*) u->memchunk.memblock->data + u->memchunk.index, len)) < 0) {
-        pa_log("write() failed: %s", pa_cstrerror(errno));
-        return;
-    }
-
-    assert(r % u->frame_size == 0);
-
-    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) {
-    pa_memchunk memchunk;
-    int err;
-    size_t 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);
-
-    /* This is to make sure it fits in the memory pool. Also, a page
-       should be the most efficient transfer size. */
-    if (l > u->page_size)
-        l = u->page_size;
-
-    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) {
-        pa_memblock_unref(memchunk.memblock);
-        if (errno != EAGAIN)
-            pa_log("read() failed: %s", pa_cstrerror(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(pa_iochannel *io, void*userdata) {
+    audio_info_t info;
+
+    switch (code) {
+        case PA_SOURCE_MESSAGE_GET_LATENCY: {
+            pa_usec_t r = 0;
+
+            if (u->fd) {
+                err = ioctl(u->fd, AUDIO_GETINFO, &info);
+                pa_assert(err >= 0);
+
+                r += pa_bytes_to_usec(info.record.samples * u->frame_size, &PA_SOURCE(o)->sample_spec);
+                r -= pa_bytes_to_usec(u->read_bytes, &PA_SOURCE(o)->sample_spec);
+            }
+
+            *((pa_usec_t*) data) = r;
+
+            return 0;
+        }
+
+        case PA_SOURCE_MESSAGE_SET_VOLUME:
+            if (u->fd >= 0) {
+                AUDIO_INITINFO(&info);
+
+                info.record.gain = pa_cvolume_avg((pa_cvolume*) data) * AUDIO_MAX_GAIN / PA_VOLUME_NORM;
+                assert(info.record.gain <= AUDIO_MAX_GAIN);
+
+                if (ioctl(u->fd, AUDIO_SETINFO, &info) < 0) {
+                    if (errno == EINVAL)
+                        pa_log("AUDIO_SETINFO: Unsupported volume.");
+                    else
+                        pa_log("AUDIO_SETINFO: %s", pa_cstrerror(errno));
+                } else {
+                    return 0;
+                }
+            }
+            break;
+
+        case PA_SOURCE_MESSAGE_GET_VOLUME:
+            if (u->fd >= 0) {
+                err = ioctl(u->fd, AUDIO_GETINFO, &info);
+                pa_assert(err >= 0);
+
+                pa_cvolume_set((pa_cvolume*) data, ((pa_cvolume*) data)->channels,
+                    info.record.gain * PA_VOLUME_NORM / AUDIO_MAX_GAIN);
+
+                return 0;
+            }
+            break;
+    }
+
+    return pa_source_process_msg(o, code, data, offset, chunk);
+}
+
+static void clear_underflow(struct userdata *u)
+{
+    audio_info_t info;
+
+    AUDIO_INITINFO(&info);
+
+    info.play.error = 0;
+
+    if (ioctl(u->fd, AUDIO_SETINFO, &info) < 0)
+        pa_log("AUDIO_SETINFO: %s", pa_cstrerror(errno));
+}
+
+static void clear_overflow(struct userdata *u)
+{
+    audio_info_t info;
+
+    AUDIO_INITINFO(&info);
+
+    info.record.error = 0;
+
+    if (ioctl(u->fd, AUDIO_SETINFO, &info) < 0)
+        pa_log("AUDIO_SETINFO: %s", pa_cstrerror(errno));
+}
+
+static void thread_func(void *userdata) {
     struct userdata *u = userdata;
-    assert(u);
-    do_write(u);
-    do_read(u);
-}
-
-static void timer_cb(pa_mainloop_api*a, pa_time_event *e, const struct timeval *tv, void *userdata) {
-    struct userdata *u = userdata;
-    struct timeval ntv;
-
-    assert(u);
-
-    do_write(u);
-
-    pa_gettimeofday(&ntv);
-    pa_timeval_add(&ntv, u->poll_timeout);
-
-    a->time_restart(e, &ntv);
+    unsigned short revents = 0;
+    int ret;
+
+    pa_assert(u);
+
+    pa_log_debug("Thread starting up");
+
+    if (u->core->high_priority)
+        pa_make_realtime();
+
+    pa_thread_mq_install(&u->thread_mq);
+    pa_rtpoll_install(u->rtpoll);
+
+    for (;;) {
+        /* Render some data and write it to the dsp */
+
+        if (u->sink && PA_SINK_OPENED(u->sink->thread_info.state)) {
+            audio_info_t info;
+            int err;
+            size_t len;
+
+            err = ioctl(u->fd, AUDIO_GETINFO, &info);
+            pa_assert(err >= 0);
+
+            /*
+             * Since we cannot modify the size of the output buffer we fake it
+             * by not filling it more than u->buffer_size.
+             */
+            len = u->buffer_size;
+            len -= u->written_bytes - (info.play.samples * u->frame_size);
+
+            /* The sample counter can sometimes go backwards :( */
+            if (len > u->buffer_size)
+                len = 0;
+
+            if (info.play.error) {
+                pa_log_debug("Solaris buffer underflow!");
+                clear_underflow(u);
+            }
+
+            len -= len % u->frame_size;
+
+            while (len) {
+                void *p;
+                ssize_t r;
+
+                if (!u->memchunk.length)
+                    pa_sink_render(u->sink, len, &u->memchunk);
+
+                pa_assert(u->memchunk.length);
+
+                p = pa_memblock_acquire(u->memchunk.memblock);
+                r = pa_write(u->fd, (uint8_t*) p + u->memchunk.index, u->memchunk.length, NULL);
+                pa_memblock_release(u->memchunk.memblock);
+
+                if (r < 0) {
+                    if (errno == EINTR)
+                        continue;
+                    else if (errno != EAGAIN) {
+                        pa_log("Failed to read data from DSP: %s", pa_cstrerror(errno));
+                        goto fail;
+                    }
+                } else {
+                    pa_assert(r % u->frame_size == 0);
+
+                    u->memchunk.index += r;
+                    u->memchunk.length -= r;
+
+                    if (u->memchunk.length <= 0) {
+                        pa_memblock_unref(u->memchunk.memblock);
+                        pa_memchunk_reset(&u->memchunk);
+                    }
+
+                    len -= r;
+                    u->written_bytes += r;
+                }
+            }
+        }
+
+        /* Try to read some data and pass it on to the source driver */
+
+        if (u->source && PA_SOURCE_OPENED(u->source->thread_info.state) && ((revents & POLLIN))) {
+            pa_memchunk memchunk;
+            int err;
+            size_t l;
+            void *p;
+            ssize_t r;
+            audio_info_t info;
+
+            err = ioctl(u->fd, AUDIO_GETINFO, &info);
+            pa_assert(err >= 0);
+
+            if (info.record.error) {
+                pa_log_debug("Solaris buffer overflow!");
+                clear_overflow(u);
+            }
+
+            err = ioctl(u->fd, I_NREAD, &l);
+            pa_assert(err >= 0);
+
+            if (l > 0) {
+                /* This is to make sure it fits in the memory pool. Also, a page
+                   should be the most efficient transfer size. */
+                if (l > u->page_size)
+                    l = u->page_size;
+
+                memchunk.memblock = pa_memblock_new(u->core->mempool, l);
+                pa_assert(memchunk.memblock);
+
+                p = pa_memblock_acquire(memchunk.memblock);
+                r = pa_read(u->fd, p, l, NULL);
+                pa_memblock_release(memchunk.memblock);
+
+                if (r < 0) {
+                    pa_memblock_unref(memchunk.memblock);
+                    if (errno != EAGAIN) {
+                        pa_log("Failed to read data from DSP: %s", pa_cstrerror(errno));
+                        goto fail;
+                    }
+                } else {
+                    memchunk.index = 0;
+                    memchunk.length = r;
+
+                    pa_source_post(u->source, &memchunk);
+                    pa_memblock_unref(memchunk.memblock);
+
+                    u->read_bytes += r;
+
+                    revents &= ~POLLIN;
+                }
+            }
+        }
+
+        if (u->fd >= 0) {
+            struct pollfd *pollfd;
+
+            pollfd = pa_rtpoll_item_get_pollfd(u->rtpoll_item, NULL);
+            pollfd->events =
+                ((u->source && PA_SOURCE_OPENED(u->source->thread_info.state)) ? POLLIN : 0);
+        }
+
+        /* Hmm, nothing to do. Let's sleep */
+        if ((ret = pa_rtpoll_run(u->rtpoll, 1)) < 0)
+            goto fail;
+
+        if (ret == 0)
+            goto finish;
+
+        if (u->fd >= 0) {
+            struct pollfd *pollfd;
+
+            pollfd = pa_rtpoll_item_get_pollfd(u->rtpoll_item, NULL);
+
+            if (pollfd->revents & ~(POLLOUT|POLLIN)) {
+                pa_log("DSP shutdown.");
+                goto fail;
+            }
+
+            revents = pollfd->revents;
+        } else
+            revents = 0;
+    }
+
+fail:
+    /* We have to continue processing messages until we receive the
+     * SHUTDOWN message */
+    pa_asyncmsgq_post(u->thread_mq.outq, PA_MSGOBJECT(u->core), PA_CORE_MESSAGE_UNLOAD_MODULE, u->module, 0, NULL, NULL);
+    pa_asyncmsgq_wait_for(u->thread_mq.inq, PA_MESSAGE_SHUTDOWN);
+
+finish:
+    pa_log_debug("Thread shutting down");
 }
 
 static void sig_callback(pa_mainloop_api *api, pa_signal_event*e, int sig, void *userdata) {
     struct userdata *u = userdata;
-    pa_cvolume old_vol;
 
     assert(u);
 
     if (u->sink) {
-        assert(u->sink->get_hw_volume);
-        memcpy(&old_vol, &u->sink->hw_volume, sizeof(pa_cvolume));
-        if (u->sink->get_hw_volume(u->sink) < 0)
-            return;
-        if (memcmp(&old_vol, &u->sink->hw_volume, sizeof(pa_cvolume)) != 0) {
-            pa_subscription_post(u->sink->core,
-                PA_SUBSCRIPTION_EVENT_SINK|PA_SUBSCRIPTION_EVENT_CHANGE,
-                u->sink->index);
-        }
-    }
-
-    if (u->source) {
-        assert(u->source->get_hw_volume);
-        memcpy(&old_vol, &u->source->hw_volume, sizeof(pa_cvolume));
-        if (u->source->get_hw_volume(u->source) < 0)
-            return;
-        if (memcmp(&old_vol, &u->source->hw_volume, sizeof(pa_cvolume)) != 0) {
-            pa_subscription_post(u->source->core,
-                PA_SUBSCRIPTION_EVENT_SOURCE|PA_SUBSCRIPTION_EVENT_CHANGE,
-                u->source->index);
-        }
-    }
-}
-
-static pa_usec_t sink_get_latency_cb(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->frame_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(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->frame_size, &s->sample_spec);
-    r -= pa_bytes_to_usec(u->read_bytes, &s->sample_spec);
-
-    return r;
-}
-
-static int sink_get_hw_volume_cb(pa_sink *s) {
-    struct userdata *u = s->userdata;
-    audio_info_t info;
-    int err;
-
-    err = ioctl(u->fd, AUDIO_GETINFO, &info);
-    assert(err >= 0);
-
-    pa_cvolume_set(&s->hw_volume, s->hw_volume.channels,
-        info.play.gain * PA_VOLUME_NORM / AUDIO_MAX_GAIN);
-
-    return 0;
-}
-
-static int sink_set_hw_volume_cb(pa_sink *s) {
-    struct userdata *u = s->userdata;
-    audio_info_t info;
-
-    AUDIO_INITINFO(&info);
-
-    info.play.gain = pa_cvolume_avg(&s->hw_volume) * AUDIO_MAX_GAIN / PA_VOLUME_NORM;
-    assert(info.play.gain <= AUDIO_MAX_GAIN);
-
-    if (ioctl(u->fd, AUDIO_SETINFO, &info) < 0) {
-        if (errno == EINVAL)
-            pa_log("AUDIO_SETINFO: Unsupported volume.");
-        else
-            pa_log("AUDIO_SETINFO: %s", pa_cstrerror(errno));
-        return -1;
-    }
-
-    return 0;
-}
-
-static int sink_get_hw_mute_cb(pa_sink *s) {
-    struct userdata *u = s->userdata;
-    audio_info_t info;
-    int err;
-
-    err = ioctl(u->fd, AUDIO_GETINFO, &info);
-    assert(err >= 0);
-
-    s->hw_muted = !!info.output_muted;
-
-    return 0;
-}
-
-static int sink_set_hw_mute_cb(pa_sink *s) {
-    struct userdata *u = s->userdata;
-    audio_info_t info;
-
-    AUDIO_INITINFO(&info);
-
-    info.output_muted = !!s->hw_muted;
-
-    if (ioctl(u->fd, AUDIO_SETINFO, &info) < 0) {
-        pa_log("AUDIO_SETINFO: %s", pa_cstrerror(errno));
-        return -1;
-    }
-
-    return 0;
-}
-
-static int source_get_hw_volume_cb(pa_source *s) {
-    struct userdata *u = s->userdata;
-    audio_info_t info;
-    int err;
-
-    err = ioctl(u->fd, AUDIO_GETINFO, &info);
-    assert(err >= 0);
-
-    pa_cvolume_set(&s->hw_volume, s->hw_volume.channels,
-        info.record.gain * PA_VOLUME_NORM / AUDIO_MAX_GAIN);
-
-    return 0;
-}
-
-static int source_set_hw_volume_cb(pa_source *s) {
-    struct userdata *u = s->userdata;
-    audio_info_t info;
-
-    AUDIO_INITINFO(&info);
-
-    info.record.gain = pa_cvolume_avg(&s->hw_volume) * AUDIO_MAX_GAIN / PA_VOLUME_NORM;
-    assert(info.record.gain <= AUDIO_MAX_GAIN);
-
-    if (ioctl(u->fd, AUDIO_SETINFO, &info) < 0) {
-        if (errno == EINVAL)
-            pa_log("AUDIO_SETINFO: Unsupported volume.");
-        else
-            pa_log("AUDIO_SETINFO: %s", pa_cstrerror(errno));
-        return -1;
-    }
-
-    return 0;
+        pa_sink_get_volume(u->sink);
+        pa_sink_get_mute(u->sink);
+    }
+
+    if (u->source)
+        pa_source_get_volume(u->source);
 }
 
 static int pa_solaris_auto_format(int fd, int mode, pa_sample_spec *ss) {
@@ -490,6 +543,7 @@
 
     AUDIO_INITINFO(&info);
 
+    info.play.buffer_size = buffer_size;
     info.record.buffer_size = buffer_size;
 
     if (ioctl(fd, AUDIO_SETINFO, &info) < 0) {
@@ -503,7 +557,7 @@
     return 0;
 }
 
-int pa__init(pa_core *c, pa_module*m) {
+int pa__init(pa_module *m) {
     struct userdata *u = NULL;
     const char *p;
     int fd = -1;
@@ -513,9 +567,10 @@
     pa_sample_spec ss;
     pa_channel_map map;
     pa_modargs *ma = NULL;
-    struct timeval tv;
     char *t;
-    assert(c && m);
+    struct pollfd *pollfd;
+
+    pa_assert(m);
 
     if (!(ma = pa_modargs_new(m->argument, valid_modargs))) {
         pa_log("failed to parse module arguments.");
@@ -540,7 +595,7 @@
         goto fail;
     }
 
-    ss = c->default_sample_spec;
+    ss = m->core->default_sample_spec;
     if (pa_modargs_get_sample_spec_and_channel_map(ma, &ss, &map, PA_CHANNEL_MAP_DEFAULT) < 0) {
         pa_log("failed to parse sample specification");
         goto fail;
@@ -554,93 +609,110 @@
     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;
+    if (pa_solaris_set_buffer(fd, buffer_size) < 0)
+        goto fail;
 
     u = pa_xmalloc(sizeof(struct userdata));
-    u->core = c;
+    u->core = m->core;
+
+    u->fd = fd;
+
+    pa_memchunk_reset(&u->memchunk);
+
+    /* We use this to get a reasonable chunk size */
+    u->page_size = PA_PAGE_SIZE;
+
+    u->frame_size = pa_frame_size(&ss);
+    u->buffer_size = buffer_size;
+
+    u->written_bytes = 0;
+    u->read_bytes = 0;
+
+    u->module = m;
+    m->userdata = u;
+
+    pa_thread_mq_init(&u->thread_mq, m->core->mainloop);
+
+    u->rtpoll = pa_rtpoll_new();
+    pa_rtpoll_item_new_asyncmsgq(u->rtpoll, PA_RTPOLL_EARLY, u->thread_mq.inq);
+
+    pa_rtpoll_set_timer_periodic(u->rtpoll, pa_bytes_to_usec(u->buffer_size / 10, &ss));
+
+    u->rtpoll_item = pa_rtpoll_item_new(u->rtpoll, PA_RTPOLL_NEVER, 1);
+    pollfd = pa_rtpoll_item_get_pollfd(u->rtpoll_item, NULL);
+    pollfd->fd = fd;
+    pollfd->events = 0;
+    pollfd->revents = 0;
 
     if (mode != O_WRONLY) {
-        u->source = pa_source_new(c, __FILE__, pa_modargs_get_value(ma, "source_name", DEFAULT_SOURCE_NAME), 0, &ss, &map);
-        assert(u->source);
+        u->source = pa_source_new(m->core, __FILE__, pa_modargs_get_value(ma, "source_name", DEFAULT_SOURCE_NAME), 0, &ss, &map);
+        pa_assert(u->source);
+
         u->source->userdata = u;
-        u->source->get_latency = source_get_latency_cb;
-        u->source->get_hw_volume = source_get_hw_volume_cb;
-        u->source->set_hw_volume = source_set_hw_volume_cb;
-        pa_source_set_owner(u->source, m);
+        u->source->parent.process_msg = source_process_msg;
+
+        pa_source_set_module(u->source, m);
         pa_source_set_description(u->source, t = pa_sprintf_malloc("Solaris PCM on '%s'", p));
         pa_xfree(t);
-        u->source->is_hardware = 1;
+        pa_source_set_asyncmsgq(u->source, u->thread_mq.inq);
+        pa_source_set_rtpoll(u->source, u->rtpoll);
+
+        u->source->flags = PA_SOURCE_HARDWARE|PA_SOURCE_LATENCY|PA_SOURCE_HW_VOLUME_CTRL;
+        u->source->refresh_volume = 1;
     } else
         u->source = NULL;
 
     if (mode != O_RDONLY) {
-        u->sink = pa_sink_new(c, __FILE__, pa_modargs_get_value(ma, "sink_name", DEFAULT_SINK_NAME), 0, &ss, &map);
-        assert(u->sink);
-        u->sink->get_latency = sink_get_latency_cb;
-        u->sink->get_hw_volume = sink_get_hw_volume_cb;
-        u->sink->set_hw_volume = sink_set_hw_volume_cb;
-        u->sink->get_hw_mute = sink_get_hw_mute_cb;
-        u->sink->set_hw_mute = sink_set_hw_mute_cb;
+        u->sink = pa_sink_new(m->core, __FILE__, pa_modargs_get_value(ma, "sink_name", DEFAULT_SINK_NAME), 0, &ss, &map);
+        pa_assert(u->sink);
+
         u->sink->userdata = u;
-        pa_sink_set_owner(u->sink, m);
+        u->sink->parent.process_msg = sink_process_msg;
+
+        pa_sink_set_module(u->sink, m);
         pa_sink_set_description(u->sink, t = pa_sprintf_malloc("Solaris PCM on '%s'", p));
         pa_xfree(t);
-        u->sink->is_hardware = 1;
+        pa_sink_set_asyncmsgq(u->sink, u->thread_mq.inq);
+        pa_sink_set_rtpoll(u->sink, u->rtpoll);
+
+        u->sink->flags = PA_SINK_HARDWARE|PA_SINK_LATENCY|PA_SINK_HW_VOLUME_CTRL;
+        u->sink->refresh_volume = 1;
+        u->sink->refresh_mute = 1;
     } 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;
-
-    /* We use this to get a reasonable chunk size */
-    u->page_size = sysconf(_SC_PAGESIZE);
-
-    u->frame_size = pa_frame_size(&ss);
-    u->buffer_size = buffer_size;
-
-    u->written_bytes = 0;
-    u->read_bytes = 0;
-
-    u->sink_underflow = 1;
-
-    u->module = m;
-    m->userdata = u;
-
-    u->poll_timeout = pa_bytes_to_usec(u->buffer_size / 10, &ss);
-
-    pa_gettimeofday(&tv);
-    pa_timeval_add(&tv, u->poll_timeout);
-
-    u->timer = c->mainloop->time_new(c->mainloop, &tv, timer_cb, u);
-    assert(u->timer);
+    pa_assert(u->source || u->sink);
 
     u->sig = pa_signal_new(SIGPOLL, sig_callback, u);
-    assert(u->sig);
+    pa_assert(u->sig);
     ioctl(u->fd, I_SETSIG, S_MSG);
 
-    pa_modargs_free(ma);
+    if (!(u->thread = pa_thread_new(thread_func, u))) {
+        pa_log("Failed to create thread.");
+        goto fail;
+    }
 
     /* Read mixer settings */
     if (u->source)
-        source_get_hw_volume_cb(u->source);
+        pa_asyncmsgq_send(u->thread_mq.inq, PA_MSGOBJECT(u->source), PA_SOURCE_MESSAGE_GET_VOLUME, &u->source->volume, 0, NULL);
     if (u->sink) {
-        sink_get_hw_volume_cb(u->sink);
-        sink_get_hw_mute_cb(u->sink);
-    }
+        pa_asyncmsgq_send(u->thread_mq.inq, PA_MSGOBJECT(u->sink), PA_SINK_MESSAGE_GET_VOLUME, &u->sink->volume, 0, NULL);
+        pa_asyncmsgq_send(u->thread_mq.inq, PA_MSGOBJECT(u->sink), PA_SINK_MESSAGE_GET_MUTE, &u->sink->muted, 0, NULL);
+    }
+
+    if (u->sink)
+        pa_sink_put(u->sink);
+    if (u->source)
+        pa_source_put(u->source);
+
+    pa_modargs_free(ma);
 
     return 0;
 
 fail:
-    if (fd >= 0)
+    if (u)
+        pa__done(m);
+    else if (fd >= 0)
         close(fd);
 
     if (ma)
@@ -649,31 +721,47 @@
     return -1;
 }
 
-void pa__done(pa_core *c, pa_module*m) {
+void pa__done(pa_module *m) {
     struct userdata *u;
-    assert(c && m);
+
+    pa_assert(m);
 
     if (!(u = m->userdata))
         return;
 
-    if (u->timer)
-        c->mainloop->time_free(u->timer);
     ioctl(u->fd, I_SETSIG, 0);
     pa_signal_free(u->sig);
 
-    if (u->memchunk.memblock)
+    if (u->sink)
+        pa_sink_unlink(u->sink);
+
+    if (u->source)
+        pa_source_unlink(u->source);
+
+    if (u->thread) {
+        pa_asyncmsgq_send(u->thread_mq.inq, NULL, PA_MESSAGE_SHUTDOWN, NULL, 0, NULL);
+        pa_thread_free(u->thread);
+    }
+
+    pa_thread_mq_done(&u->thread_mq);
+
+    if (u->sink)
+        pa_sink_unref(u->sink);
+
+    if (u->source)
+        pa_source_unref(u->source);
+
+     if (u->memchunk.memblock)
         pa_memblock_unref(u->memchunk.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);
+    if (u->rtpoll_item)
+        pa_rtpoll_item_free(u->rtpoll_item);
+
+    if (u->rtpoll)
+        pa_rtpoll_free(u->rtpoll);
+
+    if (u->fd >= 0)
+        close(u->fd);
+
     pa_xfree(u);
 }

Modified: trunk/src/modules/module-tunnel.c
URL: http://0pointer.de/cgi-bin/viewcvs.cgi/trunk/src/modules/module-tunnel.c?rev=1971&root=pulseaudio&r1=1970&r2=1971&view=diff
==============================================================================
--- trunk/src/modules/module-tunnel.c (original)
+++ trunk/src/modules/module-tunnel.c Sun Oct 28 20:13:50 2007
@@ -596,12 +596,12 @@
     }
 
 #ifdef TUNNEL_SINK
-    snprintf(name, sizeof(name), "Tunnel from host %s, user %s, sink %s",
+    pa_snprintf(name, sizeof(name), "Tunnel from host %s, user %s, sink %s",
              pa_get_host_name(hn, sizeof(hn)),
              pa_get_user_name(un, sizeof(un)),
              u->sink->name);
 #else
-    snprintf(name, sizeof(name), "Tunnel from host %s, user %s, source %s",
+    pa_snprintf(name, sizeof(name), "Tunnel from host %s, user %s, source %s",
              pa_get_host_name(hn, sizeof(hn)),
              pa_get_user_name(un, sizeof(un)),
              u->source->name);

Modified: trunk/src/modules/module-volume-restore.c
URL: http://0pointer.de/cgi-bin/viewcvs.cgi/trunk/src/modules/module-volume-restore.c?rev=1971&root=pulseaudio&r1=1970&r2=1971&view=diff
==============================================================================
--- trunk/src/modules/module-volume-restore.c (original)
+++ trunk/src/modules/module-volume-restore.c Sun Oct 28 20:13:50 2007
@@ -26,7 +26,6 @@
 #endif
 
 #include <unistd.h>
-#include <assert.h>
 #include <string.h>
 #include <errno.h>
 #include <sys/types.h>
@@ -35,6 +34,7 @@
 #include <ctype.h>
 
 #include <pulse/xmalloc.h>
+#include <pulse/volume.h>
 
 #include <pulsecore/core-error.h>
 #include <pulsecore/module.h>
@@ -44,9 +44,7 @@
 #include <pulsecore/core-subscribe.h>
 #include <pulsecore/sink-input.h>
 #include <pulsecore/source-output.h>
-#include <pulsecore/core-util.h>
 #include <pulsecore/namereg.h>
-#include <pulse/volume.h>
 
 #include "module-volume-restore-symdef.h"
 
@@ -85,8 +83,8 @@
     long k;
     unsigned i;
 
-    assert(s);
-    assert(v);
+    pa_assert(s);
+    pa_assert(v);
 
     if (!isdigit(*s))
         return NULL;
@@ -170,7 +168,7 @@
             continue;
         }
 
-        assert(ln == buf_source);
+        pa_assert(ln == buf_source);
 
         if (buf_volume[0]) {
             if (!parse_volume(buf_volume, &v)) {
@@ -297,8 +295,8 @@
     struct rule *r;
     char *name;
 
-    assert(c);
-    assert(u);
+    pa_assert(c);
+    pa_assert(u);
 
     if (t != (PA_SUBSCRIPTION_EVENT_SINK_INPUT|PA_SUBSCRIPTION_EVENT_NEW) &&
         t != (PA_SUBSCRIPTION_EVENT_SINK_INPUT|PA_SUBSCRIPTION_EVENT_CHANGE) &&
@@ -313,7 +311,7 @@
         if (!si->client || !(name = client_name(si->client)))
             return;
     } else {
-        assert((t & PA_SUBSCRIPTION_EVENT_FACILITY_MASK) == PA_SUBSCRIPTION_EVENT_SOURCE_OUTPUT);
+        pa_assert((t & PA_SUBSCRIPTION_EVENT_FACILITY_MASK) == PA_SUBSCRIPTION_EVENT_SOURCE_OUTPUT);
 
         if (!(so = pa_idxset_get_by_index(c->source_outputs, idx)))
             return;
@@ -341,7 +339,7 @@
                 u->modified = 1;
             }
         } else {
-            assert(so);
+            pa_assert(so);
 
             if (!r->source || strcmp(so->source->name, r->source) != 0) {
                 pa_log_info("Saving source for <%s>", r->name);
@@ -363,7 +361,7 @@
             r->sink = pa_xstrdup(si->sink->name);
             r->source = NULL;
         } else {
-            assert(so);
+            pa_assert(so);
             r->volume_is_set = 0;
             r->sink = NULL;
             r->source = pa_xstrdup(so->source->name);
@@ -378,7 +376,7 @@
     struct rule *r;
     char *name;
 
-    assert(data);
+    pa_assert(data);
 
     if (!data->client || !(name = client_name(data->client)))
         return PA_HOOK_OK;
@@ -396,6 +394,8 @@
         }
     }
 
+    pa_xfree(name);
+
     return PA_HOOK_OK;
 }
 
@@ -403,7 +403,7 @@
     struct rule *r;
     char *name;
 
-    assert(data);
+    pa_assert(data);
 
     if (!data->client || !(name = client_name(data->client)))
         return PA_HOOK_OK;
@@ -418,12 +418,11 @@
     return PA_HOOK_OK;
 }
 
-int pa__init(pa_core *c, pa_module*m) {
+int pa__init(pa_module*m) {
     pa_modargs *ma = NULL;
     struct userdata *u;
 
-    assert(c);
-    assert(m);
+    pa_assert(m);
 
     if (!(ma = pa_modargs_new(m->argument, valid_modargs))) {
         pa_log("Failed to parse module arguments");
@@ -442,16 +441,15 @@
     if (load_rules(u) < 0)
         goto fail;
 
-    u->subscription = pa_subscription_new(c, PA_SUBSCRIPTION_MASK_SINK_INPUT|PA_SUBSCRIPTION_MASK_SOURCE_OUTPUT, subscribe_callback, u);
-    u->sink_input_hook_slot = pa_hook_connect(&c->hook_sink_input_new, (pa_hook_cb_t) sink_input_hook_callback, u);
-    u->source_output_hook_slot = pa_hook_connect(&c->hook_source_output_new, (pa_hook_cb_t) source_output_hook_callback, u);
+    u->subscription = pa_subscription_new(m->core, PA_SUBSCRIPTION_MASK_SINK_INPUT|PA_SUBSCRIPTION_MASK_SOURCE_OUTPUT, subscribe_callback, u);
+    u->sink_input_hook_slot = pa_hook_connect(&m->core->hooks[PA_CORE_HOOK_SINK_INPUT_NEW], (pa_hook_cb_t) sink_input_hook_callback, u);
+    u->source_output_hook_slot = pa_hook_connect(&m->core->hooks[PA_CORE_HOOK_SOURCE_OUTPUT_NEW], (pa_hook_cb_t) source_output_hook_callback, u);
 
     pa_modargs_free(ma);
     return 0;
 
 fail:
-    pa__done(c, m);
-
+    pa__done(m);
     if (ma)
         pa_modargs_free(ma);
 
@@ -460,7 +458,7 @@
 
 static void free_func(void *p, void *userdata) {
     struct rule *r = p;
-    assert(r);
+    pa_assert(r);
 
     pa_xfree(r->name);
     pa_xfree(r->sink);
@@ -468,11 +466,10 @@
     pa_xfree(r);
 }
 
-void pa__done(pa_core *c, pa_module*m) {
+void pa__done(pa_module*m) {
     struct userdata* u;
 
-    assert(c);
-    assert(m);
+    pa_assert(m);
 
     if (!(u = m->userdata))
         return;

Modified: trunk/src/modules/module-x11-bell.c
URL: http://0pointer.de/cgi-bin/viewcvs.cgi/trunk/src/modules/module-x11-bell.c?rev=1971&root=pulseaudio&r1=1970&r2=1971&view=diff
==============================================================================
--- trunk/src/modules/module-x11-bell.c (original)
+++ trunk/src/modules/module-x11-bell.c Sun Oct 28 20:13:50 2007
@@ -26,7 +26,6 @@
 #endif
 
 #include <stdio.h>
-#include <assert.h>
 #include <stdlib.h>
 #include <string.h>
 
@@ -67,30 +66,21 @@
     NULL
 };
 
-static int ring_bell(struct userdata *u, int percent) {
-    pa_sink *s;
-    assert(u);
-
-    if (!(s = pa_namereg_get(u->core, u->sink_name, PA_NAMEREG_SINK, 1))) {
-        pa_log("Invalid sink: %s", u->sink_name);
-        return -1;
-    }
-
-    pa_scache_play_item(u->core, u->scache_item, s, (percent*PA_VOLUME_NORM)/100);
-    return 0;
-}
-
 static int x11_event_callback(pa_x11_wrapper *w, XEvent *e, void *userdata) {
     XkbBellNotifyEvent *bne;
     struct userdata *u = userdata;
-    assert(w && e && u && u->x11_wrapper == w);
+
+    pa_assert(w);
+    pa_assert(e);
+    pa_assert(u);
+    pa_assert(u->x11_wrapper == w);
 
     if (((XkbEvent*) e)->any.xkb_type != XkbBellNotify)
         return 0;
 
     bne = (XkbBellNotifyEvent*) e;
 
-    if (ring_bell(u, bne->percent) < 0) {
+    if (pa_scache_play_item_by_name(u->core, u->scache_item, u->sink_name, (bne->percent*PA_VOLUME_NORM)/100, 1) < 0) {
         pa_log_info("Ringing bell failed, reverting to X11 device bell.");
         XkbForceDeviceBell(pa_x11_wrapper_get_display(w), bne->device, bne->bell_class, bne->bell_id, bne->percent);
     }
@@ -98,25 +88,27 @@
     return 1;
 }
 
-int pa__init(pa_core *c, pa_module*m) {
+int pa__init(pa_module*m) {
+
     struct userdata *u = NULL;
     pa_modargs *ma = NULL;
     int major, minor;
     unsigned int auto_ctrls, auto_values;
-    assert(c && m);
+
+    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;
     }
 
-    m->userdata = u = pa_xmalloc(sizeof(struct userdata));
-    u->core = c;
+    m->userdata = u = pa_xnew(struct userdata, 1);
+    u->core = m->core;
     u->scache_item = pa_xstrdup(pa_modargs_get_value(ma, "sample", "x11-bell"));
     u->sink_name = pa_xstrdup(pa_modargs_get_value(ma, "sink", NULL));
     u->x11_client = NULL;
 
-    if (!(u->x11_wrapper = pa_x11_wrapper_get(c, pa_modargs_get_value(ma, "display", NULL))))
+    if (!(u->x11_wrapper = pa_x11_wrapper_get(m->core, pa_modargs_get_value(ma, "display", NULL))))
         goto fail;
 
     major = XkbMajorVersion;
@@ -129,7 +121,6 @@
 
     major = XkbMajorVersion;
     minor = XkbMinorVersion;
-
 
     if (!XkbQueryExtension(pa_x11_wrapper_get_display(u->x11_wrapper), NULL, &u->xkb_event_base, NULL, &major, &minor)) {
         pa_log("XkbQueryExtension() failed");
@@ -150,14 +141,21 @@
 fail:
     if (ma)
         pa_modargs_free(ma);
-    if (m->userdata)
-        pa__done(c, m);
+
+    pa__done(m);
+
     return -1;
 }
 
-void pa__done(pa_core *c, pa_module*m) {
-    struct userdata *u = m->userdata;
-    assert(c && m && u);
+void pa__done(pa_module*m) {
+    struct userdata *u;
+
+    pa_assert(m);
+
+    if (!m->userdata)
+        return;
+
+    u = m->userdata;
 
     pa_xfree(u->scache_item);
     pa_xfree(u->sink_name);

Modified: trunk/src/modules/module-x11-publish.c
URL: http://0pointer.de/cgi-bin/viewcvs.cgi/trunk/src/modules/module-x11-publish.c?rev=1971&root=pulseaudio&r1=1970&r2=1971&view=diff
==============================================================================
--- trunk/src/modules/module-x11-publish.c (original)
+++ trunk/src/modules/module-x11-publish.c Sun Oct 28 20:13:50 2007
@@ -26,7 +26,6 @@
 #endif
 
 #include <stdio.h>
-#include <assert.h>
 #include <stdlib.h>
 #include <string.h>
 #include <unistd.h>
@@ -76,7 +75,7 @@
 };
 
 static int load_key(struct userdata *u, const char*fn) {
-    assert(u);
+    pa_assert(u);
 
     u->auth_cookie_in_property = 0;
 
@@ -93,7 +92,7 @@
     if (pa_authkey_load_auto(fn, u->auth_cookie, sizeof(u->auth_cookie)) < 0)
         return -1;
 
-    pa_log_debug("loading cookie from disk.");
+    pa_log_debug("Loading cookie from disk.");
 
     if (pa_authkey_prop_put(u->core, PA_NATIVE_COOKIE_PROPERTY_NAME, u->auth_cookie, sizeof(u->auth_cookie)) >= 0)
         u->auth_cookie_in_property = 1;
@@ -101,7 +100,7 @@
     return 0;
 }
 
-int pa__init(pa_core *c, pa_module*m) {
+int pa__init(pa_module*m) {
     struct userdata *u;
     pa_modargs *ma = NULL;
     char hn[256], un[128];
@@ -110,23 +109,25 @@
     char *s;
     pa_strlist *l;
 
+    pa_assert(m);
+
     if (!(ma = pa_modargs_new(m->argument, valid_modargs))) {
         pa_log("failed to parse module arguments");
         goto fail;
     }
 
     m->userdata = u = pa_xmalloc(sizeof(struct userdata));
-    u->core = c;
+    u->core = m->core;
     u->id = NULL;
     u->auth_cookie_in_property = 0;
 
     if (load_key(u, pa_modargs_get_value(ma, "cookie", NULL)) < 0)
         goto fail;
 
-    if (!(u->x11_wrapper = pa_x11_wrapper_get(c, pa_modargs_get_value(ma, "display", NULL))))
+    if (!(u->x11_wrapper = pa_x11_wrapper_get(m->core, pa_modargs_get_value(ma, "display", NULL))))
         goto fail;
 
-    if (!(l = pa_property_get(c, PA_NATIVE_SERVER_PROPERTY_NAME)))
+    if (!(l = pa_property_get(m->core, PA_NATIVE_SERVER_PROPERTY_NAME)))
         goto fail;
 
     s = pa_strlist_tostring(l);
@@ -154,13 +155,14 @@
     if (ma)
         pa_modargs_free(ma);
 
-    pa__done(c, m);
+    pa__done(m);
     return -1;
 }
 
-void pa__done(pa_core *c, pa_module*m) {
+void pa__done(pa_module*m) {
     struct userdata*u;
-    assert(c && m);
+
+    pa_assert(m);
 
     if (!(u = m->userdata))
         return;
@@ -185,7 +187,7 @@
         pa_x11_wrapper_unref(u->x11_wrapper);
 
     if (u->auth_cookie_in_property)
-        pa_authkey_prop_unref(c, PA_NATIVE_COOKIE_PROPERTY_NAME);
+        pa_authkey_prop_unref(m->core, PA_NATIVE_COOKIE_PROPERTY_NAME);
 
     pa_xfree(u->id);
     pa_xfree(u);

Copied: trunk/src/modules/module-x11-xsmp.c (from r1970, branches/lennart/src/modules/module-x11-xsmp.c)
URL: http://0pointer.de/cgi-bin/viewcvs.cgi/trunk/src/modules/module-x11-xsmp.c?p2=trunk/src/modules/module-x11-xsmp.c&p1=branches/lennart/src/modules/module-x11-xsmp.c&r1=1970&r2=1971&rev=1971&root=pulseaudio&view=diff
==============================================================================
--- branches/lennart/src/modules/module-x11-xsmp.c (original)
+++ trunk/src/modules/module-x11-xsmp.c Sun Oct 28 20:13:50 2007
@@ -59,7 +59,7 @@
     pa_core *c = PA_CORE(client_data);
 
     pa_log_debug("Got die message from XSM. Exiting...");
-    
+
     pa_core_assert_ref(c);
     c->mainloop->quit(c->mainloop, 0);
 }
@@ -88,7 +88,7 @@
     pa_core *c = client_data;
 
     pa_assert(c);
-    
+
     if (opening)
         *watch_data = c->mainloop->io_new(c->mainloop, IceConnectionNumber(connection), PA_IO_EVENT_INPUT, ice_io_cb, connection);
     else
@@ -104,14 +104,14 @@
     SmProp *prop_list[2];
     SmPropValue val_program, val_user;
     SmcConn connection;
-    
+
     pa_assert(m);
 
     if (ice_in_use) {
         pa_log("module-x11-xsmp may no be loaded twice.");
         return -1;
     }
-    
+
     IceAddConnectionWatch(new_ice_connection, m->core);
     ice_in_use = 1;
 
@@ -124,7 +124,7 @@
         pa_log("X11 session manager not running.");
         goto fail;
     }
-    
+
     memset(&callbacks, 0, sizeof(callbacks));
     callbacks.die.callback = die_cb;
     callbacks.die.client_data = m->core;
@@ -134,14 +134,14 @@
     callbacks.save_complete.client_data = m->core;
     callbacks.shutdown_cancelled.callback = shutdown_cancelled_cb;
     callbacks.shutdown_cancelled.client_data = m->core;
-    
+
     if (!(m->userdata = connection = SmcOpenConnection(
                   NULL, m->core,
                   SmProtoMajor, SmProtoMinor,
                   SmcSaveYourselfProcMask | SmcDieProcMask | SmcSaveCompleteProcMask | SmcShutdownCancelledProcMask,
                   &callbacks, NULL, &client_id,
                   sizeof(t), t))) {
-        
+
         pa_log("Failed to open connection to session manager: %s", t);
         goto fail;
     }
@@ -168,7 +168,7 @@
     pa_log_info("Connected to session manager '%s' as '%s'.", vendor = SmcVendor(connection), client_id);
     free(vendor);
     free(client_id);
-    
+
     pa_modargs_free(ma);
 
     return 0;
@@ -176,9 +176,9 @@
 fail:
     if (ma)
         pa_modargs_free(ma);
-    
+
     pa__done(m);
-    
+
     return -1;
 }
 

Modified: trunk/src/modules/module-zeroconf-publish.c
URL: http://0pointer.de/cgi-bin/viewcvs.cgi/trunk/src/modules/module-zeroconf-publish.c?rev=1971&root=pulseaudio&r1=1970&r2=1971&view=diff
==============================================================================
--- trunk/src/modules/module-zeroconf-publish.c (original)
+++ trunk/src/modules/module-zeroconf-publish.c Sun Oct 28 20:13:50 2007
@@ -26,7 +26,6 @@
 #endif
 
 #include <stdio.h>
-#include <assert.h>
 #include <stdlib.h>
 #include <string.h>
 #include <unistd.h>
@@ -35,11 +34,11 @@
 #include <avahi-client/publish.h>
 #include <avahi-common/alternative.h>
 #include <avahi-common/error.h>
+#include <avahi-common/domain.h>
 
 #include <pulse/xmalloc.h>
 #include <pulse/util.h>
 
-#include <pulsecore/autoload.h>
 #include <pulsecore/sink.h>
 #include <pulsecore/source.h>
 #include <pulsecore/native-common.h>
@@ -71,56 +70,52 @@
     struct userdata *userdata;
     AvahiEntryGroup *entry_group;
     char *service_name;
-    char *name;
-    enum  { UNPUBLISHED, PUBLISHED_REAL, PUBLISHED_AUTOLOAD } published ;
-
-    struct {
-        int valid;
-        pa_namereg_type_t type;
-        uint32_t index;
-    } loaded;
-
-    struct {
-        int valid;
-        pa_namereg_type_t type;
-        uint32_t index;
-    } autoload;
+    pa_object *device;
 };
 
 struct userdata {
     pa_core *core;
     AvahiPoll *avahi_poll;
     AvahiClient *client;
+
     pa_hashmap *services;
-    pa_dynarray *sink_dynarray, *source_dynarray, *autoload_dynarray;
-    pa_subscription *subscription;
     char *service_name;
 
     AvahiEntryGroup *main_entry_group;
 
     uint16_t port;
+
+    pa_hook_slot *sink_new_slot, *source_new_slot, *sink_unlink_slot, *source_unlink_slot, *sink_changed_slot, *source_changed_slot;
 };
 
-static void get_service_data(struct userdata *u, struct service *s, pa_sample_spec *ret_ss, char **ret_description) {
-    assert(u && s && s->loaded.valid && ret_ss && ret_description);
-
-    if (s->loaded.type == PA_NAMEREG_SINK) {
-        pa_sink *sink = pa_idxset_get_by_index(u->core->sinks, s->loaded.index);
-        assert(sink);
+static void get_service_data(struct service *s, pa_sample_spec *ret_ss, pa_channel_map *ret_map, const char **ret_name, const char **ret_description) {
+    pa_assert(s);
+    pa_assert(ret_ss);
+    pa_assert(ret_description);
+
+    if (pa_sink_isinstance(s->device)) {
+        pa_sink *sink = PA_SINK(s->device);
+
         *ret_ss = sink->sample_spec;
+        *ret_map = sink->channel_map;
+        *ret_name = sink->name;
         *ret_description = sink->description;
-    } else if (s->loaded.type == PA_NAMEREG_SOURCE) {
-        pa_source *source = pa_idxset_get_by_index(u->core->sources, s->loaded.index);
-        assert(source);
+
+    } else if (pa_source_isinstance(s->device)) {
+        pa_source *source = PA_SOURCE(s->device);
+
         *ret_ss = source->sample_spec;
+        *ret_map = source->channel_map;
+        *ret_name = source->name;
         *ret_description = source->description;
     } else
-        assert(0);
+        pa_assert_not_reached();
 }
 
 static AvahiStringList* txt_record_server_data(pa_core *c, AvahiStringList *l) {
     char s[128];
-    assert(c);
+
+    pa_assert(c);
 
     l = avahi_string_list_add_pair(l, "server-version", PACKAGE_NAME" "PACKAGE_VERSION);
     l = avahi_string_list_add_pair(l, "user-name", pa_get_user_name(s, sizeof(s)));
@@ -130,331 +125,225 @@
     return l;
 }
 
-static int publish_service(struct userdata *u, struct service *s);
+static int publish_service(struct service *s);
 
 static void service_entry_group_callback(AvahiEntryGroup *g, AvahiEntryGroupState state, void *userdata) {
     struct service *s = userdata;
 
-    if (state == AVAHI_ENTRY_GROUP_COLLISION) {
-        char *t;
-
-        t = avahi_alternative_service_name(s->service_name);
-        pa_xfree(s->service_name);
-        s->service_name = t;
-
-        publish_service(s->userdata, s);
-    }
-}
-
-static int publish_service(struct userdata *u, struct service *s) {
+    pa_assert(s);
+
+    switch (state) {
+
+        case AVAHI_ENTRY_GROUP_ESTABLISHED:
+            pa_log_info("Successfully established service %s.", s->service_name);
+            break;
+
+        case AVAHI_ENTRY_GROUP_COLLISION: {
+            char *t;
+
+            t = avahi_alternative_service_name(s->service_name);
+            pa_log_info("Name collision, renaming %s to %s.", s->service_name, t);
+            pa_xfree(s->service_name);
+            s->service_name = t;
+
+            publish_service(s);
+            break;
+        }
+
+        case AVAHI_ENTRY_GROUP_FAILURE: {
+            pa_log("Failed to register service: %s", avahi_strerror(avahi_client_errno(avahi_entry_group_get_client(g))));
+
+            avahi_entry_group_free(g);
+            s->entry_group = NULL;
+
+            break;
+        }
+
+        case AVAHI_ENTRY_GROUP_UNCOMMITED:
+        case AVAHI_ENTRY_GROUP_REGISTERING:
+            ;
+    }
+}
+
+static void service_free(struct service *s);
+
+static int publish_service(struct service *s) {
     int r = -1;
     AvahiStringList *txt = NULL;
-
-    assert(u);
-    assert(s);
-
-    if (!u->client || avahi_client_get_state(u->client) != AVAHI_CLIENT_S_RUNNING)
+    const char *description = NULL, *name = NULL;
+    pa_sample_spec ss;
+    pa_channel_map map;
+    char cm[PA_CHANNEL_MAP_SNPRINT_MAX];
+
+    pa_assert(s);
+
+    if (!s->userdata->client || avahi_client_get_state(s->userdata->client) != AVAHI_CLIENT_S_RUNNING)
         return 0;
 
-    if ((s->published == PUBLISHED_REAL && s->loaded.valid) ||
-        (s->published == PUBLISHED_AUTOLOAD && s->autoload.valid && !s->loaded.valid))
-        return 0;
-
-    if (s->published != UNPUBLISHED) {
+    if (!s->entry_group) {
+        if (!(s->entry_group = avahi_entry_group_new(s->userdata->client, service_entry_group_callback, s))) {
+            pa_log("avahi_entry_group_new(): %s", avahi_strerror(avahi_client_errno(s->userdata->client)));
+            goto finish;
+        }
+    } else
         avahi_entry_group_reset(s->entry_group);
-        s->published = UNPUBLISHED;
-    }
-
-    if (s->loaded.valid || s->autoload.valid) {
-        pa_namereg_type_t type;
-
-        if (!s->entry_group) {
-            if (!(s->entry_group = avahi_entry_group_new(u->client, service_entry_group_callback, s))) {
-                pa_log("avahi_entry_group_new(): %s", avahi_strerror(avahi_client_errno(u->client)));
-                goto finish;
-            }
-        }
-
-        txt = avahi_string_list_add_pair(txt, "device", s->name);
-        txt = txt_record_server_data(u->core, txt);
-
-        if (s->loaded.valid) {
-            char *description;
-            pa_sample_spec ss;
-
-            get_service_data(u, s, &ss, &description);
-
-            txt = avahi_string_list_add_printf(txt, "rate=%u", ss.rate);
-            txt = avahi_string_list_add_printf(txt, "channels=%u", ss.channels);
-            txt = avahi_string_list_add_pair(txt, "format", pa_sample_format_to_string(ss.format));
-            if (description)
-                txt = avahi_string_list_add_pair(txt, "description", description);
-
-            type = s->loaded.type;
-        } else if (s->autoload.valid)
-            type = s->autoload.type;
-
-        if (avahi_entry_group_add_service_strlst(
-                    s->entry_group,
-                    AVAHI_IF_UNSPEC, AVAHI_PROTO_UNSPEC,
-                    0,
-                    s->service_name,
-                    type == PA_NAMEREG_SINK ? SERVICE_TYPE_SINK : SERVICE_TYPE_SOURCE,
-                    NULL,
-                    NULL,
-                    u->port,
-                    txt) < 0) {
-
-            pa_log("avahi_entry_group_add_service_strlst(): %s", avahi_strerror(avahi_client_errno(u->client)));
-            goto finish;
-        }
-
-        if (avahi_entry_group_commit(s->entry_group) < 0) {
-            pa_log("avahi_entry_group_commit(): %s", avahi_strerror(avahi_client_errno(u->client)));
-            goto finish;
-        }
-
-        if (s->loaded.valid)
-            s->published = PUBLISHED_REAL;
-        else if (s->autoload.valid)
-            s->published = PUBLISHED_AUTOLOAD;
+
+    txt = txt_record_server_data(s->userdata->core, txt);
+
+    get_service_data(s, &ss, &map, &name, &description);
+    txt = avahi_string_list_add_pair(txt, "device", name);
+    txt = avahi_string_list_add_printf(txt, "rate=%u", ss.rate);
+    txt = avahi_string_list_add_printf(txt, "channels=%u", ss.channels);
+    txt = avahi_string_list_add_pair(txt, "format", pa_sample_format_to_string(ss.format));
+    txt = avahi_string_list_add_pair(txt, "channel_map", pa_channel_map_snprint(cm, sizeof(cm), &map));
+
+    if (avahi_entry_group_add_service_strlst(
+                s->entry_group,
+                AVAHI_IF_UNSPEC, AVAHI_PROTO_UNSPEC,
+                0,
+                s->service_name,
+                pa_sink_isinstance(s->device) ? SERVICE_TYPE_SINK : SERVICE_TYPE_SOURCE,
+                NULL,
+                NULL,
+                s->userdata->port,
+                txt) < 0) {
+
+        pa_log("avahi_entry_group_add_service_strlst(): %s", avahi_strerror(avahi_client_errno(s->userdata->client)));
+        goto finish;
+    }
+
+    if (avahi_entry_group_commit(s->entry_group) < 0) {
+        pa_log("avahi_entry_group_commit(): %s", avahi_strerror(avahi_client_errno(s->userdata->client)));
+        goto finish;
     }
 
     r = 0;
+    pa_log_debug("Successfully created entry group for %s.", s->service_name);
 
 finish:
 
-    if (s->published == UNPUBLISHED) {
-        /* Remove this service */
-
-        if (s->entry_group)
-            avahi_entry_group_free(s->entry_group);
-
-        pa_hashmap_remove(u->services, s->name);
-        pa_xfree(s->name);
-        pa_xfree(s->service_name);
-        pa_xfree(s);
-    }
-
-    if (txt)
-        avahi_string_list_free(txt);
+    /* Remove this service */
+    if (r < 0)
+        service_free(s);
+
+    avahi_string_list_free(txt);
 
     return r;
 }
 
-static struct service *get_service(struct userdata *u, const char *name, const char *description) {
+static struct service *get_service(struct userdata *u, pa_object *device) {
     struct service *s;
-    char hn[64];
-
-    if ((s = pa_hashmap_get(u->services, name)))
+    char hn[64], un[64];
+    const char *n;
+
+    pa_assert(u);
+    pa_object_assert_ref(device);
+
+    if ((s = pa_hashmap_get(u->services, device)))
         return s;
 
     s = pa_xnew(struct service, 1);
     s->userdata = u;
     s->entry_group = NULL;
-    s->published = UNPUBLISHED;
-    s->name = pa_xstrdup(name);
-    s->loaded.valid = s->autoload.valid = 0;
-    s->service_name = pa_sprintf_malloc("%s on %s", description ? description : s->name, pa_get_host_name(hn, sizeof(hn)));
-
-    pa_hashmap_put(u->services, s->name, s);
+    s->device = device;
+
+    if (pa_sink_isinstance(device)) {
+        if (!(n = PA_SINK(device)->description))
+            n = PA_SINK(device)->name;
+    } else {
+        if (!(n = PA_SOURCE(device)->description))
+            n = PA_SOURCE(device)->name;
+    }
+
+    s->service_name = pa_truncate_utf8(pa_sprintf_malloc("%s@%s: %s",
+                                                         pa_get_user_name(un, sizeof(un)),
+                                                         pa_get_host_name(hn, sizeof(hn)),
+                                                         n),
+                                       AVAHI_LABEL_MAX-1);
+
+    pa_hashmap_put(u->services, s->device, s);
 
     return s;
 }
 
-static int publish_sink(struct userdata *u, pa_sink *s) {
-    struct service *svc;
-    int ret;
-    assert(u && s);
-
-    svc = get_service(u, s->name, s->description);
-    if (svc->loaded.valid)
-        return publish_service(u, svc);
-
-    svc->loaded.valid = 1;
-    svc->loaded.type = PA_NAMEREG_SINK;
-    svc->loaded.index = s->index;
-
-    if ((ret = publish_service(u, svc)) < 0)
-        return ret;
-
-    pa_dynarray_put(u->sink_dynarray, s->index, svc);
-    return ret;
-}
-
-static int publish_source(struct userdata *u, pa_source *s) {
-    struct service *svc;
-    int ret;
-
-    assert(u && s);
-
-    svc = get_service(u, s->name, s->description);
-    if (svc->loaded.valid)
-        return publish_service(u, svc);
-
-    svc->loaded.valid = 1;
-    svc->loaded.type = PA_NAMEREG_SOURCE;
-    svc->loaded.index = s->index;
-
-    pa_dynarray_put(u->source_dynarray, s->index, svc);
-
-    if ((ret = publish_service(u, svc)) < 0)
-        return ret;
-
-    pa_dynarray_put(u->sink_dynarray, s->index, svc);
-    return ret;
-}
-
-static int publish_autoload(struct userdata *u, pa_autoload_entry *s) {
-    struct service *svc;
-    int ret;
-
-    assert(u && s);
-
-    svc = get_service(u, s->name, NULL);
-    if (svc->autoload.valid)
-        return publish_service(u, svc);
-
-    svc->autoload.valid = 1;
-    svc->autoload.type = s->type;
-    svc->autoload.index = s->index;
-
-    if ((ret = publish_service(u, svc)) < 0)
-        return ret;
-
-    pa_dynarray_put(u->autoload_dynarray, s->index, svc);
-    return ret;
-}
-
-static int remove_sink(struct userdata *u, uint32_t idx) {
-    struct service *svc;
-    assert(u && idx != PA_INVALID_INDEX);
-
-    if (!(svc = pa_dynarray_get(u->sink_dynarray, idx)))
-        return 0;
-
-    if (!svc->loaded.valid || svc->loaded.type != PA_NAMEREG_SINK)
-        return 0;
-
-    svc->loaded.valid = 0;
-    pa_dynarray_put(u->sink_dynarray, idx, NULL);
-
-    return publish_service(u, svc);
-}
-
-static int remove_source(struct userdata *u, uint32_t idx) {
-    struct service *svc;
-    assert(u && idx != PA_INVALID_INDEX);
-
-    if (!(svc = pa_dynarray_get(u->source_dynarray, idx)))
-        return 0;
-
-    if (!svc->loaded.valid || svc->loaded.type != PA_NAMEREG_SOURCE)
-        return 0;
-
-    svc->loaded.valid = 0;
-    pa_dynarray_put(u->source_dynarray, idx, NULL);
-
-    return publish_service(u, svc);
-}
-
-static int remove_autoload(struct userdata *u, uint32_t idx) {
-    struct service *svc;
-    assert(u && idx != PA_INVALID_INDEX);
-
-    if (!(svc = pa_dynarray_get(u->autoload_dynarray, idx)))
-        return 0;
-
-    if (!svc->autoload.valid)
-        return 0;
-
-    svc->autoload.valid = 0;
-    pa_dynarray_put(u->autoload_dynarray, idx, NULL);
-
-    return publish_service(u, svc);
-}
-
-static void subscribe_callback(pa_core *c, pa_subscription_event_type_t t, uint32_t idx, void *userdata) {
-    struct userdata *u = userdata;
-    assert(u && c);
-
-    switch (t & PA_SUBSCRIPTION_EVENT_FACILITY_MASK)
-        case PA_SUBSCRIPTION_EVENT_SINK: {
-            if ((t & PA_SUBSCRIPTION_EVENT_TYPE_MASK) == PA_SUBSCRIPTION_EVENT_NEW) {
-                pa_sink *sink;
-
-                if ((sink = pa_idxset_get_by_index(c->sinks, idx))) {
-                    if (publish_sink(u, sink) < 0)
-                        goto fail;
-                }
-            } else if ((t & PA_SUBSCRIPTION_EVENT_TYPE_MASK) == PA_SUBSCRIPTION_EVENT_REMOVE) {
-                if (remove_sink(u, idx) < 0)
-                    goto fail;
-            }
-
-            break;
-
-        case PA_SUBSCRIPTION_EVENT_SOURCE:
-
-            if ((t & PA_SUBSCRIPTION_EVENT_TYPE_MASK) == PA_SUBSCRIPTION_EVENT_NEW) {
-                pa_source *source;
-
-                if ((source = pa_idxset_get_by_index(c->sources, idx))) {
-                    if (publish_source(u, source) < 0)
-                        goto fail;
-                }
-            } else if ((t & PA_SUBSCRIPTION_EVENT_TYPE_MASK) == PA_SUBSCRIPTION_EVENT_REMOVE) {
-                if (remove_source(u, idx) < 0)
-                    goto fail;
-            }
-
-            break;
-
-        case PA_SUBSCRIPTION_EVENT_AUTOLOAD:
-            if ((t & PA_SUBSCRIPTION_EVENT_TYPE_MASK) == PA_SUBSCRIPTION_EVENT_NEW) {
-                pa_autoload_entry *autoload;
-
-                if ((autoload = pa_idxset_get_by_index(c->autoload_idxset, idx))) {
-                    if (publish_autoload(u, autoload) < 0)
-                        goto fail;
-                }
-            } else if ((t & PA_SUBSCRIPTION_EVENT_TYPE_MASK) == PA_SUBSCRIPTION_EVENT_REMOVE) {
-                if (remove_autoload(u, idx) < 0)
-                        goto fail;
-            }
-
-            break;
-    }
-
-    return;
-
-fail:
-    if (u->subscription) {
-        pa_subscription_free(u->subscription);
-        u->subscription = NULL;
-    }
+static void service_free(struct service *s) {
+    pa_assert(s);
+
+    pa_hashmap_remove(s->userdata->services, s->device);
+
+    if (s->entry_group) {
+        pa_log_debug("Removing entry group for %s.", s->service_name);
+        avahi_entry_group_free(s->entry_group);
+    }
+
+    pa_xfree(s->service_name);
+    pa_xfree(s);
+}
+
+static pa_hook_result_t device_new_or_changed_cb(pa_core *c, pa_object *o, struct userdata *u) {
+    pa_assert(c);
+    pa_object_assert_ref(o);
+
+    publish_service(get_service(u, o));
+
+    return PA_HOOK_OK;
+}
+
+static pa_hook_result_t device_unlink_cb(pa_core *c, pa_object *o, struct userdata *u) {
+    struct service *s;
+
+    pa_assert(c);
+    pa_object_assert_ref(o);
+
+    if ((s = pa_hashmap_get(u->services, o)))
+        service_free(s);
+
+    return PA_HOOK_OK;
 }
 
 static int publish_main_service(struct userdata *u);
 
 static void main_entry_group_callback(AvahiEntryGroup *g, AvahiEntryGroupState state, void *userdata) {
     struct userdata *u = userdata;
-    assert(u);
-
-    if (state == AVAHI_ENTRY_GROUP_COLLISION) {
-        char *t;
-
-        t = avahi_alternative_service_name(u->service_name);
-        pa_xfree(u->service_name);
-        u->service_name = t;
-
-        publish_main_service(u);
+    pa_assert(u);
+
+    switch (state) {
+
+        case AVAHI_ENTRY_GROUP_ESTABLISHED:
+            pa_log_info("Successfully established main service.");
+            break;
+
+        case AVAHI_ENTRY_GROUP_COLLISION: {
+            char *t;
+
+            t = avahi_alternative_service_name(u->service_name);
+            pa_log_info("Name collision: renaming main service %s to %s.", u->service_name, t);
+            pa_xfree(u->service_name);
+            u->service_name = t;
+
+            publish_main_service(u);
+            break;
+        }
+
+        case AVAHI_ENTRY_GROUP_FAILURE: {
+            pa_log("Failed to register main service: %s", avahi_strerror(avahi_client_errno(avahi_entry_group_get_client(g))));
+
+            avahi_entry_group_free(g);
+            u->main_entry_group = NULL;
+            break;
+        }
+
+        case AVAHI_ENTRY_GROUP_UNCOMMITED:
+        case AVAHI_ENTRY_GROUP_REGISTERING:
+            break;
     }
 }
 
 static int publish_main_service(struct userdata *u) {
     AvahiStringList *txt = NULL;
     int r = -1;
+
+    pa_assert(u);
 
     if (!u->main_entry_group) {
         if (!(u->main_entry_group = avahi_entry_group_new(u->client, main_entry_group_callback, u))) {
@@ -464,7 +353,7 @@
     } else
         avahi_entry_group_reset(u->main_entry_group);
 
-    txt = txt_record_server_data(u->core, NULL);
+    txt = txt_record_server_data(u->core, txt);
 
     if (avahi_entry_group_add_service_strlst(
                 u->main_entry_group,
@@ -497,26 +386,18 @@
 static int publish_all_services(struct userdata *u) {
     pa_sink *sink;
     pa_source *source;
-    pa_autoload_entry *autoload;
     int r = -1;
     uint32_t idx;
 
-    assert(u);
+    pa_assert(u);
 
     pa_log_debug("Publishing services in Zeroconf");
 
-    for (sink = pa_idxset_first(u->core->sinks, &idx); sink; sink = pa_idxset_next(u->core->sinks, &idx))
-        if (publish_sink(u, sink) < 0)
-            goto fail;
-
-    for (source = pa_idxset_first(u->core->sources, &idx); source; source = pa_idxset_next(u->core->sources, &idx))
-        if (publish_source(u, source) < 0)
-            goto fail;
-
-    if (u->core->autoload_idxset)
-        for (autoload = pa_idxset_first(u->core->autoload_idxset, &idx); autoload; autoload = pa_idxset_next(u->core->autoload_idxset, &idx))
-            if (publish_autoload(u, autoload) < 0)
-                goto fail;
+    for (sink = PA_SINK(pa_idxset_first(u->core->sinks, &idx)); sink; sink = PA_SINK(pa_idxset_next(u->core->sinks, &idx)))
+        publish_service(get_service(u, PA_OBJECT(sink)));
+
+    for (source = PA_SOURCE(pa_idxset_first(u->core->sources, &idx)); source; source = PA_SOURCE(pa_idxset_next(u->core->sources, &idx)))
+        publish_service(get_service(u, PA_OBJECT(source)));
 
     if (publish_main_service(u) < 0)
         goto fail;
@@ -527,38 +408,44 @@
     return r;
 }
 
-static void unpublish_all_services(struct userdata *u, int rem) {
+static void unpublish_all_services(struct userdata *u, pa_bool_t rem) {
     void *state = NULL;
     struct service *s;
 
-    assert(u);
+    pa_assert(u);
 
     pa_log_debug("Unpublishing services in Zeroconf");
 
     while ((s = pa_hashmap_iterate(u->services, &state, NULL))) {
         if (s->entry_group) {
             if (rem) {
+                pa_log_debug("Removing entry group for %s.", s->service_name);
                 avahi_entry_group_free(s->entry_group);
                 s->entry_group = NULL;
-            } else
+            } else {
                 avahi_entry_group_reset(s->entry_group);
-        }
-
-        s->published = UNPUBLISHED;
+                pa_log_debug("Resetting entry group for %s.", s->service_name);
+            }
+        }
     }
 
     if (u->main_entry_group) {
         if (rem) {
+            pa_log_debug("Removing main entry group.");
             avahi_entry_group_free(u->main_entry_group);
             u->main_entry_group = NULL;
-        } else
+        } else {
             avahi_entry_group_reset(u->main_entry_group);
+            pa_log_debug("Resetting main entry group.");
+        }
     }
 }
 
 static void client_callback(AvahiClient *c, AvahiClientState state, void *userdata) {
     struct userdata *u = userdata;
-    assert(c);
+
+    pa_assert(c);
+    pa_assert(u);
 
     u->client = c;
 
@@ -568,13 +455,17 @@
             break;
 
         case AVAHI_CLIENT_S_COLLISION:
-            unpublish_all_services(u, 0);
+            pa_log_debug("Host name collision");
+            unpublish_all_services(u, FALSE);
             break;
 
         case AVAHI_CLIENT_FAILURE:
             if (avahi_client_errno(c) == AVAHI_ERR_DISCONNECTED) {
                 int error;
-                unpublish_all_services(u, 1);
+
+                pa_log_debug("Avahi daemon disconnected.");
+
+                unpublish_all_services(u, TRUE);
                 avahi_client_free(u->client);
 
                 if (!(u->client = avahi_client_new(u->avahi_poll, AVAHI_CLIENT_NO_FAIL, client_callback, u, &error)))
@@ -587,11 +478,12 @@
     }
 }
 
-int pa__init(pa_core *c, pa_module*m) {
+int pa__init(pa_module*m) {
+
     struct userdata *u;
     uint32_t port = PA_NATIVE_DEFAULT_PORT;
     pa_modargs *ma = NULL;
-    char hn[256];
+    char hn[256], un[256];
     int error;
 
     if (!(ma = pa_modargs_new(m->argument, valid_modargs))) {
@@ -599,30 +491,29 @@
         goto fail;
     }
 
-    if (pa_modargs_get_value_u32(ma, "port", &port) < 0 || port == 0 || port >= 0xFFFF) {
+    if (pa_modargs_get_value_u32(ma, "port", &port) < 0 || port <= 0 || port > 0xFFFF) {
         pa_log("invalid port specified.");
         goto fail;
     }
 
     m->userdata = u = pa_xnew(struct userdata, 1);
-    u->core = c;
+    u->core = m->core;
     u->port = (uint16_t) port;
 
-    u->avahi_poll = pa_avahi_poll_new(c->mainloop);
-
-    u->services = pa_hashmap_new(pa_idxset_string_hash_func, pa_idxset_string_compare_func);
-    u->sink_dynarray = pa_dynarray_new();
-    u->source_dynarray = pa_dynarray_new();
-    u->autoload_dynarray = pa_dynarray_new();
-
-    u->subscription = pa_subscription_new(c,
-                                          PA_SUBSCRIPTION_MASK_SINK|
-                                          PA_SUBSCRIPTION_MASK_SOURCE|
-                                          PA_SUBSCRIPTION_MASK_AUTOLOAD, subscribe_callback, u);
+    u->avahi_poll = pa_avahi_poll_new(m->core->mainloop);
+
+    u->services = pa_hashmap_new(pa_idxset_trivial_hash_func, pa_idxset_trivial_compare_func);
+
+    u->sink_new_slot = pa_hook_connect(&m->core->hooks[PA_CORE_HOOK_SINK_NEW_POST], (pa_hook_cb_t) device_new_or_changed_cb, u);
+    u->sink_changed_slot = pa_hook_connect(&m->core->hooks[PA_CORE_HOOK_SINK_DESCRIPTION_CHANGED], (pa_hook_cb_t) device_new_or_changed_cb, u);
+    u->sink_unlink_slot = pa_hook_connect(&m->core->hooks[PA_CORE_HOOK_SINK_UNLINK], (pa_hook_cb_t) device_unlink_cb, u);
+    u->source_new_slot = pa_hook_connect(&m->core->hooks[PA_CORE_HOOK_SOURCE_NEW_POST], (pa_hook_cb_t) device_new_or_changed_cb, u);
+    u->source_changed_slot = pa_hook_connect(&m->core->hooks[PA_CORE_HOOK_SOURCE_DESCRIPTION_CHANGED], (pa_hook_cb_t) device_new_or_changed_cb, u);
+    u->source_unlink_slot = pa_hook_connect(&m->core->hooks[PA_CORE_HOOK_SOURCE_UNLINK], (pa_hook_cb_t) device_unlink_cb, u);
 
     u->main_entry_group = NULL;
 
-    u->service_name = pa_xstrdup(pa_get_host_name(hn, sizeof(hn)));
+    u->service_name = pa_truncate_utf8(pa_sprintf_malloc("%s@%s", pa_get_user_name(un, sizeof(un)), pa_get_host_name(hn, sizeof(hn))), AVAHI_LABEL_MAX);
 
     if (!(u->client = avahi_client_new(u->avahi_poll, AVAHI_CLIENT_NO_FAIL, client_callback, u, &error))) {
         pa_log("pa_avahi_client_new() failed: %s", avahi_strerror(error));
@@ -634,7 +525,7 @@
     return 0;
 
 fail:
-    pa__done(c, m);
+    pa__done(m);
 
     if (ma)
         pa_modargs_free(ma);
@@ -642,41 +533,34 @@
     return -1;
 }
 
-static void service_free(void *p, void *userdata) {
-    struct service *s = p;
-    struct userdata *u = userdata;
-
-    assert(s);
-    assert(u);
-
-    if (s->entry_group)
-        avahi_entry_group_free(s->entry_group);
-
-    pa_xfree(s->service_name);
-    pa_xfree(s->name);
-    pa_xfree(s);
-}
-
-void pa__done(pa_core *c, pa_module*m) {
+void pa__done(pa_module*m) {
     struct userdata*u;
-    assert(c && m);
+    pa_assert(m);
 
     if (!(u = m->userdata))
         return;
 
-    if (u->services)
-        pa_hashmap_free(u->services, service_free, u);
-
-    if (u->subscription)
-        pa_subscription_free(u->subscription);
-
-    if (u->sink_dynarray)
-        pa_dynarray_free(u->sink_dynarray, NULL, NULL);
-    if (u->source_dynarray)
-        pa_dynarray_free(u->source_dynarray, NULL, NULL);
-    if (u->autoload_dynarray)
-        pa_dynarray_free(u->autoload_dynarray, NULL, NULL);
-
+    if (u->services) {
+        struct service *s;
+
+        while ((s = pa_hashmap_get_first(u->services)))
+            service_free(s);
+
+        pa_hashmap_free(u->services, NULL, NULL);
+    }
+
+    if (u->sink_new_slot)
+        pa_hook_slot_free(u->sink_new_slot);
+    if (u->source_new_slot)
+        pa_hook_slot_free(u->source_new_slot);
+    if (u->sink_changed_slot)
+        pa_hook_slot_free(u->sink_changed_slot);
+    if (u->source_changed_slot)
+        pa_hook_slot_free(u->source_changed_slot);
+    if (u->sink_unlink_slot)
+        pa_hook_slot_free(u->sink_unlink_slot);
+    if (u->source_unlink_slot)
+        pa_hook_slot_free(u->source_unlink_slot);
 
     if (u->main_entry_group)
         avahi_entry_group_free(u->main_entry_group);
@@ -690,4 +574,3 @@
     pa_xfree(u->service_name);
     pa_xfree(u);
 }
-

Modified: trunk/src/modules/oss-util.c
URL: http://0pointer.de/cgi-bin/viewcvs.cgi/trunk/src/modules/oss-util.c?rev=1971&root=pulseaudio&r1=1970&r2=1971&view=diff
==============================================================================
--- trunk/src/modules/oss-util.c (original)
+++ trunk/src/modules/oss-util.c Sun Oct 28 20:13:50 2007
@@ -26,7 +26,6 @@
 #include <config.h>
 #endif
 
-#include <assert.h>
 #include <sys/soundcard.h>
 #include <sys/ioctl.h>
 #include <stdio.h>
@@ -37,9 +36,11 @@
 #include <sys/stat.h>
 #include <fcntl.h>
 
+#include <pulse/xmalloc.h>
 #include <pulsecore/core-error.h>
 #include <pulsecore/core-util.h>
 #include <pulsecore/log.h>
+#include <pulsecore/macro.h>
 
 #include "oss-util.h"
 
@@ -47,59 +48,58 @@
     int fd = -1;
     int caps;
 
-    assert(device && mode && (*mode == O_RDWR || *mode == O_RDONLY || *mode == O_WRONLY));
+    pa_assert(device);
+    pa_assert(mode);
+    pa_assert(*mode == O_RDWR || *mode == O_RDONLY || *mode == O_WRONLY);
 
     if(!pcaps)
         pcaps = &caps;
 
     if (*mode == O_RDWR) {
-        if ((fd = open(device, O_RDWR|O_NDELAY)) >= 0) {
-            int dcaps, *tcaps;
+        if ((fd = open(device, O_RDWR|O_NDELAY|O_NOCTTY)) >= 0) {
             ioctl(fd, SNDCTL_DSP_SETDUPLEX, 0);
 
-            tcaps = pcaps ? pcaps : &dcaps;
-
-            if (ioctl(fd, SNDCTL_DSP_GETCAPS, tcaps) < 0) {
+            if (ioctl(fd, SNDCTL_DSP_GETCAPS, pcaps) < 0) {
                 pa_log("SNDCTL_DSP_GETCAPS: %s", pa_cstrerror(errno));
                 goto fail;
             }
 
-            if (*tcaps & DSP_CAP_DUPLEX)
+            if (*pcaps & DSP_CAP_DUPLEX)
                 goto success;
 
             pa_log_warn("'%s' doesn't support full duplex", device);
 
-            close(fd);
+            pa_close(fd);
         }
 
-        if ((fd = open(device, (*mode = O_WRONLY)|O_NDELAY)) < 0) {
-            if ((fd = open(device, (*mode = O_RDONLY)|O_NDELAY)) < 0) {
+        if ((fd = open(device, (*mode = O_WRONLY)|O_NDELAY|O_NOCTTY)) < 0) {
+            if ((fd = open(device, (*mode = O_RDONLY)|O_NDELAY|O_NOCTTY)) < 0) {
                 pa_log("open('%s'): %s", device, pa_cstrerror(errno));
                 goto fail;
             }
         }
     } else {
-        if ((fd = open(device, *mode|O_NDELAY)) < 0) {
+        if ((fd = open(device, *mode|O_NDELAY|O_NOCTTY)) < 0) {
             pa_log("open('%s'): %s", device, pa_cstrerror(errno));
             goto fail;
         }
     }
 
-success:
-
     *pcaps = 0;
 
     if (ioctl(fd, SNDCTL_DSP_GETCAPS, pcaps) < 0) {
         pa_log("SNDCTL_DSP_GETCAPS: %s", pa_cstrerror(errno));
         goto fail;
     }
+
+success:
 
     pa_log_debug("capabilities:%s%s%s%s%s%s%s%s%s%s%s%s%s%s",
                  *pcaps & DSP_CAP_BATCH ? " BATCH" : "",
 #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 @@
 #ifdef DSP_CAP_MULTI
                  *pcaps & DSP_CAP_MULTI ? " MULTI" : "",
 #else
-		 "",
+                 "",
 #endif
 #ifdef DSP_CAP_OUTPUT
                  *pcaps & DSP_CAP_OUTPUT ? " OUTPUT" : "",
@@ -142,13 +142,13 @@
 #endif
                  *pcaps & DSP_CAP_TRIGGER ? " TRIGGER" : "");
 
-    pa_fd_set_cloexec(fd, 1);
+    pa_make_fd_cloexec(fd);
 
     return fd;
 
 fail:
     if (fd >= 0)
-        close(fd);
+        pa_close(fd);
     return -1;
 }
 
@@ -166,7 +166,8 @@
         [PA_SAMPLE_FLOAT32BE] = AFMT_QUERY, /* not supported */
     };
 
-    assert(fd >= 0 && ss);
+    pa_assert(fd >= 0);
+    pa_assert(ss);
 
     orig_format = ss->format;
 
@@ -199,7 +200,7 @@
         pa_log("SNDCTL_DSP_CHANNELS: %s", pa_cstrerror(errno));
         return -1;
     }
-    assert(channels > 0);
+    pa_assert(channels > 0);
 
     if (ss->channels != channels) {
         pa_log_warn("device doesn't support %i channels, using %i channels.", ss->channels, channels);
@@ -211,7 +212,7 @@
         pa_log("SNDCTL_DSP_SPEED: %s", pa_cstrerror(errno));
         return -1;
     }
-    assert(speed > 0);
+    pa_assert(speed > 0);
 
     if (ss->rate != (unsigned) speed) {
         pa_log_warn("device doesn't support %i Hz, changed to %i Hz.", ss->rate, speed);
@@ -248,27 +249,29 @@
     return 0;
 }
 
-static int pa_oss_get_volume(int fd, int mixer, const pa_sample_spec *ss, pa_cvolume *volume) {
+int pa_oss_get_volume(int fd, int mixer, const pa_sample_spec *ss, pa_cvolume *volume) {
     char cv[PA_CVOLUME_SNPRINT_MAX];
     unsigned vol;
 
-    assert(fd >= 0);
-    assert(ss);
-    assert(volume);
+    pa_assert(fd >= 0);
+    pa_assert(ss);
+    pa_assert(volume);
 
     if (ioctl(fd, mixer, &vol) < 0)
         return -1;
 
+    pa_cvolume_reset(volume, ss->channels);
+
     volume->values[0] = ((vol & 0xFF) * PA_VOLUME_NORM) / 100;
 
-    if ((volume->channels = ss->channels) >= 2)
+    if (volume->channels >= 2)
         volume->values[1] = (((vol >> 8) & 0xFF) * PA_VOLUME_NORM) / 100;
 
     pa_log_debug("Read mixer settings: %s", pa_cvolume_snprint(cv, sizeof(cv), volume));
     return 0;
 }
 
-static int pa_oss_set_volume(int fd, int mixer, const pa_sample_spec *ss, const pa_cvolume *volume) {
+int pa_oss_set_volume(int fd, long mixer, const pa_sample_spec *ss, const pa_cvolume *volume) {
     char cv[PA_CVOLUME_SNPRINT_MAX];
     unsigned vol;
     pa_volume_t l, r;
@@ -289,40 +292,38 @@
     return 0;
 }
 
-int pa_oss_get_pcm_volume(int fd, const pa_sample_spec *ss, pa_cvolume *volume) {
-    return pa_oss_get_volume(fd, SOUND_MIXER_READ_PCM, ss, volume);
-}
-
-int pa_oss_set_pcm_volume(int fd, const pa_sample_spec *ss, const pa_cvolume *volume) {
-    return pa_oss_set_volume(fd, SOUND_MIXER_WRITE_PCM, ss, volume);
-}
-
-int pa_oss_get_input_volume(int fd, const pa_sample_spec *ss, pa_cvolume *volume) {
-    return pa_oss_get_volume(fd, SOUND_MIXER_READ_IGAIN, ss, volume);
-}
-
-int pa_oss_set_input_volume(int fd, const pa_sample_spec *ss, const pa_cvolume *volume) {
-    return pa_oss_set_volume(fd, SOUND_MIXER_WRITE_IGAIN, ss, volume);
+static int get_device_number(const char *dev) {
+    char buf[PATH_MAX];
+    const char *p, *e;
+
+    if (readlink(dev, buf, sizeof(buf)) < 0) {
+        if (errno != EINVAL && errno != ENOLINK)
+            return -1;
+
+        p = dev;
+    } else
+        p = buf;
+
+    if ((e = strrchr(p, '/')))
+        p = e+1;
+
+    if (p == 0)
+        return 0;
+
+    p = strchr(p, 0) -1;
+
+    if (*p >= '0' && *p <= '9')
+        return *p - '0';
+
+    return -1;
 }
 
 int pa_oss_get_hw_description(const char *dev, char *name, size_t l) {
     FILE *f;
-    const char *e = NULL;
     int n, r = -1;
     int b = 0;
 
-    if (strncmp(dev, "/dev/dsp", 8) == 0)
-        e = dev+8;
-    else if (strncmp(dev, "/dev/adsp", 9) == 0)
-        e = dev+9;
-    else
-        return -1;
-
-    if (*e == 0)
-        n = 0;
-    else if (*e >= '0' && *e <= '9' && *(e+1) == 0)
-        n = *e - '0';
-    else
+    if ((n = get_device_number(dev)) < 0)
         return -1;
 
     if (!(f = fopen("/dev/sndstat", "r")) &&
@@ -357,7 +358,7 @@
 
         if (device == n) {
             char *k = strchr(line, ':');
-            assert(k);
+            pa_assert(k);
             k++;
             k += strspn(k, " ");
 
@@ -373,3 +374,34 @@
     fclose(f);
     return r;
 }
+
+static int open_mixer(const char *mixer) {
+    int fd;
+
+    if ((fd = open(mixer, O_RDWR|O_NDELAY|O_NOCTTY)) >= 0)
+        return fd;
+
+    return -1;
+}
+
+int pa_oss_open_mixer_for_device(const char *device) {
+    int n;
+    char *fn;
+    int fd;
+
+    if ((n = get_device_number(device)) < 0)
+        return -1;
+
+    if (n == 0)
+        if ((fd = open_mixer("/dev/mixer")) >= 0)
+            return fd;
+
+    fn = pa_sprintf_malloc("/dev/mixer%i", n);
+    fd = open_mixer(fn);
+    pa_xfree(fn);
+
+    if (fd < 0)
+        pa_log_warn("Failed to open mixer '%s': %s", device, pa_cstrerror(errno));
+
+    return fd;
+}

Modified: trunk/src/modules/oss-util.h
URL: http://0pointer.de/cgi-bin/viewcvs.cgi/trunk/src/modules/oss-util.h?rev=1971&root=pulseaudio&r1=1970&r2=1971&view=diff
==============================================================================
--- trunk/src/modules/oss-util.h (original)
+++ trunk/src/modules/oss-util.h Sun Oct 28 20:13:50 2007
@@ -33,12 +33,11 @@
 
 int pa_oss_set_fragments(int fd, int frags, int frag_size);
 
-int pa_oss_get_pcm_volume(int fd, const pa_sample_spec *ss, pa_cvolume *volume);
-int pa_oss_set_pcm_volume(int fd, const pa_sample_spec *ss, const pa_cvolume *volume);
-
-int pa_oss_get_input_volume(int fd, const pa_sample_spec *ss, pa_cvolume *volume);
-int pa_oss_set_input_volume(int fd, const pa_sample_spec *ss, const pa_cvolume *volume);
+int pa_oss_set_volume(int fd, long mixer, const pa_sample_spec *ss, const pa_cvolume *volume);
+int pa_oss_get_volume(int fd, int mixer, const pa_sample_spec *ss, pa_cvolume *volume);
 
 int pa_oss_get_hw_description(const char *dev, char *name, size_t l);
 
+int pa_oss_open_mixer_for_device(const char *device);
+
 #endif

Modified: trunk/src/modules/rtp/module-rtp-recv.c
URL: http://0pointer.de/cgi-bin/viewcvs.cgi/trunk/src/modules/rtp/module-rtp-recv.c?rev=1971&root=pulseaudio&r1=1970&r2=1971&view=diff
==============================================================================
--- trunk/src/modules/rtp/module-rtp-recv.c (original)
+++ trunk/src/modules/rtp/module-rtp-recv.c Sun Oct 28 20:13:50 2007
@@ -24,7 +24,6 @@
 #include <config.h>
 #endif
 
-#include <assert.h>
 #include <stdio.h>
 #include <sys/socket.h>
 #include <netinet/in.h>
@@ -32,6 +31,7 @@
 #include <errno.h>
 #include <string.h>
 #include <unistd.h>
+#include <poll.h>
 
 #include <pulse/timeval.h>
 #include <pulse/xmalloc.h>
@@ -47,6 +47,10 @@
 #include <pulsecore/modargs.h>
 #include <pulsecore/namereg.h>
 #include <pulsecore/sample-util.h>
+#include <pulsecore/macro.h>
+#include <pulsecore/atomic.h>
+#include <pulsecore/rtclock.h>
+#include <pulsecore/atomic.h>
 
 #include "module-rtp-recv-symdef.h"
 
@@ -66,7 +70,7 @@
 #define DEFAULT_SAP_ADDRESS "224.0.0.56"
 #define MEMBLOCKQ_MAXLENGTH (1024*170)
 #define MAX_SESSIONS 16
-#define DEATH_TIMEOUT 20000000
+#define DEATH_TIMEOUT 20
 
 static const char* const valid_modargs[] = {
     "sink",
@@ -76,102 +80,126 @@
 
 struct session {
     struct userdata *userdata;
+    PA_LLIST_FIELDS(struct session);
 
     pa_sink_input *sink_input;
     pa_memblockq *memblockq;
 
-    pa_time_event *death_event;
-
-    int first_packet;
+    pa_bool_t first_packet;
     uint32_t ssrc;
     uint32_t offset;
 
     struct pa_sdp_info sdp_info;
 
     pa_rtp_context rtp_context;
-    pa_io_event* rtp_event;
+
+    pa_rtpoll_item *rtpoll_item;
+
+    pa_atomic_t timestamp;
 };
 
 struct userdata {
     pa_module *module;
-    pa_core *core;
 
     pa_sap_context sap_context;
     pa_io_event* sap_event;
 
+    pa_time_event *check_death_event;
+
+    char *sink_name;
+
+    PA_LLIST_HEAD(struct session, sessions);
     pa_hashmap *by_origin;
-
-    char *sink_name;
-
     int n_sessions;
 };
 
-static void session_free(struct session *s, int from_hash);
-
-static int sink_input_peek(pa_sink_input *i, pa_memchunk *chunk) {
-    struct session *s;
-    assert(i);
-    s = i->userdata;
+static void session_free(struct session *s);
+
+/* Called from I/O thread context */
+static int sink_input_process_msg(pa_msgobject *o, int code, void *data, int64_t offset, pa_memchunk *chunk) {
+    struct session *s = PA_SINK_INPUT(o)->userdata;
+
+    switch (code) {
+        case PA_SINK_INPUT_MESSAGE_GET_LATENCY:
+            *((pa_usec_t*) data) = pa_bytes_to_usec(pa_memblockq_get_length(s->memblockq), &s->sink_input->sample_spec);
+
+            /* Fall through, the default handler will add in the extra
+             * latency added by the resampler */
+            break;
+    }
+
+    return pa_sink_input_process_msg(o, code, data, offset, chunk);
+}
+
+/* Called from I/O thread context */
+static int sink_input_peek(pa_sink_input *i, size_t length, pa_memchunk *chunk) {
+    struct session *s;
+    pa_sink_input_assert_ref(i);
+    pa_assert_se(s = i->userdata);
 
     return pa_memblockq_peek(s->memblockq, chunk);
 }
 
-static void sink_input_drop(pa_sink_input *i, const pa_memchunk *chunk, size_t length) {
-    struct session *s;
-    assert(i);
-    s = i->userdata;
-
-    pa_memblockq_drop(s->memblockq, chunk, length);
-}
-
+/* Called from I/O thread context */
+static void sink_input_drop(pa_sink_input *i, size_t length) {
+    struct session *s;
+    pa_sink_input_assert_ref(i);
+    pa_assert_se(s = i->userdata);
+
+    pa_memblockq_drop(s->memblockq, length);
+}
+
+/* Called from main context */
 static void sink_input_kill(pa_sink_input* i) {
     struct session *s;
-    assert(i);
-    s = i->userdata;
-
-    session_free(s, 1);
-}
-
-static pa_usec_t sink_input_get_latency(pa_sink_input *i) {
-    struct session *s;
-    assert(i);
-    s = i->userdata;
-
-    return pa_bytes_to_usec(pa_memblockq_get_length(s->memblockq), &i->sample_spec);
-}
-
-static void rtp_event_cb(pa_mainloop_api *m, pa_io_event *e, int fd, pa_io_event_flags_t flags, void *userdata) {
-    struct session *s = userdata;
+    pa_sink_input_assert_ref(i);
+    pa_assert_se(s = i->userdata);
+
+    session_free(s);
+}
+
+/* Called from I/O thread context */
+static int rtpoll_work_cb(pa_rtpoll_item *i) {
     pa_memchunk chunk;
     int64_t k, j, delta;
-    struct timeval tv;
-
-    assert(m);
-    assert(e);
-    assert(s);
-    assert(fd == s->rtp_context.fd);
-    assert(flags == PA_IO_EVENT_INPUT);
-
-    if (pa_rtp_recv(&s->rtp_context, &chunk, s->userdata->core->mempool) < 0)
-        return;
+    struct timeval now;
+    struct session *s;
+    struct pollfd *p;
+
+    pa_assert_se(s = pa_rtpoll_item_get_userdata(i));
+
+    p = pa_rtpoll_item_get_pollfd(i, NULL);
+
+    if (p->revents & (POLLERR|POLLNVAL|POLLHUP|POLLOUT)) {
+        pa_log("poll() signalled bad revents.");
+        return -1;
+    }
+
+    if ((p->revents & POLLIN) == 0)
+        return 0;
+
+    p->revents = 0;
+
+    if (pa_rtp_recv(&s->rtp_context, &chunk, s->userdata->module->core->mempool) < 0)
+        return 0;
 
     if (s->sdp_info.payload != s->rtp_context.payload) {
         pa_memblock_unref(chunk.memblock);
-        return;
+        return 0;
     }
 
     if (!s->first_packet) {
-        s->first_packet = 1;
+        s->first_packet = TRUE;
 
         s->ssrc = s->rtp_context.ssrc;
         s->offset = s->rtp_context.timestamp;
 
-        if (s->ssrc == s->userdata->core->cookie)
-            pa_log_warn("WARNING! Detected RTP packet loop!");
+        if (s->ssrc == s->userdata->module->core->cookie)
+            pa_log_warn("Detected RTP packet loop!");
     } else {
         if (s->ssrc != s->rtp_context.ssrc) {
             pa_memblock_unref(chunk.memblock);
-            return;
+            return 0;
         }
     }
 
@@ -197,25 +225,48 @@
 
     pa_memblock_unref(chunk.memblock);
 
-    /* Reset death timer */
-    pa_gettimeofday(&tv);
-    pa_timeval_add(&tv, DEATH_TIMEOUT);
-    m->time_restart(s->death_event, &tv);
-}
-
-static void death_event_cb(pa_mainloop_api *m, pa_time_event *t, const struct timeval *tv, void *userdata) {
-    struct session *s = userdata;
-
-    assert(m);
-    assert(t);
-    assert(tv);
-    assert(s);
-
-    session_free(s, 1);
+    pa_rtclock_get(&now);
+    pa_atomic_store(&s->timestamp, now.tv_sec);
+
+    return 1;
+}
+
+/* Called from I/O thread context */
+static void sink_input_attach(pa_sink_input *i) {
+    struct session *s;
+    struct pollfd *p;
+
+    pa_sink_input_assert_ref(i);
+    pa_assert_se(s = i->userdata);
+
+    pa_assert(!s->rtpoll_item);
+    s->rtpoll_item = pa_rtpoll_item_new(i->sink->rtpoll, PA_RTPOLL_LATE, 1);
+
+    p = pa_rtpoll_item_get_pollfd(s->rtpoll_item, NULL);
+    p->fd = s->rtp_context.fd;
+    p->events = POLLIN;
+    p->revents = 0;
+
+    pa_rtpoll_item_set_work_callback(s->rtpoll_item, rtpoll_work_cb);
+    pa_rtpoll_item_set_userdata(s->rtpoll_item, s);
+}
+
+/* Called from I/O thread context */
+static void sink_input_detach(pa_sink_input *i) {
+    struct session *s;
+    pa_sink_input_assert_ref(i);
+    pa_assert_se(s = i->userdata);
+
+    pa_assert(s->rtpoll_item);
+    pa_rtpoll_item_free(s->rtpoll_item);
+    s->rtpoll_item = NULL;
 }
 
 static int mcast_socket(const struct sockaddr* sa, socklen_t salen) {
     int af, fd = -1, r, one;
+
+    pa_assert(sa);
+    pa_assert(salen > 0);
 
     af = sa->sa_family;
     if ((fd = socket(af, SOCK_DGRAM, 0)) < 0) {
@@ -262,27 +313,34 @@
 
 static struct session *session_new(struct userdata *u, const pa_sdp_info *sdp_info) {
     struct session *s = NULL;
-    struct timeval tv;
     char *c;
     pa_sink *sink;
     int fd = -1;
     pa_memblock *silence;
     pa_sink_input_new_data data;
+    struct timeval now;
+
+    pa_assert(u);
+    pa_assert(sdp_info);
 
     if (u->n_sessions >= MAX_SESSIONS) {
-        pa_log("session limit reached.");
-        goto fail;
-    }
-
-    if (!(sink = pa_namereg_get(u->core, u->sink_name, PA_NAMEREG_SINK, 1))) {
-        pa_log("sink does not exist.");
+        pa_log("Session limit reached.");
+        goto fail;
+    }
+
+    if (!(sink = pa_namereg_get(u->module->core, u->sink_name, PA_NAMEREG_SINK, 1))) {
+        pa_log("Sink does not exist.");
         goto fail;
     }
 
     s = pa_xnew0(struct session, 1);
     s->userdata = u;
-    s->first_packet = 0;
+    s->first_packet = FALSE;
     s->sdp_info = *sdp_info;
+    s->rtpoll_item = NULL;
+
+    pa_rtclock_get(&now);
+    pa_atomic_store(&s->timestamp, now.tv_sec);
 
     if ((fd = mcast_socket((const struct sockaddr*) &sdp_info->sa, sdp_info->salen)) < 0)
         goto fail;
@@ -299,25 +357,27 @@
     data.module = u->module;
     pa_sink_input_new_data_set_sample_spec(&data, &sdp_info->sample_spec);
 
-    s->sink_input = pa_sink_input_new(u->core, &data, 0);
+    s->sink_input = pa_sink_input_new(u->module->core, &data, 0);
     pa_xfree(c);
 
     if (!s->sink_input) {
-        pa_log("failed to create sink input.");
+        pa_log("Failed to create sink input.");
         goto fail;
     }
 
     s->sink_input->userdata = s;
 
+    s->sink_input->parent.process_msg = sink_input_process_msg;
     s->sink_input->peek = sink_input_peek;
     s->sink_input->drop = sink_input_drop;
     s->sink_input->kill = sink_input_kill;
-    s->sink_input->get_latency = sink_input_get_latency;
-
-    silence = pa_silence_memblock_new(s->userdata->core->mempool,
-                                      &s->sink_input->sample_spec,
-                                      (pa_bytes_per_second(&s->sink_input->sample_spec)/128/pa_frame_size(&s->sink_input->sample_spec))*
-                                      pa_frame_size(&s->sink_input->sample_spec));
+    s->sink_input->attach = sink_input_attach;
+    s->sink_input->detach = sink_input_detach;
+
+    silence = pa_silence_memblock_new(
+            s->userdata->module->core->mempool,
+            &s->sink_input->sample_spec,
+            pa_frame_align(pa_bytes_per_second(&s->sink_input->sample_spec)/128, &s->sink_input->sample_spec));
 
     s->memblockq = pa_memblockq_new(
             0,
@@ -330,53 +390,43 @@
 
     pa_memblock_unref(silence);
 
-    s->rtp_event = u->core->mainloop->io_new(u->core->mainloop, fd, PA_IO_EVENT_INPUT, rtp_event_cb, s);
-
-    pa_gettimeofday(&tv);
-    pa_timeval_add(&tv, DEATH_TIMEOUT);
-    s->death_event = u->core->mainloop->time_new(u->core->mainloop, &tv, death_event_cb, s);
+    pa_rtp_context_init_recv(&s->rtp_context, fd, pa_frame_size(&s->sdp_info.sample_spec));
 
     pa_hashmap_put(s->userdata->by_origin, s->sdp_info.origin, s);
-
-    pa_rtp_context_init_recv(&s->rtp_context, fd, pa_frame_size(&s->sdp_info.sample_spec));
-
-    pa_log_info("Found new session '%s'", s->sdp_info.session_name);
-
     u->n_sessions++;
+    PA_LLIST_PREPEND(struct session, s->userdata->sessions, s);
+
+    pa_sink_input_put(s->sink_input);
+
+    pa_log_info("New session '%s'", s->sdp_info.session_name);
 
     return s;
 
 fail:
-    if (s) {
-        if (fd >= 0)
-            close(fd);
-
-        pa_xfree(s);
-    }
+    pa_xfree(s);
+
+    if (fd >= 0)
+        pa_close(fd);
 
     return NULL;
 }
 
-static void session_free(struct session *s, int from_hash) {
-    assert(s);
+static void session_free(struct session *s) {
+    pa_assert(s);
 
     pa_log_info("Freeing session '%s'", s->sdp_info.session_name);
 
-    s->userdata->core->mainloop->time_free(s->death_event);
-    s->userdata->core->mainloop->io_free(s->rtp_event);
-
-    if (from_hash)
-        pa_hashmap_remove(s->userdata->by_origin, s->sdp_info.origin);
-
-    pa_sink_input_disconnect(s->sink_input);
+    pa_sink_input_unlink(s->sink_input);
     pa_sink_input_unref(s->sink_input);
+
+    PA_LLIST_REMOVE(struct session, s->userdata->sessions, s);
+    pa_assert(s->userdata->n_sessions >= 1);
+    s->userdata->n_sessions--;
+    pa_hashmap_remove(s->userdata->by_origin, s->sdp_info.origin);
 
     pa_memblockq_free(s->memblockq);
     pa_sdp_info_destroy(&s->sdp_info);
     pa_rtp_context_destroy(&s->rtp_context);
-
-    assert(s->userdata->n_sessions >= 1);
-    s->userdata->n_sessions--;
 
     pa_xfree(s);
 }
@@ -387,11 +437,11 @@
     pa_sdp_info info;
     struct session *s;
 
-    assert(m);
-    assert(e);
-    assert(u);
-    assert(fd == u->sap_context.fd);
-    assert(flags == PA_IO_EVENT_INPUT);
+    pa_assert(m);
+    pa_assert(e);
+    pa_assert(u);
+    pa_assert(fd == u->sap_context.fd);
+    pa_assert(flags == PA_IO_EVENT_INPUT);
 
     if (pa_sap_recv(&u->sap_context, &goodbye) < 0)
         return;
@@ -402,7 +452,7 @@
     if (goodbye) {
 
         if ((s = pa_hashmap_get(u->by_origin, info.origin)))
-            session_free(s, 1);
+            session_free(s);
 
         pa_sdp_info_destroy(&info);
     } else {
@@ -412,18 +462,47 @@
                 pa_sdp_info_destroy(&info);
 
         } else {
-            struct timeval tv;
-
-            pa_gettimeofday(&tv);
-            pa_timeval_add(&tv, DEATH_TIMEOUT);
-            m->time_restart(s->death_event, &tv);
+            struct timeval now;
+            pa_rtclock_get(&now);
+            pa_atomic_store(&s->timestamp, now.tv_sec);
 
             pa_sdp_info_destroy(&info);
         }
     }
 }
 
-int pa__init(pa_core *c, pa_module*m) {
+static void check_death_event_cb(pa_mainloop_api *m, pa_time_event *t, const struct timeval *ptv, void *userdata) {
+    struct session *s, *n;
+    struct userdata *u = userdata;
+    struct timeval now;
+    struct timeval tv;
+
+    pa_assert(m);
+    pa_assert(t);
+    pa_assert(ptv);
+    pa_assert(u);
+
+    pa_rtclock_get(&now);
+
+    pa_log_debug("Checking for dead streams ...");
+
+    for (s = u->sessions; s; s = n) {
+        int k;
+        n = s->next;
+
+        k = pa_atomic_load(&s->timestamp);
+
+        if (k + DEATH_TIMEOUT < now.tv_sec)
+            session_free(s);
+    }
+
+    /* Restart timer */
+    pa_gettimeofday(&tv);
+    pa_timeval_add(&tv, DEATH_TIMEOUT*PA_USEC_PER_SEC);
+    m->time_restart(t, &tv);
+}
+
+int pa__init(pa_module*m) {
     struct userdata *u;
     pa_modargs *ma = NULL;
     struct sockaddr_in sa4;
@@ -432,9 +511,9 @@
     socklen_t salen;
     const char *sap_address;
     int fd = -1;
-
-    assert(c);
-    assert(m);
+    struct timeval tv;
+
+    pa_assert(m);
 
     if (!(ma = pa_modargs_new(m->argument, valid_modargs))) {
         pa_log("failed to parse module arguments");
@@ -454,7 +533,7 @@
         sa = (struct sockaddr*) &sa4;
         salen = sizeof(sa4);
     } else {
-        pa_log("invalid SAP address '%s'", sap_address);
+        pa_log("Invalid SAP address '%s'", sap_address);
         goto fail;
     }
 
@@ -464,15 +543,18 @@
     u = pa_xnew(struct userdata, 1);
     m->userdata = u;
     u->module = m;
-    u->core = c;
     u->sink_name = pa_xstrdup(pa_modargs_get_value(ma, "sink", NULL));
+
+    u->sap_event = m->core->mainloop->io_new(m->core->mainloop, fd, PA_IO_EVENT_INPUT, sap_event_cb, u);
+    pa_sap_context_init_recv(&u->sap_context, fd);
+
+    PA_LLIST_HEAD_INIT(struct session, u->sessions);
     u->n_sessions = 0;
-
-    u->sap_event = c->mainloop->io_new(c->mainloop, fd, PA_IO_EVENT_INPUT, sap_event_cb, u);
-
     u->by_origin = pa_hashmap_new(pa_idxset_string_hash_func, pa_idxset_string_compare_func);
 
-    pa_sap_context_init_recv(&u->sap_context, fd);
+    pa_gettimeofday(&tv);
+    pa_timeval_add(&tv, DEATH_TIMEOUT * PA_USEC_PER_SEC);
+    u->check_death_event = m->core->mainloop->time_new(m->core->mainloop, &tv, check_death_event_cb, u);
 
     pa_modargs_free(ma);
 
@@ -483,27 +565,34 @@
         pa_modargs_free(ma);
 
     if (fd >= 0)
-        close(fd);
+        pa_close(fd);
 
     return -1;
 }
 
-static void free_func(void *p, PA_GCC_UNUSED void *userdata) {
-    session_free(p, 0);
-}
-
-void pa__done(pa_core *c, pa_module*m) {
+void pa__done(pa_module*m) {
     struct userdata *u;
-    assert(c);
-    assert(m);
+    struct session *s;
+
+    pa_assert(m);
 
     if (!(u = m->userdata))
         return;
 
-    c->mainloop->io_free(u->sap_event);
+    if (u->sap_event)
+        m->core->mainloop->io_free(u->sap_event);
+
+    if (u->check_death_event)
+        m->core->mainloop->time_free(u->check_death_event);
+
     pa_sap_context_destroy(&u->sap_context);
 
-    pa_hashmap_free(u->by_origin, free_func, NULL);
+    if (u->by_origin) {
+        while ((s = pa_hashmap_get_first(u->by_origin)))
+            session_free(s);
+
+        pa_hashmap_free(u->by_origin, NULL, NULL);
+    }
 
     pa_xfree(u->sink_name);
     pa_xfree(u);

Modified: trunk/src/modules/rtp/module-rtp-send.c
URL: http://0pointer.de/cgi-bin/viewcvs.cgi/trunk/src/modules/rtp/module-rtp-send.c?rev=1971&root=pulseaudio&r1=1970&r2=1971&view=diff
==============================================================================
--- trunk/src/modules/rtp/module-rtp-send.c (original)
+++ trunk/src/modules/rtp/module-rtp-send.c Sun Oct 28 20:13:50 2007
@@ -25,7 +25,6 @@
 #include <config.h>
 #endif
 
-#include <assert.h>
 #include <stdio.h>
 #include <sys/socket.h>
 #include <netinet/in.h>
@@ -48,6 +47,9 @@
 #include <pulsecore/core-util.h>
 #include <pulsecore/modargs.h>
 #include <pulsecore/namereg.h>
+#include <pulsecore/sample-util.h>
+#include <pulsecore/macro.h>
+#include <pulsecore/socket-util.h>
 
 #include "module-rtp-send-symdef.h"
 
@@ -74,7 +76,7 @@
 #define DEFAULT_DESTINATION "224.0.0.56"
 #define MEMBLOCKQ_MAXLENGTH (1024*170)
 #define DEFAULT_MTU 1280
-#define SAP_INTERVAL 5000000
+#define SAP_INTERVAL 5
 
 static const char* const valid_modargs[] = {
     "source",
@@ -90,7 +92,6 @@
 
 struct userdata {
     pa_module *module;
-    pa_core *core;
 
     pa_source_output *source_output;
     pa_memblockq *memblockq;
@@ -102,56 +103,67 @@
     pa_time_event *sap_event;
 };
 
+/* Called from I/O thread context */
+static int source_output_process_msg(pa_msgobject *o, int code, void *data, int64_t offset, pa_memchunk *chunk) {
+    struct userdata *u;
+    pa_assert_se(u = PA_SOURCE_OUTPUT(o)->userdata);
+
+    switch (code) {
+        case PA_SOURCE_OUTPUT_MESSAGE_GET_LATENCY:
+            *((pa_usec_t*) data) = pa_bytes_to_usec(pa_memblockq_get_length(u->memblockq), &u->source_output->sample_spec);
+
+            /* Fall through, the default handler will add in the extra
+             * latency added by the resampler */
+            break;
+    }
+
+    return pa_source_output_process_msg(o, code, data, offset, chunk);
+}
+
+/* Called from I/O thread context */
 static void source_output_push(pa_source_output *o, const pa_memchunk *chunk) {
     struct userdata *u;
-    assert(o);
-    u = o->userdata;
+    pa_source_output_assert_ref(o);
+    pa_assert_se(u = o->userdata);
 
     if (pa_memblockq_push(u->memblockq, chunk) < 0) {
-        pa_log("Failed to push chunk into memblockq.");
+        pa_log_warn("Failed to push chunk into memblockq.");
         return;
     }
 
     pa_rtp_send(&u->rtp_context, u->mtu, u->memblockq);
 }
 
+/* Called from main context */
 static void source_output_kill(pa_source_output* o) {
     struct userdata *u;
-    assert(o);
-    u = o->userdata;
+    pa_source_output_assert_ref(o);
+    pa_assert_se(u = o->userdata);
 
     pa_module_unload_request(u->module);
 
-    pa_source_output_disconnect(u->source_output);
+    pa_source_output_unlink(u->source_output);
     pa_source_output_unref(u->source_output);
     u->source_output = NULL;
-}
-
-static pa_usec_t source_output_get_latency (pa_source_output *o) {
-    struct userdata *u;
-    assert(o);
-    u = o->userdata;
-
-    return pa_bytes_to_usec(pa_memblockq_get_length(u->memblockq), &o->sample_spec);
 }
 
 static void sap_event_cb(pa_mainloop_api *m, pa_time_event *t, const struct timeval *tv, void *userdata) {
     struct userdata *u = userdata;
     struct timeval next;
 
-    assert(m);
-    assert(t);
-    assert(tv);
-    assert(u);
+    pa_assert(m);
+    pa_assert(t);
+    pa_assert(tv);
+    pa_assert(u);
 
     pa_sap_send(&u->sap_context, 0);
 
     pa_gettimeofday(&next);
-    pa_timeval_add(&next, SAP_INTERVAL);
+    pa_timeval_add(&next, SAP_INTERVAL * PA_USEC_PER_SEC);
     m->time_restart(t, &next);
 }
 
-int pa__init(pa_core *c, pa_module*m) {
+int pa__init(pa_module*m) {
     struct userdata *u;
     pa_modargs *ma = NULL;
     const char *dest;
@@ -173,21 +185,20 @@
     int loop = 0;
     pa_source_output_new_data data;
 
-    assert(c);
-    assert(m);
+    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;
     }
 
     if (!(s = pa_namereg_get(m->core, pa_modargs_get_value(ma, "source", NULL), PA_NAMEREG_SOURCE, 1))) {
-        pa_log("source does not exist.");
+        pa_log("Source does not exist.");
         goto fail;
     }
 
     if (pa_modargs_get_value_boolean(ma, "loop", &loop) < 0) {
-        pa_log("failed to parse \"loop\" parameter.");
+        pa_log("Failed to parse \"loop\" parameter.");
         goto fail;
     }
 
@@ -195,12 +206,12 @@
     pa_rtp_sample_spec_fixup(&ss);
     cm = s->channel_map;
     if (pa_modargs_get_sample_spec(ma, &ss) < 0) {
-        pa_log("failed to parse sample specification");
+        pa_log("Failed to parse sample specification");
         goto fail;
     }
 
     if (!pa_rtp_sample_spec_valid(&ss)) {
-        pa_log("specified sample type not compatible with RTP");
+        pa_log("Specified sample type not compatible with RTP");
         goto fail;
     }
 
@@ -209,10 +220,10 @@
 
     payload = pa_rtp_payload_from_sample_spec(&ss);
 
-    mtu = (DEFAULT_MTU/pa_frame_size(&ss))*pa_frame_size(&ss);
+    mtu = pa_frame_align(DEFAULT_MTU, &ss);
 
     if (pa_modargs_get_value_u32(ma, "mtu", &mtu) < 0 || mtu < 1 || mtu % pa_frame_size(&ss) != 0) {
-        pa_log("invalid mtu.");
+        pa_log("Invalid MTU.");
         goto fail;
     }
 
@@ -223,7 +234,7 @@
     }
 
     if (port & 1)
-        pa_log_warn("WARNING: port number not even as suggested in RFC3550!");
+        pa_log_warn("Port number not even as suggested in RFC3550!");
 
     dest = pa_modargs_get_value(ma, "destination", DEFAULT_DESTINATION);
 
@@ -238,7 +249,7 @@
         sap_sa4 = sa4;
         sap_sa4.sin_port = htons(SAP_PORT);
     } else {
-        pa_log("invalid destination '%s'", dest);
+        pa_log("Invalid destination '%s'", dest);
         goto fail;
     }
 
@@ -267,6 +278,12 @@
         pa_log("IP_MULTICAST_LOOP failed: %s", pa_cstrerror(errno));
         goto fail;
     }
+
+    /* If the socket queue is full, let's drop packets */
+    pa_make_fd_nonblock(fd);
+    pa_make_udp_socket_low_delay(fd);
+    pa_make_fd_cloexec(fd);
+    pa_make_fd_cloexec(sap_fd);
 
     pa_source_output_new_data_init(&data);
     data.name = "RTP Monitor Stream";
@@ -276,21 +293,20 @@
     pa_source_output_new_data_set_sample_spec(&data, &ss);
     pa_source_output_new_data_set_channel_map(&data, &cm);
 
-    if (!(o = pa_source_output_new(c, &data, 0))) {
+    if (!(o = pa_source_output_new(m->core, &data, 0))) {
         pa_log("failed to create source output.");
         goto fail;
     }
 
+    o->parent.process_msg = source_output_process_msg;
     o->push = source_output_push;
     o->kill = source_output_kill;
-    o->get_latency = source_output_get_latency;
 
     u = pa_xnew(struct userdata, 1);
     m->userdata = u;
     o->userdata = u;
 
     u->module = m;
-    u->core = c;
     u->source_output = o;
 
     u->memblockq = pa_memblockq_new(
@@ -305,8 +321,7 @@
     u->mtu = mtu;
 
     k = sizeof(sa_dst);
-    r = getsockname(fd, (struct sockaddr*) &sa_dst, &k);
-    assert(r >= 0);
+    pa_assert_se((r = getsockname(fd, (struct sockaddr*) &sa_dst, &k)) >= 0);
 
     n = pa_sprintf_malloc("PulseAudio RTP Stream on %s", pa_get_fqdn(hn, sizeof(hn)));
 
@@ -317,17 +332,19 @@
 
     pa_xfree(n);
 
-    pa_rtp_context_init_send(&u->rtp_context, fd, c->cookie, payload, pa_frame_size(&ss));
+    pa_rtp_context_init_send(&u->rtp_context, fd, m->core->cookie, payload, pa_frame_size(&ss));
     pa_sap_context_init_send(&u->sap_context, sap_fd, p);
 
     pa_log_info("RTP stream initialized with mtu %u on %s:%u, SSRC=0x%08x, payload=%u, initial sequence #%u", mtu, dest, port, u->rtp_context.ssrc, payload, u->rtp_context.sequence);
-    pa_log_info("SDP-Data:\n%s\n"__FILE__": EOF", p);
+    pa_log_info("SDP-Data:\n%s\nEOF", p);
 
     pa_sap_send(&u->sap_context, 0);
 
     pa_gettimeofday(&tv);
-    pa_timeval_add(&tv, SAP_INTERVAL);
-    u->sap_event = c->mainloop->time_new(c->mainloop, &tv, sap_event_cb, u);
+    pa_timeval_add(&tv, SAP_INTERVAL * PA_USEC_PER_SEC);
+    u->sap_event = m->core->mainloop->time_new(m->core->mainloop, &tv, sap_event_cb, u);
+
+    pa_source_output_put(u->source_output);
 
     pa_modargs_free(ma);
 
@@ -338,31 +355,31 @@
         pa_modargs_free(ma);
 
     if (fd >= 0)
-        close(fd);
+        pa_close(fd);
 
     if (sap_fd >= 0)
-        close(sap_fd);
+        pa_close(sap_fd);
 
     if (o) {
-        pa_source_output_disconnect(o);
+        pa_source_output_unlink(o);
         pa_source_output_unref(o);
     }
 
     return -1;
 }
 
-void pa__done(pa_core *c, pa_module*m) {
-    struct userdata *u;
-    assert(c);
-    assert(m);
+void pa__done(pa_module*m) {
+    struct userdata *u;
+    pa_assert(m);
 
     if (!(u = m->userdata))
         return;
 
-    c->mainloop->time_free(u->sap_event);
+    if (u->sap_event)
+        m->core->mainloop->time_free(u->sap_event);
 
     if (u->source_output) {
-        pa_source_output_disconnect(u->source_output);
+        pa_source_output_unlink(u->source_output);
         pa_source_output_unref(u->source_output);
     }
 
@@ -371,7 +388,8 @@
     pa_sap_send(&u->sap_context, 1);
     pa_sap_context_destroy(&u->sap_context);
 
-    pa_memblockq_free(u->memblockq);
+    if (u->memblockq)
+        pa_memblockq_free(u->memblockq);
 
     pa_xfree(u);
 }

Modified: trunk/src/modules/rtp/rtp.c
URL: http://0pointer.de/cgi-bin/viewcvs.cgi/trunk/src/modules/rtp/rtp.c?rev=1971&root=pulseaudio&r1=1970&r2=1971&view=diff
==============================================================================
--- trunk/src/modules/rtp/rtp.c (original)
+++ trunk/src/modules/rtp/rtp.c Sun Oct 28 20:13:50 2007
@@ -25,7 +25,6 @@
 #include <config.h>
 #endif
 
-#include <assert.h>
 #include <fcntl.h>
 #include <stdlib.h>
 #include <string.h>
@@ -40,12 +39,14 @@
 
 #include <pulsecore/core-error.h>
 #include <pulsecore/log.h>
+#include <pulsecore/macro.h>
+#include <pulsecore/core-util.h>
 
 #include "rtp.h"
 
 pa_rtp_context* pa_rtp_context_init_send(pa_rtp_context *c, int fd, uint32_t ssrc, uint8_t payload, size_t frame_size) {
-    assert(c);
-    assert(fd >= 0);
+    pa_assert(c);
+    pa_assert(fd >= 0);
 
     c->fd = fd;
     c->sequence = (uint16_t) (rand()*rand());
@@ -63,11 +64,11 @@
     struct iovec iov[MAX_IOVECS];
     pa_memblock* mb[MAX_IOVECS];
     int iov_idx = 1;
-    size_t n = 0, skip = 0;
-
-    assert(c);
-    assert(size > 0);
-    assert(q);
+    size_t n = 0;
+
+    pa_assert(c);
+    pa_assert(size > 0);
+    pa_assert(q);
 
     if (pa_memblockq_get_length(q) < size)
         return 0;
@@ -76,24 +77,26 @@
         int r;
         pa_memchunk chunk;
 
+        pa_memchunk_reset(&chunk);
+
         if ((r = pa_memblockq_peek(q, &chunk)) >= 0) {
 
             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_len = k;
-                mb[iov_idx] = chunk.memblock;
-                iov_idx ++;
-
-                n += k;
-            }
-
-            skip += k;
-            pa_memblockq_drop(q, &chunk, k);
+            pa_assert(chunk.memblock);
+
+            iov[iov_idx].iov_base = ((uint8_t*) pa_memblock_acquire(chunk.memblock) + chunk.index);
+            iov[iov_idx].iov_len = k;
+            mb[iov_idx] = chunk.memblock;
+            iov_idx ++;
+
+            n += k;
+            pa_memblockq_drop(q, k);
         }
 
-        if (r < 0 || !chunk.memblock || n >= size || iov_idx >= MAX_IOVECS) {
+        pa_assert(n % c->frame_size == 0);
+
+        if (r < 0 || n >= size || iov_idx >= MAX_IOVECS) {
             uint32_t header[3];
             struct msghdr m;
             int k, i;
@@ -116,17 +119,19 @@
 
                 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
                 k = 0;
 
-            c->timestamp += skip/c->frame_size;
+            c->timestamp += n/c->frame_size;
 
             if (k < 0) {
-                if (errno != EAGAIN) /* If the queue is full, just ignore it */
+                if (errno != EAGAIN && errno != EINTR) /* If the queue is full, just ignore it */
                     pa_log("sendmsg() failed: %s", pa_cstrerror(errno));
                 return -1;
             }
@@ -135,7 +140,6 @@
                 break;
 
             n = 0;
-            skip = 0;
             iov_idx = 1;
         }
     }
@@ -144,7 +148,7 @@
 }
 
 pa_rtp_context* pa_rtp_context_init_recv(pa_rtp_context *c, int fd, size_t frame_size) {
-    assert(c);
+    pa_assert(c);
 
     c->fd = fd;
     c->frame_size = frame_size;
@@ -159,13 +163,13 @@
     int cc;
     ssize_t r;
 
-    assert(c);
-    assert(chunk);
-
-    chunk->memblock = NULL;
+    pa_assert(c);
+    pa_assert(chunk);
+
+    pa_memchunk_reset(chunk);
 
     if (ioctl(c->fd, FIONREAD, &size) < 0) {
-        pa_log("FIONREAD failed: %s", pa_cstrerror(errno));
+        pa_log_warn("FIONREAD failed: %s", pa_cstrerror(errno));
         goto fail;
     }
 
@@ -174,7 +178,7 @@
 
     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;
@@ -185,36 +189,41 @@
     m.msg_controllen = 0;
     m.msg_flags = 0;
 
-    if ((r = recvmsg(c->fd, &m, 0)) != size) {
-        pa_log("recvmsg() failed: %s", r < 0 ? pa_cstrerror(errno) : "size mismatch");
+    r = recvmsg(c->fd, &m, 0);
+    pa_memblock_release(chunk->memblock);
+
+    if (r != size) {
+        if (r < 0 && errno != EAGAIN && errno != EINTR)
+            pa_log_warn("recvmsg() failed: %s", r < 0 ? pa_cstrerror(errno) : "size mismatch");
+
         goto fail;
     }
 
     if (size < 12) {
-        pa_log("RTP packet too short.");
-        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));
+        pa_log_warn("RTP packet too short.");
+        goto fail;
+    }
+
+    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);
     c->ssrc = ntohl(c->ssrc);
 
     if ((header >> 30) != 2) {
-        pa_log("Unsupported RTP version.");
+        pa_log_warn("Unsupported RTP version.");
         goto fail;
     }
 
     if ((header >> 29) & 1) {
-        pa_log("RTP padding not supported.");
+        pa_log_warn("RTP padding not supported.");
         goto fail;
     }
 
     if ((header >> 28) & 1) {
-        pa_log("RTP header extensions not supported.");
+        pa_log_warn("RTP header extensions not supported.");
         goto fail;
     }
 
@@ -223,7 +232,7 @@
     c->sequence = header & 0xFFFF;
 
     if (12 + cc*4 > size) {
-        pa_log("RTP packet too short. (CSRC)");
+        pa_log_warn("RTP packet too short. (CSRC)");
         goto fail;
     }
 
@@ -231,7 +240,7 @@
     chunk->length = size - chunk->index;
 
     if (chunk->length % c->frame_size != 0) {
-        pa_log("Vad RTP packet size.");
+        pa_log_warn("Bad RTP packet size.");
         goto fail;
     }
 
@@ -245,7 +254,7 @@
 }
 
 uint8_t pa_rtp_payload_from_sample_spec(const pa_sample_spec *ss) {
-    assert(ss);
+    pa_assert(ss);
 
     if (ss->format == PA_SAMPLE_ULAW && ss->rate == 8000 && ss->channels == 1)
         return 0;
@@ -260,7 +269,7 @@
 }
 
 pa_sample_spec *pa_rtp_sample_spec_from_payload(uint8_t payload, pa_sample_spec *ss) {
-    assert(ss);
+    pa_assert(ss);
 
     switch (payload) {
         case 0:
@@ -295,17 +304,17 @@
 }
 
 pa_sample_spec *pa_rtp_sample_spec_fixup(pa_sample_spec * ss) {
-    assert(ss);
+    pa_assert(ss);
 
     if (!pa_rtp_sample_spec_valid(ss))
         ss->format = PA_SAMPLE_S16BE;
 
-    assert(pa_rtp_sample_spec_valid(ss));
+    pa_assert(pa_rtp_sample_spec_valid(ss));
     return ss;
 }
 
 int pa_rtp_sample_spec_valid(const pa_sample_spec *ss) {
-    assert(ss);
+    pa_assert(ss);
 
     if (!pa_sample_spec_valid(ss))
         return 0;
@@ -318,9 +327,9 @@
 }
 
 void pa_rtp_context_destroy(pa_rtp_context *c) {
-    assert(c);
-
-    close(c->fd);
+    pa_assert(c);
+
+    pa_close(c->fd);
 }
 
 const char* pa_rtp_format_to_string(pa_sample_format_t f) {
@@ -339,7 +348,7 @@
 }
 
 pa_sample_format_t pa_rtp_string_to_format(const char *s) {
-    assert(s);
+    pa_assert(s);
 
     if (!(strcmp(s, "L16")))
         return PA_SAMPLE_S16BE;

Modified: trunk/src/modules/rtp/sap.c
URL: http://0pointer.de/cgi-bin/viewcvs.cgi/trunk/src/modules/rtp/sap.c?rev=1971&root=pulseaudio&r1=1970&r2=1971&view=diff
==============================================================================
--- trunk/src/modules/rtp/sap.c (original)
+++ trunk/src/modules/rtp/sap.c Sun Oct 28 20:13:50 2007
@@ -25,7 +25,6 @@
 #include <config.h>
 #endif
 
-#include <assert.h>
 #include <time.h>
 #include <stdlib.h>
 #include <sys/types.h>
@@ -46,6 +45,7 @@
 #include <pulsecore/core-error.h>
 #include <pulsecore/core-util.h>
 #include <pulsecore/log.h>
+#include <pulsecore/macro.h>
 
 #include "sap.h"
 #include "sdp.h"
@@ -53,9 +53,9 @@
 #define MIME_TYPE "application/sdp"
 
 pa_sap_context* pa_sap_context_init_send(pa_sap_context *c, int fd, char *sdp_data) {
-    assert(c);
-    assert(fd >= 0);
-    assert(sdp_data);
+    pa_assert(c);
+    pa_assert(fd >= 0);
+    pa_assert(sdp_data);
 
     c->fd = fd;
     c->sdp_data = sdp_data;
@@ -65,9 +65,9 @@
 }
 
 void pa_sap_context_destroy(pa_sap_context *c) {
-    assert(c);
-
-    close(c->fd);
+    pa_assert(c);
+
+    pa_close(c->fd);
     pa_xfree(c->sdp_data);
 }
 
@@ -85,7 +85,7 @@
         return -1;
     }
 
-    assert(sa->sa_family == AF_INET || sa->sa_family == AF_INET6);
+    pa_assert(sa->sa_family == AF_INET || sa->sa_family == AF_INET6);
 
     header = htonl(((uint32_t) 1 << 29) |
                    (sa->sa_family == AF_INET6 ? (uint32_t) 1 << 28 : 0) |
@@ -113,14 +113,14 @@
     m.msg_flags = 0;
 
     if ((k = sendmsg(c->fd, &m, MSG_DONTWAIT)) < 0)
-        pa_log("sendmsg() failed: %s\n", pa_cstrerror(errno));
+        pa_log_warn("sendmsg() failed: %s\n", pa_cstrerror(errno));
 
     return k;
 }
 
 pa_sap_context* pa_sap_context_init_recv(pa_sap_context *c, int fd) {
-    assert(c);
-    assert(fd >= 0);
+    pa_assert(c);
+    pa_assert(fd >= 0);
 
     c->fd = fd;
     c->sdp_data = NULL;
@@ -136,11 +136,11 @@
     int six, ac;
     ssize_t r;
 
-    assert(c);
-    assert(goodbye);
+    pa_assert(c);
+    pa_assert(goodbye);
 
     if (ioctl(c->fd, FIONREAD, &size) < 0) {
-        pa_log("FIONREAD failed: %s", pa_cstrerror(errno));
+        pa_log_warn("FIONREAD failed: %s", pa_cstrerror(errno));
         goto fail;
     }
 
@@ -159,12 +159,12 @@
     m.msg_flags = 0;
 
     if ((r = recvmsg(c->fd, &m, 0)) != size) {
-        pa_log("recvmsg() failed: %s", r < 0 ? pa_cstrerror(errno) : "size mismatch");
+        pa_log_warn("recvmsg() failed: %s", r < 0 ? pa_cstrerror(errno) : "size mismatch");
         goto fail;
     }
 
     if (size < 4) {
-        pa_log("SAP packet too short.");
+        pa_log_warn("SAP packet too short.");
         goto fail;
     }
 
@@ -172,17 +172,17 @@
     header = ntohl(header);
 
     if (header >> 29 != 1) {
-        pa_log("Unsupported SAP version.");
+        pa_log_warn("Unsupported SAP version.");
         goto fail;
     }
 
     if ((header >> 25) & 1) {
-        pa_log("Encrypted SAP not supported.");
+        pa_log_warn("Encrypted SAP not supported.");
         goto fail;
     }
 
     if ((header >> 24) & 1) {
-        pa_log("Compressed SAP not supported.");
+        pa_log_warn("Compressed SAP not supported.");
         goto fail;
     }
 
@@ -191,7 +191,7 @@
 
     k = 4 + (six ? 16 : 4) + ac*4;
     if (size < k) {
-        pa_log("SAP packet too short (AD).");
+        pa_log_warn("SAP packet too short (AD).");
         goto fail;
     }
 
@@ -202,7 +202,7 @@
         e += sizeof(MIME_TYPE);
         size -= sizeof(MIME_TYPE);
     } else if ((unsigned) size < sizeof(PA_SDP_HEADER)-1 || strncmp(e, PA_SDP_HEADER, sizeof(PA_SDP_HEADER)-1)) {
-        pa_log("Invalid SDP header.");
+        pa_log_warn("Invalid SDP header.");
         goto fail;
     }
 

Modified: trunk/src/modules/rtp/sdp.c
URL: http://0pointer.de/cgi-bin/viewcvs.cgi/trunk/src/modules/rtp/sdp.c?rev=1971&root=pulseaudio&r1=1970&r2=1971&view=diff
==============================================================================
--- trunk/src/modules/rtp/sdp.c (original)
+++ trunk/src/modules/rtp/sdp.c Sun Oct 28 20:13:50 2007
@@ -25,7 +25,6 @@
 #include <config.h>
 #endif
 
-#include <assert.h>
 #include <time.h>
 #include <stdlib.h>
 #include <sys/types.h>
@@ -35,36 +34,33 @@
 #include <string.h>
 
 #include <pulse/xmalloc.h>
+#include <pulse/util.h>
 
 #include <pulsecore/core-util.h>
 #include <pulsecore/log.h>
+#include <pulsecore/macro.h>
 
 #include "sdp.h"
 #include "rtp.h"
 
-
 char *pa_sdp_build(int af, const void *src, const void *dst, const char *name, uint16_t port, uint8_t payload, const pa_sample_spec *ss) {
     uint32_t ntp;
-    char buf_src[64], buf_dst[64];
+    char buf_src[64], buf_dst[64], un[64];
     const char *u, *f, *a;
 
-    assert(src);
-    assert(dst);
-    assert(af == AF_INET || af == AF_INET6);
-
-    f = pa_rtp_format_to_string(ss->format);
-    assert(f);
-
-    if (!(u = getenv("USER")))
-        if (!(u = getenv("USERNAME")))
-            u = "-";
+    pa_assert(src);
+    pa_assert(dst);
+    pa_assert(af == AF_INET || af == AF_INET6);
+
+    pa_assert_se(f = pa_rtp_format_to_string(ss->format));
+
+    if (!(u = pa_get_user_name(un, sizeof(un))))
+        u = "-";
 
     ntp = time(NULL) + 2208988800U;
 
-    a = inet_ntop(af, src, buf_src, sizeof(buf_src));
-    assert(a);
-    a = inet_ntop(af, dst, buf_dst, sizeof(buf_dst));
-    assert(a);
+    pa_assert_se(a = inet_ntop(af, src, buf_src, sizeof(buf_src)));
+    pa_assert_se(a = inet_ntop(af, dst, buf_dst, sizeof(buf_dst)));
 
     return pa_sprintf_malloc(
             PA_SDP_HEADER
@@ -86,8 +82,8 @@
 
 static pa_sample_spec *parse_sdp_sample_spec(pa_sample_spec *ss, char *c) {
     unsigned rate, channels;
-    assert(ss);
-    assert(c);
+    pa_assert(ss);
+    pa_assert(c);
 
     if (pa_startswith(c, "L16/")) {
         ss->format = PA_SAMPLE_S16BE;
@@ -123,8 +119,8 @@
     uint16_t port = 0;
     int ss_valid = 0;
 
-    assert(t);
-    assert(i);
+    pa_assert(t);
+    pa_assert(i);
 
     i->origin = i->session_name = NULL;
     i->salen = 0;
@@ -258,7 +254,7 @@
 }
 
 void pa_sdp_info_destroy(pa_sdp_info *i) {
-    assert(i);
+    pa_assert(i);
 
     pa_xfree(i->origin);
     pa_xfree(i->session_name);

Modified: trunk/src/pulse/browser.c
URL: http://0pointer.de/cgi-bin/viewcvs.cgi/trunk/src/pulse/browser.c?rev=1971&root=pulseaudio&r1=1970&r2=1971&view=diff
==============================================================================
--- trunk/src/pulse/browser.c (original)
+++ trunk/src/pulse/browser.c Sun Oct 28 20:13:50 2007
@@ -25,7 +25,6 @@
 #include "config.h"
 #endif
 
-#include <assert.h>
 #include <string.h>
 
 #include <avahi-client/lookup.h>
@@ -36,8 +35,9 @@
 
 #include <pulsecore/log.h>
 #include <pulsecore/core-util.h>
-
 #include <pulsecore/avahi-wrap.h>
+#include <pulsecore/refcnt.h>
+#include <pulsecore/macro.h>
 
 #include "browser.h"
 
@@ -46,7 +46,8 @@
 #define SERVICE_TYPE_SERVER "_pulse-server._tcp."
 
 struct pa_browser {
-    int ref;
+    PA_REFCNT_DECLARE;
+
     pa_mainloop_api *mainloop;
     AvahiPoll* avahi_poll;
 
@@ -62,6 +63,7 @@
 };
 
 static int map_to_opcode(const char *type, int new) {
+
     if (avahi_domain_equal(type, SERVICE_TYPE_SINK))
         return new ? PA_BROWSE_NEW_SINK : PA_BROWSE_REMOVE_SINK;
     else if (avahi_domain_equal(type, SERVICE_TYPE_SOURCE))
@@ -97,7 +99,8 @@
     int ss_valid = 0;
     char *key = NULL, *value = NULL;
 
-    assert(b);
+    pa_assert(b);
+    pa_assert(PA_REFCNT_VALUE(b) >= 1);
 
     memset(&i, 0, sizeof(i));
     i.name = name;
@@ -109,13 +112,13 @@
         goto fail;
 
     opcode = map_to_opcode(type, 1);
-    assert(opcode >= 0);
+    pa_assert(opcode >= 0);
 
     if (aa->proto == AVAHI_PROTO_INET)
-        snprintf(a, sizeof(a), "tcp:%s:%u", avahi_address_snprint(ip, sizeof(ip), aa), port);
+        pa_snprintf(a, sizeof(a), "tcp:%s:%u", avahi_address_snprint(ip, sizeof(ip), aa), port);
     else {
-        assert(aa->proto == AVAHI_PROTO_INET6);
-        snprintf(a, sizeof(a), "tcp6:%s:%u", avahi_address_snprint(ip, sizeof(ip), aa), port);
+        pa_assert(aa->proto == AVAHI_PROTO_INET6);
+        pa_snprintf(a, sizeof(a), "tcp6:%s:%u", avahi_address_snprint(ip, sizeof(ip), aa), port);
     }
     i.server = a;
 
@@ -146,7 +149,7 @@
             value = NULL;
 
             l = strlen(a);
-            assert(l+1 <= sizeof(a));
+            pa_assert(l+1 <= sizeof(a));
             strncat(a, " ", sizeof(a)-l-1);
             strncat(a, i.fqdn, sizeof(a)-l-2);
         } else if (!strcmp(key, "cookie")) {
@@ -211,7 +214,9 @@
 
 static void handle_failure(pa_browser *b) {
     const char *e = NULL;
-    assert(b);
+
+    pa_assert(b);
+    pa_assert(PA_REFCNT_VALUE(b) >= 1);
 
     if (b->sink_browser)
         avahi_service_browser_free(b->sink_browser);
@@ -245,7 +250,9 @@
         void *userdata) {
 
     pa_browser *b = userdata;
-    assert(b);
+
+    pa_assert(b);
+    pa_assert(PA_REFCNT_VALUE(b) >= 1);
 
     switch (event) {
         case AVAHI_BROWSER_NEW: {
@@ -276,7 +283,7 @@
                 i.name = name;
 
                 opcode = map_to_opcode(type, 0);
-                assert(opcode >= 0);
+                pa_assert(opcode >= 0);
 
                 b->callback(b, opcode, &i, b->userdata);
             }
@@ -295,7 +302,10 @@
 
 static void client_callback(AvahiClient *s, AvahiClientState state, void *userdata) {
     pa_browser *b = userdata;
-    assert(s);
+
+    pa_assert(s);
+    pa_assert(b);
+    pa_assert(PA_REFCNT_VALUE(b) >= 1);
 
     if (state == AVAHI_CLIENT_FAILURE)
         handle_failure(b);
@@ -311,14 +321,14 @@
     pa_browser *b;
     int error;
 
-    assert(mainloop);
+    pa_assert(mainloop);
 
     if (flags & ~(PA_BROWSE_FOR_SERVERS|PA_BROWSE_FOR_SINKS|PA_BROWSE_FOR_SOURCES) || flags == 0)
         return NULL;
 
     b = pa_xnew(pa_browser, 1);
     b->mainloop = mainloop;
-    b->ref = 1;
+    PA_REFCNT_INIT(b);
     b->callback = NULL;
     b->userdata = NULL;
     b->error_callback = NULL;
@@ -391,7 +401,8 @@
 }
 
 static void browser_free(pa_browser *b) {
-    assert(b && b->mainloop);
+    pa_assert(b);
+    pa_assert(b->mainloop);
 
     if (b->sink_browser)
         avahi_service_browser_free(b->sink_browser);
@@ -410,29 +421,32 @@
 }
 
 pa_browser *pa_browser_ref(pa_browser *b) {
-    assert(b);
-    assert(b->ref >= 1);
-    b->ref++;
+    pa_assert(b);
+    pa_assert(PA_REFCNT_VALUE(b) >= 1);
+
+    PA_REFCNT_INC(b);
     return b;
 }
 
 void pa_browser_unref(pa_browser *b) {
-    assert(b);
-    assert(b->ref >= 1);
-
-    if ((-- (b->ref)) <= 0)
+    pa_assert(b);
+    pa_assert(PA_REFCNT_VALUE(b) >= 1);
+
+    if (PA_REFCNT_DEC(b) <= 0)
         browser_free(b);
 }
 
 void pa_browser_set_callback(pa_browser *b, pa_browse_cb_t cb, void *userdata) {
-    assert(b);
+    pa_assert(b);
+    pa_assert(PA_REFCNT_VALUE(b) >= 1);
 
     b->callback = cb;
     b->userdata = userdata;
 }
 
 void pa_browser_set_error_callback(pa_browser *b, pa_browser_error_cb_t cb, void *userdata) {
-    assert(b);
+    pa_assert(b);
+    pa_assert(PA_REFCNT_VALUE(b) >= 1);
 
     b->error_callback = cb;
     b->error_userdata = userdata;

Modified: trunk/src/pulse/cdecl.h
URL: http://0pointer.de/cgi-bin/viewcvs.cgi/trunk/src/pulse/cdecl.h?rev=1971&root=pulseaudio&r1=1970&r2=1971&view=diff
==============================================================================
--- trunk/src/pulse/cdecl.h (original)
+++ trunk/src/pulse/cdecl.h Sun Oct 28 20:13:50 2007
@@ -41,4 +41,22 @@
 
 #endif
 
+#ifndef PA_GCC_PURE
+#ifdef __GNUCC__
+#define PA_GCC_PURE __attribute__ ((pure))
+#else
+/** This function's return value depends only the arguments list and global state **/
+#define PA_GCC_PURE
 #endif
+#endif
+
+#ifndef PA_GCC_CONST
+#ifdef __GNUCC__
+#define PA_GCC_CONST __attribute__ ((pure))
+#else
+/** This function's return value depends only the arguments list (stricter version of PA_GCC_CONST) **/
+#define PA_GCC_CONST
+#endif
+#endif
+
+#endif

Modified: trunk/src/pulse/channelmap.c
URL: http://0pointer.de/cgi-bin/viewcvs.cgi/trunk/src/pulse/channelmap.c?rev=1971&root=pulseaudio&r1=1970&r2=1971&view=diff
==============================================================================
--- trunk/src/pulse/channelmap.c (original)
+++ trunk/src/pulse/channelmap.c Sun Oct 28 20:13:50 2007
@@ -27,12 +27,12 @@
 #endif
 
 #include <stdlib.h>
-#include <assert.h>
 #include <stdio.h>
 #include <string.h>
 
 #include <pulse/xmalloc.h>
 #include <pulsecore/core-util.h>
+#include <pulsecore/macro.h>
 
 #include "channelmap.h"
 
@@ -90,18 +90,81 @@
 
     [PA_CHANNEL_POSITION_TOP_CENTER] = "top-center",
 
+    [PA_CHANNEL_POSITION_TOP_FRONT_CENTER] = "top-front-center",
     [PA_CHANNEL_POSITION_TOP_FRONT_LEFT] = "top-front-left",
     [PA_CHANNEL_POSITION_TOP_FRONT_RIGHT] = "top-front-right",
-    [PA_CHANNEL_POSITION_TOP_FRONT_CENTER] = "top-front-center",
-
+
+    [PA_CHANNEL_POSITION_TOP_REAR_CENTER] = "top-rear-center",
     [PA_CHANNEL_POSITION_TOP_REAR_LEFT] = "top-rear-left",
-    [PA_CHANNEL_POSITION_TOP_REAR_RIGHT] = "top-rear-right",
-    [PA_CHANNEL_POSITION_TOP_REAR_CENTER] = "top-rear-center"
+    [PA_CHANNEL_POSITION_TOP_REAR_RIGHT] = "top-rear-right"
+};
+
+const char *const pretty_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] = "Low Frequency Emmiter",
+
+    [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",
+
+    [PA_CHANNEL_POSITION_AUX0] = "Auxiliary 0",
+    [PA_CHANNEL_POSITION_AUX1] = "Auxiliary 1",
+    [PA_CHANNEL_POSITION_AUX2] = "Auxiliary 2",
+    [PA_CHANNEL_POSITION_AUX3] = "Auxiliary 3",
+    [PA_CHANNEL_POSITION_AUX4] = "Auxiliary 4",
+    [PA_CHANNEL_POSITION_AUX5] = "Auxiliary 5",
+    [PA_CHANNEL_POSITION_AUX6] = "Auxiliary 6",
+    [PA_CHANNEL_POSITION_AUX7] = "Auxiliary 7",
+    [PA_CHANNEL_POSITION_AUX8] = "Auxiliary 8",
+    [PA_CHANNEL_POSITION_AUX9] = "Auxiliary 9",
+    [PA_CHANNEL_POSITION_AUX10] = "Auxiliary 10",
+    [PA_CHANNEL_POSITION_AUX11] = "Auxiliary 11",
+    [PA_CHANNEL_POSITION_AUX12] = "Auxiliary 12",
+    [PA_CHANNEL_POSITION_AUX13] = "Auxiliary 13",
+    [PA_CHANNEL_POSITION_AUX14] = "Auxiliary 14",
+    [PA_CHANNEL_POSITION_AUX15] = "Auxiliary 15",
+    [PA_CHANNEL_POSITION_AUX16] = "Auxiliary 16",
+    [PA_CHANNEL_POSITION_AUX17] = "Auxiliary 17",
+    [PA_CHANNEL_POSITION_AUX18] = "Auxiliary 18",
+    [PA_CHANNEL_POSITION_AUX19] = "Auxiliary 19",
+    [PA_CHANNEL_POSITION_AUX20] = "Auxiliary 20",
+    [PA_CHANNEL_POSITION_AUX21] = "Auxiliary 21",
+    [PA_CHANNEL_POSITION_AUX22] = "Auxiliary 22",
+    [PA_CHANNEL_POSITION_AUX23] = "Auxiliary 23",
+    [PA_CHANNEL_POSITION_AUX24] = "Auxiliary 24",
+    [PA_CHANNEL_POSITION_AUX25] = "Auxiliary 25",
+    [PA_CHANNEL_POSITION_AUX26] = "Auxiliary 26",
+    [PA_CHANNEL_POSITION_AUX27] = "Auxiliary 27",
+    [PA_CHANNEL_POSITION_AUX28] = "Auxiliary 28",
+    [PA_CHANNEL_POSITION_AUX29] = "Auxiliary 29",
+    [PA_CHANNEL_POSITION_AUX30] = "Auxiliary 30",
+    [PA_CHANNEL_POSITION_AUX31] = "Auxiliary 31",
+
+    [PA_CHANNEL_POSITION_TOP_CENTER] = "Top Center",
+
+    [PA_CHANNEL_POSITION_TOP_FRONT_CENTER] = "Top Front Center",
+    [PA_CHANNEL_POSITION_TOP_FRONT_LEFT] = "Top Front Left",
+    [PA_CHANNEL_POSITION_TOP_FRONT_RIGHT] = "Top Front Right",
+
+    [PA_CHANNEL_POSITION_TOP_REAR_CENTER] = "Top Rear Center",
+    [PA_CHANNEL_POSITION_TOP_REAR_LEFT] = "Top Rear left",
+    [PA_CHANNEL_POSITION_TOP_REAR_RIGHT] = "Top Rear Right"
 };
 
 pa_channel_map* pa_channel_map_init(pa_channel_map *m) {
     unsigned c;
-    assert(m);
+    pa_assert(m);
 
     m->channels = 0;
 
@@ -112,7 +175,7 @@
 }
 
 pa_channel_map* pa_channel_map_init_mono(pa_channel_map *m) {
-    assert(m);
+    pa_assert(m);
 
     pa_channel_map_init(m);
 
@@ -122,7 +185,7 @@
 }
 
 pa_channel_map* pa_channel_map_init_stereo(pa_channel_map *m) {
-    assert(m);
+    pa_assert(m);
 
     pa_channel_map_init(m);
 
@@ -133,9 +196,9 @@
 }
 
 pa_channel_map* pa_channel_map_init_auto(pa_channel_map *m, unsigned channels, pa_channel_map_def_t def) {
-    assert(m);
-    assert(channels > 0);
-    assert(channels <= PA_CHANNELS_MAX);
+    pa_assert(m);
+    pa_assert(channels > 0);
+    pa_assert(channels <= PA_CHANNELS_MAX);
 
     pa_channel_map_init(m);
 
@@ -342,11 +405,18 @@
     return table[pos];
 }
 
+const char* pa_channel_position_to_pretty_string(pa_channel_position_t pos) {
+    if (pos < 0 || pos >= PA_CHANNEL_POSITION_MAX)
+        return NULL;
+
+    return pretty_table[pos];
+}
+
 int pa_channel_map_equal(const pa_channel_map *a, const pa_channel_map *b) {
     unsigned c;
 
-    assert(a);
-    assert(b);
+    pa_assert(a);
+    pa_assert(b);
 
     if (a->channels != b->channels)
         return 0;
@@ -363,14 +433,14 @@
     int first = 1;
     char *e;
 
-    assert(s);
-    assert(l > 0);
-    assert(map);
+    pa_assert(s);
+    pa_assert(l > 0);
+    pa_assert(map);
 
     *(e = s) = 0;
 
     for (channel = 0; channel < map->channels && l > 1; channel++) {
-        l -= snprintf(e, l, "%s%s",
+        l -= pa_snprintf(e, l, "%s%s",
                       first ? "" : ",",
                       pa_channel_position_to_string(map->map[channel]));
 
@@ -386,8 +456,8 @@
     pa_channel_map map;
     char *p;
 
-    assert(rmap);
-    assert(s);
+    pa_assert(rmap);
+    pa_assert(s);
 
     memset(&map, 0, sizeof(map));
 
@@ -447,7 +517,7 @@
 int pa_channel_map_valid(const pa_channel_map *map) {
     unsigned c;
 
-    assert(map);
+    pa_assert(map);
 
     if (map->channels <= 0 || map->channels > PA_CHANNELS_MAX)
         return 0;

Modified: trunk/src/pulse/channelmap.h
URL: http://0pointer.de/cgi-bin/viewcvs.cgi/trunk/src/pulse/channelmap.h?rev=1971&root=pulseaudio&r1=1970&r2=1971&view=diff
==============================================================================
--- trunk/src/pulse/channelmap.h (original)
+++ trunk/src/pulse/channelmap.h Sun Oct 28 20:13:50 2007
@@ -172,7 +172,10 @@
 pa_channel_map* pa_channel_map_init_auto(pa_channel_map *m, unsigned channels, pa_channel_map_def_t def);
 
 /** Return a text label for the specified channel position */
-const char* pa_channel_position_to_string(pa_channel_position_t pos);
+const char* pa_channel_position_to_string(pa_channel_position_t pos) PA_GCC_PURE;
+
+/** Return a human readable text label for the specified channel position. \since 0.9.7 */
+const char* pa_channel_position_to_pretty_string(pa_channel_position_t pos);
 
 /** The maximum length of strings returned by pa_channel_map_snprint() */
 #define PA_CHANNEL_MAP_SNPRINT_MAX 336
@@ -184,10 +187,10 @@
 pa_channel_map *pa_channel_map_parse(pa_channel_map *map, const char *s);
 
 /** Compare two channel maps. Return 1 if both match. */
-int pa_channel_map_equal(const pa_channel_map *a, const pa_channel_map *b);
+int pa_channel_map_equal(const pa_channel_map *a, const pa_channel_map *b) PA_GCC_PURE;
 
 /** Return non-zero of the specified channel map is considered valid */
-int pa_channel_map_valid(const pa_channel_map *map);
+int pa_channel_map_valid(const pa_channel_map *map) PA_GCC_PURE;
 
 PA_C_DECL_END
 

Modified: trunk/src/pulse/client-conf-x11.c
URL: http://0pointer.de/cgi-bin/viewcvs.cgi/trunk/src/pulse/client-conf-x11.c?rev=1971&root=pulseaudio&r1=1970&r2=1971&view=diff
==============================================================================
--- trunk/src/pulse/client-conf-x11.c (original)
+++ trunk/src/pulse/client-conf-x11.c Sun Oct 28 20:13:50 2007
@@ -26,7 +26,6 @@
 #endif
 
 #include <string.h>
-#include <assert.h>
 
 #include <X11/Xlib.h>
 #include <X11/Xatom.h>
@@ -36,6 +35,7 @@
 #include <pulsecore/x11prop.h>
 #include <pulsecore/log.h>
 #include <pulsecore/core-util.h>
+#include <pulsecore/macro.h>
 
 #include "client-conf-x11.h"
 
@@ -43,6 +43,8 @@
     Display *d = NULL;
     int ret = -1;
     char t[1024];
+
+    pa_assert(c);
 
     if (!dname && (!(dname = getenv("DISPLAY")) || *dname == '\0'))
         goto finish;
@@ -75,7 +77,7 @@
             goto finish;
         }
 
-        assert(sizeof(cookie) == sizeof(c->cookie));
+        pa_assert(sizeof(cookie) == sizeof(c->cookie));
         memcpy(c->cookie, cookie, sizeof(cookie));
 
         c->cookie_valid = 1;

Modified: trunk/src/pulse/client-conf.c
URL: http://0pointer.de/cgi-bin/viewcvs.cgi/trunk/src/pulse/client-conf.c?rev=1971&root=pulseaudio&r1=1970&r2=1971&view=diff
==============================================================================
--- trunk/src/pulse/client-conf.c (original)
+++ trunk/src/pulse/client-conf.c Sun Oct 28 20:13:50 2007
@@ -27,14 +27,14 @@
 #endif
 
 #include <stdlib.h>
-#include <assert.h>
 #include <unistd.h>
 #include <errno.h>
 #include <string.h>
 
-#include <pulsecore/core-error.h>
 #include <pulse/xmalloc.h>
 
+#include <pulsecore/macro.h>
+#include <pulsecore/core-error.h>
 #include <pulsecore/log.h>
 #include <pulsecore/conf-parser.h>
 #include <pulsecore/core-util.h>
@@ -42,13 +42,7 @@
 
 #include "client-conf.h"
 
-#ifndef OS_IS_WIN32
-# define PATH_SEP "/"
-#else
-# define PATH_SEP "\\"
-#endif
-
-#define DEFAULT_CLIENT_CONFIG_FILE PA_DEFAULT_CONFIG_DIR PATH_SEP "client.conf"
+#define DEFAULT_CLIENT_CONFIG_FILE PA_DEFAULT_CONFIG_DIR PA_PATH_SEP "client.conf"
 #define DEFAULT_CLIENT_CONFIG_FILE_USER "client.conf"
 
 #define ENV_CLIENT_CONFIG_FILE "PULSE_CLIENTCONFIG"
@@ -81,7 +75,7 @@
 }
 
 void pa_client_conf_free(pa_client_conf *c) {
-    assert(c);
+    pa_assert(c);
     pa_xfree(c->daemon_binary);
     pa_xfree(c->extra_arguments);
     pa_xfree(c->default_sink);
@@ -90,6 +84,7 @@
     pa_xfree(c->cookie_file);
     pa_xfree(c);
 }
+
 int pa_client_conf_load(pa_client_conf *c, const char *filename) {
     FILE *f = NULL;
     char *fn = NULL;
@@ -122,7 +117,7 @@
         pa_open_config_file(DEFAULT_CLIENT_CONFIG_FILE, DEFAULT_CLIENT_CONFIG_FILE_USER, ENV_CLIENT_CONFIG_FILE, &fn, "r");
 
     if (!f && errno != EINTR) {
-        pa_log("WARNING: failed to open configuration file '%s': %s", fn, pa_cstrerror(errno));
+        pa_log_warn("Failed to open configuration file '%s': %s", fn, pa_cstrerror(errno));
         goto finish;
     }
 
@@ -175,7 +170,7 @@
 }
 
 int pa_client_conf_load_cookie(pa_client_conf* c) {
-    assert(c);
+    pa_assert(c);
 
     c->cookie_valid = 0;
 

Modified: trunk/src/pulse/context.c
URL: http://0pointer.de/cgi-bin/viewcvs.cgi/trunk/src/pulse/context.c?rev=1971&root=pulseaudio&r1=1970&r2=1971&view=diff
==============================================================================
--- trunk/src/pulse/context.c (original)
+++ trunk/src/pulse/context.c Sun Oct 28 20:13:50 2007
@@ -27,7 +27,6 @@
 #endif
 
 #include <stdio.h>
-#include <assert.h>
 #include <stdlib.h>
 #include <string.h>
 #include <sys/types.h>
@@ -67,6 +66,7 @@
 #include <pulsecore/log.h>
 #include <pulsecore/socket-util.h>
 #include <pulsecore/creds.h>
+#include <pulsecore/macro.h>
 
 #include "internal.h"
 
@@ -90,7 +90,7 @@
 };
 
 static void unlock_autospawn_lock_file(pa_context *c) {
-    assert(c);
+    pa_assert(c);
 
     if (c->autospawn_lock_fd >= 0) {
         char lf[PATH_MAX];
@@ -106,11 +106,11 @@
 pa_context *pa_context_new(pa_mainloop_api *mainloop, const char *name) {
     pa_context *c;
 
-    assert(mainloop);
-    assert(name);
+    pa_assert(mainloop);
+    pa_assert(name);
 
     c = pa_xnew(pa_context, 1);
-    c->ref = 1;
+    PA_REFCNT_INIT(c);
     c->name = pa_xstrdup(name);
     c->mainloop = mainloop;
     c->client = NULL;
@@ -168,7 +168,7 @@
 }
 
 static void context_free(pa_context *c) {
-    assert(c);
+    pa_assert(c);
 
     unlock_autospawn_lock_file(c);
 
@@ -183,7 +183,7 @@
     if (c->pdispatch)
         pa_pdispatch_unref(c->pdispatch);
     if (c->pstream) {
-        pa_pstream_close(c->pstream);
+        pa_pstream_unlink(c->pstream);
         pa_pstream_unref(c->pstream);
     }
 
@@ -206,24 +206,24 @@
 }
 
 pa_context* pa_context_ref(pa_context *c) {
-    assert(c);
-    assert(c->ref >= 1);
-
-    c->ref++;
+    pa_assert(c);
+    pa_assert(PA_REFCNT_VALUE(c) >= 1);
+
+    PA_REFCNT_INC(c);
     return c;
 }
 
 void pa_context_unref(pa_context *c) {
-    assert(c);
-    assert(c->ref >= 1);
-
-    if (--c->ref <= 0)
+    pa_assert(c);
+    pa_assert(PA_REFCNT_VALUE(c) >= 1);
+
+    if (PA_REFCNT_DEC(c) <= 0)
         context_free(c);
 }
 
 void pa_context_set_state(pa_context *c, pa_context_state_t st) {
-    assert(c);
-    assert(c->ref >= 1);
+    pa_assert(c);
+    pa_assert(PA_REFCNT_VALUE(c) >= 1);
 
     if (c->state == st)
         return;
@@ -250,7 +250,7 @@
         c->pdispatch = NULL;
 
         if (c->pstream) {
-            pa_pstream_close(c->pstream);
+            pa_pstream_unlink(c->pstream);
             pa_pstream_unref(c->pstream);
         }
         c->pstream = NULL;
@@ -264,16 +264,16 @@
 }
 
 void pa_context_fail(pa_context *c, int error) {
-    assert(c);
-    assert(c->ref >= 1);
+    pa_assert(c);
+    pa_assert(PA_REFCNT_VALUE(c) >= 1);
 
     pa_context_set_error(c, error);
     pa_context_set_state(c, PA_CONTEXT_FAILED);
 }
 
 int pa_context_set_error(pa_context *c, int error) {
-    assert(error >= 0);
-    assert(error < PA_ERR_MAX);
+    pa_assert(error >= 0);
+    pa_assert(error < PA_ERR_MAX);
 
     if (c)
         c->error = error;
@@ -284,8 +284,8 @@
 static void pstream_die_callback(pa_pstream *p, void *userdata) {
     pa_context *c = userdata;
 
-    assert(p);
-    assert(c);
+    pa_assert(p);
+    pa_assert(c);
 
     pa_context_fail(c, PA_ERR_CONNECTIONTERMINATED);
 }
@@ -293,9 +293,9 @@
 static void pstream_packet_callback(pa_pstream *p, pa_packet *packet, const pa_creds *creds, void *userdata) {
     pa_context *c = userdata;
 
-    assert(p);
-    assert(packet);
-    assert(c);
+    pa_assert(p);
+    pa_assert(packet);
+    pa_assert(c);
 
     pa_context_ref(c);
 
@@ -309,18 +309,19 @@
     pa_context *c = userdata;
     pa_stream *s;
 
-    assert(p);
-    assert(chunk);
-    assert(chunk->memblock);
-    assert(chunk->length);
-    assert(c);
-    assert(c->ref >= 1);
+    pa_assert(p);
+    pa_assert(chunk);
+    pa_assert(chunk->memblock);
+    pa_assert(chunk->length);
+    pa_assert(c);
+    pa_assert(PA_REFCNT_VALUE(c) >= 1);
 
     pa_context_ref(c);
 
     if ((s = pa_dynarray_get(c->record_streams, channel))) {
 
-        assert(seek == PA_SEEK_RELATIVE && offset == 0);
+        pa_assert(seek == PA_SEEK_RELATIVE);
+        pa_assert(offset == 0);
 
         pa_memblockq_seek(s->record_memblockq, offset, seek);
         pa_memblockq_push_align(s->record_memblockq, chunk);
@@ -337,11 +338,11 @@
 }
 
 int pa_context_handle_error(pa_context *c, uint32_t command, pa_tagstruct *t) {
-    assert(c);
-    assert(c->ref >= 1);
+    pa_assert(c);
+    pa_assert(PA_REFCNT_VALUE(c) >= 1);
 
     if (command == PA_COMMAND_ERROR) {
-        assert(t);
+        pa_assert(t);
 
         if (pa_tagstruct_getu32(t, &c->error) < 0) {
             pa_context_fail(c, PA_ERR_PROTOCOL);
@@ -361,9 +362,9 @@
 static void setup_complete_callback(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
     pa_context *c = userdata;
 
-    assert(pd);
-    assert(c);
-    assert(c->state == PA_CONTEXT_AUTHORIZING || c->state == PA_CONTEXT_SETTING_NAME);
+    pa_assert(pd);
+    pa_assert(c);
+    pa_assert(c->state == PA_CONTEXT_AUTHORIZING || c->state == PA_CONTEXT_SETTING_NAME);
 
     pa_context_ref(c);
 
@@ -423,7 +424,7 @@
             break;
 
         default:
-            assert(0);
+            pa_assert(0);
     }
 
 finish:
@@ -434,19 +435,19 @@
     pa_tagstruct *t;
     uint32_t tag;
 
-    assert(c);
-    assert(io);
+    pa_assert(c);
+    pa_assert(io);
 
     pa_context_ref(c);
 
-    assert(!c->pstream);
+    pa_assert(!c->pstream);
     c->pstream = pa_pstream_new(c->mainloop, io, c->mempool);
 
     pa_pstream_set_die_callback(c->pstream, pstream_die_callback, c);
     pa_pstream_set_recieve_packet_callback(c->pstream, pstream_packet_callback, c);
     pa_pstream_set_recieve_memblock_callback(c->pstream, pstream_memblock_callback, c);
 
-    assert(!c->pdispatch);
+    pa_assert(!c->pdispatch);
     c->pdispatch = pa_pdispatch_new(c->mainloop, command_table, PA_COMMAND_MAX);
 
     if (!c->conf->cookie_valid)
@@ -497,10 +498,10 @@
         goto fail;
     }
 
-    pa_fd_set_cloexec(fds[0], 1);
-
-    pa_socket_low_delay(fds[0]);
-    pa_socket_low_delay(fds[1]);
+    pa_make_fd_cloexec(fds[0]);
+
+    pa_make_socket_low_delay(fds[0]);
+    pa_make_socket_low_delay(fds[1]);
 
     if (c->spawn_api.prefork)
         c->spawn_api.prefork();
@@ -523,7 +524,7 @@
         int n;
 
         /* Not required, since fds[0] has CLOEXEC enabled anyway */
-        close(fds[0]);
+        pa_assert_se(pa_close(fds[0]) == 0);
 
         if (c->spawn_api.atfork)
             c->spawn_api.atfork();
@@ -535,7 +536,7 @@
         argv[n++] = c->conf->daemon_binary;
         argv[n++] = "--daemonize=yes";
 
-        snprintf(t, sizeof(t), "-Lmodule-native-protocol-fd fd=%i", fds[1]);
+        pa_snprintf(t, sizeof(t), "-Lmodule-native-protocol-fd fd=%i", fds[1]);
         argv[n++] = strdup(t);
 
         while (n < MAX_ARGS) {
@@ -570,7 +571,7 @@
         goto fail;
     }
 
-    close(fds[1]);
+    pa_assert_se(pa_close(fds[1]) == 0);
 
     c->is_local = 1;
 
@@ -584,10 +585,7 @@
     return 0;
 
 fail:
-    if (fds[0] != -1)
-        close(fds[0]);
-    if (fds[1] != -1)
-        close(fds[1]);
+    pa_close_pipe(fds);
 
     unlock_autospawn_lock_file(c);
 
@@ -602,8 +600,8 @@
     char *u = NULL;
     int r = -1;
 
-    assert(c);
-    assert(!c->client);
+    pa_assert(c);
+    pa_assert(!c->client);
 
     for (;;) {
         pa_xfree(u);
@@ -648,9 +646,9 @@
 static void on_connection(pa_socket_client *client, pa_iochannel*io, void *userdata) {
     pa_context *c = userdata;
 
-    assert(client);
-    assert(c);
-    assert(c->state == PA_CONTEXT_CONNECTING);
+    pa_assert(client);
+    pa_assert(c);
+    pa_assert(c->state == PA_CONTEXT_CONNECTING);
 
     pa_context_ref(c);
 
@@ -683,8 +681,8 @@
 
     int r = -1;
 
-    assert(c);
-    assert(c->ref >= 1);
+    pa_assert(c);
+    pa_assert(PA_REFCNT_VALUE(c) >= 1);
 
     PA_CHECK_VALIDITY(c, c->state == PA_CONTEXT_UNCONNECTED, PA_ERR_BADSTATE);
     PA_CHECK_VALIDITY(c, !(flags & ~PA_CONTEXT_NOAUTOSPAWN), PA_ERR_INVALID);
@@ -695,7 +693,7 @@
 
     pa_context_ref(c);
 
-    assert(!c->server_list);
+    pa_assert(!c->server_list);
 
     if (server) {
         if (!(c->server_list = pa_strlist_parse(server))) {
@@ -735,7 +733,7 @@
 
             pa_runtime_path(AUTOSPAWN_LOCK, lf, sizeof(lf));
             pa_make_secure_parent_dir(lf, 0700, (uid_t)-1, (gid_t)-1);
-            assert(c->autospawn_lock_fd <= 0);
+            pa_assert(c->autospawn_lock_fd <= 0);
             c->autospawn_lock_fd = pa_lock_lockfile(lf);
 
             if (api)
@@ -755,37 +753,37 @@
 }
 
 void pa_context_disconnect(pa_context *c) {
-    assert(c);
-    assert(c->ref >= 1);
+    pa_assert(c);
+    pa_assert(PA_REFCNT_VALUE(c) >= 1);
 
     pa_context_set_state(c, PA_CONTEXT_TERMINATED);
 }
 
 pa_context_state_t pa_context_get_state(pa_context *c) {
-    assert(c);
-    assert(c->ref >= 1);
+    pa_assert(c);
+    pa_assert(PA_REFCNT_VALUE(c) >= 1);
 
     return c->state;
 }
 
 int pa_context_errno(pa_context *c) {
-    assert(c);
-    assert(c->ref >= 1);
+    pa_assert(c);
+    pa_assert(PA_REFCNT_VALUE(c) >= 1);
 
     return c->error;
 }
 
 void pa_context_set_state_callback(pa_context *c, pa_context_notify_cb_t cb, void *userdata) {
-    assert(c);
-    assert(c->ref >= 1);
+    pa_assert(c);
+    pa_assert(PA_REFCNT_VALUE(c) >= 1);
 
     c->state_callback = cb;
     c->state_userdata = userdata;
 }
 
 int pa_context_is_pending(pa_context *c) {
-    assert(c);
-    assert(c->ref >= 1);
+    pa_assert(c);
+    pa_assert(PA_REFCNT_VALUE(c) >= 1);
 
     PA_CHECK_VALIDITY(c,
                       c->state == PA_CONTEXT_CONNECTING ||
@@ -811,11 +809,11 @@
 static void set_dispatch_callbacks(pa_operation *o) {
     int done = 1;
 
-    assert(o);
-    assert(o->ref >= 1);
-    assert(o->context);
-    assert(o->context->ref >= 1);
-    assert(o->context->state == PA_CONTEXT_READY);
+    pa_assert(o);
+    pa_assert(PA_REFCNT_VALUE(o) >= 1);
+    pa_assert(o->context);
+    pa_assert(PA_REFCNT_VALUE(o->context) >= 1);
+    pa_assert(o->context->state == PA_CONTEXT_READY);
 
     pa_pstream_set_drain_callback(o->context->pstream, NULL, NULL);
     pa_pdispatch_set_drain_callback(o->context->pdispatch, NULL, NULL);
@@ -844,8 +842,8 @@
 pa_operation* pa_context_drain(pa_context *c, pa_context_notify_cb_t cb, void *userdata) {
     pa_operation *o;
 
-    assert(c);
-    assert(c->ref >= 1);
+    pa_assert(c);
+    pa_assert(PA_REFCNT_VALUE(c) >= 1);
 
     PA_CHECK_VALIDITY_RETURN_NULL(c, c->state == PA_CONTEXT_READY, PA_ERR_BADSTATE);
     PA_CHECK_VALIDITY_RETURN_NULL(c, pa_context_is_pending(c), PA_ERR_BADSTATE);
@@ -860,9 +858,9 @@
     pa_operation *o = userdata;
     int success = 1;
 
-    assert(pd);
-    assert(o);
-    assert(o->ref >= 1);
+    pa_assert(pd);
+    pa_assert(o);
+    pa_assert(PA_REFCNT_VALUE(o) >= 1);
 
     if (!o->context)
         goto finish;
@@ -892,8 +890,8 @@
     pa_operation *o;
     uint32_t tag;
 
-    assert(c);
-    assert(c->ref >= 1);
+    pa_assert(c);
+    pa_assert(PA_REFCNT_VALUE(c) >= 1);
 
     PA_CHECK_VALIDITY_RETURN_NULL(c, c->state == PA_CONTEXT_READY, PA_ERR_BADSTATE);
 
@@ -911,8 +909,8 @@
     pa_operation *o;
     uint32_t tag;
 
-    assert(c);
-    assert(c->ref >= 1);
+    pa_assert(c);
+    pa_assert(PA_REFCNT_VALUE(c) >= 1);
 
     PA_CHECK_VALIDITY_RETURN_NULL(c, c->state == PA_CONTEXT_READY, PA_ERR_BADSTATE);
 
@@ -930,8 +928,8 @@
     pa_operation *o;
     uint32_t tag;
 
-    assert(c);
-    assert(c->ref >= 1);
+    pa_assert(c);
+    pa_assert(PA_REFCNT_VALUE(c) >= 1);
 
     PA_CHECK_VALIDITY_RETURN_NULL(c, c->state == PA_CONTEXT_READY, PA_ERR_BADSTATE);
 
@@ -950,8 +948,8 @@
     pa_operation *o;
     uint32_t tag;
 
-    assert(c);
-    assert(c->ref >= 1);
+    pa_assert(c);
+    pa_assert(PA_REFCNT_VALUE(c) >= 1);
 
     PA_CHECK_VALIDITY_RETURN_NULL(c, c->state == PA_CONTEXT_READY, PA_ERR_BADSTATE);
 
@@ -966,7 +964,7 @@
 }
 
 int pa_context_is_local(pa_context *c) {
-    assert(c);
+    pa_assert(c);
 
     return c->is_local;
 }
@@ -976,9 +974,9 @@
     pa_operation *o;
     uint32_t tag;
 
-    assert(c);
-    assert(c->ref >= 1);
-    assert(name);
+    pa_assert(c);
+    pa_assert(PA_REFCNT_VALUE(c) >= 1);
+    pa_assert(name);
 
     PA_CHECK_VALIDITY_RETURN_NULL(c, c->state == PA_CONTEXT_READY, PA_ERR_BADSTATE);
 
@@ -997,8 +995,8 @@
 }
 
 const char* pa_context_get_server(pa_context *c) {
-    assert(c);
-    assert(c->ref >= 1);
+    pa_assert(c);
+    pa_assert(PA_REFCNT_VALUE(c) >= 1);
 
     if (!c->server)
         return NULL;
@@ -1016,8 +1014,8 @@
 }
 
 uint32_t pa_context_get_server_protocol_version(pa_context *c) {
-    assert(c);
-    assert(c->ref >= 1);
+    pa_assert(c);
+    pa_assert(PA_REFCNT_VALUE(c) >= 1);
 
     return c->version;
 }
@@ -1025,8 +1023,8 @@
 pa_tagstruct *pa_tagstruct_command(pa_context *c, uint32_t command, uint32_t *tag) {
     pa_tagstruct *t;
 
-    assert(c);
-    assert(tag);
+    pa_assert(c);
+    pa_assert(tag);
 
     t = pa_tagstruct_new(NULL, 0);
     pa_tagstruct_putu32(t, command);

Modified: trunk/src/pulse/glib-mainloop.c
URL: http://0pointer.de/cgi-bin/viewcvs.cgi/trunk/src/pulse/glib-mainloop.c?rev=1971&root=pulseaudio&r1=1970&r2=1971&view=diff
==============================================================================
--- trunk/src/pulse/glib-mainloop.c (original)
+++ trunk/src/pulse/glib-mainloop.c Sun Oct 28 20:13:50 2007
@@ -24,8 +24,6 @@
 #ifdef HAVE_CONFIG_H
 #include <config.h>
 #endif
-
-#include <assert.h>
 
 #include <pulse/xmalloc.h>
 #include <pulse/timeval.h>

Modified: trunk/src/pulse/internal.h
URL: http://0pointer.de/cgi-bin/viewcvs.cgi/trunk/src/pulse/internal.h?rev=1971&root=pulseaudio&r1=1970&r2=1971&view=diff
==============================================================================
--- trunk/src/pulse/internal.h (original)
+++ trunk/src/pulse/internal.h Sun Oct 28 20:13:50 2007
@@ -41,13 +41,14 @@
 #include <pulsecore/mcalign.h>
 #include <pulsecore/memblockq.h>
 #include <pulsecore/hashmap.h>
+#include <pulsecore/refcnt.h>
 
 #include "client-conf.h"
 
 #define DEFAULT_TIMEOUT (30)
 
 struct pa_context {
-    int ref;
+    PA_REFCNT_DECLARE;
 
     char *name;
     pa_mainloop_api* mainloop;
@@ -96,7 +97,7 @@
 } pa_index_correction;
 
 struct pa_stream {
-    int ref;
+    PA_REFCNT_DECLARE;
     pa_context *context;
     pa_mainloop_api *mainloop;
     PA_LLIST_FIELDS(pa_stream);
@@ -116,6 +117,7 @@
     uint32_t requested_bytes;
 
     pa_memchunk peek_memchunk;
+    void *peek_data;
     pa_memblockq *record_memblockq;
 
     int corked;
@@ -160,7 +162,8 @@
 typedef void (*pa_operation_cb_t)(void);
 
 struct pa_operation {
-    int ref;
+    PA_REFCNT_DECLARE;
+
     pa_context *context;
     pa_stream *stream;
 

Modified: trunk/src/pulse/introspect.c
URL: http://0pointer.de/cgi-bin/viewcvs.cgi/trunk/src/pulse/introspect.c?rev=1971&root=pulseaudio&r1=1970&r2=1971&view=diff
==============================================================================
--- trunk/src/pulse/introspect.c (original)
+++ trunk/src/pulse/introspect.c Sun Oct 28 20:13:50 2007
@@ -26,11 +26,10 @@
 #include <config.h>
 #endif
 
-#include <assert.h>
-
 #include <pulse/context.h>
 
 #include <pulsecore/gccmacro.h>
+#include <pulsecore/macro.h>
 #include <pulsecore/pstream-util.h>
 
 #include "internal.h"
@@ -43,9 +42,11 @@
     pa_operation *o = userdata;
     pa_stat_info i, *p = &i;
 
-    assert(pd);
-    assert(o);
-    assert(o->ref >= 1);
+    pa_assert(pd);
+    pa_assert(o);
+    pa_assert(PA_REFCNT_VALUE(o) >= 1);
+
+    memset(&i, 0, sizeof(i));
 
     if (!o->context)
         goto finish;
@@ -59,8 +60,7 @@
                pa_tagstruct_getu32(t, &i.memblock_total_size) < 0 ||
                pa_tagstruct_getu32(t, &i.memblock_allocated) < 0 ||
                pa_tagstruct_getu32(t, &i.memblock_allocated_size) < 0 ||
-               pa_tagstruct_getu32(t, &i.scache_size) < 0 ||
-               !pa_tagstruct_eof(t)) {
+               pa_tagstruct_getu32(t, &i.scache_size) < 0) {
         pa_context_fail(o->context, PA_ERR_PROTOCOL);
         goto finish;
     }
@@ -85,9 +85,11 @@
     pa_operation *o = userdata;
     pa_server_info i, *p = &i;
 
-    assert(pd);
-    assert(o);
-    assert(o->ref >= 1);
+    pa_assert(pd);
+    pa_assert(o);
+    pa_assert(PA_REFCNT_VALUE(o) >= 1);
+
+    memset(&i, 0, sizeof(i));
 
     if (!o->context)
         goto finish;
@@ -104,8 +106,7 @@
                pa_tagstruct_get_sample_spec(t, &i.sample_spec) < 0 ||
                pa_tagstruct_gets(t, &i.default_sink_name) < 0 ||
                pa_tagstruct_gets(t, &i.default_source_name) < 0 ||
-               pa_tagstruct_getu32(t, &i.cookie) < 0 ||
-               !pa_tagstruct_eof(t)) {
+               pa_tagstruct_getu32(t, &i.cookie) < 0) {
 
         pa_context_fail(o->context, PA_ERR_PROTOCOL);
         goto finish;
@@ -131,9 +132,9 @@
     pa_operation *o = userdata;
     int eol = 1;
 
-    assert(pd);
-    assert(o);
-    assert(o->ref >= 1);
+    pa_assert(pd);
+    pa_assert(o);
+    pa_assert(PA_REFCNT_VALUE(o) >= 1);
 
     if (!o->context)
         goto finish;
@@ -148,6 +149,7 @@
 
         while (!pa_tagstruct_eof(t)) {
             pa_sink_info i;
+            memset(&i, 0, sizeof(i));
 
             if (pa_tagstruct_getu32(t, &i.index) < 0 ||
                 pa_tagstruct_gets(t, &i.name) < 0 ||
@@ -195,9 +197,9 @@
     pa_operation *o;
     uint32_t tag;
 
-    assert(c);
-    assert(c->ref >= 1);
-    assert(cb);
+    pa_assert(c);
+    pa_assert(PA_REFCNT_VALUE(c) >= 1);
+    pa_assert(cb);
 
     PA_CHECK_VALIDITY_RETURN_NULL(c, c->state == PA_CONTEXT_READY, PA_ERR_BADSTATE);
 
@@ -217,9 +219,9 @@
     pa_operation *o;
     uint32_t tag;
 
-    assert(c);
-    assert(c->ref >= 1);
-    assert(cb);
+    pa_assert(c);
+    pa_assert(PA_REFCNT_VALUE(c) >= 1);
+    pa_assert(cb);
 
     PA_CHECK_VALIDITY_RETURN_NULL(c, c->state == PA_CONTEXT_READY, PA_ERR_BADSTATE);
     PA_CHECK_VALIDITY_RETURN_NULL(c, !name || *name, PA_ERR_INVALID);
@@ -241,9 +243,9 @@
     pa_operation *o = userdata;
     int eol = 1;
 
-    assert(pd);
-    assert(o);
-    assert(o->ref >= 1);
+    pa_assert(pd);
+    pa_assert(o);
+    pa_assert(PA_REFCNT_VALUE(o) >= 1);
 
     if (!o->context)
         goto finish;
@@ -258,6 +260,7 @@
         while (!pa_tagstruct_eof(t)) {
             pa_source_info i;
             uint32_t flags;
+            memset(&i, 0, sizeof(i));
 
             if (pa_tagstruct_getu32(t, &i.index) < 0 ||
                 pa_tagstruct_gets(t, &i.name) < 0 ||
@@ -305,9 +308,9 @@
     pa_operation *o;
     uint32_t tag;
 
-    assert(c);
-    assert(c->ref >= 1);
-    assert(cb);
+    pa_assert(c);
+    pa_assert(PA_REFCNT_VALUE(c) >= 1);
+    pa_assert(cb);
 
     PA_CHECK_VALIDITY_RETURN_NULL(c, c->state == PA_CONTEXT_READY, PA_ERR_BADSTATE);
 
@@ -327,9 +330,9 @@
     pa_operation *o;
     uint32_t tag;
 
-    assert(c);
-    assert(c->ref >= 1);
-    assert(cb);
+    pa_assert(c);
+    pa_assert(PA_REFCNT_VALUE(c) >= 1);
+    pa_assert(cb);
 
     PA_CHECK_VALIDITY_RETURN_NULL(c, c->state == PA_CONTEXT_READY, PA_ERR_BADSTATE);
     PA_CHECK_VALIDITY_RETURN_NULL(c, !name || *name, PA_ERR_INVALID);
@@ -351,9 +354,9 @@
     pa_operation *o = userdata;
     int eol = 1;
 
-    assert(pd);
-    assert(o);
-    assert(o->ref >= 1);
+    pa_assert(pd);
+    pa_assert(o);
+    pa_assert(PA_REFCNT_VALUE(o) >= 1);
 
     if (!o->context)
         goto finish;
@@ -367,6 +370,7 @@
 
         while (!pa_tagstruct_eof(t)) {
             pa_client_info i;
+            memset(&i, 0, sizeof(i));
 
             if (pa_tagstruct_getu32(t, &i.index) < 0 ||
                 pa_tagstruct_gets(t, &i.name) < 0 ||
@@ -398,9 +402,9 @@
     pa_operation *o;
     uint32_t tag;
 
-    assert(c);
-    assert(c->ref >= 1);
-    assert(cb);
+    pa_assert(c);
+    pa_assert(PA_REFCNT_VALUE(c) >= 1);
+    pa_assert(cb);
 
     PA_CHECK_VALIDITY_RETURN_NULL(c, c->state == PA_CONTEXT_READY, PA_ERR_BADSTATE);
     PA_CHECK_VALIDITY_RETURN_NULL(c, idx != PA_INVALID_INDEX, PA_ERR_INVALID);
@@ -425,9 +429,9 @@
     pa_operation *o = userdata;
     int eol = 1;
 
-    assert(pd);
-    assert(o);
-    assert(o->ref >= 1);
+    pa_assert(pd);
+    pa_assert(o);
+    pa_assert(PA_REFCNT_VALUE(o) >= 1);
 
     if (!o->context)
         goto finish;
@@ -441,6 +445,7 @@
 
         while (!pa_tagstruct_eof(t)) {
             pa_module_info i;
+            memset(&i, 0, sizeof(i));
 
             if (pa_tagstruct_getu32(t, &i.index) < 0 ||
                 pa_tagstruct_gets(t, &i.name) < 0 ||
@@ -473,9 +478,9 @@
     pa_operation *o;
     uint32_t tag;
 
-    assert(c);
-    assert(c->ref >= 1);
-    assert(cb);
+    pa_assert(c);
+    pa_assert(PA_REFCNT_VALUE(c) >= 1);
+    pa_assert(cb);
 
     PA_CHECK_VALIDITY_RETURN_NULL(c, c->state == PA_CONTEXT_READY, PA_ERR_BADSTATE);
     PA_CHECK_VALIDITY_RETURN_NULL(c, idx != PA_INVALID_INDEX, PA_ERR_INVALID);
@@ -500,9 +505,9 @@
     pa_operation *o = userdata;
     int eol = 1;
 
-    assert(pd);
-    assert(o);
-    assert(o->ref >= 1);
+    pa_assert(pd);
+    pa_assert(o);
+    pa_assert(PA_REFCNT_VALUE(o) >= 1);
 
     if (!o->context)
         goto finish;
@@ -516,6 +521,7 @@
 
         while (!pa_tagstruct_eof(t)) {
             pa_sink_input_info i;
+            memset(&i, 0, sizeof(i));
 
             if (pa_tagstruct_getu32(t, &i.index) < 0 ||
                 pa_tagstruct_gets(t, &i.name) < 0 ||
@@ -528,7 +534,8 @@
                 pa_tagstruct_get_usec(t, &i.buffer_usec) < 0 ||
                 pa_tagstruct_get_usec(t, &i.sink_usec) < 0 ||
                 pa_tagstruct_gets(t, &i.resample_method) < 0 ||
-                pa_tagstruct_gets(t, &i.driver) < 0) {
+                pa_tagstruct_gets(t, &i.driver) < 0 ||
+                (o->context->version >= 11 && pa_tagstruct_get_boolean(t, &i.mute) < 0)) {
 
                 pa_context_fail(o->context, PA_ERR_PROTOCOL);
                 goto finish;
@@ -556,9 +563,9 @@
     pa_operation *o;
     uint32_t tag;
 
-    assert(c);
-    assert(c->ref >= 1);
-    assert(cb);
+    pa_assert(c);
+    pa_assert(PA_REFCNT_VALUE(c) >= 1);
+    pa_assert(cb);
 
     PA_CHECK_VALIDITY_RETURN_NULL(c, c->state == PA_CONTEXT_READY, PA_ERR_BADSTATE);
     PA_CHECK_VALIDITY_RETURN_NULL(c, idx != PA_INVALID_INDEX, PA_ERR_INVALID);
@@ -583,9 +590,9 @@
     pa_operation *o = userdata;
     int eol = 1;
 
-    assert(pd);
-    assert(o);
-    assert(o->ref >= 1);
+    pa_assert(pd);
+    pa_assert(o);
+    pa_assert(PA_REFCNT_VALUE(o) >= 1);
 
     if (!o->context)
         goto finish;
@@ -599,6 +606,8 @@
 
         while (!pa_tagstruct_eof(t)) {
             pa_source_output_info i;
+
+            memset(&i, 0, sizeof(i));
 
             if (pa_tagstruct_getu32(t, &i.index) < 0 ||
                 pa_tagstruct_gets(t, &i.name) < 0 ||
@@ -638,9 +647,9 @@
     pa_operation *o;
     uint32_t tag;
 
-    assert(c);
-    assert(c->ref >= 1);
-    assert(cb);
+    pa_assert(c);
+    pa_assert(PA_REFCNT_VALUE(c) >= 1);
+    pa_assert(cb);
 
     PA_CHECK_VALIDITY_RETURN_NULL(c, c->state == PA_CONTEXT_READY, PA_ERR_BADSTATE);
     PA_CHECK_VALIDITY_RETURN_NULL(c, idx != PA_INVALID_INDEX, PA_ERR_INVALID);
@@ -666,9 +675,9 @@
     pa_tagstruct *t;
     uint32_t tag;
 
-    assert(c);
-    assert(c->ref >= 1);
-    assert(volume);
+    pa_assert(c);
+    pa_assert(PA_REFCNT_VALUE(c) >= 1);
+    pa_assert(volume);
 
     PA_CHECK_VALIDITY_RETURN_NULL(c, c->state == PA_CONTEXT_READY, PA_ERR_BADSTATE);
     PA_CHECK_VALIDITY_RETURN_NULL(c, pa_cvolume_valid(volume), PA_ERR_INVALID);
@@ -690,10 +699,10 @@
     pa_tagstruct *t;
     uint32_t tag;
 
-    assert(c);
-    assert(c->ref >= 1);
-    assert(name);
-    assert(volume);
+    pa_assert(c);
+    pa_assert(PA_REFCNT_VALUE(c) >= 1);
+    pa_assert(name);
+    pa_assert(volume);
 
     PA_CHECK_VALIDITY_RETURN_NULL(c, c->state == PA_CONTEXT_READY, PA_ERR_BADSTATE);
     PA_CHECK_VALIDITY_RETURN_NULL(c, pa_cvolume_valid(volume), PA_ERR_INVALID);
@@ -716,8 +725,8 @@
     pa_tagstruct *t;
     uint32_t tag;
 
-    assert(c);
-    assert(c->ref >= 1);
+    pa_assert(c);
+    pa_assert(PA_REFCNT_VALUE(c) >= 1);
 
     PA_CHECK_VALIDITY_RETURN_NULL(c, c->state == PA_CONTEXT_READY, PA_ERR_BADSTATE);
 
@@ -738,9 +747,9 @@
     pa_tagstruct *t;
     uint32_t tag;
 
-    assert(c);
-    assert(c->ref >= 1);
-    assert(name);
+    pa_assert(c);
+    pa_assert(PA_REFCNT_VALUE(c) >= 1);
+    pa_assert(name);
 
     PA_CHECK_VALIDITY_RETURN_NULL(c, c->state == PA_CONTEXT_READY, PA_ERR_BADSTATE);
     PA_CHECK_VALIDITY_RETURN_NULL(c, !name || *name, PA_ERR_INVALID);
@@ -762,9 +771,9 @@
     pa_tagstruct *t;
     uint32_t tag;
 
-    assert(c);
-    assert(c->ref >= 1);
-    assert(volume);
+    pa_assert(c);
+    pa_assert(PA_REFCNT_VALUE(c) >= 1);
+    pa_assert(volume);
 
     PA_CHECK_VALIDITY_RETURN_NULL(c, c->state == PA_CONTEXT_READY, PA_ERR_BADSTATE);
     PA_CHECK_VALIDITY_RETURN_NULL(c, idx != PA_INVALID_INDEX, PA_ERR_INVALID);
@@ -781,14 +790,37 @@
     return o;
 }
 
+pa_operation* pa_context_set_sink_input_mute(pa_context *c, uint32_t idx, int mute, pa_context_success_cb_t cb, void *userdata) {
+    pa_operation *o;
+    pa_tagstruct *t;
+    uint32_t tag;
+
+    pa_assert(c);
+    pa_assert(PA_REFCNT_VALUE(c) >= 1);
+
+    PA_CHECK_VALIDITY_RETURN_NULL(c, c->state == PA_CONTEXT_READY, PA_ERR_BADSTATE);
+    PA_CHECK_VALIDITY_RETURN_NULL(c, idx != PA_INVALID_INDEX, PA_ERR_INVALID);
+    PA_CHECK_VALIDITY_RETURN_NULL(c, c->version >= 11, PA_ERR_NOTSUPPORTED);
+
+    o = pa_operation_new(c, NULL, (pa_operation_cb_t) cb, userdata);
+
+    t = pa_tagstruct_command(c, PA_COMMAND_SET_SINK_INPUT_MUTE, &tag);
+    pa_tagstruct_putu32(t, idx);
+    pa_tagstruct_put_boolean(t, mute);
+    pa_pstream_send_tagstruct(c->pstream, t);
+    pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, pa_context_simple_ack_callback, pa_operation_ref(o), (pa_free_cb_t) pa_operation_unref);
+
+    return o;
+}
+
 pa_operation* pa_context_set_source_volume_by_index(pa_context *c, uint32_t idx, const pa_cvolume *volume, pa_context_success_cb_t cb, void *userdata) {
     pa_operation *o;
     pa_tagstruct *t;
     uint32_t tag;
 
-    assert(c);
-    assert(c->ref >= 1);
-    assert(volume);
+    pa_assert(c);
+    pa_assert(PA_REFCNT_VALUE(c) >= 1);
+    pa_assert(volume);
 
     PA_CHECK_VALIDITY_RETURN_NULL(c, c->state == PA_CONTEXT_READY, PA_ERR_BADSTATE);
     PA_CHECK_VALIDITY_RETURN_NULL(c, pa_cvolume_valid(volume), PA_ERR_INVALID);
@@ -810,10 +842,10 @@
     pa_tagstruct *t;
     uint32_t tag;
 
-    assert(c);
-    assert(c->ref >= 1);
-    assert(name);
-    assert(volume);
+    pa_assert(c);
+    pa_assert(PA_REFCNT_VALUE(c) >= 1);
+    pa_assert(name);
+    pa_assert(volume);
 
     PA_CHECK_VALIDITY_RETURN_NULL(c, c->state == PA_CONTEXT_READY, PA_ERR_BADSTATE);
     PA_CHECK_VALIDITY_RETURN_NULL(c, pa_cvolume_valid(volume), PA_ERR_INVALID);
@@ -836,8 +868,8 @@
     pa_tagstruct *t;
     uint32_t tag;
 
-    assert(c);
-    assert(c->ref >= 1);
+    pa_assert(c);
+    pa_assert(PA_REFCNT_VALUE(c) >= 1);
 
     PA_CHECK_VALIDITY_RETURN_NULL(c, c->state == PA_CONTEXT_READY, PA_ERR_BADSTATE);
 
@@ -858,9 +890,9 @@
     pa_tagstruct *t;
     uint32_t tag;
 
-    assert(c);
-    assert(c->ref >= 1);
-    assert(name);
+    pa_assert(c);
+    pa_assert(PA_REFCNT_VALUE(c) >= 1);
+    pa_assert(name);
 
     PA_CHECK_VALIDITY_RETURN_NULL(c, c->state == PA_CONTEXT_READY, PA_ERR_BADSTATE);
     PA_CHECK_VALIDITY_RETURN_NULL(c, !name || *name, PA_ERR_INVALID);
@@ -883,9 +915,9 @@
     pa_operation *o = userdata;
     int eol = 1;
 
-    assert(pd);
-    assert(o);
-    assert(o->ref >= 1);
+    pa_assert(pd);
+    pa_assert(o);
+    pa_assert(PA_REFCNT_VALUE(o) >= 1);
 
     if (!o->context)
         goto finish;
@@ -899,6 +931,8 @@
 
         while (!pa_tagstruct_eof(t)) {
             pa_sample_info i;
+
+            memset(&i, 0, sizeof(i));
 
             if (pa_tagstruct_getu32(t, &i.index) < 0 ||
                 pa_tagstruct_gets(t, &i.name) < 0 ||
@@ -936,9 +970,9 @@
     pa_operation *o;
     uint32_t tag;
 
-    assert(c);
-    assert(c->ref >= 1);
-    assert(cb);
+    pa_assert(c);
+    pa_assert(PA_REFCNT_VALUE(c) >= 1);
+    pa_assert(cb);
 
     PA_CHECK_VALIDITY_RETURN_NULL(c, c->state == PA_CONTEXT_READY, PA_ERR_BADSTATE);
     PA_CHECK_VALIDITY_RETURN_NULL(c, name && *name, PA_ERR_INVALID);
@@ -959,9 +993,9 @@
     pa_operation *o;
     uint32_t tag;
 
-    assert(c);
-    assert(c->ref >= 1);
-    assert(cb);
+    pa_assert(c);
+    pa_assert(PA_REFCNT_VALUE(c) >= 1);
+    pa_assert(cb);
 
     PA_CHECK_VALIDITY_RETURN_NULL(c, c->state == PA_CONTEXT_READY, PA_ERR_BADSTATE);
     PA_CHECK_VALIDITY_RETURN_NULL(c, idx != PA_INVALID_INDEX, PA_ERR_INVALID);
@@ -986,8 +1020,8 @@
     pa_tagstruct *t;
     uint32_t tag;
 
-    assert(c);
-    assert(c->ref >= 1);
+    pa_assert(c);
+    pa_assert(PA_REFCNT_VALUE(c) >= 1);
 
     PA_CHECK_VALIDITY_RETURN_NULL(c, c->state == PA_CONTEXT_READY, PA_ERR_BADSTATE);
     PA_CHECK_VALIDITY_RETURN_NULL(c, idx != PA_INVALID_INDEX, PA_ERR_INVALID);
@@ -1018,9 +1052,9 @@
     pa_operation *o = userdata;
     uint32_t idx;
 
-    assert(pd);
-    assert(o);
-    assert(o->ref >= 1);
+    pa_assert(pd);
+    pa_assert(o);
+    pa_assert(PA_REFCNT_VALUE(o) >= 1);
 
     if (!o->context)
         goto finish;
@@ -1052,8 +1086,8 @@
     pa_tagstruct *t;
     uint32_t tag;
 
-    assert(c);
-    assert(c->ref >= 1);
+    pa_assert(c);
+    pa_assert(PA_REFCNT_VALUE(c) >= 1);
 
     PA_CHECK_VALIDITY_RETURN_NULL(c, c->state == PA_CONTEXT_READY, PA_ERR_BADSTATE);
     PA_CHECK_VALIDITY_RETURN_NULL(c, name && *name, PA_ERR_INVALID);
@@ -1079,9 +1113,9 @@
     pa_operation *o = userdata;
     int eol = 1;
 
-    assert(pd);
-    assert(o);
-    assert(o->ref >= 1);
+    pa_assert(pd);
+    pa_assert(o);
+    pa_assert(PA_REFCNT_VALUE(o) >= 1);
 
     if (!o->context)
         goto finish;
@@ -1095,6 +1129,8 @@
 
         while (!pa_tagstruct_eof(t)) {
             pa_autoload_info i;
+
+            memset(&i, 0, sizeof(i));
 
             if (pa_tagstruct_getu32(t, &i.index) < 0 ||
                 pa_tagstruct_gets(t, &i.name) < 0 ||
@@ -1127,9 +1163,9 @@
     pa_operation *o;
     uint32_t tag;
 
-    assert(c);
-    assert(c->ref >= 1);
-    assert(cb);
+    pa_assert(c);
+    pa_assert(PA_REFCNT_VALUE(c) >= 1);
+    pa_assert(cb);
 
     PA_CHECK_VALIDITY_RETURN_NULL(c, c->state == PA_CONTEXT_READY, PA_ERR_BADSTATE);
     PA_CHECK_VALIDITY_RETURN_NULL(c, name && *name, PA_ERR_INVALID);
@@ -1151,9 +1187,9 @@
     pa_operation *o;
     uint32_t tag;
 
-    assert(c);
-    assert(c->ref >= 1);
-    assert(cb);
+    pa_assert(c);
+    pa_assert(PA_REFCNT_VALUE(c) >= 1);
+    pa_assert(cb);
 
     PA_CHECK_VALIDITY_RETURN_NULL(c, c->state == PA_CONTEXT_READY, PA_ERR_BADSTATE);
     PA_CHECK_VALIDITY_RETURN_NULL(c, idx != PA_INVALID_INDEX, PA_ERR_INVALID);
@@ -1177,8 +1213,8 @@
     pa_tagstruct *t;
     uint32_t tag;
 
-    assert(c);
-    assert(c->ref >= 1);
+    pa_assert(c);
+    pa_assert(PA_REFCNT_VALUE(c) >= 1);
 
     PA_CHECK_VALIDITY_RETURN_NULL(c, c->state == PA_CONTEXT_READY, PA_ERR_BADSTATE);
     PA_CHECK_VALIDITY_RETURN_NULL(c, name && *name, PA_ERR_INVALID);
@@ -1203,8 +1239,8 @@
     pa_tagstruct *t;
     uint32_t tag;
 
-    assert(c);
-    assert(c->ref >= 1);
+    pa_assert(c);
+    pa_assert(PA_REFCNT_VALUE(c) >= 1);
 
     PA_CHECK_VALIDITY_RETURN_NULL(c, c->state == PA_CONTEXT_READY, PA_ERR_BADSTATE);
     PA_CHECK_VALIDITY_RETURN_NULL(c, name && *name, PA_ERR_INVALID);
@@ -1226,8 +1262,8 @@
     pa_tagstruct *t;
     uint32_t tag;
 
-    assert(c);
-    assert(c->ref >= 1);
+    pa_assert(c);
+    pa_assert(PA_REFCNT_VALUE(c) >= 1);
 
     PA_CHECK_VALIDITY_RETURN_NULL(c, c->state == PA_CONTEXT_READY, PA_ERR_BADSTATE);
     PA_CHECK_VALIDITY_RETURN_NULL(c, idx != PA_INVALID_INDEX, PA_ERR_INVALID);
@@ -1247,8 +1283,8 @@
     pa_tagstruct *t;
     uint32_t tag;
 
-    assert(c);
-    assert(c->ref >= 1);
+    pa_assert(c);
+    pa_assert(PA_REFCNT_VALUE(c) >= 1);
 
     PA_CHECK_VALIDITY_RETURN_NULL(c, c->state == PA_CONTEXT_READY, PA_ERR_BADSTATE);
     PA_CHECK_VALIDITY_RETURN_NULL(c, c->version >= 10, PA_ERR_NOTSUPPORTED);
@@ -1272,8 +1308,8 @@
     pa_tagstruct *t;
     uint32_t tag;
 
-    assert(c);
-    assert(c->ref >= 1);
+    pa_assert(c);
+    pa_assert(PA_REFCNT_VALUE(c) >= 1);
 
     PA_CHECK_VALIDITY_RETURN_NULL(c, c->state == PA_CONTEXT_READY, PA_ERR_BADSTATE);
     PA_CHECK_VALIDITY_RETURN_NULL(c, c->version >= 10, PA_ERR_NOTSUPPORTED);
@@ -1297,8 +1333,8 @@
     pa_tagstruct *t;
     uint32_t tag;
 
-    assert(c);
-    assert(c->ref >= 1);
+    pa_assert(c);
+    pa_assert(PA_REFCNT_VALUE(c) >= 1);
 
     PA_CHECK_VALIDITY_RETURN_NULL(c, c->state == PA_CONTEXT_READY, PA_ERR_BADSTATE);
     PA_CHECK_VALIDITY_RETURN_NULL(c, c->version >= 10, PA_ERR_NOTSUPPORTED);
@@ -1322,8 +1358,8 @@
     pa_tagstruct *t;
     uint32_t tag;
 
-    assert(c);
-    assert(c->ref >= 1);
+    pa_assert(c);
+    pa_assert(PA_REFCNT_VALUE(c) >= 1);
 
     PA_CHECK_VALIDITY_RETURN_NULL(c, c->state == PA_CONTEXT_READY, PA_ERR_BADSTATE);
     PA_CHECK_VALIDITY_RETURN_NULL(c, c->version >= 10, PA_ERR_NOTSUPPORTED);
@@ -1341,3 +1377,97 @@
 
     return o;
 }
+
+pa_operation* pa_context_suspend_sink_by_name(pa_context *c, char *sink_name, int suspend, pa_context_success_cb_t cb, void* userdata) {
+    pa_operation *o;
+    pa_tagstruct *t;
+    uint32_t tag;
+
+    pa_assert(c);
+    pa_assert(PA_REFCNT_VALUE(c) >= 1);
+
+    PA_CHECK_VALIDITY_RETURN_NULL(c, c->state == PA_CONTEXT_READY, PA_ERR_BADSTATE);
+    PA_CHECK_VALIDITY_RETURN_NULL(c, c->version >= 11, PA_ERR_NOTSUPPORTED);
+    PA_CHECK_VALIDITY_RETURN_NULL(c, !sink_name || *sink_name, PA_ERR_INVALID);
+
+    o = pa_operation_new(c, NULL, (pa_operation_cb_t) cb, userdata);
+
+    t = pa_tagstruct_command(c, PA_COMMAND_SUSPEND_SINK, &tag);
+    pa_tagstruct_putu32(t, PA_INVALID_INDEX);
+    pa_tagstruct_puts(t, sink_name);
+    pa_tagstruct_put_boolean(t, suspend);
+    pa_pstream_send_tagstruct(c->pstream, t);
+    pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, pa_context_simple_ack_callback, pa_operation_ref(o), (pa_free_cb_t) pa_operation_unref);
+
+    return o;
+}
+
+pa_operation* pa_context_suspend_sink_by_index(pa_context *c, uint32_t idx, int suspend, pa_context_success_cb_t cb, void* userdata) {
+    pa_operation *o;
+    pa_tagstruct *t;
+    uint32_t tag;
+
+    pa_assert(c);
+    pa_assert(PA_REFCNT_VALUE(c) >= 1);
+
+    PA_CHECK_VALIDITY_RETURN_NULL(c, c->state == PA_CONTEXT_READY, PA_ERR_BADSTATE);
+    PA_CHECK_VALIDITY_RETURN_NULL(c, c->version >= 11, PA_ERR_NOTSUPPORTED);
+
+    o = pa_operation_new(c, NULL, (pa_operation_cb_t) cb, userdata);
+
+    t = pa_tagstruct_command(c, PA_COMMAND_SUSPEND_SINK, &tag);
+    pa_tagstruct_putu32(t, idx);
+    pa_tagstruct_puts(t, idx == PA_INVALID_INDEX ? "" : NULL);
+    pa_tagstruct_put_boolean(t, suspend);
+    pa_pstream_send_tagstruct(c->pstream, t);
+    pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, pa_context_simple_ack_callback, pa_operation_ref(o), (pa_free_cb_t) pa_operation_unref);
+
+    return o;
+}
+
+pa_operation* pa_context_suspend_source_by_name(pa_context *c, char *source_name, int suspend, pa_context_success_cb_t cb, void* userdata) {
+    pa_operation *o;
+    pa_tagstruct *t;
+    uint32_t tag;
+
+    pa_assert(c);
+    pa_assert(PA_REFCNT_VALUE(c) >= 1);
+
+    PA_CHECK_VALIDITY_RETURN_NULL(c, c->state == PA_CONTEXT_READY, PA_ERR_BADSTATE);
+    PA_CHECK_VALIDITY_RETURN_NULL(c, c->version >= 11, PA_ERR_NOTSUPPORTED);
+    PA_CHECK_VALIDITY_RETURN_NULL(c, !source_name || *source_name, PA_ERR_INVALID);
+
+    o = pa_operation_new(c, NULL, (pa_operation_cb_t) cb, userdata);
+
+    t = pa_tagstruct_command(c, PA_COMMAND_SUSPEND_SOURCE, &tag);
+    pa_tagstruct_putu32(t, PA_INVALID_INDEX);
+    pa_tagstruct_puts(t, source_name);
+    pa_tagstruct_put_boolean(t, suspend);
+    pa_pstream_send_tagstruct(c->pstream, t);
+    pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, pa_context_simple_ack_callback, pa_operation_ref(o), (pa_free_cb_t) pa_operation_unref);
+
+    return o;
+}
+
+pa_operation* pa_context_suspend_source_by_index(pa_context *c, uint32_t idx, int suspend, pa_context_success_cb_t cb, void* userdata) {
+    pa_operation *o;
+    pa_tagstruct *t;
+    uint32_t tag;
+
+    pa_assert(c);
+    pa_assert(PA_REFCNT_VALUE(c) >= 1);
+
+    PA_CHECK_VALIDITY_RETURN_NULL(c, c->state == PA_CONTEXT_READY, PA_ERR_BADSTATE);
+    PA_CHECK_VALIDITY_RETURN_NULL(c, c->version >= 11, PA_ERR_NOTSUPPORTED);
+
+    o = pa_operation_new(c, NULL, (pa_operation_cb_t) cb, userdata);
+
+    t = pa_tagstruct_command(c, PA_COMMAND_SUSPEND_SOURCE, &tag);
+    pa_tagstruct_putu32(t, idx);
+    pa_tagstruct_puts(t, idx == PA_INVALID_INDEX ? "" : NULL);
+    pa_tagstruct_put_boolean(t, suspend);
+    pa_pstream_send_tagstruct(c->pstream, t);
+    pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, pa_context_simple_ack_callback, pa_operation_ref(o), (pa_free_cb_t) pa_operation_unref);
+
+    return o;
+}

Modified: trunk/src/pulse/introspect.h
URL: http://0pointer.de/cgi-bin/viewcvs.cgi/trunk/src/pulse/introspect.h?rev=1971&root=pulseaudio&r1=1970&r2=1971&view=diff
==============================================================================
--- trunk/src/pulse/introspect.h (original)
+++ trunk/src/pulse/introspect.h Sun Oct 28 20:13:50 2007
@@ -331,6 +331,7 @@
     pa_usec_t sink_usec;                 /**< Latency of the sink device, see pa_latency_info for details */
     const char *resample_method;         /**< Thre resampling method used by this sink input. \since 0.7 */
     const char *driver;                  /**< Driver name \since 0.8 */
+    int mute;                            /**< Stream muted \since 0.9.7 */
 } pa_sink_input_info;
 
 /** Callback prototype for pa_context_get_sink_input_info() and firends*/
@@ -381,6 +382,9 @@
 /** Set the volume of a sink input stream */
 pa_operation* pa_context_set_sink_input_volume(pa_context *c, uint32_t idx, const pa_cvolume *volume, pa_context_success_cb_t cb, void *userdata);
 
+/** Set the mute switch of a sink input stream \since 0.9.7 */
+pa_operation* pa_context_set_sink_input_mute(pa_context *c, uint32_t idx, int mute, pa_context_success_cb_t cb, void *userdata);
+
 /** Set the volume of a source device specified by its index \since 0.8 */
 pa_operation* pa_context_set_source_volume_by_index(pa_context *c, uint32_t idx, const pa_cvolume *volume, pa_context_success_cb_t cb, void *userdata);
 
@@ -499,6 +503,18 @@
 /** Move the specified source output to a different source. \since 0.9.5 */
 pa_operation* pa_context_move_source_output_by_index(pa_context *c, uint32_t idx, uint32_t source_idx, pa_context_success_cb_t cb, void* userdata);
 
+/** Suspend/Resume a sink. \since 0.9.7 */
+pa_operation* pa_context_suspend_sink_by_name(pa_context *c, char *sink_name, int suspend, pa_context_success_cb_t cb, void* userdata);
+
+/** Suspend/Resume a sink. If idx is PA_INVALID_INDEX all sinks will be suspended. \since 0.9.7 */
+pa_operation* pa_context_suspend_sink_by_index(pa_context *c, uint32_t idx, int suspend,  pa_context_success_cb_t cb, void* userdata);
+
+/** Suspend/Resume a source. \since 0.9.7 */
+pa_operation* pa_context_suspend_source_by_name(pa_context *c, char *source_name, int suspend, pa_context_success_cb_t cb, void* userdata);
+
+/** Suspend/Resume a source. If idx is PA_INVALID_INDEX all sources will be suspended. \since 0.9.7 */
+pa_operation* pa_context_suspend_source_by_index(pa_context *c, uint32_t idx, int suspend, pa_context_success_cb_t cb, void* userdata);
+
 PA_C_DECL_END
 
 #endif

Modified: trunk/src/pulse/mainloop-api.c
URL: http://0pointer.de/cgi-bin/viewcvs.cgi/trunk/src/pulse/mainloop-api.c?rev=1971&root=pulseaudio&r1=1970&r2=1971&view=diff
==============================================================================
--- trunk/src/pulse/mainloop-api.c (original)
+++ trunk/src/pulse/mainloop-api.c Sun Oct 28 20:13:50 2007
@@ -25,12 +25,12 @@
 #include <config.h>
 #endif
 
-#include <assert.h>
 #include <stdlib.h>
 
 #include <pulse/xmalloc.h>
 
 #include <pulsecore/gccmacro.h>
+#include <pulsecore/macro.h>
 
 #include "mainloop-api.h"
 
@@ -41,32 +41,38 @@
 
 static void once_callback(pa_mainloop_api *m, pa_defer_event *e, void *userdata) {
     struct once_info *i = userdata;
-    assert(m && i && i->callback);
 
+    pa_assert(m);
+    pa_assert(i);
+
+    pa_assert(i->callback);
     i->callback(m, i->userdata);
 
-    assert(m->defer_free);
+    pa_assert(m->defer_free);
     m->defer_free(e);
 }
 
 static void free_callback(pa_mainloop_api *m, PA_GCC_UNUSED pa_defer_event *e, void *userdata) {
     struct once_info *i = userdata;
-    assert(m && i);
+
+    pa_assert(m);
+    pa_assert(i);
     pa_xfree(i);
 }
 
 void pa_mainloop_api_once(pa_mainloop_api* m, void (*callback)(pa_mainloop_api *m, void *userdata), void *userdata) {
     struct once_info *i;
     pa_defer_event *e;
-    assert(m && callback);
+
+    pa_assert(m);
+    pa_assert(callback);
 
     i = pa_xnew(struct once_info, 1);
     i->callback = callback;
     i->userdata = userdata;
 
-    assert(m->defer_new);
-    e = m->defer_new(m, once_callback, i);
-    assert(e);
+    pa_assert(m->defer_new);
+    pa_assert_se(e = m->defer_new(m, once_callback, i));
     m->defer_set_destroy(e, free_callback);
 }
 

Modified: trunk/src/pulse/mainloop-signal.c
URL: http://0pointer.de/cgi-bin/viewcvs.cgi/trunk/src/pulse/mainloop-signal.c?rev=1971&root=pulseaudio&r1=1970&r2=1971&view=diff
==============================================================================
--- trunk/src/pulse/mainloop-signal.c (original)
+++ trunk/src/pulse/mainloop-signal.c Sun Oct 28 20:13:50 2007
@@ -27,7 +27,6 @@
 #endif
 
 #include <stdio.h>
-#include <assert.h>
 #include <signal.h>
 #include <errno.h>
 #include <stdlib.h>
@@ -39,12 +38,13 @@
 #include <windows.h>
 #endif
 
+#include <pulse/xmalloc.h>
+
 #include <pulsecore/core-error.h>
-#include <pulse/xmalloc.h>
-
 #include <pulsecore/core-util.h>
 #include <pulsecore/log.h>
 #include <pulsecore/gccmacro.h>
+#include <pulsecore/macro.h>
 
 #include "mainloop-signal.h"
 
@@ -74,11 +74,11 @@
 }
 
 static void dispatch(pa_mainloop_api*a, int sig) {
-    pa_signal_event*s;
+    pa_signal_event *s;
 
     for (s = signals; s; s = s->next)
         if (s->sig == sig) {
-            assert(s->callback);
+            pa_assert(s->callback);
             s->callback(a, s, sig, s->userdata);
             break;
         }
@@ -87,7 +87,12 @@
 static void callback(pa_mainloop_api*a, pa_io_event*e, int fd, pa_io_event_flags_t f, PA_GCC_UNUSED void *userdata) {
     ssize_t r;
     int sig;
-    assert(a && e && f == PA_IO_EVENT_INPUT && e == io_event && fd == signal_pipe[0]);
+
+    pa_assert(a);
+    pa_assert(e);
+    pa_assert(f == PA_IO_EVENT_INPUT);
+    pa_assert(e == io_event);
+    pa_assert(fd == signal_pipe[0]);
 
     if ((r = pa_read(signal_pipe[0], &sig, sizeof(sig), NULL)) < 0) {
         if (errno == EAGAIN)
@@ -107,28 +112,34 @@
 
 int pa_signal_init(pa_mainloop_api *a) {
 
-    assert(!api && a && signal_pipe[0] == -1 && signal_pipe[1] == -1 && !io_event);
+    pa_assert(a);
+    pa_assert(!api);
+    pa_assert(signal_pipe[0] == -1);
+    pa_assert(signal_pipe[1] == -1);
+    pa_assert(!io_event);
 
     if (pipe(signal_pipe) < 0) {
         pa_log("pipe(): %s", pa_cstrerror(errno));
         return -1;
     }
 
-    pa_make_nonblock_fd(signal_pipe[0]);
-    pa_make_nonblock_fd(signal_pipe[1]);
-    pa_fd_set_cloexec(signal_pipe[0], 1);
-    pa_fd_set_cloexec(signal_pipe[1], 1);
+    pa_make_fd_nonblock(signal_pipe[0]);
+    pa_make_fd_nonblock(signal_pipe[1]);
+    pa_make_fd_cloexec(signal_pipe[0]);
+    pa_make_fd_cloexec(signal_pipe[1]);
 
     api = a;
 
-    io_event = api->io_new(api, signal_pipe[0], PA_IO_EVENT_INPUT, callback, NULL);
-    assert(io_event);
+    pa_assert_se(io_event = api->io_new(api, signal_pipe[0], PA_IO_EVENT_INPUT, callback, NULL));
 
     return 0;
 }
 
 void pa_signal_done(void) {
-    assert(api && signal_pipe[0] >= 0 && signal_pipe[1] >= 0 && io_event);
+    pa_assert(api);
+    pa_assert(signal_pipe[0] >= 0);
+    pa_assert(signal_pipe[1] >= 0);
+    pa_assert(io_event);
 
     while (signals)
         pa_signal_free(signals);
@@ -136,9 +147,7 @@
     api->io_free(io_event);
     io_event = NULL;
 
-    close(signal_pipe[0]);
-    close(signal_pipe[1]);
-    signal_pipe[0] = signal_pipe[1] = -1;
+    pa_close_pipe(signal_pipe);
 
     api = NULL;
 }
@@ -150,13 +159,14 @@
     struct sigaction sa;
 #endif
 
-    assert(sig > 0 && _callback);
+    pa_assert(sig > 0);
+    pa_assert(_callback);
 
     for (e = signals; e; e = e->next)
         if (e->sig == sig)
             goto fail;
 
-    e = pa_xmalloc(sizeof(pa_signal_event));
+    e = pa_xnew(pa_signal_event, 1);
     e->sig = sig;
     e->callback = _callback;
     e->userdata = userdata;
@@ -186,7 +196,7 @@
 }
 
 void pa_signal_free(pa_signal_event *e) {
-    assert(e);
+    pa_assert(e);
 
     if (e->next)
         e->next->previous = e->previous;
@@ -196,9 +206,9 @@
         signals = e->next;
 
 #ifdef HAVE_SIGACTION
-    sigaction(e->sig, &e->saved_sigaction, NULL);
+    pa_assert_se(sigaction(e->sig, &e->saved_sigaction, NULL) == 0);
 #else
-    signal(e->sig, e->saved_handler);
+    pa_assert_se(signal(e->sig, e->saved_handler) == signal_handler);
 #endif
 
     if (e->destroy_callback)
@@ -208,6 +218,7 @@
 }
 
 void pa_signal_set_destroy(pa_signal_event *e, void (*_callback) (pa_mainloop_api *api, pa_signal_event*e, void *userdata)) {
-    assert(e);
+    pa_assert(e);
+
     e->destroy_callback = _callback;
 }

Modified: trunk/src/pulse/mainloop.c
URL: http://0pointer.de/cgi-bin/viewcvs.cgi/trunk/src/pulse/mainloop.c?rev=1971&root=pulseaudio&r1=1970&r2=1971&view=diff
==============================================================================
--- trunk/src/pulse/mainloop.c (original)
+++ trunk/src/pulse/mainloop.c Sun Oct 28 20:13:50 2007
@@ -31,29 +31,28 @@
 #include <unistd.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>
+#ifdef HAVE_POLL_H
+#include <poll.h>
 #else
-#include "../pulsecore/poll.h"
+#include <pulsecore/poll.h>
 #endif
 
-#include "../pulsecore/winsock.h"
-
 #ifndef HAVE_PIPE
-#include "../pulsecore/pipe.h"
+#include <pulsecore/pipe.h>
 #endif
 
-#include <pulsecore/core-error.h>
 #include <pulse/timeval.h>
 #include <pulse/xmalloc.h>
 
 #include <pulsecore/core-util.h>
 #include <pulsecore/llist.h>
 #include <pulsecore/log.h>
+#include <pulsecore/core-error.h>
+#include <pulsecore/winsock.h>
+#include <pulsecore/macro.h>
 
 #include "mainloop.h"
 
@@ -161,13 +160,13 @@
     pa_mainloop *m;
     pa_io_event *e;
 
-    assert(a);
-    assert(a->userdata);
-    assert(fd >= 0);
-    assert(callback);
+    pa_assert(a);
+    pa_assert(a->userdata);
+    pa_assert(fd >= 0);
+    pa_assert(callback);
 
     m = a->userdata;
-    assert(a == &m->api);
+    pa_assert(a == &m->api);
 
     e = pa_xnew(pa_io_event, 1);
     e->mainloop = m;
@@ -195,7 +194,7 @@
         if ((select((SELECT_TYPE_ARG1) fd, NULL, NULL, SELECT_TYPE_ARG234 &xset,
                     SELECT_TYPE_ARG5 &tv) == -1) &&
              (WSAGetLastError() == WSAENOTSOCK)) {
-            pa_log_warn("WARNING: cannot monitor non-socket file descriptors.");
+            pa_log_warn("Cannot monitor non-socket file descriptors.");
             e->dead = 1;
         }
     }
@@ -211,8 +210,8 @@
 }
 
 static void mainloop_io_enable(pa_io_event *e, pa_io_event_flags_t events) {
-    assert(e);
-    assert(!e->dead);
+    pa_assert(e);
+    pa_assert(!e->dead);
 
     if (e->events == events)
         return;
@@ -228,8 +227,8 @@
 }
 
 static void mainloop_io_free(pa_io_event *e) {
-    assert(e);
-    assert(!e->dead);
+    pa_assert(e);
+    pa_assert(!e->dead);
 
     e->dead = 1;
     e->mainloop->io_events_please_scan ++;
@@ -241,7 +240,7 @@
 }
 
 static void mainloop_io_set_destroy(pa_io_event *e, pa_io_event_destroy_cb_t callback) {
-    assert(e);
+    pa_assert(e);
 
     e->destroy_callback = callback;
 }
@@ -255,12 +254,12 @@
     pa_mainloop *m;
     pa_defer_event *e;
 
-    assert(a);
-    assert(a->userdata);
-    assert(callback);
+    pa_assert(a);
+    pa_assert(a->userdata);
+    pa_assert(callback);
 
     m = a->userdata;
-    assert(a == &m->api);
+    pa_assert(a == &m->api);
 
     e = pa_xnew(pa_defer_event, 1);
     e->mainloop = m;
@@ -281,11 +280,11 @@
 }
 
 static void mainloop_defer_enable(pa_defer_event *e, int b) {
-    assert(e);
-    assert(!e->dead);
+    pa_assert(e);
+    pa_assert(!e->dead);
 
     if (e->enabled && !b) {
-        assert(e->mainloop->n_enabled_defer_events > 0);
+        pa_assert(e->mainloop->n_enabled_defer_events > 0);
         e->mainloop->n_enabled_defer_events--;
     } else if (!e->enabled && b) {
         e->mainloop->n_enabled_defer_events++;
@@ -296,21 +295,22 @@
 }
 
 static void mainloop_defer_free(pa_defer_event *e) {
-    assert(e);
-    assert(!e->dead);
+    pa_assert(e);
+    pa_assert(!e->dead);
 
     e->dead = 1;
     e->mainloop->defer_events_please_scan ++;
 
     if (e->enabled) {
-        assert(e->mainloop->n_enabled_defer_events > 0);
+        pa_assert(e->mainloop->n_enabled_defer_events > 0);
         e->mainloop->n_enabled_defer_events--;
+        e->enabled = 0;
     }
 }
 
 static void mainloop_defer_set_destroy(pa_defer_event *e, pa_defer_event_destroy_cb_t callback) {
-    assert(e);
-    assert(!e->dead);
+    pa_assert(e);
+    pa_assert(!e->dead);
 
     e->destroy_callback = callback;
 }
@@ -325,12 +325,12 @@
     pa_mainloop *m;
     pa_time_event *e;
 
-    assert(a);
-    assert(a->userdata);
-    assert(callback);
+    pa_assert(a);
+    pa_assert(a->userdata);
+    pa_assert(callback);
 
     m = a->userdata;
-    assert(a == &m->api);
+    pa_assert(a == &m->api);
 
     e = pa_xnew(pa_time_event, 1);
     e->mainloop = m;
@@ -342,7 +342,7 @@
         m->n_enabled_time_events++;
 
         if (m->cached_next_time_event) {
-            assert(m->cached_next_time_event->enabled);
+            pa_assert(m->cached_next_time_event->enabled);
 
             if (pa_timeval_cmp(tv, &m->cached_next_time_event->timeval) < 0)
                 m->cached_next_time_event = e;
@@ -362,11 +362,11 @@
 }
 
 static void mainloop_time_restart(pa_time_event *e, const struct timeval *tv) {
-    assert(e);
-    assert(!e->dead);
+    pa_assert(e);
+    pa_assert(!e->dead);
 
     if (e->enabled && !tv) {
-        assert(e->mainloop->n_enabled_time_events > 0);
+        pa_assert(e->mainloop->n_enabled_time_events > 0);
         e->mainloop->n_enabled_time_events--;
     } else if (!e->enabled && tv)
         e->mainloop->n_enabled_time_events++;
@@ -377,7 +377,7 @@
     }
 
     if (e->mainloop->cached_next_time_event && e->enabled) {
-        assert(e->mainloop->cached_next_time_event->enabled);
+        pa_assert(e->mainloop->cached_next_time_event->enabled);
 
         if (pa_timeval_cmp(tv, &e->mainloop->cached_next_time_event->timeval) < 0)
             e->mainloop->cached_next_time_event = e;
@@ -386,15 +386,16 @@
 }
 
 static void mainloop_time_free(pa_time_event *e) {
-    assert(e);
-    assert(!e->dead);
+    pa_assert(e);
+    pa_assert(!e->dead);
 
     e->dead = 1;
     e->mainloop->time_events_please_scan ++;
 
     if (e->enabled) {
-        assert(e->mainloop->n_enabled_time_events > 0);
+        pa_assert(e->mainloop->n_enabled_time_events > 0);
         e->mainloop->n_enabled_time_events--;
+        e->enabled = 0;
     }
 
     if (e->mainloop->cached_next_time_event == e)
@@ -404,8 +405,8 @@
 }
 
 static void mainloop_time_set_destroy(pa_time_event *e, pa_time_event_destroy_cb_t callback) {
-    assert(e);
-    assert(!e->dead);
+    pa_assert(e);
+    pa_assert(!e->dead);
 
     e->destroy_callback = callback;
 }
@@ -415,10 +416,10 @@
 static void mainloop_quit(pa_mainloop_api*a, int retval) {
     pa_mainloop *m;
 
-    assert(a);
-    assert(a->userdata);
+    pa_assert(a);
+    pa_assert(a->userdata);
     m = a->userdata;
-    assert(a == &m->api);
+    pa_assert(a == &m->api);
 
     pa_mainloop_quit(m, retval);
 }
@@ -456,8 +457,10 @@
         return NULL;
     }
 
-    pa_make_nonblock_fd(m->wakeup_pipe[0]);
-    pa_make_nonblock_fd(m->wakeup_pipe[1]);
+    pa_make_fd_nonblock(m->wakeup_pipe[0]);
+    pa_make_fd_nonblock(m->wakeup_pipe[1]);
+    pa_make_fd_cloexec(m->wakeup_pipe[0]);
+    pa_make_fd_cloexec(m->wakeup_pipe[1]);
     m->wakeup_requested = 0;
 
     PA_LLIST_HEAD_INIT(pa_io_event, m->io_events);
@@ -502,7 +505,7 @@
             PA_LLIST_REMOVE(pa_io_event, m->io_events, e);
 
             if (e->dead) {
-                assert(m->io_events_please_scan > 0);
+                pa_assert(m->io_events_please_scan > 0);
                 m->io_events_please_scan--;
             }
 
@@ -517,7 +520,7 @@
         e = n;
     }
 
-    assert(m->io_events_please_scan == 0);
+    pa_assert(m->io_events_please_scan == 0);
 }
 
 static void cleanup_time_events(pa_mainloop *m, int force) {
@@ -534,13 +537,14 @@
             PA_LLIST_REMOVE(pa_time_event, m->time_events, e);
 
             if (e->dead) {
-                assert(m->time_events_please_scan > 0);
+                pa_assert(m->time_events_please_scan > 0);
                 m->time_events_please_scan--;
             }
 
             if (!e->dead && e->enabled) {
-                assert(m->n_enabled_time_events > 0);
+                pa_assert(m->n_enabled_time_events > 0);
                 m->n_enabled_time_events--;
+                e->enabled = 0;
             }
 
             if (e->destroy_callback)
@@ -552,7 +556,7 @@
         e = n;
     }
 
-    assert(m->time_events_please_scan == 0);
+    pa_assert(m->time_events_please_scan == 0);
 }
 
 static void cleanup_defer_events(pa_mainloop *m, int force) {
@@ -569,13 +573,14 @@
             PA_LLIST_REMOVE(pa_defer_event, m->defer_events, e);
 
             if (e->dead) {
-                assert(m->defer_events_please_scan > 0);
+                pa_assert(m->defer_events_please_scan > 0);
                 m->defer_events_please_scan--;
             }
 
             if (!e->dead && e->enabled) {
-                assert(m->n_enabled_defer_events > 0);
+                pa_assert(m->n_enabled_defer_events > 0);
                 m->n_enabled_defer_events--;
+                e->enabled = 0;
             }
 
             if (e->destroy_callback)
@@ -587,12 +592,12 @@
         e = n;
     }
 
-    assert(m->defer_events_please_scan == 0);
+    pa_assert(m->defer_events_please_scan == 0);
 }
 
 
 void pa_mainloop_free(pa_mainloop* m) {
-    assert(m);
+    pa_assert(m);
 
     cleanup_io_events(m, 1);
     cleanup_defer_events(m, 1);
@@ -600,16 +605,13 @@
 
     pa_xfree(m->pollfds);
 
-    if (m->wakeup_pipe[0] >= 0)
-        close(m->wakeup_pipe[0]);
-    if (m->wakeup_pipe[1] >= 0)
-        close(m->wakeup_pipe[1]);
+    pa_close_pipe(m->wakeup_pipe);
 
     pa_xfree(m);
 }
 
 static void scan_dead(pa_mainloop *m) {
-    assert(m);
+    pa_assert(m);
 
     if (m->io_events_please_scan)
         cleanup_io_events(m, 0);
@@ -666,13 +668,14 @@
     pa_io_event *e;
     int r = 0, k;
 
-    assert(m->poll_func_ret > 0);
+    pa_assert(m->poll_func_ret > 0);
 
     for (e = m->io_events, k = m->poll_func_ret; e && !m->quit && k > 0; e = e->next) {
         if (e->dead || !e->pollfd || !e->pollfd->revents)
             continue;
 
-        assert(e->pollfd->fd == e->fd && e->callback);
+        pa_assert(e->pollfd->fd == e->fd);
+        pa_assert(e->callback);
         e->callback(&m->api, e, e->fd, map_flags_from_libc(e->pollfd->revents), e->userdata);
         e->pollfd->revents = 0;
         r++;
@@ -694,7 +697,7 @@
         if (e->dead || !e->enabled)
             continue;
 
-        assert(e->callback);
+        pa_assert(e->callback);
         e->callback(&m->api, e, e->userdata);
         r++;
     }
@@ -704,7 +707,7 @@
 
 static pa_time_event* find_next_time_event(pa_mainloop *m) {
     pa_time_event *t, *n = NULL;
-    assert(m);
+    pa_assert(m);
 
     if (m->cached_next_time_event)
         return m->cached_next_time_event;
@@ -736,7 +739,7 @@
         return -1;
 
     t = find_next_time_event(m);
-    assert(t);
+    pa_assert(t);
 
     if (t->timeval.tv_sec <= 0)
         return 0;
@@ -754,7 +757,7 @@
     pa_time_event *e;
     struct timeval now;
     int r = 0;
-    assert(m);
+    pa_assert(m);
 
     if (m->n_enabled_time_events <= 0)
         return 0;
@@ -767,7 +770,7 @@
             continue;
 
         if (pa_timeval_cmp(&e->timeval, &now) <= 0) {
-            assert(e->callback);
+            pa_assert(e->callback);
 
             /* Disable time event */
             mainloop_time_restart(e, NULL);
@@ -783,7 +786,7 @@
 
 void pa_mainloop_wakeup(pa_mainloop *m) {
     char c = 'W';
-    assert(m);
+    pa_assert(m);
 
     if (m->wakeup_pipe[1] >= 0 && m->state == STATE_POLLING) {
         pa_write(m->wakeup_pipe[1], &c, sizeof(c), &m->wakeup_pipe_type);
@@ -794,7 +797,7 @@
 static void clear_wakeup(pa_mainloop *m) {
     char c[10];
 
-    assert(m);
+    pa_assert(m);
 
     if (m->wakeup_pipe[0] < 0)
         return;
@@ -806,8 +809,8 @@
 }
 
 int pa_mainloop_prepare(pa_mainloop *m, int timeout) {
-    assert(m);
-    assert(m->state == STATE_PASSIVE);
+    pa_assert(m);
+    pa_assert(m->state == STATE_PASSIVE);
 
     clear_wakeup(m);
     scan_dead(m);
@@ -833,8 +836,8 @@
 }
 
 int pa_mainloop_poll(pa_mainloop *m) {
-    assert(m);
-    assert(m->state == STATE_PREPARED);
+    pa_assert(m);
+    pa_assert(m->state == STATE_PREPARED);
 
     if (m->quit)
         goto quit;
@@ -844,7 +847,7 @@
     if (m->n_enabled_defer_events )
         m->poll_func_ret = 0;
     else {
-        assert(!m->rebuild_pollfds);
+        pa_assert(!m->rebuild_pollfds);
 
         if (m->poll_func)
             m->poll_func_ret = m->poll_func(m->pollfds, m->n_pollfds, m->prepared_timeout, m->poll_func_userdata);
@@ -870,8 +873,8 @@
 int pa_mainloop_dispatch(pa_mainloop *m) {
     int dispatched = 0;
 
-    assert(m);
-    assert(m->state == STATE_POLLED);
+    pa_assert(m);
+    pa_assert(m->state == STATE_POLLED);
 
     if (m->quit)
         goto quit;
@@ -902,13 +905,13 @@
 }
 
 int pa_mainloop_get_retval(pa_mainloop *m) {
-    assert(m);
+    pa_assert(m);
     return m->retval;
 }
 
 int pa_mainloop_iterate(pa_mainloop *m, int block, int *retval) {
     int r;
-    assert(m);
+    pa_assert(m);
 
     if ((r = pa_mainloop_prepare(m, block ? -1 : 0)) < 0)
         goto quit;
@@ -942,7 +945,7 @@
 }
 
 void pa_mainloop_quit(pa_mainloop *m, int retval) {
-    assert(m);
+    pa_assert(m);
 
     m->quit = 1;
     m->retval = retval;
@@ -950,12 +953,12 @@
 }
 
 pa_mainloop_api* pa_mainloop_get_api(pa_mainloop*m) {
-    assert(m);
+    pa_assert(m);
     return &m->api;
 }
 
 void pa_mainloop_set_poll_func(pa_mainloop *m, pa_poll_func poll_func, void *userdata) {
-    assert(m);
+    pa_assert(m);
 
     m->poll_func = poll_func;
     m->poll_func_userdata = userdata;

Modified: trunk/src/pulse/operation.c
URL: http://0pointer.de/cgi-bin/viewcvs.cgi/trunk/src/pulse/operation.c?rev=1971&root=pulseaudio&r1=1970&r2=1971&view=diff
==============================================================================
--- trunk/src/pulse/operation.c (original)
+++ trunk/src/pulse/operation.c Sun Oct 28 20:13:50 2007
@@ -25,19 +25,18 @@
 #include <config.h>
 #endif
 
-#include <assert.h>
-
 #include <pulse/xmalloc.h>
+#include <pulsecore/macro.h>
 
 #include "internal.h"
 #include "operation.h"
 
 pa_operation *pa_operation_new(pa_context *c, pa_stream *s, pa_operation_cb_t cb, void *userdata) {
     pa_operation *o;
-    assert(c);
+    pa_assert(c);
 
     o = pa_xnew(pa_operation, 1);
-    o->ref = 1;
+    PA_REFCNT_INIT(o);
     o->context = c;
     o->stream = s;
 
@@ -53,27 +52,27 @@
 }
 
 pa_operation *pa_operation_ref(pa_operation *o) {
-    assert(o);
-    assert(o->ref >= 1);
+    pa_assert(o);
+    pa_assert(PA_REFCNT_VALUE(o) >= 1);
 
-    o->ref++;
+    PA_REFCNT_INC(o);
     return o;
 }
 
 void pa_operation_unref(pa_operation *o) {
-    assert(o);
-    assert(o->ref >= 1);
+    pa_assert(o);
+    pa_assert(PA_REFCNT_VALUE(o) >= 1);
 
-    if ((--(o->ref)) == 0) {
-        assert(!o->context);
-        assert(!o->stream);
+    if (PA_REFCNT_DEC(o) <= 0) {
+        pa_assert(!o->context);
+        pa_assert(!o->stream);
         pa_xfree(o);
     }
 }
 
 static void operation_set_state(pa_operation *o, pa_operation_state_t st) {
-    assert(o);
-    assert(o->ref >= 1);
+    pa_assert(o);
+    pa_assert(PA_REFCNT_VALUE(o) >= 1);
 
     if (st == o->state)
         return;
@@ -85,7 +84,7 @@
     if ((o->state == PA_OPERATION_DONE) || (o->state == PA_OPERATION_CANCELED)) {
 
         if (o->context) {
-            assert(o->ref >= 2);
+            pa_assert(PA_REFCNT_VALUE(o) >= 2);
 
             PA_LLIST_REMOVE(pa_operation, o->context->operations, o);
             pa_operation_unref(o);
@@ -101,22 +100,22 @@
 }
 
 void pa_operation_cancel(pa_operation *o) {
-    assert(o);
-    assert(o->ref >= 1);
+    pa_assert(o);
+    pa_assert(PA_REFCNT_VALUE(o) >= 1);
 
     operation_set_state(o, PA_OPERATION_CANCELED);
 }
 
 void pa_operation_done(pa_operation *o) {
-    assert(o);
-    assert(o->ref >= 1);
+    pa_assert(o);
+    pa_assert(PA_REFCNT_VALUE(o) >= 1);
 
     operation_set_state(o, PA_OPERATION_DONE);
 }
 
 pa_operation_state_t pa_operation_get_state(pa_operation *o) {
-    assert(o);
-    assert(o->ref >= 1);
+    pa_assert(o);
+    pa_assert(PA_REFCNT_VALUE(o) >= 1);
 
     return o->state;
 }

Modified: trunk/src/pulse/sample.c
URL: http://0pointer.de/cgi-bin/viewcvs.cgi/trunk/src/pulse/sample.c?rev=1971&root=pulseaudio&r1=1970&r2=1971&view=diff
==============================================================================
--- trunk/src/pulse/sample.c (original)
+++ trunk/src/pulse/sample.c Sun Oct 28 20:13:50 2007
@@ -27,57 +27,58 @@
 #endif
 
 #include <stdio.h>
-#include <assert.h>
 #include <math.h>
 #include <string.h>
+
+#include <pulsecore/core-util.h>
+#include <pulsecore/macro.h>
 
 #include "sample.h"
 
 size_t pa_sample_size(const pa_sample_spec *spec) {
-    assert(spec);
 
-    switch (spec->format) {
-        case PA_SAMPLE_U8:
-        case PA_SAMPLE_ULAW:
-        case PA_SAMPLE_ALAW:
-            return 1;
-        case PA_SAMPLE_S16LE:
-        case PA_SAMPLE_S16BE:
-            return 2;
-        case PA_SAMPLE_FLOAT32LE:
-        case PA_SAMPLE_FLOAT32BE:
-            return 4;
-        default:
-            assert(0);
-            return 0;
-    }
+    static const size_t table[] = {
+        [PA_SAMPLE_U8] = 1,
+        [PA_SAMPLE_ULAW] = 1,
+        [PA_SAMPLE_ALAW] = 1,
+        [PA_SAMPLE_S16LE] = 2,
+        [PA_SAMPLE_S16BE] = 2,
+        [PA_SAMPLE_FLOAT32LE] = 4,
+        [PA_SAMPLE_FLOAT32BE] = 4
+    };
+
+    pa_assert(spec);
+    pa_assert(spec->format >= 0);
+    pa_assert(spec->format < PA_SAMPLE_MAX);
+
+    return table[spec->format];
 }
 
 size_t pa_frame_size(const pa_sample_spec *spec) {
-    assert(spec);
+    pa_assert(spec);
 
     return pa_sample_size(spec) * spec->channels;
 }
 
 size_t pa_bytes_per_second(const pa_sample_spec *spec) {
-    assert(spec);
+    pa_assert(spec);
     return spec->rate*pa_frame_size(spec);
 }
 
 pa_usec_t pa_bytes_to_usec(uint64_t length, const pa_sample_spec *spec) {
-    assert(spec);
+    pa_assert(spec);
 
     return (pa_usec_t) (((double) length/pa_frame_size(spec)*1000000)/spec->rate);
 }
 
 size_t pa_usec_to_bytes(pa_usec_t t, const pa_sample_spec *spec) {
-    assert(spec);
+    pa_assert(spec);
 
     return (size_t) (((double) t * spec->rate / 1000000))*pa_frame_size(spec);
 }
 
 int pa_sample_spec_valid(const pa_sample_spec *spec) {
-    assert(spec);
+    pa_assert(spec);
 
     if (spec->rate <= 0 ||
         spec->rate > PA_RATE_MAX ||
@@ -91,7 +92,8 @@
 }
 
 int pa_sample_spec_equal(const pa_sample_spec*a, const pa_sample_spec*b) {
-    assert(a && b);
+    pa_assert(a);
+    pa_assert(b);
 
     return (a->format == b->format) && (a->rate == b->rate) && (a->channels == b->channels);
 }
@@ -107,37 +109,42 @@
         [PA_SAMPLE_FLOAT32BE] = "float32be",
     };
 
-    if (f >= PA_SAMPLE_MAX)
+    if (f < 0 || f >= PA_SAMPLE_MAX)
         return NULL;
 
     return table[f];
 }
 
 char *pa_sample_spec_snprint(char *s, size_t l, const pa_sample_spec *spec) {
-    assert(s && l && spec);
+    pa_assert(s);
+    pa_assert(l);
+    pa_assert(spec);
 
     if (!pa_sample_spec_valid(spec))
-        snprintf(s, l, "Invalid");
+        pa_snprintf(s, l, "Invalid");
     else
-        snprintf(s, l, "%s %uch %uHz", pa_sample_format_to_string(spec->format), spec->channels, spec->rate);
+        pa_snprintf(s, l, "%s %uch %uHz", pa_sample_format_to_string(spec->format), spec->channels, spec->rate);
 
     return s;
 }
 
 char* pa_bytes_snprint(char *s, size_t l, unsigned v) {
+    pa_assert(s);
+
     if (v >= ((unsigned) 1024)*1024*1024)
-        snprintf(s, l, "%0.1f GiB", ((double) v)/1024/1024/1024);
+        pa_snprintf(s, l, "%0.1f GiB", ((double) v)/1024/1024/1024);
     else if (v >= ((unsigned) 1024)*1024)
-        snprintf(s, l, "%0.1f MiB", ((double) v)/1024/1024);
+        pa_snprintf(s, l, "%0.1f MiB", ((double) v)/1024/1024);
     else if (v >= (unsigned) 1024)
-        snprintf(s, l, "%0.1f KiB", ((double) v)/1024);
+        pa_snprintf(s, l, "%0.1f KiB", ((double) v)/1024);
     else
-        snprintf(s, l, "%u B", (unsigned) v);
+        pa_snprintf(s, l, "%u B", (unsigned) v);
 
     return s;
 }
 
 pa_sample_format_t pa_parse_sample_format(const char *format) {
+    pa_assert(format);
 
     if (strcasecmp(format, "s16le") == 0)
         return PA_SAMPLE_S16LE;
@@ -145,15 +152,19 @@
         return PA_SAMPLE_S16BE;
     else if (strcasecmp(format, "s16ne") == 0 || strcasecmp(format, "s16") == 0 || strcasecmp(format, "16") == 0)
         return PA_SAMPLE_S16NE;
+    else if (strcasecmp(format, "s16re") == 0)
+        return PA_SAMPLE_S16RE;
     else if (strcasecmp(format, "u8") == 0 || strcasecmp(format, "8") == 0)
         return PA_SAMPLE_U8;
     else if (strcasecmp(format, "float32") == 0 || strcasecmp(format, "float32ne") == 0)
-        return PA_SAMPLE_FLOAT32;
+        return PA_SAMPLE_FLOAT32NE;
+    else if (strcasecmp(format, "float32re") == 0)
+        return PA_SAMPLE_FLOAT32RE;
     else if (strcasecmp(format, "float32le") == 0)
         return PA_SAMPLE_FLOAT32LE;
     else if (strcasecmp(format, "float32be") == 0)
         return PA_SAMPLE_FLOAT32BE;
-    else if (strcasecmp(format, "ulaw") == 0)
+    else if (strcasecmp(format, "ulaw") == 0 || strcasecmp(format, "mulaw") == 0)
         return PA_SAMPLE_ULAW;
     else if (strcasecmp(format, "alaw") == 0)
         return PA_SAMPLE_ALAW;

Modified: trunk/src/pulse/sample.h
URL: http://0pointer.de/cgi-bin/viewcvs.cgi/trunk/src/pulse/sample.h?rev=1971&root=pulseaudio&r1=1970&r2=1971&view=diff
==============================================================================
--- trunk/src/pulse/sample.h (original)
+++ trunk/src/pulse/sample.h Sun Oct 28 20:13:50 2007
@@ -155,31 +155,31 @@
 typedef uint64_t pa_usec_t;
 
 /** Return the amount of bytes playback of a second of audio with the specified sample type takes */
-size_t pa_bytes_per_second(const pa_sample_spec *spec);
+size_t pa_bytes_per_second(const pa_sample_spec *spec) PA_GCC_PURE;
 
 /** Return the size of a frame with the specific sample type */
-size_t pa_frame_size(const pa_sample_spec *spec);
+size_t pa_frame_size(const pa_sample_spec *spec) PA_GCC_PURE;
 
 /** Return the size of a sample with the specific sample type */
-size_t pa_sample_size(const pa_sample_spec *spec);
+size_t pa_sample_size(const pa_sample_spec *spec) PA_GCC_PURE;
 
 /** Calculate the time the specified bytes take to play with the specified sample type */
-pa_usec_t pa_bytes_to_usec(uint64_t length, const pa_sample_spec *spec);
+pa_usec_t pa_bytes_to_usec(uint64_t length, const pa_sample_spec *spec) PA_GCC_PURE;
 
 /** Calculates the number of bytes that are required for the specified time. \since 0.9 */
-size_t pa_usec_to_bytes(pa_usec_t t, const pa_sample_spec *spec);
+size_t pa_usec_to_bytes(pa_usec_t t, const pa_sample_spec *spec) PA_GCC_PURE;
 
 /** Return non-zero when the sample type specification is valid */
-int pa_sample_spec_valid(const pa_sample_spec *spec);
+int pa_sample_spec_valid(const pa_sample_spec *spec) PA_GCC_PURE;
 
 /** Return non-zero when the two sample type specifications match */
-int pa_sample_spec_equal(const pa_sample_spec*a, const pa_sample_spec*b);
+int pa_sample_spec_equal(const pa_sample_spec*a, const pa_sample_spec*b) PA_GCC_PURE;
 
 /** Return a descriptive string for the specified sample format. \since 0.8 */
-const char *pa_sample_format_to_string(pa_sample_format_t f);
+const char *pa_sample_format_to_string(pa_sample_format_t f) PA_GCC_PURE;
 
 /** Parse a sample format text. Inverse of pa_sample_format_to_string() */
-pa_sample_format_t pa_parse_sample_format(const char *format);
+pa_sample_format_t pa_parse_sample_format(const char *format) PA_GCC_PURE;
 
 /** Maximum required string length for pa_sample_spec_snprint() */
 #define PA_SAMPLE_SPEC_SNPRINT_MAX 32

Modified: trunk/src/pulse/scache.c
URL: http://0pointer.de/cgi-bin/viewcvs.cgi/trunk/src/pulse/scache.c?rev=1971&root=pulseaudio&r1=1970&r2=1971&view=diff
==============================================================================
--- trunk/src/pulse/scache.c (original)
+++ trunk/src/pulse/scache.c Sun Oct 28 20:13:50 2007
@@ -25,12 +25,12 @@
 #include <config.h>
 #endif
 
-#include <assert.h>
 #include <stdlib.h>
 #include <stdio.h>
 #include <string.h>
 
 #include <pulsecore/pstream-util.h>
+#include <pulsecore/macro.h>
 
 #include "internal.h"
 
@@ -40,7 +40,8 @@
     pa_tagstruct *t;
     uint32_t tag;
 
-    assert(s);
+    pa_assert(s);
+    pa_assert(PA_REFCNT_VALUE(s) >= 1);
 
     PA_CHECK_VALIDITY(s->context, s->state == PA_STREAM_UNCONNECTED, PA_ERR_BADSTATE);
     PA_CHECK_VALIDITY(s->context, length > 0, PA_ERR_INVALID);
@@ -66,7 +67,9 @@
 int pa_stream_finish_upload(pa_stream *s) {
     pa_tagstruct *t;
     uint32_t tag;
-    assert(s);
+
+    pa_assert(s);
+    pa_assert(PA_REFCNT_VALUE(s) >= 1);
 
     PA_CHECK_VALIDITY(s->context, s->channel_valid, PA_ERR_BADSTATE);
     PA_CHECK_VALIDITY(s->context, s->context->state == PA_CONTEXT_READY, PA_ERR_BADSTATE);
@@ -87,8 +90,8 @@
     pa_tagstruct *t;
     uint32_t tag;
 
-    assert(c);
-    assert(c->ref >= 1);
+    pa_assert(c);
+    pa_assert(PA_REFCNT_VALUE(c) >= 1);
 
     PA_CHECK_VALIDITY_RETURN_NULL(c, c->state == PA_CONTEXT_READY, PA_ERR_BADSTATE);
     PA_CHECK_VALIDITY_RETURN_NULL(c, name && *name, PA_ERR_INVALID);
@@ -115,8 +118,8 @@
     pa_tagstruct *t;
     uint32_t tag;
 
-    assert(c);
-    assert(c->ref >= 1);
+    pa_assert(c);
+    pa_assert(PA_REFCNT_VALUE(c) >= 1);
 
     PA_CHECK_VALIDITY_RETURN_NULL(c, c->state == PA_CONTEXT_READY, PA_ERR_BADSTATE);
     PA_CHECK_VALIDITY_RETURN_NULL(c, name && *name, PA_ERR_INVALID);

Modified: trunk/src/pulse/simple.c
URL: http://0pointer.de/cgi-bin/viewcvs.cgi/trunk/src/pulse/simple.c?rev=1971&root=pulseaudio&r1=1970&r2=1971&view=diff
==============================================================================
--- trunk/src/pulse/simple.c (original)
+++ trunk/src/pulse/simple.c Sun Oct 28 20:13:50 2007
@@ -1,3 +1,4 @@
+
 /* $Id$ */
 
 /***
@@ -27,7 +28,6 @@
 
 #include <stdio.h>
 #include <string.h>
-#include <assert.h>
 #include <stdlib.h>
 
 #include <pulse/pulseaudio.h>
@@ -36,6 +36,7 @@
 
 #include <pulsecore/native-common.h>
 #include <pulsecore/log.h>
+#include <pulsecore/macro.h>
 
 #include "simple.h"
 
@@ -83,8 +84,8 @@
 
 static void context_state_cb(pa_context *c, void *userdata) {
     pa_simple *p = userdata;
-    assert(c);
-    assert(p);
+    pa_assert(c);
+    pa_assert(p);
 
     switch (pa_context_get_state(c)) {
         case PA_CONTEXT_READY:
@@ -103,8 +104,8 @@
 
 static void stream_state_cb(pa_stream *s, void * userdata) {
     pa_simple *p = userdata;
-    assert(s);
-    assert(p);
+    pa_assert(s);
+    pa_assert(p);
 
     switch (pa_stream_get_state(s)) {
 
@@ -122,7 +123,7 @@
 
 static void stream_request_cb(pa_stream *s, size_t length, void *userdata) {
     pa_simple *p = userdata;
-    assert(p);
+    pa_assert(p);
 
     pa_threaded_mainloop_signal(p->mainloop, 0);
 }
@@ -130,21 +131,21 @@
 static void stream_latency_update_cb(pa_stream *s, void *userdata) {
     pa_simple *p = userdata;
 
-    assert(p);
+    pa_assert(p);
 
     pa_threaded_mainloop_signal(p->mainloop, 0);
 }
 
 pa_simple* pa_simple_new(
-    const char *server,
-    const char *name,
-    pa_stream_direction_t dir,
-    const char *dev,
-    const char *stream_name,
-    const pa_sample_spec *ss,
-    const pa_channel_map *map,
-    const pa_buffer_attr *attr,
-    int *rerror) {
+        const char *server,
+        const char *name,
+        pa_stream_direction_t dir,
+        const char *dev,
+        const char *stream_name,
+        const pa_sample_spec *ss,
+        const pa_channel_map *map,
+        const pa_buffer_attr *attr,
+        int *rerror) {
 
     pa_simple *p;
     int error = PA_ERR_INTERNAL, r;
@@ -232,7 +233,7 @@
 }
 
 void pa_simple_free(pa_simple *s) {
-    assert(s);
+    pa_assert(s);
 
     if (s->mainloop)
         pa_threaded_mainloop_stop(s->mainloop);
@@ -250,7 +251,7 @@
 }
 
 int pa_simple_write(pa_simple *p, const void*data, size_t length, int *rerror) {
-    assert(p);
+    pa_assert(p);
 
     CHECK_VALIDITY_RETURN_ANY(rerror, p->direction == PA_STREAM_PLAYBACK, PA_ERR_BADSTATE, -1);
     CHECK_VALIDITY_RETURN_ANY(rerror, data && length, PA_ERR_INVALID, -1);
@@ -289,7 +290,7 @@
 }
 
 int pa_simple_read(pa_simple *p, void*data, size_t length, int *rerror) {
-    assert(p);
+    pa_assert(p);
 
     CHECK_VALIDITY_RETURN_ANY(rerror, p->direction == PA_STREAM_RECORD, PA_ERR_BADSTATE, -1);
     CHECK_VALIDITY_RETURN_ANY(rerror, data && length, PA_ERR_INVALID, -1);
@@ -346,8 +347,8 @@
 static void success_cb(pa_stream *s, int success, void *userdata) {
     pa_simple *p = userdata;
 
-    assert(s);
-    assert(p);
+    pa_assert(s);
+    pa_assert(p);
 
     p->operation_success = success;
     pa_threaded_mainloop_signal(p->mainloop, 0);
@@ -356,7 +357,7 @@
 int pa_simple_drain(pa_simple *p, int *rerror) {
     pa_operation *o = NULL;
 
-    assert(p);
+    pa_assert(p);
 
     CHECK_VALIDITY_RETURN_ANY(rerror, p->direction == PA_STREAM_PLAYBACK, PA_ERR_BADSTATE, -1);
 
@@ -392,7 +393,7 @@
 int pa_simple_flush(pa_simple *p, int *rerror) {
     pa_operation *o = NULL;
 
-    assert(p);
+    pa_assert(p);
 
     CHECK_VALIDITY_RETURN_ANY(rerror, p->direction == PA_STREAM_PLAYBACK, PA_ERR_BADSTATE, -1);
 
@@ -429,7 +430,7 @@
     pa_usec_t t;
     int negative;
 
-    assert(p);
+    pa_assert(p);
 
     pa_threaded_mainloop_lock(p->mainloop);
 

Modified: trunk/src/pulse/simple.h
URL: http://0pointer.de/cgi-bin/viewcvs.cgi/trunk/src/pulse/simple.h?rev=1971&root=pulseaudio&r1=1970&r2=1971&view=diff
==============================================================================
--- trunk/src/pulse/simple.h (original)
+++ trunk/src/pulse/simple.h Sun Oct 28 20:13:50 2007
@@ -51,7 +51,7 @@
  * pa_simple *s;
  * pa_sample_spec ss;
  *
- * ss.format = PA_SAMPLE_S16_NE;
+ * ss.format = PA_SAMPLE_S16NE;
  * ss.channels = 2;
  * ss.rate = 44100;
  *

Modified: trunk/src/pulse/stream.c
URL: http://0pointer.de/cgi-bin/viewcvs.cgi/trunk/src/pulse/stream.c?rev=1971&root=pulseaudio&r1=1970&r2=1971&view=diff
==============================================================================
--- trunk/src/pulse/stream.c (original)
+++ trunk/src/pulse/stream.c Sun Oct 28 20:13:50 2007
@@ -26,7 +26,6 @@
 #include <config.h>
 #endif
 
-#include <assert.h>
 #include <string.h>
 #include <stdio.h>
 #include <string.h>
@@ -38,6 +37,7 @@
 #include <pulsecore/pstream-util.h>
 #include <pulsecore/log.h>
 #include <pulsecore/hashmap.h>
+#include <pulsecore/macro.h>
 
 #include "internal.h"
 
@@ -47,13 +47,14 @@
     pa_stream *s;
     int i;
 
-    assert(c);
+    pa_assert(c);
+    pa_assert(PA_REFCNT_VALUE(c) >= 1);
 
     PA_CHECK_VALIDITY_RETURN_NULL(c, ss && pa_sample_spec_valid(ss), PA_ERR_INVALID);
     PA_CHECK_VALIDITY_RETURN_NULL(c, !map || (pa_channel_map_valid(map) && map->channels == ss->channels), PA_ERR_INVALID);
 
     s = pa_xnew(pa_stream, 1);
-    s->ref = 1;
+    PA_REFCNT_INIT(s);
     s->context = c;
     s->mainloop = c->mainloop;
 
@@ -91,6 +92,7 @@
     s->peek_memchunk.index = 0;
     s->peek_memchunk.length = 0;
     s->peek_memchunk.memblock = NULL;
+    s->peek_data = NULL;
 
     s->record_memblockq = NULL;
 
@@ -118,15 +120,20 @@
 }
 
 static void stream_free(pa_stream *s) {
-    assert(s && !s->context && !s->channel_valid);
+    pa_assert(s);
+    pa_assert(!s->context);
+    pa_assert(!s->channel_valid);
 
     if (s->auto_timing_update_event) {
-        assert(s->mainloop);
+        pa_assert(s->mainloop);
         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);
@@ -136,38 +143,38 @@
 }
 
 void pa_stream_unref(pa_stream *s) {
-    assert(s);
-    assert(s->ref >= 1);
-
-    if (--(s->ref) == 0)
+    pa_assert(s);
+    pa_assert(PA_REFCNT_VALUE(s) >= 1);
+
+    if (PA_REFCNT_DEC(s) <= 0)
         stream_free(s);
 }
 
 pa_stream* pa_stream_ref(pa_stream *s) {
-    assert(s);
-    assert(s->ref >= 1);
-
-    s->ref++;
+    pa_assert(s);
+    pa_assert(PA_REFCNT_VALUE(s) >= 1);
+
+    PA_REFCNT_INC(s);
     return s;
 }
 
 pa_stream_state_t pa_stream_get_state(pa_stream *s) {
-    assert(s);
-    assert(s->ref >= 1);
+    pa_assert(s);
+    pa_assert(PA_REFCNT_VALUE(s) >= 1);
 
     return s->state;
 }
 
 pa_context* pa_stream_get_context(pa_stream *s) {
-    assert(s);
-    assert(s->ref >= 1);
+    pa_assert(s);
+    pa_assert(PA_REFCNT_VALUE(s) >= 1);
 
     return s->context;
 }
 
 uint32_t pa_stream_get_index(pa_stream *s) {
-    assert(s);
-    assert(s->ref >= 1);
+    pa_assert(s);
+    pa_assert(PA_REFCNT_VALUE(s) >= 1);
 
     PA_CHECK_VALIDITY_RETURN_ANY(s->context, s->state == PA_STREAM_READY, PA_ERR_BADSTATE, PA_INVALID_INDEX);
 
@@ -175,8 +182,8 @@
 }
 
 void pa_stream_set_state(pa_stream *s, pa_stream_state_t st) {
-    assert(s);
-    assert(s->ref >= 1);
+    pa_assert(s);
+    pa_assert(PA_REFCNT_VALUE(s) >= 1);
 
     if (s->state == st)
         return;
@@ -214,6 +221,13 @@
         s->channel_valid = 0;
 
         s->context = NULL;
+
+        s->read_callback = NULL;
+        s->write_callback = NULL;
+        s->state_callback = NULL;
+        s->overflow_callback = NULL;
+        s->underflow_callback = NULL;
+        s->latency_update_callback = NULL;
     }
 
     pa_stream_unref(s);
@@ -224,10 +238,11 @@
     pa_stream *s;
     uint32_t channel;
 
-    assert(pd);
-    assert(command == PA_COMMAND_PLAYBACK_STREAM_KILLED || command == PA_COMMAND_RECORD_STREAM_KILLED);
-    assert(t);
-    assert(c);
+    pa_assert(pd);
+    pa_assert(command == PA_COMMAND_PLAYBACK_STREAM_KILLED || command == PA_COMMAND_RECORD_STREAM_KILLED);
+    pa_assert(t);
+    pa_assert(c);
+    pa_assert(PA_REFCNT_VALUE(c) >= 1);
 
     pa_context_ref(c);
 
@@ -252,10 +267,11 @@
     pa_context *c = userdata;
     uint32_t bytes, channel;
 
-    assert(pd);
-    assert(command == PA_COMMAND_REQUEST);
-    assert(t);
-    assert(c);
+    pa_assert(pd);
+    pa_assert(command == PA_COMMAND_REQUEST);
+    pa_assert(t);
+    pa_assert(c);
+    pa_assert(PA_REFCNT_VALUE(c) >= 1);
 
     pa_context_ref(c);
 
@@ -285,10 +301,11 @@
     pa_context *c = userdata;
     uint32_t channel;
 
-    assert(pd);
-    assert(command == PA_COMMAND_OVERFLOW || command == PA_COMMAND_UNDERFLOW);
-    assert(t);
-    assert(c);
+    pa_assert(pd);
+    pa_assert(command == PA_COMMAND_OVERFLOW || command == PA_COMMAND_UNDERFLOW);
+    pa_assert(t);
+    pa_assert(c);
+    pa_assert(PA_REFCNT_VALUE(c) >= 1);
 
     pa_context_ref(c);
 
@@ -317,8 +334,8 @@
 }
 
 static void request_auto_timing_update(pa_stream *s, int force) {
-    struct timeval next;
-    assert(s);
+    pa_assert(s);
+    pa_assert(PA_REFCNT_VALUE(s) >= 1);
 
     if (!(s->flags & PA_STREAM_AUTO_TIMING_UPDATE))
         return;
@@ -335,13 +352,17 @@
         }
     }
 
-    pa_gettimeofday(&next);
-    pa_timeval_add(&next, LATENCY_IPOL_INTERVAL_USEC);
-    s->mainloop->time_restart(s->auto_timing_update_event, &next);
+    if (s->auto_timing_update_event) {
+        struct timeval next;
+        pa_gettimeofday(&next);
+        pa_timeval_add(&next, LATENCY_IPOL_INTERVAL_USEC);
+        s->mainloop->time_restart(s->auto_timing_update_event, &next);
+    }
 }
 
 static void invalidate_indexes(pa_stream *s, int r, int w) {
-    assert(s);
+    pa_assert(s);
+    pa_assert(PA_REFCNT_VALUE(s) >= 1);
 
 /*     pa_log("invalidate r:%u w:%u tag:%u", r, w, s->context->ctag); */
 
@@ -376,6 +397,9 @@
 static void auto_timing_update_callback(PA_GCC_UNUSED pa_mainloop_api *m, PA_GCC_UNUSED pa_time_event *e, PA_GCC_UNUSED const struct timeval *tv, void *userdata) {
     pa_stream *s = userdata;
 
+    pa_assert(s);
+    pa_assert(PA_REFCNT_VALUE(s) >= 1);
+
 /*     pa_log("time event");    */
 
     pa_stream_ref(s);
@@ -383,12 +407,32 @@
     pa_stream_unref(s);
 }
 
+static void create_stream_complete(pa_stream *s) {
+    pa_assert(s);
+    pa_assert(PA_REFCNT_VALUE(s) >= 1);
+    pa_assert(s->state == PA_STREAM_CREATING);
+
+    pa_stream_set_state(s, PA_STREAM_READY);
+
+    if (s->requested_bytes > 0 && s->write_callback)
+        s->write_callback(s, s->requested_bytes, s->write_userdata);
+
+    if (s->flags & PA_STREAM_AUTO_TIMING_UPDATE) {
+        struct timeval tv;
+        pa_gettimeofday(&tv);
+        tv.tv_usec += LATENCY_IPOL_INTERVAL_USEC; /* every 100 ms */
+        pa_assert(!s->auto_timing_update_event);
+        s->auto_timing_update_event = s->mainloop->time_new(s->mainloop, &tv, &auto_timing_update_callback, s);
+    }
+}
+
 void pa_create_stream_callback(pa_pdispatch *pd, uint32_t command, PA_GCC_UNUSED uint32_t tag, pa_tagstruct *t, void *userdata) {
     pa_stream *s = userdata;
 
-    assert(pd);
-    assert(s);
-    assert(s->state == PA_STREAM_CREATING);
+    pa_assert(pd);
+    pa_assert(s);
+    pa_assert(PA_REFCNT_VALUE(s) >= 1);
+    pa_assert(s->state == PA_STREAM_CREATING);
 
     pa_stream_ref(s);
 
@@ -431,7 +475,7 @@
     }
 
     if (s->direction == PA_STREAM_RECORD) {
-        assert(!s->record_memblockq);
+        pa_assert(!s->record_memblockq);
 
         s->record_memblockq = pa_memblockq_new(
                 0,
@@ -446,23 +490,16 @@
     s->channel_valid = 1;
     pa_dynarray_put((s->direction == PA_STREAM_RECORD) ? s->context->record_streams : s->context->playback_streams, s->channel, s);
 
-    pa_stream_set_state(s, PA_STREAM_READY);
-
-    if (s->direction != PA_STREAM_UPLOAD &&
-        s->flags & PA_STREAM_AUTO_TIMING_UPDATE) {
-        struct timeval tv;
-
-        pa_gettimeofday(&tv);
-        tv.tv_usec += LATENCY_IPOL_INTERVAL_USEC; /* every 100 ms */
-
-        assert(!s->auto_timing_update_event);
-        s->auto_timing_update_event = s->mainloop->time_new(s->mainloop, &tv, &auto_timing_update_callback, s);
-
+    if (s->direction != PA_STREAM_UPLOAD && s->flags & PA_STREAM_AUTO_TIMING_UPDATE) {
+        /* If automatic timing updates are active, we wait for the
+         * first timing update before going to PA_STREAM_READY
+         * state */
+        s->state = PA_STREAM_READY;
         request_auto_timing_update(s, 1);
-    }
-
-    if (s->requested_bytes > 0 && s->ref > 1 && s->write_callback)
-        s->write_callback(s, s->requested_bytes, s->write_userdata);
+        s->state = PA_STREAM_CREATING;
+
+    } else
+        create_stream_complete(s);
 
 finish:
     pa_stream_unref(s);
@@ -480,8 +517,8 @@
     pa_tagstruct *t;
     uint32_t tag;
 
-    assert(s);
-    assert(s->ref >= 1);
+    pa_assert(s);
+    pa_assert(PA_REFCNT_VALUE(s) >= 1);
 
     PA_CHECK_VALIDITY(s->context, s->state == PA_STREAM_UNCONNECTED, PA_ERR_BADSTATE);
     PA_CHECK_VALIDITY(s->context, !(flags & ~((direction != PA_STREAM_UPLOAD ?
@@ -503,12 +540,12 @@
     if (attr)
         s->buffer_attr = *attr;
     else {
-        /* half a second */
+        /* half a second, with minimum request of 10 ms */
         s->buffer_attr.tlength = pa_bytes_per_second(&s->sample_spec)/2;
         s->buffer_attr.maxlength = (s->buffer_attr.tlength*3)/2;
-        s->buffer_attr.minreq = s->buffer_attr.tlength/100;
+        s->buffer_attr.minreq = s->buffer_attr.tlength/50;
         s->buffer_attr.prebuf = s->buffer_attr.tlength - s->buffer_attr.minreq;
-        s->buffer_attr.fragsize = s->buffer_attr.tlength/100;
+        s->buffer_attr.fragsize = s->buffer_attr.tlength/50;
     }
 
     if (!dev)
@@ -565,8 +602,8 @@
         pa_cvolume *volume,
         pa_stream *sync_stream) {
 
-    assert(s);
-    assert(s->ref >= 1);
+    pa_assert(s);
+    pa_assert(PA_REFCNT_VALUE(s) >= 1);
 
     return create_stream(PA_STREAM_PLAYBACK, s, dev, attr, flags, volume, sync_stream);
 }
@@ -577,8 +614,8 @@
         const pa_buffer_attr *attr,
         pa_stream_flags_t flags) {
 
-    assert(s);
-    assert(s->ref >= 1);
+    pa_assert(s);
+    pa_assert(PA_REFCNT_VALUE(s) >= 1);
 
     return create_stream(PA_STREAM_RECORD, s, dev, attr, flags, NULL, NULL);
 }
@@ -593,9 +630,9 @@
 
     pa_memchunk chunk;
 
-    assert(s);
-    assert(s->ref >= 1);
-    assert(data);
+    pa_assert(s);
+    pa_assert(PA_REFCNT_VALUE(s) >= 1);
+    pa_assert(data);
 
     PA_CHECK_VALIDITY(s->context, s->state == PA_STREAM_READY, PA_ERR_BADSTATE);
     PA_CHECK_VALIDITY(s->context, s->direction == PA_STREAM_PLAYBACK || s->direction == PA_STREAM_UPLOAD, PA_ERR_BADSTATE);
@@ -608,8 +645,11 @@
     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;
@@ -660,10 +700,10 @@
 }
 
 int pa_stream_peek(pa_stream *s, const void **data, size_t *length) {
-    assert(s);
-    assert(s->ref >= 1);
-    assert(data);
-    assert(length);
+    pa_assert(s);
+    pa_assert(PA_REFCNT_VALUE(s) >= 1);
+    pa_assert(data);
+    pa_assert(length);
 
     PA_CHECK_VALIDITY(s->context, s->state == PA_STREAM_READY, PA_ERR_BADSTATE);
     PA_CHECK_VALIDITY(s->context, s->direction == PA_STREAM_RECORD, PA_ERR_BADSTATE);
@@ -675,27 +715,32 @@
             *length = 0;
             return 0;
         }
-    }
-
-    *data = (const char*) s->peek_memchunk.memblock->data + s->peek_memchunk.index;
+
+        s->peek_data = pa_memblock_acquire(s->peek_memchunk.memblock);
+    }
+
+    pa_assert(s->peek_data);
+    *data = (uint8_t*) s->peek_data + s->peek_memchunk.index;
     *length = s->peek_memchunk.length;
     return 0;
 }
 
 int pa_stream_drop(pa_stream *s) {
-    assert(s);
-    assert(s->ref >= 1);
+    pa_assert(s);
+    pa_assert(PA_REFCNT_VALUE(s) >= 1);
 
     PA_CHECK_VALIDITY(s->context, s->state == PA_STREAM_READY, PA_ERR_BADSTATE);
     PA_CHECK_VALIDITY(s->context, s->direction == PA_STREAM_RECORD, PA_ERR_BADSTATE);
     PA_CHECK_VALIDITY(s->context, s->peek_memchunk.memblock, PA_ERR_BADSTATE);
 
-    pa_memblockq_drop(s->record_memblockq, &s->peek_memchunk, s->peek_memchunk.length);
+    pa_memblockq_drop(s->record_memblockq, s->peek_memchunk.length);
 
     /* Fix the simulated local read index */
     if (s->timing_info_valid && !s->timing_info.read_index_corrupt)
         s->timing_info.read_index += s->peek_memchunk.length;
 
+    pa_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;
@@ -705,8 +750,8 @@
 }
 
 size_t pa_stream_writable_size(pa_stream *s) {
-    assert(s);
-    assert(s->ref >= 1);
+    pa_assert(s);
+    pa_assert(PA_REFCNT_VALUE(s) >= 1);
 
     PA_CHECK_VALIDITY_RETURN_ANY(s->context, s->state == PA_STREAM_READY, PA_ERR_BADSTATE, (size_t) -1);
     PA_CHECK_VALIDITY_RETURN_ANY(s->context, s->direction != PA_STREAM_RECORD, PA_ERR_BADSTATE, (size_t) -1);
@@ -715,8 +760,8 @@
 }
 
 size_t pa_stream_readable_size(pa_stream *s) {
-    assert(s);
-    assert(s->ref >= 1);
+    pa_assert(s);
+    pa_assert(PA_REFCNT_VALUE(s) >= 1);
 
     PA_CHECK_VALIDITY_RETURN_ANY(s->context, s->state == PA_STREAM_READY, PA_ERR_BADSTATE, (size_t) -1);
     PA_CHECK_VALIDITY_RETURN_ANY(s->context, s->direction == PA_STREAM_RECORD, PA_ERR_BADSTATE, (size_t) -1);
@@ -729,8 +774,8 @@
     pa_tagstruct *t;
     uint32_t tag;
 
-    assert(s);
-    assert(s->ref >= 1);
+    pa_assert(s);
+    pa_assert(PA_REFCNT_VALUE(s) >= 1);
 
     PA_CHECK_VALIDITY_RETURN_NULL(s->context, s->state == PA_STREAM_READY, PA_ERR_BADSTATE);
     PA_CHECK_VALIDITY_RETURN_NULL(s->context, s->direction == PA_STREAM_PLAYBACK, PA_ERR_BADSTATE);
@@ -750,8 +795,9 @@
     struct timeval local, remote, now;
     pa_timing_info *i;
 
-    assert(pd);
-    assert(o);
+    pa_assert(pd);
+    pa_assert(o);
+    pa_assert(PA_REFCNT_VALUE(o) >= 1);
 
     if (!o->context || !o->stream)
         goto finish;
@@ -874,6 +920,10 @@
         }
     }
 
+    /* First, let's complete the initialization, if necessary. */
+    if (o->stream->state == PA_STREAM_CREATING)
+        create_stream_complete(o->stream);
+
     if (o->stream->latency_update_callback)
         o->stream->latency_update_callback(o->stream, o->stream->latency_update_userdata);
 
@@ -895,8 +945,8 @@
     struct timeval now;
     int cidx = 0;
 
-    assert(s);
-    assert(s->ref >= 1);
+    pa_assert(s);
+    pa_assert(PA_REFCNT_VALUE(s) >= 1);
 
     PA_CHECK_VALIDITY_RETURN_NULL(s->context, s->state == PA_STREAM_READY, PA_ERR_BADSTATE);
     PA_CHECK_VALIDITY_RETURN_NULL(s->context, s->direction != PA_STREAM_UPLOAD, PA_ERR_BADSTATE);
@@ -938,9 +988,9 @@
 void pa_stream_disconnect_callback(pa_pdispatch *pd, uint32_t command, PA_GCC_UNUSED uint32_t tag, pa_tagstruct *t, void *userdata) {
     pa_stream *s = userdata;
 
-    assert(pd);
-    assert(s);
-    assert(s->ref >= 1);
+    pa_assert(pd);
+    pa_assert(s);
+    pa_assert(PA_REFCNT_VALUE(s) >= 1);
 
     pa_stream_ref(s);
 
@@ -965,8 +1015,8 @@
     pa_tagstruct *t;
     uint32_t tag;
 
-    assert(s);
-    assert(s->ref >= 1);
+    pa_assert(s);
+    pa_assert(PA_REFCNT_VALUE(s) >= 1);
 
     PA_CHECK_VALIDITY(s->context, s->channel_valid, PA_ERR_BADSTATE);
     PA_CHECK_VALIDITY(s->context, s->context->state == PA_CONTEXT_READY, PA_ERR_BADSTATE);
@@ -987,48 +1037,48 @@
 }
 
 void pa_stream_set_read_callback(pa_stream *s, pa_stream_request_cb_t cb, void *userdata) {
-    assert(s);
-    assert(s->ref >= 1);
+    pa_assert(s);
+    pa_assert(PA_REFCNT_VALUE(s) >= 1);
 
     s->read_callback = cb;
     s->read_userdata = userdata;
 }
 
 void pa_stream_set_write_callback(pa_stream *s, pa_stream_request_cb_t cb, void *userdata) {
-    assert(s);
-    assert(s->ref >= 1);
+    pa_assert(s);
+    pa_assert(PA_REFCNT_VALUE(s) >= 1);
 
     s->write_callback = cb;
     s->write_userdata = userdata;
 }
 
 void pa_stream_set_state_callback(pa_stream *s, pa_stream_notify_cb_t cb, void *userdata) {
-    assert(s);
-    assert(s->ref >= 1);
+    pa_assert(s);
+    pa_assert(PA_REFCNT_VALUE(s) >= 1);
 
     s->state_callback = cb;
     s->state_userdata = userdata;
 }
 
 void pa_stream_set_overflow_callback(pa_stream *s, pa_stream_notify_cb_t cb, void *userdata) {
-    assert(s);
-    assert(s->ref >= 1);
+    pa_assert(s);
+    pa_assert(PA_REFCNT_VALUE(s) >= 1);
 
     s->overflow_callback = cb;
     s->overflow_userdata = userdata;
 }
 
 void pa_stream_set_underflow_callback(pa_stream *s, pa_stream_notify_cb_t cb, void *userdata) {
-    assert(s);
-    assert(s->ref >= 1);
+    pa_assert(s);
+    pa_assert(PA_REFCNT_VALUE(s) >= 1);
 
     s->underflow_callback = cb;
     s->underflow_userdata = userdata;
 }
 
 void pa_stream_set_latency_update_callback(pa_stream *s, pa_stream_notify_cb_t cb, void *userdata) {
-    assert(s);
-    assert(s->ref >= 1);
+    pa_assert(s);
+    pa_assert(PA_REFCNT_VALUE(s) >= 1);
 
     s->latency_update_callback = cb;
     s->latency_update_userdata = userdata;
@@ -1038,9 +1088,9 @@
     pa_operation *o = userdata;
     int success = 1;
 
-    assert(pd);
-    assert(o);
-    assert(o->ref >= 1);
+    pa_assert(pd);
+    pa_assert(o);
+    pa_assert(PA_REFCNT_VALUE(o) >= 1);
 
     if (!o->context)
         goto finish;
@@ -1070,8 +1120,8 @@
     pa_tagstruct *t;
     uint32_t tag;
 
-    assert(s);
-    assert(s->ref >= 1);
+    pa_assert(s);
+    pa_assert(PA_REFCNT_VALUE(s) >= 1);
 
     PA_CHECK_VALIDITY_RETURN_NULL(s->context, s->state == PA_STREAM_READY, PA_ERR_BADSTATE);
     PA_CHECK_VALIDITY_RETURN_NULL(s->context, s->direction != PA_STREAM_UPLOAD, PA_ERR_BADSTATE);
@@ -1100,8 +1150,8 @@
     pa_operation *o;
     uint32_t tag;
 
-    assert(s);
-    assert(s->ref >= 1);
+    pa_assert(s);
+    pa_assert(PA_REFCNT_VALUE(s) >= 1);
 
     PA_CHECK_VALIDITY_RETURN_NULL(s->context, s->state == PA_STREAM_READY, PA_ERR_BADSTATE);
 
@@ -1117,6 +1167,9 @@
 
 pa_operation* pa_stream_flush(pa_stream *s, pa_stream_success_cb_t cb, void *userdata) {
     pa_operation *o;
+
+    pa_assert(s);
+    pa_assert(PA_REFCNT_VALUE(s) >= 1);
 
     PA_CHECK_VALIDITY_RETURN_NULL(s->context, s->direction != PA_STREAM_UPLOAD, PA_ERR_BADSTATE);
 
@@ -1143,6 +1196,9 @@
 pa_operation* pa_stream_prebuf(pa_stream *s, pa_stream_success_cb_t cb, void *userdata) {
     pa_operation *o;
 
+    pa_assert(s);
+    pa_assert(PA_REFCNT_VALUE(s) >= 1);
+
     PA_CHECK_VALIDITY_RETURN_NULL(s->context, s->direction == PA_STREAM_PLAYBACK, PA_ERR_BADSTATE);
     PA_CHECK_VALIDITY_RETURN_NULL(s->context, s->buffer_attr.prebuf > 0, PA_ERR_BADSTATE);
 
@@ -1154,6 +1210,9 @@
 
 pa_operation* pa_stream_trigger(pa_stream *s, pa_stream_success_cb_t cb, void *userdata) {
     pa_operation *o;
+
+    pa_assert(s);
+    pa_assert(PA_REFCNT_VALUE(s) >= 1);
 
     PA_CHECK_VALIDITY_RETURN_NULL(s->context, s->direction == PA_STREAM_PLAYBACK, PA_ERR_BADSTATE);
     PA_CHECK_VALIDITY_RETURN_NULL(s->context, s->buffer_attr.prebuf > 0, PA_ERR_BADSTATE);
@@ -1169,9 +1228,9 @@
     pa_tagstruct *t;
     uint32_t tag;
 
-    assert(s);
-    assert(s->ref >= 1);
-    assert(name);
+    pa_assert(s);
+    pa_assert(PA_REFCNT_VALUE(s) >= 1);
+    pa_assert(name);
 
     PA_CHECK_VALIDITY_RETURN_NULL(s->context, s->state == PA_STREAM_READY, PA_ERR_BADSTATE);
     PA_CHECK_VALIDITY_RETURN_NULL(s->context, s->direction != PA_STREAM_UPLOAD, PA_ERR_BADSTATE);
@@ -1193,8 +1252,8 @@
 int pa_stream_get_time(pa_stream *s, pa_usec_t *r_usec) {
     pa_usec_t usec = 0;
 
-    assert(s);
-    assert(s->ref >= 1);
+    pa_assert(s);
+    pa_assert(PA_REFCNT_VALUE(s) >= 1);
 
     PA_CHECK_VALIDITY(s->context, s->state == PA_STREAM_READY, PA_ERR_BADSTATE);
     PA_CHECK_VALIDITY(s->context, s->direction != PA_STREAM_UPLOAD, PA_ERR_BADSTATE);
@@ -1277,8 +1336,8 @@
 }
 
 static pa_usec_t time_counter_diff(pa_stream *s, pa_usec_t a, pa_usec_t b, int *negative) {
-    assert(s);
-    assert(s->ref >= 1);
+    pa_assert(s);
+    pa_assert(PA_REFCNT_VALUE(s) >= 1);
 
     if (negative)
         *negative = 0;
@@ -1299,9 +1358,9 @@
     int r;
     int64_t cindex;
 
-    assert(s);
-    assert(s->ref >= 1);
-    assert(r_usec);
+    pa_assert(s);
+    pa_assert(PA_REFCNT_VALUE(s) >= 1);
+    pa_assert(r_usec);
 
     PA_CHECK_VALIDITY(s->context, s->state == PA_STREAM_READY, PA_ERR_BADSTATE);
     PA_CHECK_VALIDITY(s->context, s->direction != PA_STREAM_UPLOAD, PA_ERR_BADSTATE);
@@ -1331,8 +1390,8 @@
 }
 
 const pa_timing_info* pa_stream_get_timing_info(pa_stream *s) {
-    assert(s);
-    assert(s->ref >= 1);
+    pa_assert(s);
+    pa_assert(PA_REFCNT_VALUE(s) >= 1);
 
     PA_CHECK_VALIDITY_RETURN_NULL(s->context, s->state == PA_STREAM_READY, PA_ERR_BADSTATE);
     PA_CHECK_VALIDITY_RETURN_NULL(s->context, s->direction != PA_STREAM_UPLOAD, PA_ERR_BADSTATE);
@@ -1342,22 +1401,22 @@
 }
 
 const pa_sample_spec* pa_stream_get_sample_spec(pa_stream *s) {
-    assert(s);
-    assert(s->ref >= 1);
+    pa_assert(s);
+    pa_assert(PA_REFCNT_VALUE(s) >= 1);
 
     return &s->sample_spec;
 }
 
 const pa_channel_map* pa_stream_get_channel_map(pa_stream *s) {
-    assert(s);
-    assert(s->ref >= 1);
+    pa_assert(s);
+    pa_assert(PA_REFCNT_VALUE(s) >= 1);
 
     return &s->channel_map;
 }
 
 const pa_buffer_attr* pa_stream_get_buffer_attr(pa_stream *s) {
-    assert(s);
-    assert(s->ref >= 1);
+    pa_assert(s);
+    pa_assert(PA_REFCNT_VALUE(s) >= 1);
 
     PA_CHECK_VALIDITY_RETURN_NULL(s->context, s->state == PA_STREAM_READY, PA_ERR_BADSTATE);
     PA_CHECK_VALIDITY_RETURN_NULL(s->context, s->direction != PA_STREAM_UPLOAD, PA_ERR_BADSTATE);

Modified: trunk/src/pulse/subscribe.c
URL: http://0pointer.de/cgi-bin/viewcvs.cgi/trunk/src/pulse/subscribe.c?rev=1971&root=pulseaudio&r1=1970&r2=1971&view=diff
==============================================================================
--- trunk/src/pulse/subscribe.c (original)
+++ trunk/src/pulse/subscribe.c Sun Oct 28 20:13:50 2007
@@ -25,10 +25,10 @@
 #include <config.h>
 #endif
 
-#include <assert.h>
 #include <stdio.h>
 
 #include <pulsecore/gccmacro.h>
+#include <pulsecore/macro.h>
 #include <pulsecore/pstream-util.h>
 
 #include "internal.h"
@@ -40,10 +40,11 @@
     pa_subscription_event_type_t e;
     uint32_t idx;
 
-    assert(pd);
-    assert(command == PA_COMMAND_SUBSCRIBE_EVENT);
-    assert(t);
-    assert(c);
+    pa_assert(pd);
+    pa_assert(command == PA_COMMAND_SUBSCRIBE_EVENT);
+    pa_assert(t);
+    pa_assert(c);
+    pa_assert(PA_REFCNT_VALUE(c) >= 1);
 
     pa_context_ref(c);
 
@@ -67,8 +68,8 @@
     pa_tagstruct *t;
     uint32_t tag;
 
-    assert(c);
-    assert(c->ref >= 1);
+    pa_assert(c);
+    pa_assert(PA_REFCNT_VALUE(c) >= 1);
 
     PA_CHECK_VALIDITY_RETURN_NULL(c, c->state == PA_CONTEXT_READY, PA_ERR_BADSTATE);
 
@@ -83,8 +84,8 @@
 }
 
 void pa_context_set_subscribe_callback(pa_context *c, pa_context_subscribe_cb_t cb, void *userdata) {
-    assert(c);
-    assert(c->ref >= 1);
+    pa_assert(c);
+    pa_assert(PA_REFCNT_VALUE(c) >= 1);
 
     c->subscribe_callback = cb;
     c->subscribe_userdata = userdata;

Modified: trunk/src/pulse/thread-mainloop.c
URL: http://0pointer.de/cgi-bin/viewcvs.cgi/trunk/src/pulse/thread-mainloop.c?rev=1971&root=pulseaudio&r1=1970&r2=1971&view=diff
==============================================================================
--- trunk/src/pulse/thread-mainloop.c (original)
+++ trunk/src/pulse/thread-mainloop.c Sun Oct 28 20:13:50 2007
@@ -26,24 +26,24 @@
 #include <config.h>
 #endif
 
-#include <assert.h>
 #include <signal.h>
 #include <stdio.h>
 
-#ifdef HAVE_SYS_POLL_H
-#include <sys/poll.h>
+#ifdef HAVE_POLL_H
+#include <poll.h>
 #else
-#include "../pulsecore/poll.h"
+#include <pulsecore/poll.h>
 #endif
 
 #include <pulse/xmalloc.h>
+#include <pulse/mainloop.h>
 
 #include <pulsecore/log.h>
 #include <pulsecore/hashmap.h>
 #include <pulsecore/thread.h>
 #include <pulsecore/mutex.h>
-
-#include "mainloop.h"
+#include <pulsecore/macro.h>
+
 #include "thread-mainloop.h"
 
 struct pa_threaded_mainloop {
@@ -63,7 +63,7 @@
     pa_mutex *mutex = userdata;
     int r;
 
-    assert(mutex);
+    pa_assert(mutex);
 
     /* Before entering poll() we unlock the mutex, so that
      * avahi_simple_poll_quit() can succeed from another thread. */
@@ -103,7 +103,7 @@
         return NULL;
     }
 
-    m->mutex = pa_mutex_new(1);
+    m->mutex = pa_mutex_new(TRUE, FALSE);
     m->cond = pa_cond_new();
     m->accept_cond = pa_cond_new();
     m->thread = NULL;
@@ -116,10 +116,10 @@
 }
 
 void pa_threaded_mainloop_free(pa_threaded_mainloop* m) {
-    assert(m);
-
-    /* Make sure that this function is not called from the helper thread */
-    assert((m->thread && !pa_thread_is_running(m->thread)) || !in_worker(m));
+    pa_assert(m);
+
+    /* Make sure that this function is not called from the helper thread */
+    pa_assert((m->thread && !pa_thread_is_running(m->thread)) || !in_worker(m));
 
     pa_threaded_mainloop_stop(m);
 
@@ -136,9 +136,9 @@
 }
 
 int pa_threaded_mainloop_start(pa_threaded_mainloop *m) {
-    assert(m);
-
-    assert(!m->thread || !pa_thread_is_running(m->thread));
+    pa_assert(m);
+
+    pa_assert(!m->thread || !pa_thread_is_running(m->thread));
 
     if (!(m->thread = pa_thread_new(thread, m)))
         return -1;
@@ -147,13 +147,13 @@
 }
 
 void pa_threaded_mainloop_stop(pa_threaded_mainloop *m) {
-    assert(m);
+    pa_assert(m);
 
     if (!m->thread || !pa_thread_is_running(m->thread))
         return;
 
     /* Make sure that this function is not called from the helper thread */
-    assert(!in_worker(m));
+    pa_assert(!in_worker(m));
 
     pa_mutex_lock(m->mutex);
     pa_mainloop_quit(m->real_mainloop, 0);
@@ -163,25 +163,25 @@
 }
 
 void pa_threaded_mainloop_lock(pa_threaded_mainloop *m) {
-    assert(m);
-
-    /* Make sure that this function is not called from the helper thread */
-    assert(!m->thread || !pa_thread_is_running(m->thread) || !in_worker(m));
+    pa_assert(m);
+
+    /* Make sure that this function is not called from the helper thread */
+    pa_assert(!m->thread || !pa_thread_is_running(m->thread) || !in_worker(m));
 
     pa_mutex_lock(m->mutex);
 }
 
 void pa_threaded_mainloop_unlock(pa_threaded_mainloop *m) {
-    assert(m);
-
-    /* Make sure that this function is not called from the helper thread */
-    assert(!m->thread || !pa_thread_is_running(m->thread) || !in_worker(m));
+    pa_assert(m);
+
+    /* Make sure that this function is not called from the helper thread */
+    pa_assert(!m->thread || !pa_thread_is_running(m->thread) || !in_worker(m));
 
     pa_mutex_unlock(m->mutex);
 }
 
 void pa_threaded_mainloop_signal(pa_threaded_mainloop *m, int wait_for_accept) {
-    assert(m);
+    pa_assert(m);
 
     pa_cond_signal(m->cond, 1);
 
@@ -190,36 +190,42 @@
 }
 
 void pa_threaded_mainloop_wait(pa_threaded_mainloop *m) {
-    assert(m);
-
-    /* Make sure that this function is not called from the helper thread */
-    assert(!m->thread || !pa_thread_is_running(m->thread) || !in_worker(m));
+    pa_assert(m);
+
+    /* Make sure that this function is not called from the helper thread */
+    pa_assert(!m->thread || !pa_thread_is_running(m->thread) || !in_worker(m));
 
     m->n_waiting ++;
 
     pa_cond_wait(m->cond, m->mutex);
 
-    assert(m->n_waiting > 0);
+    pa_assert(m->n_waiting > 0);
     m->n_waiting --;
 }
 
 void pa_threaded_mainloop_accept(pa_threaded_mainloop *m) {
-    assert(m);
-
-    /* Make sure that this function is not called from the helper thread */
-    assert(!m->thread || !pa_thread_is_running(m->thread) || !in_worker(m));
+    pa_assert(m);
+
+    /* Make sure that this function is not called from the helper thread */
+    pa_assert(!m->thread || !pa_thread_is_running(m->thread) || !in_worker(m));
 
     pa_cond_signal(m->accept_cond, 0);
 }
 
 int pa_threaded_mainloop_get_retval(pa_threaded_mainloop *m) {
-    assert(m);
+    pa_assert(m);
 
     return pa_mainloop_get_retval(m->real_mainloop);
 }
 
 pa_mainloop_api* pa_threaded_mainloop_get_api(pa_threaded_mainloop*m) {
-    assert(m);
+    pa_assert(m);
 
     return pa_mainloop_get_api(m->real_mainloop);
 }
+
+int pa_threaded_mainloop_in_thread(pa_threaded_mainloop *m) {
+    pa_assert(m);
+
+    return m->thread && pa_thread_self() == m->thread;
+}

Modified: trunk/src/pulse/thread-mainloop.h
URL: http://0pointer.de/cgi-bin/viewcvs.cgi/trunk/src/pulse/thread-mainloop.h?rev=1971&root=pulseaudio&r1=1970&r2=1971&view=diff
==============================================================================
--- trunk/src/pulse/thread-mainloop.h (original)
+++ trunk/src/pulse/thread-mainloop.h Sun Oct 28 20:13:50 2007
@@ -297,6 +297,9 @@
 /** Return the abstract main loop abstraction layer vtable for this main loop. */
 pa_mainloop_api* pa_threaded_mainloop_get_api(pa_threaded_mainloop*m);
 
+/** Returns non-zero when called from withing the event loop thread. \since 0.9.7 */
+int pa_threaded_mainloop_in_thread(pa_threaded_mainloop *m);
+
 PA_C_DECL_END
 
 #endif

Modified: trunk/src/pulse/timeval.c
URL: http://0pointer.de/cgi-bin/viewcvs.cgi/trunk/src/pulse/timeval.c?rev=1971&root=pulseaudio&r1=1970&r2=1971&view=diff
==============================================================================
--- trunk/src/pulse/timeval.c (original)
+++ trunk/src/pulse/timeval.c Sun Oct 28 20:13:50 2007
@@ -26,7 +26,6 @@
 #include <config.h>
 #endif
 
-#include <assert.h>
 #include <stddef.h>
 #include <sys/time.h>
 
@@ -34,15 +33,17 @@
 #include <windows.h>
 #endif
 
-#include "../pulsecore/winsock.h"
+#include <pulsecore/winsock.h>
+#include <pulsecore/macro.h>
 
 #include "timeval.h"
 
 struct timeval *pa_gettimeofday(struct timeval *tv) {
 #ifdef HAVE_GETTIMEOFDAY
-    assert(tv);
+    pa_assert(tv);
 
-    return gettimeofday(tv, NULL) < 0 ? NULL : tv;
+    pa_assert_se(gettimeofday(tv, NULL) == 0);
+    return tv;
 #elif defined(OS_IS_WIN32)
     /*
      * Copied from implementation by Steven Edwards (LGPL).
@@ -59,7 +60,7 @@
     LARGE_INTEGER   li;
     __int64         t;
 
-    assert(tv);
+    pa_assert(tv);
 
     GetSystemTimeAsFileTime(&ft);
     li.LowPart  = ft.dwLowDateTime;
@@ -67,8 +68,8 @@
     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);
+    tv->tv_sec  = (time_t) (t / PA_USEC_PER_SEC);
+    tv->tv_usec = (suseconds_t) (t % PA_USEC_PER_SEC);
 
     return tv;
 #else
@@ -78,9 +79,11 @@
 
 pa_usec_t pa_timeval_diff(const struct timeval *a, const struct timeval *b) {
     pa_usec_t r;
-    assert(a && b);
 
-    /* Check which whan is the earlier time and swap the two arguments if reuqired. */
+    pa_assert(a);
+    pa_assert(b);
+
+    /* Check which whan is the earlier time and swap the two arguments if required. */
     if (pa_timeval_cmp(a, b) < 0) {
         const struct timeval *c;
         c = a;
@@ -89,7 +92,7 @@
     }
 
     /* Calculate the second difference*/
-    r = ((pa_usec_t) a->tv_sec - b->tv_sec)* 1000000;
+    r = ((pa_usec_t) a->tv_sec - b->tv_sec) * PA_USEC_PER_SEC;
 
     /* Calculate the microsecond difference */
     if (a->tv_usec > b->tv_usec)
@@ -101,7 +104,8 @@
 }
 
 int pa_timeval_cmp(const struct timeval *a, const struct timeval *b) {
-    assert(a && b);
+    pa_assert(a);
+    pa_assert(b);
 
     if (a->tv_sec < b->tv_sec)
         return -1;
@@ -120,26 +124,43 @@
 
 pa_usec_t pa_timeval_age(const struct timeval *tv) {
     struct timeval now;
-    assert(tv);
+    pa_assert(tv);
 
     return pa_timeval_diff(pa_gettimeofday(&now), tv);
 }
 
 struct timeval* pa_timeval_add(struct timeval *tv, pa_usec_t v) {
     unsigned long secs;
-    assert(tv);
+    pa_assert(tv);
 
-    secs = (v/1000000);
-    tv->tv_sec += (unsigned long) secs;
-    v -= secs*1000000;
+    secs = (unsigned long) (v/PA_USEC_PER_SEC);
+    tv->tv_sec += secs;
+    v -= ((pa_usec_t) secs) * PA_USEC_PER_SEC;
 
-    tv->tv_usec += v;
+    tv->tv_usec += (suseconds_t) v;
 
     /* Normalize */
-    while (tv->tv_usec >= 1000000) {
+    while (tv->tv_usec >= PA_USEC_PER_SEC) {
         tv->tv_sec++;
-        tv->tv_usec -= 1000000;
+        tv->tv_usec -= PA_USEC_PER_SEC;
     }
 
     return tv;
 }
+
+struct timeval* pa_timeval_store(struct timeval *tv, pa_usec_t v) {
+    pa_assert(tv);
+
+    tv->tv_sec = v / PA_USEC_PER_SEC;
+    tv->tv_usec = v % PA_USEC_PER_SEC;
+
+    return tv;
+}
+
+pa_usec_t pa_timeval_load(const struct timeval *tv) {
+    pa_assert(tv);
+
+    return
+        (pa_usec_t) tv->tv_sec * PA_USEC_PER_SEC +
+        (pa_usec_t) tv->tv_usec;
+}

Modified: trunk/src/pulse/timeval.h
URL: http://0pointer.de/cgi-bin/viewcvs.cgi/trunk/src/pulse/timeval.h?rev=1971&root=pulseaudio&r1=1970&r2=1971&view=diff
==============================================================================
--- trunk/src/pulse/timeval.h (original)
+++ trunk/src/pulse/timeval.h Sun Oct 28 20:13:50 2007
@@ -33,6 +33,11 @@
 
 PA_C_DECL_BEGIN
 
+#define PA_MSEC_PER_SEC 1000
+#define PA_USEC_PER_SEC 1000000
+#define PA_NSEC_PER_SEC 1000000000
+#define PA_USEC_PER_MSEC 1000
+
 struct timeval;
 
 /** Return the current timestamp, just like UNIX gettimeofday() */
@@ -40,16 +45,22 @@
 
 /** Calculate the difference between the two specified timeval
  * structs. */
-pa_usec_t pa_timeval_diff(const struct timeval *a, const struct timeval *b);
+pa_usec_t pa_timeval_diff(const struct timeval *a, const struct timeval *b) PA_GCC_PURE;
 
 /** Compare the two timeval structs and return 0 when equal, negative when a < b, positive otherwse */
-int pa_timeval_cmp(const struct timeval *a, const struct timeval *b);
+int pa_timeval_cmp(const struct timeval *a, const struct timeval *b) PA_GCC_PURE;
 
 /** Return the time difference between now and the specified timestamp */
 pa_usec_t pa_timeval_age(const struct timeval *tv);
 
 /** Add the specified time inmicroseconds to the specified timeval structure */
-struct timeval* pa_timeval_add(struct timeval *tv, pa_usec_t v);
+struct timeval* pa_timeval_add(struct timeval *tv, pa_usec_t v) PA_GCC_PURE;
+
+/** Store the specified uec value in the timeval struct. \since 0.9.7 */
+struct timeval* pa_timeval_store(struct timeval *tv, pa_usec_t v);
+
+/** Load the specified tv value and return it in usec. \since 0.9.7 */
+pa_usec_t pa_timeval_load(const struct timeval *tv);
 
 PA_C_DECL_END
 

Modified: trunk/src/pulse/utf8.c
URL: http://0pointer.de/cgi-bin/viewcvs.cgi/trunk/src/pulse/utf8.c?rev=1971&root=pulseaudio&r1=1970&r2=1971&view=diff
==============================================================================
--- trunk/src/pulse/utf8.c (original)
+++ trunk/src/pulse/utf8.c Sun Oct 28 20:13:50 2007
@@ -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
@@ -50,7 +50,6 @@
 #include <config.h>
 #endif
 
-#include <assert.h>
 #include <errno.h>
 #include <stdlib.h>
 #include <inttypes.h>
@@ -60,12 +59,15 @@
 #include <iconv.h>
 #endif
 
+#include <pulse/xmalloc.h>
+#include <pulsecore/macro.h>
+
 #include "utf8.h"
-#include "xmalloc.h"
 
 #define FILTER_CHAR '_'
 
 static inline int is_unicode_valid(uint32_t ch) {
+
     if (ch >= 0x110000) /* End of unicode space */
         return 0;
     if ((ch & 0xFFFFF800) == 0xD800) /* Reserved area for UTF-16 */
@@ -74,6 +76,7 @@
         return 0;
     if ((ch & 0xFFFE) == 0xFFFE) /* BOM (Byte Order Mark) */
         return 0;
+
     return 1;
 }
 
@@ -94,6 +97,8 @@
     const uint8_t *p, *last;
     int size;
     uint8_t *o;
+
+    pa_assert(str);
 
     o = (uint8_t*) output;
     for (p = (const uint8_t*) str; *p; p++) {
@@ -178,15 +183,15 @@
     return NULL;
 }
 
-const char* pa_utf8_valid (const char *str) {
+char* pa_utf8_valid (const char *str) {
     return utf8_validate(str, NULL);
 }
 
 char* pa_utf8_filter (const char *str) {
     char *new_str;
 
+    pa_assert(str);
     new_str = pa_xnew(char, strlen(str) + 1);
-
     return utf8_validate(str, new_str);
 }
 
@@ -195,22 +200,24 @@
 static char* iconv_simple(const char *str, const char *to, const char *from) {
     char *new_str;
     size_t len, inlen;
-
     iconv_t cd;
     ICONV_CONST char *inbuf;
     char *outbuf;
     size_t res, inbytes, outbytes;
 
+    pa_assert(str);
+    pa_assert(to);
+    pa_assert(from);
+
     cd = iconv_open(to, from);
     if (cd == (iconv_t)-1)
         return NULL;
 
     inlen = len = strlen(str) + 1;
-    new_str = pa_xmalloc(len);
-    assert(new_str);
-
-    while (1) {
-        inbuf = (ICONV_CONST char*)str; /* Brain dead prototype for iconv() */
+    new_str = pa_xnew(char, len);
+
+    for (;;) {
+        inbuf = (ICONV_CONST char*) str; /* Brain dead prototype for iconv() */
         inbytes = inlen;
         outbuf = new_str;
         outbytes = len;
@@ -226,11 +233,10 @@
             break;
         }
 
-        assert(inbytes != 0);
+        pa_assert(inbytes != 0);
 
         len += inbytes;
         new_str = pa_xrealloc(new_str, len);
-        assert(new_str);
     }
 
     iconv_close(cd);
@@ -249,10 +255,12 @@
 #else
 
 char* pa_utf8_to_locale (const char *str) {
+    pa_assert(str);
     return NULL;
 }
 
 char* pa_locale_to_utf8 (const char *str) {
+    pa_assert(str);
     return NULL;
 }
 

Modified: trunk/src/pulse/utf8.h
URL: http://0pointer.de/cgi-bin/viewcvs.cgi/trunk/src/pulse/utf8.h?rev=1971&root=pulseaudio&r1=1970&r2=1971&view=diff
==============================================================================
--- trunk/src/pulse/utf8.h (original)
+++ trunk/src/pulse/utf8.h Sun Oct 28 20:13:50 2007
@@ -34,7 +34,7 @@
 PA_C_DECL_BEGIN
 
 /** Test if the specified strings qualifies as valid UTF8. Return the string if so, otherwise NULL */
-const char *pa_utf8_valid(const char *str);
+char *pa_utf8_valid(const char *str) PA_GCC_PURE;
 
 /** Filter all invalid UTF8 characters from the specified string, returning a new fully UTF8 valid string. Don't forget to free the returned string with pa_xfree() */
 char *pa_utf8_filter(const char *str);

Modified: trunk/src/pulse/util.c
URL: http://0pointer.de/cgi-bin/viewcvs.cgi/trunk/src/pulse/util.c?rev=1971&root=pulseaudio&r1=1970&r2=1971&view=diff
==============================================================================
--- trunk/src/pulse/util.c (original)
+++ trunk/src/pulse/util.c Sun Oct 28 20:13:50 2007
@@ -26,7 +26,6 @@
 #include <config.h>
 #endif
 
-#include <assert.h>
 #include <errno.h>
 #include <limits.h>
 #include <stdio.h>
@@ -56,19 +55,13 @@
 #include <sys/prctl.h>
 #endif
 
-#include "../pulsecore/winsock.h"
-
+#include <pulsecore/winsock.h>
 #include <pulsecore/core-error.h>
 #include <pulsecore/log.h>
 #include <pulsecore/core-util.h>
+#include <pulsecore/macro.h>
 
 #include "util.h"
-
-#ifndef OS_IS_WIN32
-#define PATH_SEP '/'
-#else
-#define PATH_SEP '\\'
-#endif
 
 char *pa_get_user_name(char *s, size_t l) {
     char *p;
@@ -78,7 +71,8 @@
     struct passwd pw, *r;
 #endif
 
-    assert(s && l > 0);
+    pa_assert(s);
+    pa_assert(l > 0);
 
     if (!(p = getenv("USER")) && !(p = getenv("LOGNAME")) && !(p = getenv("USERNAME"))) {
 #ifdef HAVE_PWD_H
@@ -90,7 +84,7 @@
             * that do not support getpwuid_r. */
         if ((r = getpwuid(getuid())) == NULL) {
 #endif
-            snprintf(s, l, "%lu", (unsigned long) getuid());
+            pa_snprintf(s, l, "%lu", (unsigned long) getuid());
             return s;
         }
 
@@ -113,11 +107,15 @@
 }
 
 char *pa_get_host_name(char *s, size_t l) {
-    assert(s && l > 0);
+
+    pa_assert(s);
+    pa_assert(l > 0);
+
     if (gethostname(s, l) < 0) {
         pa_log("gethostname(): %s", pa_cstrerror(errno));
         return NULL;
     }
+
     s[l-1] = 0;
     return s;
 }
@@ -130,7 +128,8 @@
     struct passwd pw, *r;
 #endif
 
-    assert(s && l);
+    pa_assert(s);
+    pa_assert(l > 0);
 
     if ((e = getenv("HOME")))
         return pa_strlcpy(s, e, l);
@@ -159,8 +158,8 @@
 
 char *pa_get_binary_name(char *s, size_t l) {
 
-    assert(s);
-    assert(l);
+    pa_assert(s);
+    pa_assert(l > 0);
 
 #if defined(OS_IS_WIN32)
     {
@@ -171,7 +170,7 @@
     }
 #endif
 
-#ifdef HAVE_READLINK
+#ifdef __linux__
     {
         int i;
         char path[PATH_MAX];
@@ -206,13 +205,15 @@
     return NULL;
 }
 
-const char *pa_path_get_filename(const char *p) {
+char *pa_path_get_filename(const char *p) {
     char *fn;
 
-    if ((fn = strrchr(p, PATH_SEP)))
+    pa_assert(p);
+
+    if ((fn = strrchr(p, PA_PATH_SEP_CHAR)))
         return fn+1;
 
-    return (const char*) p;
+    return (char*) p;
 }
 
 char *pa_get_fqdn(char *s, size_t l) {
@@ -220,6 +221,9 @@
 #ifdef HAVE_GETADDRINFO
     struct addrinfo *a, hints;
 #endif
+
+    pa_assert(s);
+    pa_assert(l > 0);
 
     if (!pa_get_host_name(hn, sizeof(hn)))
         return NULL;

Modified: trunk/src/pulse/util.h
URL: http://0pointer.de/cgi-bin/viewcvs.cgi/trunk/src/pulse/util.h?rev=1971&root=pulseaudio&r1=1970&r2=1971&view=diff
==============================================================================
--- trunk/src/pulse/util.h (original)
+++ trunk/src/pulse/util.h Sun Oct 28 20:13:50 2007
@@ -52,7 +52,7 @@
 
 /** Return a pointer to the filename inside a path (which is the last
  * component). */
-const char *pa_path_get_filename(const char *p);
+char *pa_path_get_filename(const char *p);
 
 /** Wait t milliseconds */
 int pa_msleep(unsigned long t);

Modified: trunk/src/pulse/volume.c
URL: http://0pointer.de/cgi-bin/viewcvs.cgi/trunk/src/pulse/volume.c?rev=1971&root=pulseaudio&r1=1970&r2=1971&view=diff
==============================================================================
--- trunk/src/pulse/volume.c (original)
+++ trunk/src/pulse/volume.c Sun Oct 28 20:13:50 2007
@@ -25,16 +25,18 @@
 #include <config.h>
 #endif
 
-#include <assert.h>
 #include <stdio.h>
 #include <string.h>
+
+#include <pulsecore/core-util.h>
+#include <pulsecore/macro.h>
 
 #include "volume.h"
 
 int pa_cvolume_equal(const pa_cvolume *a, const pa_cvolume *b) {
     int i;
-    assert(a);
-    assert(b);
+    pa_assert(a);
+    pa_assert(b);
 
     if (a->channels != b->channels)
         return 0;
@@ -49,9 +51,9 @@
 pa_cvolume* pa_cvolume_set(pa_cvolume *a, unsigned channels, pa_volume_t v) {
     int i;
 
-    assert(a);
-    assert(channels > 0);
-    assert(channels <= PA_CHANNELS_MAX);
+    pa_assert(a);
+    pa_assert(channels > 0);
+    pa_assert(channels <= PA_CHANNELS_MAX);
 
     a->channels = channels;
 
@@ -64,7 +66,7 @@
 pa_volume_t pa_cvolume_avg(const pa_cvolume *a) {
     uint64_t sum = 0;
     int i;
-    assert(a);
+    pa_assert(a);
 
     for (i = 0; i < a->channels; i++)
         sum += a->values[i];
@@ -118,14 +120,14 @@
     int first = 1;
     char *e;
 
-    assert(s);
-    assert(l > 0);
-    assert(c);
+    pa_assert(s);
+    pa_assert(l > 0);
+    pa_assert(c);
 
     *(e = s) = 0;
 
     for (channel = 0; channel < c->channels && l > 1; channel++) {
-        l -= snprintf(e, l, "%s%u: %3u%%",
+        l -= pa_snprintf(e, l, "%s%u: %3u%%",
                       first ? "" : " ",
                       channel,
                       (c->values[channel]*100)/PA_VOLUME_NORM);
@@ -140,7 +142,7 @@
 /** Return non-zero if the volume of all channels is equal to the specified value */
 int pa_cvolume_channels_equal_to(const pa_cvolume *a, pa_volume_t v) {
     unsigned c;
-    assert(a);
+    pa_assert(a);
 
     for (c = 0; c < a->channels; c++)
         if (a->values[c] != v)
@@ -152,9 +154,9 @@
 pa_cvolume *pa_sw_cvolume_multiply(pa_cvolume *dest, const pa_cvolume *a, const pa_cvolume *b) {
     unsigned i;
 
-    assert(dest);
-    assert(a);
-    assert(b);
+    pa_assert(dest);
+    pa_assert(a);
+    pa_assert(b);
 
     for (i = 0; i < a->channels && i < b->channels && i < PA_CHANNELS_MAX; i++) {
 
@@ -169,7 +171,7 @@
 }
 
 int pa_cvolume_valid(const pa_cvolume *v) {
-    assert(v);
+    pa_assert(v);
 
     if (v->channels <= 0 || v->channels > PA_CHANNELS_MAX)
         return 0;

Modified: trunk/src/pulse/volume.h
URL: http://0pointer.de/cgi-bin/viewcvs.cgi/trunk/src/pulse/volume.h?rev=1971&root=pulseaudio&r1=1970&r2=1971&view=diff
==============================================================================
--- trunk/src/pulse/volume.h (original)
+++ trunk/src/pulse/volume.h Sun Oct 28 20:13:50 2007
@@ -113,7 +113,7 @@
 } pa_cvolume;
 
 /** Return non-zero when *a == *b */
-int pa_cvolume_equal(const pa_cvolume *a, const pa_cvolume *b);
+int pa_cvolume_equal(const pa_cvolume *a, const pa_cvolume *b) PA_GCC_PURE;
 
 /** Set the volume of all channels to PA_VOLUME_NORM */
 #define pa_cvolume_reset(a, n) pa_cvolume_set((a), (n), PA_VOLUME_NORM)
@@ -131,13 +131,13 @@
 char *pa_cvolume_snprint(char *s, size_t l, const pa_cvolume *c);
 
 /** Return the average volume of all channels */
-pa_volume_t pa_cvolume_avg(const pa_cvolume *a);
+pa_volume_t pa_cvolume_avg(const pa_cvolume *a) PA_GCC_PURE;
 
 /** Return TRUE when the passed cvolume structure is valid, FALSE otherwise */
-int pa_cvolume_valid(const pa_cvolume *v);
+int pa_cvolume_valid(const pa_cvolume *v) PA_GCC_PURE;
 
 /** Return non-zero if the volume of all channels is equal to the specified value */
-int pa_cvolume_channels_equal_to(const pa_cvolume *a, pa_volume_t v);
+int pa_cvolume_channels_equal_to(const pa_cvolume *a, pa_volume_t v) PA_GCC_PURE;
 
 /** Return 1 if the specified volume has all channels muted */
 #define pa_cvolume_is_muted(a) pa_cvolume_channels_equal_to((a), PA_VOLUME_MUTED)
@@ -146,22 +146,22 @@
 #define pa_cvolume_is_norm(a) pa_cvolume_channels_equal_to((a), PA_VOLUME_NORM)
 
 /** Multiply two volumes specifications, return the result. This uses PA_VOLUME_NORM as neutral element of multiplication. This is only valid for software volumes! */
-pa_volume_t pa_sw_volume_multiply(pa_volume_t a, pa_volume_t b);
+pa_volume_t pa_sw_volume_multiply(pa_volume_t a, pa_volume_t b) PA_GCC_CONST;
 
 /** Multiply to per-channel volumes and return the result in *dest. This is only valid for software volumes! */
-pa_cvolume *pa_sw_cvolume_multiply(pa_cvolume *dest, const pa_cvolume *a, const pa_cvolume *b);
+pa_cvolume *pa_sw_cvolume_multiply(pa_cvolume *dest, const pa_cvolume *a, const pa_cvolume *b) PA_GCC_PURE;
 
 /** Convert a decibel value to a volume. This is only valid for software volumes! \since 0.4 */
-pa_volume_t pa_sw_volume_from_dB(double f);
+pa_volume_t pa_sw_volume_from_dB(double f) PA_GCC_CONST;
 
 /** Convert a volume to a decibel value. This is only valid for software volumes! \since 0.4 */
-double pa_sw_volume_to_dB(pa_volume_t v);
+double pa_sw_volume_to_dB(pa_volume_t v) PA_GCC_CONST;
 
 /** Convert a linear factor to a volume. This is only valid for software volumes! \since 0.8 */
-pa_volume_t pa_sw_volume_from_linear(double v);
+pa_volume_t pa_sw_volume_from_linear(double v) PA_GCC_CONST;
 
 /** Convert a volume to a linear factor. This is only valid for software volumes! \since 0.8 */
-double pa_sw_volume_to_linear(pa_volume_t v);
+double pa_sw_volume_to_linear(pa_volume_t v) PA_GCC_CONST;
 
 #ifdef INFINITY
 #define PA_DECIBEL_MININFTY (-INFINITY)

Modified: trunk/src/pulse/xmalloc.c
URL: http://0pointer.de/cgi-bin/viewcvs.cgi/trunk/src/pulse/xmalloc.c?rev=1971&root=pulseaudio&r1=1970&r2=1971&view=diff
==============================================================================
--- trunk/src/pulse/xmalloc.c (original)
+++ trunk/src/pulse/xmalloc.c Sun Oct 28 20:13:50 2007
@@ -27,12 +27,12 @@
 
 #include <stdlib.h>
 #include <signal.h>
-#include <assert.h>
 #include <unistd.h>
 #include <string.h>
 
 #include <pulsecore/core-util.h>
 #include <pulsecore/gccmacro.h>
+#include <pulsecore/macro.h>
 
 #include "xmalloc.h"
 
@@ -60,8 +60,8 @@
 
 void* pa_xmalloc(size_t size) {
     void *p;
-    assert(size > 0);
-    assert(size < MAX_ALLOC_SIZE);
+    pa_assert(size > 0);
+    pa_assert(size < MAX_ALLOC_SIZE);
 
     if (!(p = malloc(size)))
         oom();
@@ -71,8 +71,8 @@
 
 void* pa_xmalloc0(size_t size) {
     void *p;
-    assert(size > 0);
-    assert(size < MAX_ALLOC_SIZE);
+    pa_assert(size > 0);
+    pa_assert(size < MAX_ALLOC_SIZE);
 
     if (!(p = calloc(1, size)))
         oom();
@@ -82,8 +82,8 @@
 
 void *pa_xrealloc(void *ptr, size_t size) {
     void *p;
-    assert(size > 0);
-    assert(size < MAX_ALLOC_SIZE);
+    pa_assert(size > 0);
+    pa_assert(size < MAX_ALLOC_SIZE);
 
     if (!(p = realloc(ptr, size)))
         oom();

Modified: trunk/src/pulse/xmalloc.h
URL: http://0pointer.de/cgi-bin/viewcvs.cgi/trunk/src/pulse/xmalloc.h?rev=1971&root=pulseaudio&r1=1970&r2=1971&view=diff
==============================================================================
--- trunk/src/pulse/xmalloc.h (original)
+++ trunk/src/pulse/xmalloc.h Sun Oct 28 20:13:50 2007
@@ -75,6 +75,15 @@
 /** 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

Copied: trunk/src/pulsecore/asyncq.c (from r1970, branches/lennart/src/pulsecore/asyncq.c)
URL: http://0pointer.de/cgi-bin/viewcvs.cgi/trunk/src/pulsecore/asyncq.c?p2=trunk/src/pulsecore/asyncq.c&p1=branches/lennart/src/pulsecore/asyncq.c&r1=1970&r2=1971&rev=1971&root=pulseaudio&view=diff
==============================================================================
--- branches/lennart/src/pulsecore/asyncq.c (original)
+++ trunk/src/pulsecore/asyncq.c Sun Oct 28 20:13:50 2007
@@ -127,7 +127,7 @@
             return -1;
 
 /*         pa_log("sleeping on push"); */
-        
+
         do {
             pa_fdsem_wait(l->read_fdsem);
         } while (!pa_atomic_ptr_cmpxchg(&cells[idx], NULL, p));
@@ -147,7 +147,7 @@
     pa_atomic_ptr_t *cells;
 
     pa_assert(l);
-    
+
     cells = PA_ASYNCQ_CELLS(l);
 
     _Y;
@@ -159,7 +159,7 @@
             return NULL;
 
 /*         pa_log("sleeping on pop"); */
-        
+
         do {
             pa_fdsem_wait(l->write_fdsem);
         } while (!(ret = pa_atomic_ptr_load(&cells[idx])));
@@ -174,7 +174,7 @@
     l->read_idx++;
 
     pa_fdsem_post(l->read_fdsem);
-    
+
     return ret;
 }
 

Modified: trunk/src/pulsecore/atomic.h
URL: http://0pointer.de/cgi-bin/viewcvs.cgi/trunk/src/pulsecore/atomic.h?rev=1971&root=pulseaudio&r1=1970&r2=1971&view=diff
==============================================================================
--- trunk/src/pulsecore/atomic.h (original)
+++ trunk/src/pulsecore/atomic.h Sun Oct 28 20:13:50 2007
@@ -24,48 +24,201 @@
   USA.
 ***/
 
+/*
+ * atomic_ops guarantees us that sizeof(AO_t) == sizeof(void*).  It is
+ * not guaranteed however, that sizeof(AO_t) == sizeof(size_t).
+ * however very likely.
+ *
+ * For now we do only full memory barriers. Eventually we might want
+ * to support more elaborate memory barriers, in which case we will add
+ * suffixes to the function names.
+ *
+ * On gcc >= 4.1 we use the builtin atomic functions. otherwise we use
+ * libatomic_ops
+ */
+
+#ifndef PACKAGE
+#error "Please include config.h before including this file!"
+#endif
+
+#ifdef HAVE_ATOMIC_BUILTINS
+
+/* __sync based implementation */
+
+typedef struct pa_atomic {
+    volatile int value;
+} pa_atomic_t;
+
+#define PA_ATOMIC_INIT(v) { .value = (v) }
+
+static inline int pa_atomic_load(const pa_atomic_t *a) {
+    __sync_synchronize();
+    return a->value;
+}
+
+static inline void pa_atomic_store(pa_atomic_t *a, int i) {
+    a->value = i;
+    __sync_synchronize();
+}
+
+/* Returns the previously set value */
+static inline int pa_atomic_add(pa_atomic_t *a, int i) {
+    return __sync_fetch_and_add(&a->value, i);
+}
+
+/* Returns the previously set value */
+static inline int pa_atomic_sub(pa_atomic_t *a, int i) {
+    return __sync_fetch_and_sub(&a->value, i);
+}
+
+/* Returns the previously set value */
+static inline int pa_atomic_inc(pa_atomic_t *a) {
+    return pa_atomic_add(a, 1);
+}
+
+/* Returns the previously set value */
+static inline int pa_atomic_dec(pa_atomic_t *a) {
+    return pa_atomic_sub(a, 1);
+}
+
+/* Returns non-zero when the operation was successful. */
+static inline int pa_atomic_cmpxchg(pa_atomic_t *a, int old_i, int new_i) {
+    return __sync_bool_compare_and_swap(&a->value, old_i, new_i);
+}
+
+typedef struct pa_atomic_ptr {
+    volatile unsigned long value;
+} pa_atomic_ptr_t;
+
+#define PA_ATOMIC_PTR_INIT(v) { .value = (long) (v) }
+
+static inline void* pa_atomic_ptr_load(const pa_atomic_ptr_t *a) {
+    __sync_synchronize();
+    return (void*) a->value;
+}
+
+static inline void pa_atomic_ptr_store(pa_atomic_ptr_t *a, void *p) {
+    a->value = (unsigned long) p;
+    __sync_synchronize();
+}
+
+static inline int pa_atomic_ptr_cmpxchg(pa_atomic_ptr_t *a, void *old_p, void* new_p) {
+    return __sync_bool_compare_and_swap(&a->value, (long) old_p, (long) new_p);
+}
+
+#elif defined(__GNUC__) && (defined(__amd64__) || defined(__x86_64__))
+
+#error "The native atomic operations implementation for AMD64 has not been tested. libatomic_ops is known to not work properly on AMD64 and your gcc version is too old for the gcc-builtin atomic ops support. You have three options now: make the native atomic operations implementation for AMD64 work, fix libatomic_ops, or upgrade your GCC."
+
+/* Addapted from glibc */
+
+typedef struct pa_atomic {
+    volatile int value;
+} pa_atomic_t;
+
+#define PA_ATOMIC_INIT(v) { .value = (v) }
+
+static inline int pa_atomic_load(const pa_atomic_t *a) {
+    return a->value;
+}
+
+static inline void pa_atomic_store(pa_atomic_t *a, int i) {
+    a->value = i;
+}
+
+static inline int pa_atomic_add(pa_atomic_t *a, int i) {
+    int result;
+
+    __asm __volatile ("lock; xaddl %0, %1"
+                      : "=r" (result), "=m" (a->value)
+                      : "0" (i), "m" (a->value));
+
+    return result;
+}
+
+static inline int pa_atomic_sub(pa_atomic_t *a, int i) {
+    return pa_atomic_add(a, -i);
+}
+
+static inline int pa_atomic_inc(pa_atomic_t *a) {
+    return pa_atomic_add(a, 1);
+}
+
+static inline int pa_atomic_dec(pa_atomic_t *a) {
+    return pa_atomic_sub(a, 1);
+}
+
+static inline int pa_atomic_cmpxchg(pa_atomic_t *a, int old_i, int new_i) {
+    int result;
+
+    __asm__ __volatile__ ("lock; cmpxchgl %2, %1"
+                          : "=a" (result), "=m" (a->value)
+                          : "r" (new_i), "m" (a->value), "0" (old_i));
+
+    return result == oldval;
+}
+
+typedef struct pa_atomic_ptr {
+    volatile unsigned long value;
+} pa_atomic_ptr_t;
+
+#define PA_ATOMIC_PTR_INIT(v) { .value = (long) (v) }
+
+static inline void* pa_atomic_ptr_load(const pa_atomic_ptr_t *a) {
+    return (void*) a->value;
+}
+
+static inline void pa_atomic_ptr_store(pa_atomic_ptr_t *a, void *p) {
+    a->value = (unsigned long) p;
+}
+
+static inline int pa_atomic_ptr_cmpxchg(pa_atomic_ptr_t *a, void *old_p, void* new_p) {
+    void *result;
+
+    __asm__ __volatile__ ("lock; cmpxchgq %q2, %1"
+                          : "=a" (result), "=m" (a->value)
+                          : "r" (new_p), "m" (a->value), "0" (old_p));
+
+    return result;
+}
+
+#else
+
+/* libatomic_ops based implementation */
+
 #include <atomic_ops.h>
 
-/* atomic_ops guarantees us that sizeof(AO_t) == sizeof(void*).
- *
- * 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) }
 
-/* For now we do only full memory barriers. Eventually we might want
- * 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 +226,8 @@
     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);
 }
@@ -86,3 +241,5 @@
 }
 
 #endif
+
+#endif

Modified: trunk/src/pulsecore/authkey-prop.c
URL: http://0pointer.de/cgi-bin/viewcvs.cgi/trunk/src/pulsecore/authkey-prop.c?rev=1971&root=pulseaudio&r1=1970&r2=1971&view=diff
==============================================================================
--- trunk/src/pulsecore/authkey-prop.c (original)
+++ trunk/src/pulsecore/authkey-prop.c Sun Oct 28 20:13:50 2007
@@ -21,44 +21,56 @@
   USA.
 ***/
 
-#include <assert.h>
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
 #include <string.h>
 
 #include <pulse/xmalloc.h>
 
 #include <pulsecore/props.h>
+#include <pulsecore/macro.h>
 #include <pulsecore/log.h>
+#include <pulsecore/refcnt.h>
 
 #include "authkey-prop.h"
 
 struct authkey_data {
-    int ref;
+    PA_REFCNT_DECLARE;
     size_t length;
 };
 
 int pa_authkey_prop_get(pa_core *c, const char *name, void *data, size_t len) {
     struct authkey_data *a;
-    assert(c && name && data && len > 0);
+
+    pa_assert(c);
+    pa_assert(name);
+    pa_assert(data);
+    pa_assert(len > 0);
 
     if (!(a = pa_property_get(c, name)))
         return -1;
 
-    assert(a->length == len);
-    memcpy(data, a+1, len);
+    pa_assert(a->length == len);
+    memcpy(data, (uint8_t*) a + PA_ALIGN(sizeof(struct authkey_data)), len);
+
     return 0;
 }
 
 int pa_authkey_prop_put(pa_core *c, const char *name, const void *data, size_t len) {
     struct authkey_data *a;
-    assert(c && name);
+
+    pa_assert(c);
+    pa_assert(name);
 
     if (pa_property_get(c, name))
         return -1;
 
-    a = pa_xmalloc(sizeof(struct authkey_data) + len);
-    a->ref = 1;
+    a = pa_xmalloc(PA_ALIGN(sizeof(struct authkey_data)) + len);
+    PA_REFCNT_INIT(a);
     a->length = len;
-    memcpy(a+1, data, len);
+    memcpy((uint8_t*) a + PA_ALIGN(sizeof(struct authkey_data)), data, len);
 
     pa_property_set(c, name, a);
 
@@ -67,22 +79,27 @@
 
 void pa_authkey_prop_ref(pa_core *c, const char *name) {
     struct authkey_data *a;
-    assert(c && name);
+
+    pa_assert(c);
+    pa_assert(name);
 
     a = pa_property_get(c, name);
-    assert(a && a->ref >= 1);
-
-    a->ref++;
+    pa_assert(a);
+    pa_assert(PA_REFCNT_VALUE(a) >= 1);
+    PA_REFCNT_INC(a);
 }
 
 void pa_authkey_prop_unref(pa_core *c, const char *name) {
     struct authkey_data *a;
-    assert(c && name);
+
+    pa_assert(c);
+    pa_assert(name);
 
     a = pa_property_get(c, name);
-    assert(a && a->ref >= 1);
+    pa_assert(a);
+    pa_assert(PA_REFCNT_VALUE(a) >= 1);
 
-    if (!(--a->ref)) {
+    if (PA_REFCNT_DEC(a) <= 0) {
         pa_property_remove(c, name);
         pa_xfree(a);
     }

Modified: trunk/src/pulsecore/authkey.c
URL: http://0pointer.de/cgi-bin/viewcvs.cgi/trunk/src/pulsecore/authkey.c?rev=1971&root=pulseaudio&r1=1970&r2=1971&view=diff
==============================================================================
--- trunk/src/pulsecore/authkey.c (original)
+++ trunk/src/pulsecore/authkey.c Sun Oct 28 20:13:50 2007
@@ -26,7 +26,6 @@
 #include <config.h>
 #endif
 
-#include <assert.h>
 #include <unistd.h>
 #include <fcntl.h>
 #include <string.h>
@@ -43,21 +42,25 @@
 #include <pulsecore/core-util.h>
 #include <pulsecore/log.h>
 #include <pulsecore/random.h>
+#include <pulsecore/macro.h>
 
 #include "authkey.h"
 
 /* Generate a new authorization key, store it in file fd and return it in *data  */
 static int generate(int fd, void *ret_data, size_t length) {
     ssize_t r;
-    assert(fd >= 0 && ret_data && length);
+
+    pa_assert(fd >= 0);
+    pa_assert(ret_data);
+    pa_assert(length > 0);
 
     pa_random(ret_data, length);
 
     lseek(fd, 0, SEEK_SET);
-    ftruncate(fd, 0);
+    (void) ftruncate(fd, 0);
 
     if ((r = pa_loop_write(fd, ret_data, length, NULL)) < 0 || (size_t) r != length) {
-        pa_log("failed to write cookie file: %s", pa_cstrerror(errno));
+        pa_log("Failed to write cookie file: %s", pa_cstrerror(errno));
         return -1;
     }
 
@@ -66,6 +69,10 @@
 
 #ifndef O_BINARY
 #define O_BINARY 0
+#endif
+
+#ifndef O_NOCTTY
+#define O_NOCTTY 0
 #endif
 
 /* Load an euthorization cookie from file fn and store it in data. If
@@ -75,11 +82,15 @@
     int writable = 1;
     int unlock = 0, ret = -1;
     ssize_t r;
-    assert(fn && data && length);
-
-    if ((fd = open(fn, O_RDWR|O_CREAT|O_BINARY, S_IRUSR|S_IWUSR)) < 0) {
-        if (errno != EACCES || (fd = open(fn, O_RDONLY|O_BINARY)) < 0) {
-            pa_log("failed to open cookie file '%s': %s", fn, pa_cstrerror(errno));
+
+    pa_assert(fn);
+    pa_assert(data);
+    pa_assert(length > 0);
+
+    if ((fd = open(fn, O_RDWR|O_CREAT|O_BINARY|O_NOCTTY, S_IRUSR|S_IWUSR)) < 0) {
+
+        if (errno != EACCES || (fd = open(fn, O_RDONLY|O_BINARY|O_NOCTTY)) < 0) {
+            pa_log("Failed to open cookie file '%s': %s", fn, pa_cstrerror(errno));
             goto finish;
         } else
             writable = 0;
@@ -88,15 +99,15 @@
     unlock = pa_lock_fd(fd, 1) >= 0;
 
     if ((r = pa_loop_read(fd, data, length, NULL)) < 0) {
-        pa_log("failed to read cookie file '%s': %s", fn, pa_cstrerror(errno));
+        pa_log("Failed to read cookie file '%s': %s", fn, pa_cstrerror(errno));
         goto finish;
     }
 
     if ((size_t) r != length) {
-        pa_log_debug("got %d bytes from cookie file '%s', expected %d", (int)r, fn, (int)length);
+        pa_log_debug("Got %d bytes from cookie file '%s', expected %d", (int) r, fn, (int) length);
 
         if (!writable) {
-            pa_log("unable to write cookie to read only file");
+            pa_log("Unable to write cookie to read only file");
             goto finish;
         }
 
@@ -113,7 +124,10 @@
         if (unlock)
             pa_lock_fd(fd, 0);
 
-        close(fd);
+        if (pa_close(fd) < 0) {
+            pa_log_warn("Failed to close cookie file: %s", pa_cstrerror(errno));
+            ret = -1;
+        }
     }
 
     return ret;
@@ -123,13 +137,12 @@
 int pa_authkey_load(const char *path, void *data, size_t length) {
     int ret;
 
-    assert(path && data && length);
-
-    ret = load(path, data, length);
-
-    if (ret < 0)
-        pa_log("Failed to load authorization key '%s': %s", path,
-               (ret == -1) ? pa_cstrerror(errno) : "file corrupt");
+    pa_assert(path);
+    pa_assert(data);
+    pa_assert(length > 0);
+
+    if ((ret = load(path, data, length)) < 0)
+        pa_log("Failed to load authorization key '%s': %s", path, (ret < 0) ? pa_cstrerror(errno) : "File corrupt");
 
     return ret;
 }
@@ -137,7 +150,10 @@
 /* If the specified file path starts with / return it, otherwise
  * return path prepended with home directory */
 static const char *normalize_path(const char *fn, char *s, size_t l) {
-    assert(fn && s && l > 0);
+
+    pa_assert(fn);
+    pa_assert(s);
+    pa_assert(l > 0);
 
 #ifndef OS_IS_WIN32
     if (fn[0] != '/') {
@@ -145,13 +161,14 @@
     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);
+        pa_snprintf(s, l, "%s/%s", homedir, fn);
 #else
-        snprintf(s, l, "%s\\%s", homedir, fn);
+        pa_snprintf(s, l, "%s\\%s", homedir, fn);
 #endif
         return s;
     }
@@ -164,7 +181,10 @@
 int pa_authkey_load_auto(const char *fn, void *data, size_t length) {
     char path[PATH_MAX];
     const char *p;
-    assert(fn && data && length);
+
+    pa_assert(fn);
+    pa_assert(data);
+    pa_assert(length > 0);
 
     if (!(p = normalize_path(fn, path, sizeof(path))))
         return -2;
@@ -179,20 +199,23 @@
     ssize_t r;
     char path[PATH_MAX];
     const char *p;
-    assert(fn && data && length);
+
+    pa_assert(fn);
+    pa_assert(data);
+    pa_assert(length > 0);
 
     if (!(p = normalize_path(fn, path, sizeof(path))))
         return -2;
 
-    if ((fd = open(p, O_RDWR|O_CREAT, S_IRUSR|S_IWUSR)) < 0) {
-        pa_log("failed to open cookie file '%s': %s", fn, pa_cstrerror(errno));
+    if ((fd = open(p, O_RDWR|O_CREAT|O_NOCTTY, S_IRUSR|S_IWUSR)) < 0) {
+        pa_log("Failed to open cookie file '%s': %s", fn, pa_cstrerror(errno));
         goto finish;
     }
 
     unlock = pa_lock_fd(fd, 1) >= 0;
 
     if ((r = pa_loop_write(fd, data, length, NULL)) < 0 || (size_t) r != length) {
-        pa_log("failed to read cookie file '%s': %s", fn, pa_cstrerror(errno));
+        pa_log("Failed to read cookie file '%s': %s", fn, pa_cstrerror(errno));
         goto finish;
     }
 
@@ -205,7 +228,10 @@
         if (unlock)
             pa_lock_fd(fd, 0);
 
-        close(fd);
+        if (pa_close(fd) < 0) {
+            pa_log_warn("Failed to close cookie file: %s", pa_cstrerror(errno));
+            ret = -1;
+        }
     }
 
     return ret;

Modified: trunk/src/pulsecore/autoload.c
URL: http://0pointer.de/cgi-bin/viewcvs.cgi/trunk/src/pulsecore/autoload.c?rev=1971&root=pulseaudio&r1=1970&r2=1971&view=diff
==============================================================================
--- trunk/src/pulsecore/autoload.c (original)
+++ trunk/src/pulsecore/autoload.c Sun Oct 28 20:13:50 2007
@@ -26,7 +26,6 @@
 #include <config.h>
 #endif
 
-#include <assert.h>
 #include <stdlib.h>
 #include <string.h>
 
@@ -36,13 +35,14 @@
 #include <pulsecore/memchunk.h>
 #include <pulsecore/sound-file.h>
 #include <pulsecore/log.h>
+#include <pulsecore/macro.h>
 #include <pulsecore/core-scache.h>
 #include <pulsecore/core-subscribe.h>
 
 #include "autoload.h"
 
 static void entry_free(pa_autoload_entry *e) {
-    assert(e);
+    pa_assert(e);
     pa_subscription_post(e->core, PA_SUBSCRIPTION_EVENT_AUTOLOAD|PA_SUBSCRIPTION_EVENT_REMOVE, PA_INVALID_INDEX);
     pa_xfree(e->name);
     pa_xfree(e->module);
@@ -51,7 +51,8 @@
 }
 
 static void entry_remove_and_free(pa_autoload_entry *e) {
-    assert(e && e->core);
+    pa_assert(e);
+    pa_assert(e->core);
 
     pa_idxset_remove_by_data(e->core->autoload_idxset, e, NULL);
     pa_hashmap_remove(e->core->autoload_hashmap, e->name);
@@ -60,12 +61,14 @@
 
 static pa_autoload_entry* entry_new(pa_core *c, const char *name) {
     pa_autoload_entry *e = NULL;
-    assert(c && name);
+
+    pa_core_assert_ref(c);
+    pa_assert(name);
 
     if (c->autoload_hashmap && (e = pa_hashmap_get(c->autoload_hashmap, name)))
         return NULL;
 
-    e = pa_xmalloc(sizeof(pa_autoload_entry));
+    e = pa_xnew(pa_autoload_entry, 1);
     e->core = c;
     e->name = pa_xstrdup(name);
     e->module = e->argument = NULL;
@@ -73,7 +76,7 @@
 
     if (!c->autoload_hashmap)
         c->autoload_hashmap = pa_hashmap_new(pa_idxset_string_hash_func, pa_idxset_string_compare_func);
-    assert(c->autoload_hashmap);
+    pa_assert(c->autoload_hashmap);
 
     pa_hashmap_put(c->autoload_hashmap, e->name, e);
 
@@ -88,7 +91,11 @@
 
 int pa_autoload_add(pa_core *c, const char*name, pa_namereg_type_t type, const char*module, const char *argument, uint32_t *idx) {
     pa_autoload_entry *e = NULL;
-    assert(c && name && module && (type == PA_NAMEREG_SINK || type == PA_NAMEREG_SOURCE));
+
+    pa_assert(c);
+    pa_assert(name);
+    pa_assert(module);
+    pa_assert(type == PA_NAMEREG_SINK || type == PA_NAMEREG_SOURCE);
 
     if (!(e = entry_new(c, name)))
         return -1;
@@ -105,7 +112,10 @@
 
 int pa_autoload_remove_by_name(pa_core *c, const char*name, pa_namereg_type_t type) {
     pa_autoload_entry *e;
-    assert(c && name && (type == PA_NAMEREG_SINK || type == PA_NAMEREG_SOURCE));
+
+    pa_assert(c);
+    pa_assert(name);
+    pa_assert(type == PA_NAMEREG_SINK || type == PA_NAMEREG_SOURCE);
 
     if (!c->autoload_hashmap || !(e = pa_hashmap_get(c->autoload_hashmap, name)) || e->type != type)
         return -1;
@@ -116,7 +126,9 @@
 
 int pa_autoload_remove_by_index(pa_core *c, uint32_t idx) {
     pa_autoload_entry *e;
-    assert(c && idx != PA_IDXSET_INVALID);
+
+    pa_assert(c);
+    pa_assert(idx != PA_IDXSET_INVALID);
 
     if (!c->autoload_idxset || !(e = pa_idxset_get_by_index(c->autoload_idxset, idx)))
         return -1;
@@ -128,7 +140,9 @@
 void pa_autoload_request(pa_core *c, const char *name, pa_namereg_type_t type) {
     pa_autoload_entry *e;
     pa_module *m;
-    assert(c && name);
+
+    pa_assert(c);
+    pa_assert(name);
 
     if (!c->autoload_hashmap || !(e = pa_hashmap_get(c->autoload_hashmap, name)) || (e->type != type))
         return;
@@ -153,6 +167,7 @@
 }
 
 void pa_autoload_free(pa_core *c) {
+
     if (c->autoload_hashmap) {
         pa_hashmap_free(c->autoload_hashmap, free_func, NULL);
         c->autoload_hashmap = NULL;
@@ -166,7 +181,9 @@
 
 const pa_autoload_entry* pa_autoload_get_by_name(pa_core *c, const char*name, pa_namereg_type_t type) {
     pa_autoload_entry *e;
-    assert(c && name);
+
+    pa_core_assert_ref(c);
+    pa_assert(name);
 
     if (!c->autoload_hashmap || !(e = pa_hashmap_get(c->autoload_hashmap, name)) || e->type != type)
         return NULL;
@@ -176,7 +193,9 @@
 
 const pa_autoload_entry* pa_autoload_get_by_index(pa_core *c, uint32_t idx) {
     pa_autoload_entry *e;
-    assert(c && idx != PA_IDXSET_INVALID);
+
+    pa_core_assert_ref(c);
+    pa_assert(idx != PA_IDXSET_INVALID);
 
     if (!c->autoload_idxset || !(e = pa_idxset_get_by_index(c->autoload_idxset, idx)))
         return NULL;

Modified: trunk/src/pulsecore/avahi-wrap.c
URL: http://0pointer.de/cgi-bin/viewcvs.cgi/trunk/src/pulsecore/avahi-wrap.c?rev=1971&root=pulseaudio&r1=1970&r2=1971&view=diff
==============================================================================
--- trunk/src/pulsecore/avahi-wrap.c (original)
+++ trunk/src/pulsecore/avahi-wrap.c Sun Oct 28 20:13:50 2007
@@ -21,11 +21,14 @@
   USA.
 ***/
 
-#include <assert.h>
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
 
 #include <pulse/xmalloc.h>
 
 #include <pulsecore/log.h>
+#include <pulsecore/macro.h>
 
 #include "avahi-wrap.h"
 
@@ -61,9 +64,9 @@
 static void watch_callback(pa_mainloop_api*a, pa_io_event* e, int fd, pa_io_event_flags_t events, void *userdata) {
     AvahiWatch *w = userdata;
 
-    assert(a);
-    assert(e);
-    assert(w);
+    pa_assert(a);
+    pa_assert(e);
+    pa_assert(w);
 
     w->current_event = translate_io_flags_back(events);
     w->callback(w, fd, w->current_event, w->userdata);
@@ -74,12 +77,10 @@
     pa_avahi_poll *p;
     AvahiWatch *w;
 
-    assert(api);
-    assert(fd >= 0);
-    assert(callback);
-
-    p = api->userdata;
-    assert(p);
+    pa_assert(api);
+    pa_assert(fd >= 0);
+    pa_assert(callback);
+    pa_assert_se(p = api->userdata);
 
     w = pa_xnew(AvahiWatch, 1);
     w->avahi_poll = p;
@@ -92,19 +93,19 @@
 }
 
 static void watch_update(AvahiWatch *w, AvahiWatchEvent event) {
-    assert(w);
+    pa_assert(w);
 
     w->avahi_poll->mainloop->io_enable(w->io_event, translate_io_flags(event));
 }
 
 static AvahiWatchEvent watch_get_events(AvahiWatch *w) {
-    assert(w);
+    pa_assert(w);
 
     return w->current_event;
 }
 
 static void watch_free(AvahiWatch *w) {
-    assert(w);
+    pa_assert(w);
 
     w->avahi_poll->mainloop->io_free(w->io_event);
     pa_xfree(w);
@@ -120,9 +121,9 @@
 static void timeout_callback(pa_mainloop_api*a, pa_time_event* e, const struct timeval *tv, void *userdata) {
     AvahiTimeout *t = userdata;
 
-    assert(a);
-    assert(e);
-    assert(t);
+    pa_assert(a);
+    pa_assert(e);
+    pa_assert(t);
 
     t->callback(t, t->userdata);
 }
@@ -131,11 +132,9 @@
     pa_avahi_poll *p;
     AvahiTimeout *t;
 
-    assert(api);
-    assert(callback);
-
-    p = api->userdata;
-    assert(p);
+    pa_assert(api);
+    pa_assert(callback);
+    pa_assert_se(p = api->userdata);
 
     t = pa_xnew(AvahiTimeout, 1);
     t->avahi_poll = p;
@@ -148,7 +147,7 @@
 }
 
 static void timeout_update(AvahiTimeout *t, const struct timeval *tv) {
-    assert(t);
+    pa_assert(t);
 
     if (t->time_event && tv)
         t->avahi_poll->mainloop->time_restart(t->time_event, tv);
@@ -161,7 +160,7 @@
 }
 
 static void timeout_free(AvahiTimeout *t) {
-    assert(t);
+    pa_assert(t);
 
     if (t->time_event)
         t->avahi_poll->mainloop->time_free(t->time_event);
@@ -171,7 +170,7 @@
 AvahiPoll* pa_avahi_poll_new(pa_mainloop_api *m) {
     pa_avahi_poll *p;
 
-    assert(m);
+    pa_assert(m);
 
     p = pa_xnew(pa_avahi_poll, 1);
 
@@ -190,9 +189,8 @@
 
 void pa_avahi_poll_free(AvahiPoll *api) {
     pa_avahi_poll *p;
-    assert(api);
-    p = api->userdata;
-    assert(p);
+    pa_assert(api);
+    pa_assert_se(p = api->userdata);
 
     pa_xfree(p);
 }

Modified: trunk/src/pulsecore/cli-command.c
URL: http://0pointer.de/cgi-bin/viewcvs.cgi/trunk/src/pulsecore/cli-command.c?rev=1971&root=pulseaudio&r1=1970&r2=1971&view=diff
==============================================================================
--- trunk/src/pulsecore/cli-command.c (original)
+++ trunk/src/pulsecore/cli-command.c Sun Oct 28 20:13:50 2007
@@ -28,7 +28,6 @@
 
 #include <stdio.h>
 #include <string.h>
-#include <assert.h>
 #include <stdlib.h>
 #include <errno.h>
 #include <unistd.h>
@@ -95,6 +94,7 @@
 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);
@@ -114,6 +114,9 @@
 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);
+static int pa_cli_command_suspend(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, int *fail);
 
 /* A method table for all available commands */
 
@@ -130,13 +133,14 @@
     { "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},
-    { "set-sink-input-volume",   pa_cli_command_sink_input_volume,  "Set the volume of a sink input (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, 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-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},
@@ -159,6 +163,9 @@
     { "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},
+    { "suspend",                 pa_cli_command_suspend,            "Suspend all sinks and all sources (args: bool)", 2},
     { NULL, NULL, NULL, 0 }
 };
 
@@ -174,15 +181,23 @@
     return idx;
 }
 
-static int pa_cli_command_exit(pa_core *c, pa_tokenizer *t, PA_GCC_UNUSED pa_strbuf *buf, PA_GCC_UNUSED int *fail) {
-    assert(c && c->mainloop && t);
+static int pa_cli_command_exit(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, int *fail) {
+    pa_core_assert_ref(c);
+    pa_assert(t);
+    pa_assert(buf);
+    pa_assert(fail);
+
     c->mainloop->quit(c->mainloop, 0);
     return 0;
 }
 
-static int pa_cli_command_help(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, PA_GCC_UNUSED int *fail) {
+static int pa_cli_command_help(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, int *fail) {
     const struct command*command;
-    assert(c && t && buf);
+
+    pa_core_assert_ref(c);
+    pa_assert(t);
+    pa_assert(buf);
+    pa_assert(fail);
 
     pa_strbuf_puts(buf, "Available commands:\n");
 
@@ -192,67 +207,91 @@
     return 0;
 }
 
-static int pa_cli_command_modules(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, PA_GCC_UNUSED int *fail) {
+static int pa_cli_command_modules(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, int *fail) {
     char *s;
-    assert(c && t);
-    s = pa_module_list_to_string(c);
-    assert(s);
+
+    pa_core_assert_ref(c);
+    pa_assert(t);
+    pa_assert(buf);
+    pa_assert(fail);
+
+    pa_assert_se(s = pa_module_list_to_string(c));
     pa_strbuf_puts(buf, s);
     pa_xfree(s);
     return 0;
 }
 
-static int pa_cli_command_clients(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, PA_GCC_UNUSED int *fail) {
+static int pa_cli_command_clients(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, int *fail) {
     char *s;
-    assert(c && t);
-    s = pa_client_list_to_string(c);
-    assert(s);
+
+    pa_core_assert_ref(c);
+    pa_assert(t);
+    pa_assert(buf);
+    pa_assert(fail);
+
+    pa_assert_se(s = pa_client_list_to_string(c));
     pa_strbuf_puts(buf, s);
     pa_xfree(s);
     return 0;
 }
 
-static int pa_cli_command_sinks(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, PA_GCC_UNUSED int *fail) {
+static int pa_cli_command_sinks(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, int *fail) {
     char *s;
-    assert(c && t);
-    s = pa_sink_list_to_string(c);
-    assert(s);
+
+    pa_core_assert_ref(c);
+    pa_assert(t);
+    pa_assert(buf);
+    pa_assert(fail);
+
+    pa_assert_se(s = pa_sink_list_to_string(c));
     pa_strbuf_puts(buf, s);
     pa_xfree(s);
     return 0;
 }
 
-static int pa_cli_command_sources(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, PA_GCC_UNUSED int *fail) {
+static int pa_cli_command_sources(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, int *fail) {
     char *s;
-    assert(c && t);
-    s = pa_source_list_to_string(c);
-    assert(s);
+
+    pa_core_assert_ref(c);
+    pa_assert(t);
+    pa_assert(buf);
+    pa_assert(fail);
+
+    pa_assert_se(s = pa_source_list_to_string(c));
     pa_strbuf_puts(buf, s);
     pa_xfree(s);
     return 0;
 }
 
-static int pa_cli_command_sink_inputs(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, PA_GCC_UNUSED int *fail) {
+static int pa_cli_command_sink_inputs(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, int *fail) {
     char *s;
-    assert(c && t);
-    s = pa_sink_input_list_to_string(c);
-    assert(s);
+
+    pa_core_assert_ref(c);
+    pa_assert(t);
+    pa_assert(buf);
+    pa_assert(fail);
+
+    pa_assert_se(s = pa_sink_input_list_to_string(c));
     pa_strbuf_puts(buf, s);
     pa_xfree(s);
     return 0;
 }
 
-static int pa_cli_command_source_outputs(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, PA_GCC_UNUSED int *fail) {
+static int pa_cli_command_source_outputs(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, int *fail) {
     char *s;
-    assert(c && t);
-    s = pa_source_output_list_to_string(c);
-    assert(s);
+
+    pa_core_assert_ref(c);
+    pa_assert(t);
+    pa_assert(buf);
+    pa_assert(fail);
+
+    pa_assert_se(s = pa_source_output_list_to_string(c));
     pa_strbuf_puts(buf, s);
     pa_xfree(s);
     return 0;
 }
 
-static int pa_cli_command_stat(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, PA_GCC_UNUSED int *fail) {
+static int pa_cli_command_stat(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, int *fail) {
     char s[256];
     const pa_mempool_stat *stat;
     unsigned k;
@@ -267,8 +306,10 @@
         [PA_MEMBLOCK_IMPORTED] = "IMPORTED",
     };
 
-    assert(c);
-    assert(t);
+    pa_core_assert_ref(c);
+    pa_assert(t);
+    pa_assert(buf);
+    pa_assert(fail);
 
     stat = pa_mempool_get_stat(c->mempool);
 
@@ -312,7 +353,11 @@
 }
 
 static int pa_cli_command_info(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, int *fail) {
-    assert(c && t);
+    pa_core_assert_ref(c);
+    pa_assert(t);
+    pa_assert(buf);
+    pa_assert(fail);
+
     pa_cli_command_stat(c, t, buf, fail);
     pa_cli_command_modules(c, t, buf, fail);
     pa_cli_command_sinks(c, t, buf, fail);
@@ -325,10 +370,14 @@
     return 0;
 }
 
-static int pa_cli_command_load(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, PA_GCC_UNUSED int *fail) {
+static int pa_cli_command_load(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, int *fail) {
     pa_module *m;
     const char *name;
-    assert(c && t);
+
+    pa_core_assert_ref(c);
+    pa_assert(t);
+    pa_assert(buf);
+    pa_assert(fail);
 
     if (!(name = pa_tokenizer_get(t, 1))) {
         pa_strbuf_puts(buf, "You need to specify the module name and optionally arguments.\n");
@@ -343,12 +392,16 @@
     return 0;
 }
 
-static int pa_cli_command_unload(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, PA_GCC_UNUSED int *fail) {
+static int pa_cli_command_unload(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, int *fail) {
     pa_module *m;
     uint32_t idx;
     const char *i;
     char *e;
-    assert(c && t);
+
+    pa_core_assert_ref(c);
+    pa_assert(t);
+    pa_assert(buf);
+    pa_assert(fail);
 
     if (!(i = pa_tokenizer_get(t, 1))) {
         pa_strbuf_puts(buf, "You need to specify the module index.\n");
@@ -365,12 +418,17 @@
     return 0;
 }
 
-static int pa_cli_command_sink_volume(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, PA_GCC_UNUSED int *fail) {
+static int pa_cli_command_sink_volume(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, int *fail) {
     const char *n, *v;
     pa_sink *sink;
     uint32_t volume;
     pa_cvolume cvolume;
 
+    pa_core_assert_ref(c);
+    pa_assert(t);
+    pa_assert(buf);
+    pa_assert(fail);
+
     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;
@@ -392,17 +450,22 @@
     }
 
     pa_cvolume_set(&cvolume, sink->sample_spec.channels, volume);
-    pa_sink_set_volume(sink, PA_MIXER_HARDWARE, &cvolume);
-    return 0;
-}
-
-static int pa_cli_command_sink_input_volume(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, PA_GCC_UNUSED int *fail) {
+    pa_sink_set_volume(sink, &cvolume);
+    return 0;
+}
+
+static int pa_cli_command_sink_input_volume(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, int *fail) {
     const char *n, *v;
     pa_sink_input *si;
     pa_volume_t volume;
     pa_cvolume cvolume;
     uint32_t idx;
 
+    pa_core_assert_ref(c);
+    pa_assert(t);
+    pa_assert(buf);
+    pa_assert(fail);
+
     if (!(n = pa_tokenizer_get(t, 1))) {
         pa_strbuf_puts(buf, "You need to specify a sink input by its index.\n");
         return -1;
@@ -433,12 +496,17 @@
     return 0;
 }
 
-static int pa_cli_command_source_volume(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, PA_GCC_UNUSED int *fail) {
+static int pa_cli_command_source_volume(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, int *fail) {
     const char *n, *v;
     pa_source *source;
     uint32_t volume;
     pa_cvolume cvolume;
 
+    pa_core_assert_ref(c);
+    pa_assert(t);
+    pa_assert(buf);
+    pa_assert(fail);
+
     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;
@@ -460,15 +528,20 @@
     }
 
     pa_cvolume_set(&cvolume, source->sample_spec.channels, volume);
-    pa_source_set_volume(source, PA_MIXER_HARDWARE, &cvolume);
-    return 0;
-}
-
-static int pa_cli_command_sink_mute(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, PA_GCC_UNUSED int *fail) {
+    pa_source_set_volume(source, &cvolume);
+    return 0;
+}
+
+static int pa_cli_command_sink_mute(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, int *fail) {
     const char *n, *m;
     pa_sink *sink;
     int mute;
 
+    pa_core_assert_ref(c);
+    pa_assert(t);
+    pa_assert(buf);
+    pa_assert(fail);
+
     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;
@@ -489,15 +562,20 @@
         return -1;
     }
 
-    pa_sink_set_mute(sink, PA_MIXER_HARDWARE, mute);
-    return 0;
-}
-
-static int pa_cli_command_source_mute(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, PA_GCC_UNUSED int *fail) {
+    pa_sink_set_mute(sink, mute);
+    return 0;
+}
+
+static int pa_cli_command_source_mute(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, int *fail) {
     const char *n, *m;
     pa_source *source;
     int mute;
 
+    pa_core_assert_ref(c);
+    pa_assert(t);
+    pa_assert(buf);
+    pa_assert(fail);
+
     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;
@@ -518,13 +596,57 @@
         return -1;
     }
 
-    pa_source_set_mute(source, PA_MIXER_HARDWARE, mute);
-    return 0;
-}
-
-static int pa_cli_command_sink_default(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, PA_GCC_UNUSED int *fail) {
+    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, int *fail) {
+    const char *n, *v;
+    pa_sink_input *si;
+    uint32_t idx;
+    int mute;
+
+    pa_core_assert_ref(c);
+    pa_assert(t);
+    pa_assert(buf);
+    pa_assert(fail);
+
+    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;
+}
+
+static int pa_cli_command_sink_default(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, int *fail) {
     const char *n;
-    assert(c && t);
+
+    pa_core_assert_ref(c);
+    pa_assert(t);
+    pa_assert(buf);
+    pa_assert(fail);
 
     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");
@@ -535,9 +657,13 @@
     return 0;
 }
 
-static int pa_cli_command_source_default(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, PA_GCC_UNUSED int *fail) {
+static int pa_cli_command_source_default(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, int *fail) {
     const char *n;
-    assert(c && t);
+
+    pa_core_assert_ref(c);
+    pa_assert(t);
+    pa_assert(buf);
+    pa_assert(fail);
 
     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");
@@ -548,11 +674,15 @@
     return 0;
 }
 
-static int pa_cli_command_kill_client(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, PA_GCC_UNUSED int *fail) {
+static int pa_cli_command_kill_client(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, int *fail) {
     const char *n;
     pa_client *client;
     uint32_t idx;
-    assert(c && t);
+
+    pa_core_assert_ref(c);
+    pa_assert(t);
+    pa_assert(buf);
+    pa_assert(fail);
 
     if (!(n = pa_tokenizer_get(t, 1))) {
         pa_strbuf_puts(buf, "You need to specify a client by its index.\n");
@@ -573,11 +703,15 @@
     return 0;
 }
 
-static int pa_cli_command_kill_sink_input(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, PA_GCC_UNUSED int *fail) {
+static int pa_cli_command_kill_sink_input(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, int *fail) {
     const char *n;
     pa_sink_input *sink_input;
     uint32_t idx;
-    assert(c && t);
+
+    pa_core_assert_ref(c);
+    pa_assert(t);
+    pa_assert(buf);
+    pa_assert(fail);
 
     if (!(n = pa_tokenizer_get(t, 1))) {
         pa_strbuf_puts(buf, "You need to specify a sink input by its index.\n");
@@ -598,11 +732,15 @@
     return 0;
 }
 
-static int pa_cli_command_kill_source_output(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, PA_GCC_UNUSED int *fail) {
+static int pa_cli_command_kill_source_output(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, int *fail) {
     const char *n;
     pa_source_output *source_output;
     uint32_t idx;
-    assert(c && t);
+
+    pa_core_assert_ref(c);
+    pa_assert(t);
+    pa_assert(buf);
+    pa_assert(fail);
 
     if (!(n = pa_tokenizer_get(t, 1))) {
         pa_strbuf_puts(buf, "You need to specify a source output by its index.\n");
@@ -623,20 +761,29 @@
     return 0;
 }
 
-static int pa_cli_command_scache_list(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, PA_GCC_UNUSED int *fail) {
+static int pa_cli_command_scache_list(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, int *fail) {
     char *s;
-    assert(c && t);
-    s = pa_scache_list_to_string(c);
-    assert(s);
+
+    pa_core_assert_ref(c);
+    pa_assert(t);
+    pa_assert(buf);
+    pa_assert(fail);
+
+    pa_assert_se(s = pa_scache_list_to_string(c));
     pa_strbuf_puts(buf, s);
     pa_xfree(s);
+
     return 0;
 }
 
 static int pa_cli_command_scache_play(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, int *fail) {
     const char *n, *sink_name;
     pa_sink *sink;
-    assert(c && t && buf && fail);
+
+    pa_core_assert_ref(c);
+    pa_assert(t);
+    pa_assert(buf);
+    pa_assert(fail);
 
     if (!(n = pa_tokenizer_get(t, 1)) || !(sink_name = pa_tokenizer_get(t, 2))) {
         pa_strbuf_puts(buf, "You need to specify a sample name and a sink name.\n");
@@ -658,7 +805,11 @@
 
 static int pa_cli_command_scache_remove(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, int *fail) {
     const char *n;
-    assert(c && t && buf && fail);
+
+    pa_core_assert_ref(c);
+    pa_assert(t);
+    pa_assert(buf);
+    pa_assert(fail);
 
     if (!(n = pa_tokenizer_get(t, 1))) {
         pa_strbuf_puts(buf, "You need to specify a sample name.\n");
@@ -676,7 +827,11 @@
 static int pa_cli_command_scache_load(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, int *fail) {
     const char *fname, *n;
     int r;
-    assert(c && t && buf && fail);
+
+    pa_core_assert_ref(c);
+    pa_assert(t);
+    pa_assert(buf);
+    pa_assert(fail);
 
     if (!(fname = pa_tokenizer_get(t, 2)) || !(n = pa_tokenizer_get(t, 1))) {
         pa_strbuf_puts(buf, "You need to specify a file name and a sample name.\n");
@@ -696,7 +851,11 @@
 
 static int pa_cli_command_scache_load_dir(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, int *fail) {
     const char *pname;
-    assert(c && t && buf && fail);
+
+    pa_core_assert_ref(c);
+    pa_assert(t);
+    pa_assert(buf);
+    pa_assert(fail);
 
     if (!(pname = pa_tokenizer_get(t, 1))) {
         pa_strbuf_puts(buf, "You need to specify a path name.\n");
@@ -714,7 +873,11 @@
 static int pa_cli_command_play_file(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, int *fail) {
     const char *fname, *sink_name;
     pa_sink *sink;
-    assert(c && t && buf && fail);
+
+    pa_core_assert_ref(c);
+    pa_assert(t);
+    pa_assert(buf);
+    pa_assert(fail);
 
     if (!(fname = pa_tokenizer_get(t, 1)) || !(sink_name = pa_tokenizer_get(t, 2))) {
         pa_strbuf_puts(buf, "You need to specify a file name and a sink name.\n");
@@ -732,7 +895,11 @@
 
 static int pa_cli_command_autoload_add(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, int *fail) {
     const char *a, *b;
-    assert(c && t && buf && fail);
+
+    pa_core_assert_ref(c);
+    pa_assert(t);
+    pa_assert(buf);
+    pa_assert(fail);
 
     if (!(a = pa_tokenizer_get(t, 1)) || !(b = pa_tokenizer_get(t, 2))) {
         pa_strbuf_puts(buf, "You need to specify a device name, a filename or a module name and optionally module arguments\n");
@@ -746,7 +913,11 @@
 
 static int pa_cli_command_autoload_remove(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, int *fail) {
     const char *name;
-    assert(c && t && buf && fail);
+
+    pa_core_assert_ref(c);
+    pa_assert(t);
+    pa_assert(buf);
+    pa_assert(fail);
 
     if (!(name = pa_tokenizer_get(t, 1))) {
         pa_strbuf_puts(buf, "You need to specify a device name\n");
@@ -761,25 +932,36 @@
     return 0;
 }
 
-static int pa_cli_command_autoload_list(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, PA_GCC_UNUSED int *fail) {
+static int pa_cli_command_autoload_list(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, int *fail) {
     char *s;
-    assert(c && t);
-    s = pa_autoload_list_to_string(c);
-    assert(s);
+
+    pa_core_assert_ref(c);
+    pa_assert(t);
+    pa_assert(buf);
+    pa_assert(fail);
+
+    pa_assert_se(s = pa_autoload_list_to_string(c));
     pa_strbuf_puts(buf, s);
     pa_xfree(s);
-    return 0;
-}
-
-static int pa_cli_command_list_props(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, PA_GCC_UNUSED int *fail) {
-    assert(c && t);
+
+    return 0;
+}
+
+static int pa_cli_command_list_props(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, int *fail) {
+    pa_core_assert_ref(c);
+    pa_assert(t);
+    pa_assert(buf);
+    pa_assert(fail);
+
     pa_property_dump(c, buf);
     return 0;
 }
 
 static int pa_cli_command_vacuum(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, int *fail) {
-    assert(c);
-    assert(t);
+    pa_core_assert_ref(c);
+    pa_assert(t);
+    pa_assert(buf);
+    pa_assert(fail);
 
     pa_mempool_vacuum(c->mempool);
 
@@ -792,6 +974,11 @@
     pa_sink *sink;
     uint32_t idx;
 
+    pa_core_assert_ref(c);
+    pa_assert(t);
+    pa_assert(buf);
+    pa_assert(fail);
+
     if (!(n = pa_tokenizer_get(t, 1))) {
         pa_strbuf_puts(buf, "You need to specify a sink input by its index.\n");
         return -1;
@@ -830,6 +1017,11 @@
     pa_source *source;
     uint32_t idx;
 
+    pa_core_assert_ref(c);
+    pa_assert(t);
+    pa_assert(buf);
+    pa_assert(fail);
+
     if (!(n = pa_tokenizer_get(t, 1))) {
         pa_strbuf_puts(buf, "You need to specify a source output by its index.\n");
         return -1;
@@ -862,7 +1054,105 @@
     return 0;
 }
 
-static int pa_cli_command_dump(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, PA_GCC_UNUSED int *fail) {
+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;
+
+    pa_core_assert_ref(c);
+    pa_assert(t);
+    pa_assert(buf);
+    pa_assert(fail);
+
+    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;
+
+    pa_core_assert_ref(c);
+    pa_assert(t);
+    pa_assert(buf);
+    pa_assert(fail);
+
+    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_suspend(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, int *fail) {
+    const char *m;
+    int suspend;
+    int ret;
+
+    pa_core_assert_ref(c);
+    pa_assert(t);
+    pa_assert(buf);
+    pa_assert(fail);
+
+    if (!(m = pa_tokenizer_get(t, 1))) {
+        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;
+    }
+
+    ret = - (pa_sink_suspend_all(c, suspend) < 0);
+    if (pa_source_suspend_all(c, suspend) < 0)
+        ret = -1;
+
+    if (ret < 0)
+        pa_strbuf_puts(buf, "Failed to resume/suspend all sinks/sources.\n");
+
+    return 0;
+}
+
+static int pa_cli_command_dump(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, int *fail) {
     pa_module *m;
     pa_sink *sink;
     pa_source *source;
@@ -874,7 +1164,10 @@
     void *i;
     pa_autoload_entry *a;
 
-    assert(c && t);
+    pa_core_assert_ref(c);
+    pa_assert(t);
+    pa_assert(buf);
+    pa_assert(fail);
 
     time(&now);
 
@@ -884,7 +1177,6 @@
     pa_strbuf_printf(buf, "### Configuration dump generated at %s\n", ctime(&now));
 #endif
 
-
     for (m = pa_idxset_first(c->modules, &idx); m; m = pa_idxset_next(c->modules, &idx)) {
         if (m->auto_unload)
             continue;
@@ -900,7 +1192,7 @@
     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 +1200,12 @@
             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 +1213,8 @@
             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));
     }
 
 
@@ -971,6 +1263,10 @@
 
 int pa_cli_command_execute_line_stateful(pa_core *c, const char *s, pa_strbuf *buf, int *fail, int *ifstate) {
     const char *cs;
+
+    pa_assert(c);
+    pa_assert(s);
+    pa_assert(buf);
 
     cs = s+strspn(s, whitespace);
 
@@ -1006,9 +1302,9 @@
 
             if (l == sizeof(META_INCLUDE)-1 && !strncmp(cs, META_INCLUDE, l)) {
                 const char *filename = cs+l+strspn(cs+l, whitespace);
-
                 if (pa_cli_command_execute_file(c, filename, buf, fail) < 0)
-                    if (*fail) return -1;
+                    if (*fail)
+                        return -1;
             } else if (l == sizeof(META_IFEXISTS)-1 && !strncmp(cs, META_IFEXISTS, l)) {
                 if (!ifstate) {
                     pa_strbuf_printf(buf, "Meta command %s is not valid in this context\n", cs);
@@ -1020,6 +1316,7 @@
                     const char *filename = cs+l+strspn(cs+l, whitespace);
 
                     *ifstate = access(filename, F_OK) == 0 ? IFSTATE_TRUE : IFSTATE_FALSE;
+                    pa_log_debug("Checking for existance of '%s': %s", filename, *ifstate == IFSTATE_TRUE ? "success" : "failure");
                 }
             } else {
                 pa_strbuf_printf(buf, "Invalid meta command: %s\n", cs);
@@ -1034,14 +1331,13 @@
         if (ifstate && *ifstate == IFSTATE_FALSE)
              return 0;
 
-
         l = strcspn(cs, whitespace);
 
         for (command = commands; command->name; command++)
             if (strlen(command->name) == l && !strncmp(cs, command->name, l)) {
                 int ret;
                 pa_tokenizer *t = pa_tokenizer_new(cs, command->args);
-                assert(t);
+                pa_assert(t);
                 ret = command->proc(c, t, buf, fail);
                 pa_tokenizer_free(t);
                 unknown = 0;
@@ -1072,9 +1368,9 @@
     int ifstate = IFSTATE_NONE;
     int ret = -1;
 
-    assert(c);
-    assert(fn);
-    assert(buf);
+    pa_assert(c);
+    pa_assert(fn);
+    pa_assert(buf);
 
     if (!(f = fopen(fn, "r"))) {
         pa_strbuf_printf(buf, "open('%s') failed: %s\n", fn, pa_cstrerror(errno));
@@ -1104,9 +1400,9 @@
     const char *p;
     int ifstate = IFSTATE_NONE;
 
-    assert(c);
-    assert(s);
-    assert(buf);
+    pa_assert(c);
+    pa_assert(s);
+    pa_assert(buf);
 
     p = s;
     while (*p) {
@@ -1125,3 +1421,4 @@
 
     return 0;
 }
+

Modified: trunk/src/pulsecore/cli-text.c
URL: http://0pointer.de/cgi-bin/viewcvs.cgi/trunk/src/pulsecore/cli-text.c?rev=1971&root=pulseaudio&r1=1970&r2=1971&view=diff
==============================================================================
--- trunk/src/pulsecore/cli-text.c (original)
+++ trunk/src/pulsecore/cli-text.c Sun Oct 28 20:13:50 2007
@@ -25,7 +25,6 @@
 #include <config.h>
 #endif
 
-#include <assert.h>
 #include <string.h>
 
 #include <pulse/volume.h>
@@ -41,6 +40,7 @@
 #include <pulsecore/sample-util.h>
 #include <pulsecore/core-scache.h>
 #include <pulsecore/autoload.h>
+#include <pulsecore/macro.h>
 
 #include "cli-text.h"
 
@@ -48,10 +48,9 @@
     pa_strbuf *s;
     pa_module *m;
     uint32_t idx = PA_IDXSET_INVALID;
-    assert(c);
-
-    s = pa_strbuf_new();
-    assert(s);
+    pa_assert(c);
+
+    s = pa_strbuf_new();
 
     pa_strbuf_printf(s, "%u module(s) loaded.\n", pa_idxset_size(c->modules));
 
@@ -72,10 +71,9 @@
     pa_strbuf *s;
     pa_client *client;
     uint32_t idx = PA_IDXSET_INVALID;
-    assert(c);
-
-    s = pa_strbuf_new();
-    assert(s);
+    pa_assert(c);
+
+    s = pa_strbuf_new();
 
     pa_strbuf_printf(s, "%u client(s) logged in.\n", pa_idxset_size(c->clients));
 
@@ -93,10 +91,15 @@
     pa_strbuf *s;
     pa_sink *sink;
     uint32_t idx = PA_IDXSET_INVALID;
-    assert(c);
-
-    s = pa_strbuf_new();
-    assert(s);
+    static const char* const state_table[] = {
+        [PA_SINK_RUNNING] = "RUNNING",
+        [PA_SINK_SUSPENDED] = "SUSPENDED",
+        [PA_SINK_IDLE] = "IDLE",
+        [PA_SINK_UNLINKED] = "UNLINKED"
+    };
+    pa_assert(c);
+
+    s = pa_strbuf_new();
 
     pa_strbuf_printf(s, "%u sink(s) available.\n", pa_idxset_size(c->sinks));
 
@@ -108,22 +111,35 @@
             "  %c index: %u\n"
             "\tname: <%s>\n"
             "\tdriver: <%s>\n"
+            "\tflags: %s%s%s\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"
+            "\tlinked by: <%u>\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->flags & PA_SINK_HW_VOLUME_CTRL ? "HW_VOLUME_CTRL " : "",
+            sink->flags & PA_SINK_LATENCY ? "LATENCY " : "",
+            sink->flags & PA_SINK_HARDWARE ? "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);
+            pa_channel_map_snprint(cm, sizeof(cm), &sink->channel_map),
+            pa_sink_used_by(sink),
+            pa_sink_linked_by(sink));
+
+        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,15 +151,20 @@
     pa_strbuf *s;
     pa_source *source;
     uint32_t idx = PA_IDXSET_INVALID;
-    assert(c);
-
-    s = pa_strbuf_new();
-    assert(s);
+    static const char* const state_table[] = {
+        [PA_SOURCE_RUNNING] = "RUNNING",
+        [PA_SOURCE_SUSPENDED] = "SUSPENDED",
+        [PA_SOURCE_IDLE] = "IDLE",
+        [PA_SOURCE_UNLINKED] = "UNLINKED"
+    };
+    pa_assert(c);
+
+    s = pa_strbuf_new();
 
     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,21 +172,35 @@
             "  %c index: %u\n"
             "\tname: <%s>\n"
             "\tdriver: <%s>\n"
+            "\tflags: %s%s%s\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"
+            "\tlinked by: <%u>\n",
             c->default_source_name && !strcmp(source->name, c->default_source_name) ? '*' : ' ',
             source->index,
             source->name,
             source->driver,
+            source->flags & PA_SOURCE_HW_VOLUME_CTRL ? "HW_VOLUME_CTRL " : "",
+            source->flags & PA_SOURCE_LATENCY ? "LATENCY " : "",
+            source->flags & PA_SOURCE_HARDWARE ? "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));
+            pa_channel_map_snprint(cm, sizeof(cm), &source->channel_map),
+            pa_source_used_by(source),
+            pa_source_linked_by(source));
 
         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,37 +214,41 @@
     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_UNLINKED] = "UNLINKED"
     };
-    assert(c);
-
-    s = pa_strbuf_new();
-    assert(s);
+    pa_assert(c);
+
+    s = pa_strbuf_new();
 
     pa_strbuf_printf(s, "%u source outputs(s) available.\n", pa_idxset_size(c->source_outputs));
 
     for (o = pa_idxset_first(c->source_outputs, &idx); o; o = pa_idxset_next(c->source_outputs, &idx)) {
         char ss[PA_SAMPLE_SPEC_SNPRINT_MAX], cm[PA_CHANNEL_MAP_SNPRINT_MAX];
 
-        assert(o->source);
+        pa_assert(o->source);
 
         pa_strbuf_printf(
             s,
             "    index: %u\n"
             "\tname: '%s'\n"
             "\tdriver: <%s>\n"
+            "\tflags: %s%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],
+            o->flags & PA_SOURCE_OUTPUT_VARIABLE_RATE ? "VARIABLE_RATE " : "",
+            o->flags & PA_SOURCE_OUTPUT_DONT_MOVE ? "DONT_MOVE " : "",
+            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,30 +266,32 @@
     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_UNLINKED] = "UNLINKED"
     };
 
-    assert(c);
-    s = pa_strbuf_new();
-    assert(s);
+    pa_assert(c);
+    s = pa_strbuf_new();
 
     pa_strbuf_printf(s, "%u sink input(s) available.\n", pa_idxset_size(c->sink_inputs));
 
     for (i = pa_idxset_first(c->sink_inputs, &idx); i; i = pa_idxset_next(c->sink_inputs, &idx)) {
         char ss[PA_SAMPLE_SPEC_SNPRINT_MAX], cv[PA_CVOLUME_SNPRINT_MAX], cm[PA_CHANNEL_MAP_SNPRINT_MAX];
 
-        assert(i->sink);
+        pa_assert(i->sink);
 
         pa_strbuf_printf(
             s,
             "    index: %u\n"
             "\tname: <%s>\n"
             "\tdriver: <%s>\n"
+            "\tflags: %s%s\n"
             "\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 +299,19 @@
             i->index,
             i->name,
             i->driver,
-            state_table[i->state],
+            i->flags & PA_SINK_INPUT_VARIABLE_RATE ? "VARIABLE_RATE " : "",
+            i->flags & PA_SINK_INPUT_DONT_MOVE ? "DONT_MOVE " : "",
+            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);
     }
@@ -277,10 +321,9 @@
 
 char *pa_scache_list_to_string(pa_core *c) {
     pa_strbuf *s;
-    assert(c);
-
-    s = pa_strbuf_new();
-    assert(s);
+    pa_assert(c);
+
+    s = pa_strbuf_new();
 
     pa_strbuf_printf(s, "%u cache entries available.\n", c->scache ? pa_idxset_size(c->scache) : 0);
 
@@ -326,10 +369,9 @@
 
 char *pa_autoload_list_to_string(pa_core *c) {
     pa_strbuf *s;
-    assert(c);
-
-    s = pa_strbuf_new();
-    assert(s);
+    pa_assert(c);
+
+    s = pa_strbuf_new();
 
     pa_strbuf_printf(s, "%u autoload entries available.\n", c->autoload_hashmap ? pa_hashmap_size(c->autoload_hashmap) : 0);
 

Modified: trunk/src/pulsecore/cli.c
URL: http://0pointer.de/cgi-bin/viewcvs.cgi/trunk/src/pulsecore/cli.c?rev=1971&root=pulseaudio&r1=1970&r2=1971&view=diff
==============================================================================
--- trunk/src/pulsecore/cli.c (original)
+++ trunk/src/pulsecore/cli.c Sun Oct 28 20:13:50 2007
@@ -27,7 +27,6 @@
 
 #include <stdio.h>
 #include <string.h>
-#include <assert.h>
 #include <stdlib.h>
 
 #include <pulse/xmalloc.h>
@@ -45,6 +44,7 @@
 #include <pulsecore/cli-text.h>
 #include <pulsecore/cli-command.h>
 #include <pulsecore/log.h>
+#include <pulsecore/macro.h>
 
 #include "cli.h"
 
@@ -68,19 +68,17 @@
 pa_cli* pa_cli_new(pa_core *core, pa_iochannel *io, pa_module *m) {
     char cname[256];
     pa_cli *c;
-    assert(io);
+    pa_assert(io);
 
-    c = pa_xmalloc(sizeof(pa_cli));
+    c = pa_xnew(pa_cli, 1);
     c->core = core;
-    c->line = pa_ioline_new(io);
-    assert(c->line);
+    pa_assert_se(c->line = pa_ioline_new(io));
 
     c->userdata = NULL;
     c->eof_callback = NULL;
 
     pa_iochannel_socket_peer_to_string(io, cname, sizeof(cname));
-    c->client = pa_client_new(core, __FILE__, cname);
-    assert(c->client);
+    pa_assert_se(c->client = pa_client_new(core, __FILE__, cname));
     c->client->kill = client_kill;
     c->client->userdata = c;
     c->client->owner = m;
@@ -94,7 +92,8 @@
 }
 
 void pa_cli_free(pa_cli *c) {
-    assert(c);
+    pa_assert(c);
+
     pa_ioline_close(c->line);
     pa_ioline_unref(c->line);
     pa_client_free(c->client);
@@ -103,8 +102,9 @@
 
 static void client_kill(pa_client *client) {
     pa_cli *c;
-    assert(client && client->userdata);
-    c = client->userdata;
+
+    pa_assert(client);
+    pa_assert_se(c = client->userdata);
 
     pa_log_debug("CLI client killed.");
     if (c->defer_kill)
@@ -119,7 +119,9 @@
     pa_strbuf *buf;
     pa_cli *c = userdata;
     char *p;
-    assert(line && c);
+
+    pa_assert(line);
+    pa_assert(c);
 
     if (!s) {
         pa_log_debug("CLI got EOF from user.");
@@ -129,8 +131,7 @@
         return;
     }
 
-    buf = pa_strbuf_new();
-    assert(buf);
+    pa_assert_se(buf = pa_strbuf_new());
     c->defer_kill++;
     pa_cli_command_execute_line(c->core, s, buf, &c->fail);
     c->defer_kill--;
@@ -145,7 +146,8 @@
 }
 
 void pa_cli_set_eof_callback(pa_cli *c, void (*cb)(pa_cli*c, void *userdata), void *userdata) {
-    assert(c);
+    pa_assert(c);
+
     c->eof_callback = cb;
     c->userdata = userdata;
 }

Modified: trunk/src/pulsecore/client.c
URL: http://0pointer.de/cgi-bin/viewcvs.cgi/trunk/src/pulsecore/client.c?rev=1971&root=pulseaudio&r1=1970&r2=1971&view=diff
==============================================================================
--- trunk/src/pulsecore/client.c (original)
+++ trunk/src/pulsecore/client.c Sun Oct 28 20:13:50 2007
@@ -27,7 +27,6 @@
 #endif
 
 #include <stdio.h>
-#include <assert.h>
 #include <stdlib.h>
 #include <string.h>
 
@@ -35,15 +34,16 @@
 
 #include <pulsecore/core-subscribe.h>
 #include <pulsecore/log.h>
+#include <pulsecore/macro.h>
 
 #include "client.h"
 
 pa_client *pa_client_new(pa_core *core, const char *driver, const char *name) {
     pa_client *c;
-    int r;
-    assert(core);
 
-    c = pa_xmalloc(sizeof(pa_client));
+    pa_core_assert_ref(core);
+
+    c = pa_xnew(pa_client, 1);
     c->name = pa_xstrdup(name);
     c->driver = pa_xstrdup(driver);
     c->owner = NULL;
@@ -52,10 +52,9 @@
     c->kill = NULL;
     c->userdata = NULL;
 
-    r = pa_idxset_put(core->clients, c, &c->index);
-    assert(c->index != PA_IDXSET_INVALID && r >= 0);
+    pa_assert_se(pa_idxset_put(core->clients, c, &c->index) >= 0);
 
-    pa_log_info("created %u \"%s\"", c->index, c->name);
+    pa_log_info("Created %u \"%s\"", c->index, c->name);
     pa_subscription_post(core, PA_SUBSCRIPTION_EVENT_CLIENT|PA_SUBSCRIPTION_EVENT_NEW, c->index);
 
     pa_core_check_quit(core);
@@ -64,13 +63,14 @@
 }
 
 void pa_client_free(pa_client *c) {
-    assert(c && c->core);
+    pa_assert(c);
+    pa_assert(c->core);
 
     pa_idxset_remove_by_data(c->core->clients, c, NULL);
 
     pa_core_check_quit(c->core);
 
-    pa_log_info("freed %u \"%s\"", c->index, c->name);
+    pa_log_info("Freed %u \"%s\"", 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);
@@ -78,7 +78,8 @@
 }
 
 void pa_client_kill(pa_client *c) {
-    assert(c);
+    pa_assert(c);
+
     if (!c->kill) {
         pa_log_warn("kill() operation not implemented for client %u", c->index);
         return;
@@ -88,9 +89,9 @@
 }
 
 void pa_client_set_name(pa_client *c, const char *name) {
-    assert(c);
+    pa_assert(c);
 
-    pa_log_info("client %u changed name from \"%s\" to \"%s\"", c->index, c->name, name);
+    pa_log_info("Client %u changed name from \"%s\" to \"%s\"", c->index, c->name, name);
 
     pa_xfree(c->name);
     c->name = pa_xstrdup(name);

Modified: trunk/src/pulsecore/conf-parser.c
URL: http://0pointer.de/cgi-bin/viewcvs.cgi/trunk/src/pulsecore/conf-parser.c?rev=1971&root=pulseaudio&r1=1970&r2=1971&view=diff
==============================================================================
--- trunk/src/pulsecore/conf-parser.c (original)
+++ trunk/src/pulsecore/conf-parser.c Sun Oct 28 20:13:50 2007
@@ -25,7 +25,6 @@
 #include <config.h>
 #endif
 
-#include <assert.h>
 #include <string.h>
 #include <stdio.h>
 #include <errno.h>
@@ -35,6 +34,7 @@
 #include <pulsecore/core-error.h>
 #include <pulsecore/log.h>
 #include <pulsecore/core-util.h>
+#include <pulsecore/macro.h>
 
 #include "conf-parser.h"
 
@@ -43,7 +43,10 @@
 
 /* Run the user supplied parser for an assignment */
 static int next_assignment(const char *filename, unsigned line, const pa_config_item *t, const char *lvalue, const char *rvalue, void *userdata) {
-    assert(filename && t && lvalue && rvalue);
+    pa_assert(filename);
+    pa_assert(t);
+    pa_assert(lvalue);
+    pa_assert(rvalue);
 
     for (; t->parse; t++)
         if (!strcmp(lvalue, t->lvalue))
@@ -56,7 +59,7 @@
 
 /* Returns non-zero when c is contained in s */
 static int in_string(char c, const char *s) {
-    assert(s);
+    pa_assert(s);
 
     for (; *s; s++)
         if (*s == c)
@@ -107,7 +110,9 @@
     int r = -1;
     unsigned line = 0;
     int do_close = !f;
-    assert(filename && t);
+
+    pa_assert(filename);
+    pa_assert(t);
 
     if (!f && !(f = fopen(filename, "r"))) {
         if (errno == ENOENT) {
@@ -115,7 +120,7 @@
             goto finish;
         }
 
-        pa_log_warn("WARNING: failed to open configuration file '%s': %s",
+        pa_log_warn("Failed to open configuration file '%s': %s",
             filename, pa_cstrerror(errno));
         goto finish;
     }
@@ -126,7 +131,7 @@
             if (feof(f))
                 break;
 
-            pa_log_warn("WARNING: failed to read configuration file '%s': %s",
+            pa_log_warn("Failed to read configuration file '%s': %s",
                 filename, pa_cstrerror(errno));
             goto finish;
         }
@@ -148,7 +153,11 @@
 int pa_config_parse_int(const char *filename, unsigned line, const char *lvalue, const char *rvalue, void *data, PA_GCC_UNUSED void *userdata) {
     int *i = data;
     int32_t k;
-    assert(filename && lvalue && rvalue && data);
+
+    pa_assert(filename);
+    pa_assert(lvalue);
+    pa_assert(rvalue);
+    pa_assert(data);
 
     if (pa_atoi(rvalue, &k) < 0) {
         pa_log("[%s:%u] Failed to parse numeric value: %s", filename, line, rvalue);
@@ -161,7 +170,11 @@
 
 int pa_config_parse_bool(const char *filename, unsigned line, const char *lvalue, const char *rvalue, void *data, PA_GCC_UNUSED void *userdata) {
     int *b = data, k;
-    assert(filename && lvalue && rvalue && data);
+
+    pa_assert(filename);
+    pa_assert(lvalue);
+    pa_assert(rvalue);
+    pa_assert(data);
 
     if ((k = pa_parse_boolean(rvalue)) < 0) {
         pa_log("[%s:%u] Failed to parse boolean value: %s", filename, line, rvalue);
@@ -175,7 +188,11 @@
 
 int pa_config_parse_string(const char *filename, PA_GCC_UNUSED unsigned line, const char *lvalue, const char *rvalue, void *data, PA_GCC_UNUSED void *userdata) {
     char **s = data;
-    assert(filename && lvalue && rvalue && data);
+
+    pa_assert(filename);
+    pa_assert(lvalue);
+    pa_assert(rvalue);
+    pa_assert(data);
 
     pa_xfree(*s);
     *s = *rvalue ? pa_xstrdup(rvalue) : NULL;

Modified: trunk/src/pulsecore/core-def.h
URL: http://0pointer.de/cgi-bin/viewcvs.cgi/trunk/src/pulsecore/core-def.h?rev=1971&root=pulseaudio&r1=1970&r2=1971&view=diff
==============================================================================
--- trunk/src/pulsecore/core-def.h (original)
+++ trunk/src/pulsecore/core-def.h Sun Oct 28 20:13:50 2007
@@ -24,9 +24,6 @@
   USA.
 ***/
 
-typedef enum pa_mixer {
-    PA_MIXER_SOFTWARE,
-    PA_MIXER_HARDWARE
-} pa_mixer_t;
+/* FIXME: Remove this shit */
 
 #endif

Modified: trunk/src/pulsecore/core-error.c
URL: http://0pointer.de/cgi-bin/viewcvs.cgi/trunk/src/pulsecore/core-error.c?rev=1971&root=pulseaudio&r1=1970&r2=1971&view=diff
==============================================================================
--- trunk/src/pulsecore/core-error.c (original)
+++ trunk/src/pulsecore/core-error.c Sun Oct 28 20:13:50 2007
@@ -31,178 +31,50 @@
 #include <stdlib.h>
 #include <string.h>
 
-#ifdef HAVE_PTHREAD
-#include <pthread.h>
-#endif
-
-#ifdef HAVE_WINDOWS_H
-#include <windows.h>
-#endif
-
 #include <pulse/utf8.h>
 #include <pulse/xmalloc.h>
 
 #include <pulsecore/core-util.h>
 #include <pulsecore/native-common.h>
+#include <pulsecore/thread.h>
+#include <pulsecore/macro.h>
+#include <pulsecore/log.h>
 
 #include "core-error.h"
 
-#ifdef HAVE_PTHREAD
+PA_STATIC_TLS_DECLARE(cstrerror, pa_xfree);
 
-static pthread_once_t cstrerror_once = PTHREAD_ONCE_INIT;
-static pthread_key_t tlsstr_key;
+const char* pa_cstrerror(int errnum) {
+    const char *original = NULL;
+    char *translated, *t;
+    char errbuf[128];
 
-static void inittls(void) {
-    int ret;
+    if ((t = PA_STATIC_TLS_GET(cstrerror)))
+        pa_xfree(t);
 
-    ret = pthread_key_create(&tlsstr_key, pa_xfree);
-    if (ret) {
-        fprintf(stderr, __FILE__ ": CRITICAL: Unable to allocate TLS key (%d)\n", errno);
-        exit(-1);
+#if defined(HAVE_STRERROR_R) && defined(__GLIBC__)
+    original = strerror_r(errnum, errbuf, sizeof(errbuf));
+#elif defined(HAVE_STRERROR_R)
+    if (strerror_r(errnum, errbuf, sizeof(errbuf)) == 0) {
+        errbuf[sizeof(errbuf) - 1] = 0;
+        original = errbuf;
     }
-}
+#else
+    /* This might not be thread safe, but we hope for the best */
+    original = strerror(errnum);
+#endif
 
-#elif HAVE_WINDOWS_H
-
-static DWORD tlsstr_key = TLS_OUT_OF_INDEXES;
-static DWORD monitor_key = TLS_OUT_OF_INDEXES;
-
-static void inittls(void) {
-    HANDLE mutex;
-    char name[64];
-
-    sprintf(name, "pulse%d", (int)GetCurrentProcessId());
-
-    mutex = CreateMutex(NULL, FALSE, name);
-    if (!mutex) {
-        fprintf(stderr, __FILE__ ": CRITICAL: Unable to create named mutex (%d)\n", (int)GetLastError());
-        exit(-1);
+    if (!original) {
+        pa_snprintf(errbuf, sizeof(errbuf), "Unknown error %i", errnum);
+        original = errbuf;
     }
 
-    WaitForSingleObject(mutex, INFINITE);
-
-    if (tlsstr_key == TLS_OUT_OF_INDEXES) {
-        tlsstr_key = TlsAlloc();
-        monitor_key = TlsAlloc();
-        if ((tlsstr_key == TLS_OUT_OF_INDEXES) || (monitor_key == TLS_OUT_OF_INDEXES)) {
-            fprintf(stderr, __FILE__ ": CRITICAL: Unable to allocate TLS key (%d)\n", (int)GetLastError());
-            exit(-1);
-        }
+    if (!(translated = pa_locale_to_utf8(original))) {
+        pa_log_warn("Unable to convert error string to locale, filtering.");
+        translated = pa_utf8_filter(original);
     }
 
-    ReleaseMutex(mutex);
+    PA_STATIC_TLS_SET(cstrerror, translated);
 
-    CloseHandle(mutex);
+    return translated;
 }
-
-/*
- * This is incredibly brain dead, but this is necessary when dealing with
- * the hell that is Win32.
- */
-struct monitor_data {
-    HANDLE thread;
-    void *data;
-};
-
-static DWORD WINAPI monitor_thread(LPVOID param) {
-    struct monitor_data *data;
-
-    data = (struct monitor_data*)param;
-    assert(data);
-
-    WaitForSingleObject(data->thread, INFINITE);
-
-    CloseHandle(data->thread);
-    pa_xfree(data->data);
-    pa_xfree(data);
-
-    return 0;
-}
-
-static void start_monitor(void) {
-    HANDLE thread;
-    struct monitor_data *data;
-
-    data = pa_xnew(struct monitor_data, 1);
-    assert(data);
-
-    DuplicateHandle(GetCurrentProcess(), GetCurrentThread(),
-        GetCurrentProcess(), &data->thread, 0, FALSE, DUPLICATE_SAME_ACCESS);
-
-    thread = CreateThread(NULL, 0, monitor_thread, data, 0, NULL);
-    assert(thread);
-
-    TlsSetValue(monitor_key, data);
-
-    CloseHandle(thread);
-}
-
-#else
-
-/* Unsafe, but we have no choice */
-static char *tlsstr;
-
-#endif
-
-const char* pa_cstrerror(int errnum) {
-    const char *origbuf;
-
-#ifdef HAVE_STRERROR_R
-    char errbuf[128];
-#endif
-
-#ifdef HAVE_PTHREAD
-    char *tlsstr;
-
-    pthread_once(&cstrerror_once, inittls);
-
-    tlsstr = pthread_getspecific(tlsstr_key);
-#elif defined(HAVE_WINDOWS_H)
-    char *tlsstr;
-    struct monitor_data *data;
-
-    inittls();
-
-    tlsstr = TlsGetValue(tlsstr_key);
-    if (!tlsstr)
-        start_monitor();
-    data = TlsGetValue(monitor_key);
-#endif
-
-    if (tlsstr)
-        pa_xfree(tlsstr);
-
-#ifdef HAVE_STRERROR_R
-
-#ifdef __GLIBC__
-    origbuf = strerror_r(errnum, errbuf, sizeof(errbuf));
-    if (origbuf == NULL)
-        origbuf = "";
-#else
-    if (strerror_r(errnum, errbuf, sizeof(errbuf)) == 0) {
-        origbuf = errbuf;
-        errbuf[sizeof(errbuf) - 1] = '\0';
-    } else
-        origbuf = "";
-#endif
-
-#else
-    /* This might not be thread safe, but we hope for the best */
-    origbuf = strerror(errnum);
-#endif
-
-    tlsstr = pa_locale_to_utf8(origbuf);
-    if (!tlsstr) {
-        fprintf(stderr, "Unable to convert, filtering\n");
-        tlsstr = pa_utf8_filter(origbuf);
-    }
-
-#ifdef HAVE_PTHREAD
-    pthread_setspecific(tlsstr_key, tlsstr);
-#elif defined(HAVE_WINDOWS_H)
-    TlsSetValue(tlsstr_key, tlsstr);
-    data->data = tlsstr;
-#endif
-
-    return tlsstr;
-}

Modified: trunk/src/pulsecore/core-scache.c
URL: http://0pointer.de/cgi-bin/viewcvs.cgi/trunk/src/pulsecore/core-scache.c?rev=1971&root=pulseaudio&r1=1970&r2=1971&view=diff
==============================================================================
--- trunk/src/pulsecore/core-scache.c (original)
+++ trunk/src/pulsecore/core-scache.c Sun Oct 28 20:13:50 2007
@@ -26,7 +26,6 @@
 #include <config.h>
 #endif
 
-#include <assert.h>
 #include <stdlib.h>
 #include <string.h>
 #include <stdio.h>
@@ -60,6 +59,7 @@
 #include <pulsecore/core-util.h>
 #include <pulsecore/log.h>
 #include <pulsecore/core-error.h>
+#include <pulsecore/macro.h>
 
 #include "core-scache.h"
 
@@ -68,7 +68,10 @@
 static void timeout_callback(pa_mainloop_api *m, pa_time_event*e, PA_GCC_UNUSED const struct timeval *tv, void *userdata) {
     pa_core *c = userdata;
     struct timeval ntv;
-    assert(c && c->mainloop == m && c->scache_auto_unload_event == e);
+
+    pa_assert(c);
+    pa_assert(c->mainloop == m);
+    pa_assert(c->scache_auto_unload_event == e);
 
     pa_scache_unload_unused(c);
 
@@ -78,7 +81,8 @@
 }
 
 static void free_entry(pa_scache_entry *e) {
-    assert(e);
+    pa_assert(e);
+
     pa_namereg_unregister(e->core, e->name);
     pa_subscription_post(e->core, PA_SUBSCRIPTION_EVENT_SAMPLE_CACHE|PA_SUBSCRIPTION_EVENT_REMOVE, e->index);
     pa_xfree(e->name);
@@ -90,7 +94,9 @@
 
 static pa_scache_entry* scache_add_item(pa_core *c, const char *name) {
     pa_scache_entry *e;
-    assert(c && name);
+
+    pa_assert(c);
+    pa_assert(name);
 
     if ((e = pa_namereg_get(c, name, PA_NAMEREG_SAMPLE, 0))) {
         if (e->memchunk.memblock)
@@ -98,11 +104,11 @@
 
         pa_xfree(e->filename);
 
-        assert(e->core == c);
+        pa_assert(e->core == c);
 
         pa_subscription_post(c, PA_SUBSCRIPTION_EVENT_SAMPLE_CACHE|PA_SUBSCRIPTION_EVENT_CHANGE, e->index);
     } else {
-        e = pa_xmalloc(sizeof(pa_scache_entry));
+        e = pa_xnew(pa_scache_entry, 1);
 
         if (!pa_namereg_register(c, name, PA_NAMEREG_SAMPLE, e, 1)) {
             pa_xfree(e);
@@ -114,7 +120,7 @@
 
         if (!c->scache) {
             c->scache = pa_idxset_new(pa_idxset_trivial_hash_func, pa_idxset_trivial_compare_func);
-            assert(c->scache);
+            pa_assert(c->scache);
         }
 
         pa_idxset_put(c->scache, e, &e->index);
@@ -139,7 +145,9 @@
 int pa_scache_add_item(pa_core *c, const char *name, const pa_sample_spec *ss, const pa_channel_map *map, const pa_memchunk *chunk, uint32_t *idx) {
     pa_scache_entry *e;
     char st[PA_SAMPLE_SPEC_SNPRINT_MAX];
-    assert(c && name);
+
+    pa_assert(c);
+    pa_assert(name);
 
     if (chunk && chunk->length > PA_SCACHE_ENTRY_SIZE_MAX)
         return -1;
@@ -164,9 +172,9 @@
     if (idx)
         *idx = e->index;
 
-    pa_log_debug("created sample \"%s\" (#%d), %d bytes with sample spec %s",
-        name, e->index, e->memchunk.length,
-        pa_sample_spec_snprint(st, sizeof(st), &e->sample_spec));
+    pa_log_debug("Created sample \"%s\" (#%d), %lu bytes with sample spec %s",
+                 name, e->index, (unsigned long) e->memchunk.length,
+                 pa_sample_spec_snprint(st, sizeof(st), &e->sample_spec));
 
     return 0;
 }
@@ -184,6 +192,10 @@
         filename = buf;
 #endif
 
+    pa_assert(c);
+    pa_assert(name);
+    pa_assert(filename);
+
     if (pa_sound_file_load(c->mempool, filename, &ss, &map, &chunk) < 0)
         return -1;
 
@@ -203,7 +215,9 @@
         filename = buf;
 #endif
 
-    assert(c && name);
+    pa_assert(c);
+    pa_assert(name);
+    pa_assert(filename);
 
     if (!(e = scache_add_item(c, name)))
         return -1;
@@ -226,15 +240,17 @@
 
 int pa_scache_remove_item(pa_core *c, const char *name) {
     pa_scache_entry *e;
-    assert(c && name);
+
+    pa_assert(c);
+    pa_assert(name);
 
     if (!(e = pa_namereg_get(c, name, PA_NAMEREG_SAMPLE, 0)))
         return -1;
 
     if (pa_idxset_remove_by_data(c->scache, e, NULL) != e)
-        assert(0);
-
-    pa_log_debug("removed sample \"%s\"", name);
+        pa_assert(0);
+
+    pa_log_debug("Removed sample \"%s\"", name);
 
     free_entry(e);
 
@@ -243,12 +259,13 @@
 
 static void free_cb(void *p, PA_GCC_UNUSED void *userdata) {
     pa_scache_entry *e = p;
-    assert(e);
+    pa_assert(e);
+
     free_entry(e);
 }
 
 void pa_scache_free(pa_core *c) {
-    assert(c);
+    pa_assert(c);
 
     if (c->scache) {
         pa_idxset_free(c->scache, free_cb, NULL);
@@ -264,9 +281,9 @@
     char *t;
     pa_cvolume r;
 
-    assert(c);
-    assert(name);
-    assert(sink);
+    pa_assert(c);
+    pa_assert(name);
+    pa_assert(sink);
 
     if (!(e = pa_namereg_get(c, name, PA_NAMEREG_SAMPLE, 1)))
         return -1;
@@ -284,7 +301,7 @@
     if (!e->memchunk.memblock)
         return -1;
 
-    pa_log_debug("playing sample \"%s\" on \"%s\"", name, sink->name);
+    pa_log_debug("Playing sample \"%s\" on \"%s\"", name, sink->name);
 
     t = pa_sprintf_malloc("sample:%s", name);
 
@@ -304,9 +321,23 @@
     return 0;
 }
 
+int pa_scache_play_item_by_name(pa_core *c, const char *name, const char*sink_name, pa_volume_t volume, int autoload) {
+    pa_sink *sink;
+
+    pa_assert(c);
+    pa_assert(name);
+
+    if (!(sink = pa_namereg_get(c, sink_name, PA_NAMEREG_SINK, autoload)))
+        return -1;
+
+    return pa_scache_play_item(c, name, sink, volume);
+}
+
 const char * pa_scache_get_name_by_id(pa_core *c, uint32_t id) {
     pa_scache_entry *e;
-    assert(c && id != PA_IDXSET_INVALID);
+
+    pa_assert(c);
+    pa_assert(id != PA_IDXSET_INVALID);
 
     if (!c->scache || !(e = pa_idxset_get_by_index(c->scache, id)))
         return NULL;
@@ -316,7 +347,9 @@
 
 uint32_t pa_scache_get_id_by_name(pa_core *c, const char *name) {
     pa_scache_entry *e;
-    assert(c && name);
+
+    pa_assert(c);
+    pa_assert(name);
 
     if (!(e = pa_namereg_get(c, name, PA_NAMEREG_SAMPLE, 0)))
         return PA_IDXSET_INVALID;
@@ -327,7 +360,8 @@
 uint32_t pa_scache_total_size(pa_core *c) {
     pa_scache_entry *e;
     uint32_t idx, sum = 0;
-    assert(c);
+
+    pa_assert(c);
 
     if (!c->scache || !pa_idxset_size(c->scache))
         return 0;
@@ -343,7 +377,8 @@
     pa_scache_entry *e;
     time_t now;
     uint32_t idx;
-    assert(c);
+
+    pa_assert(c);
 
     if (!c->scache || !pa_idxset_size(c->scache))
         return;
@@ -370,6 +405,9 @@
     struct stat st;
     const char *e;
 
+    pa_core_assert_ref(c);
+    pa_assert(pathname);
+
     e = pa_path_get_filename(pathname);
 
     if (stat(pathname, &st) < 0) {
@@ -385,7 +423,9 @@
 
 int pa_scache_add_directory_lazy(pa_core *c, const char *pathname) {
     DIR *dir;
-    assert(c && pathname);
+
+    pa_core_assert_ref(c);
+    pa_assert(pathname);
 
     /* First try to open this as directory */
     if (!(dir = opendir(pathname))) {
@@ -415,7 +455,7 @@
             if (e->d_name[0] == '.')
                 continue;
 
-            snprintf(p, sizeof(p), "%s/%s", pathname, e->d_name);
+            pa_snprintf(p, sizeof(p), "%s/%s", pathname, e->d_name);
             add_file(c, p);
         }
     }

Modified: trunk/src/pulsecore/core-scache.h
URL: http://0pointer.de/cgi-bin/viewcvs.cgi/trunk/src/pulsecore/core-scache.h?rev=1971&root=pulseaudio&r1=1970&r2=1971&view=diff
==============================================================================
--- trunk/src/pulsecore/core-scache.h (original)
+++ trunk/src/pulsecore/core-scache.h Sun Oct 28 20:13:50 2007
@@ -55,6 +55,7 @@
 
 int pa_scache_remove_item(pa_core *c, const char *name);
 int pa_scache_play_item(pa_core *c, const char *name, pa_sink *sink, pa_volume_t volume);
+int pa_scache_play_item_by_name(pa_core *c, const char *name, const char*sink_name, pa_volume_t volume, int autoload);
 void pa_scache_free(pa_core *c);
 
 const char *pa_scache_get_name_by_id(pa_core *c, uint32_t id);

Modified: trunk/src/pulsecore/core-subscribe.c
URL: http://0pointer.de/cgi-bin/viewcvs.cgi/trunk/src/pulsecore/core-subscribe.c?rev=1971&root=pulseaudio&r1=1970&r2=1971&view=diff
==============================================================================
--- trunk/src/pulsecore/core-subscribe.c (original)
+++ trunk/src/pulsecore/core-subscribe.c Sun Oct 28 20:13:50 2007
@@ -26,12 +26,12 @@
 #endif
 
 #include <stdio.h>
-#include <assert.h>
 
 #include <pulse/xmalloc.h>
 
 #include <pulsecore/queue.h>
 #include <pulsecore/log.h>
+#include <pulsecore/macro.h>
 
 #include "core-subscribe.h"
 
@@ -68,9 +68,9 @@
 pa_subscription* pa_subscription_new(pa_core *c, pa_subscription_mask_t m, pa_subscription_cb_t callback, void *userdata) {
     pa_subscription *s;
 
-    assert(c);
-    assert(m);
-    assert(callback);
+    pa_assert(c);
+    pa_assert(m);
+    pa_assert(callback);
 
     s = pa_xnew(pa_subscription, 1);
     s->core = c;
@@ -85,24 +85,24 @@
 
 /* Free a subscription object, effectively marking it for deletion */
 void pa_subscription_free(pa_subscription*s) {
-    assert(s);
-    assert(!s->dead);
+    pa_assert(s);
+    pa_assert(!s->dead);
 
     s->dead = 1;
     sched_event(s->core);
 }
 
 static void free_subscription(pa_subscription *s) {
-    assert(s);
-    assert(s->core);
+    pa_assert(s);
+    pa_assert(s->core);
 
     PA_LLIST_REMOVE(pa_subscription, s->core->subscriptions, s);
     pa_xfree(s);
 }
 
 static void free_event(pa_subscription_event *s) {
-    assert(s);
-    assert(s->core);
+    pa_assert(s);
+    pa_assert(s->core);
 
     if (!s->next)
         s->core->subscription_event_last = s->prev;
@@ -113,7 +113,7 @@
 
 /* Free all subscription objects */
 void pa_subscription_free_all(pa_core *c) {
-    assert(c);
+    pa_assert(c);
 
     while (c->subscriptions)
         free_subscription(c->subscriptions);
@@ -160,9 +160,9 @@
     pa_core *c = userdata;
     pa_subscription *s;
 
-    assert(c->mainloop == m);
-    assert(c);
-    assert(c->subscription_defer_event == de);
+    pa_assert(c->mainloop == m);
+    pa_assert(c);
+    pa_assert(c->subscription_defer_event == de);
 
     c->mainloop->defer_enable(c->subscription_defer_event, 0);
 
@@ -196,20 +196,20 @@
 
 /* Schedule an mainloop event so that a pending subscription event is dispatched */
 static void sched_event(pa_core *c) {
-    assert(c);
+    pa_assert(c);
 
     if (!c->subscription_defer_event) {
         c->subscription_defer_event = c->mainloop->defer_new(c->mainloop, defer_cb, c);
-        assert(c->subscription_defer_event);
+        pa_assert(c->subscription_defer_event);
     }
 
     c->mainloop->defer_enable(c->subscription_defer_event, 1);
 }
 
 /* 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);
+    pa_assert(c);
 
     /* No need for queuing subscriptions of noone is listening */
     if (!c->subscriptions)
@@ -227,7 +227,7 @@
                 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 @@
     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;

Modified: trunk/src/pulsecore/core-util.c
URL: http://0pointer.de/cgi-bin/viewcvs.cgi/trunk/src/pulsecore/core-util.c?rev=1971&root=pulseaudio&r1=1970&r2=1971&view=diff
==============================================================================
--- trunk/src/pulsecore/core-util.c (original)
+++ trunk/src/pulsecore/core-util.c Sun Oct 28 20:13:50 2007
@@ -31,7 +31,6 @@
 #include <stdlib.h>
 #include <signal.h>
 #include <errno.h>
-#include <assert.h>
 #include <string.h>
 #include <stdio.h>
 #include <fcntl.h>
@@ -43,6 +42,10 @@
 #include <sys/stat.h>
 #include <sys/time.h>
 
+#ifdef HAVE_STRTOF_L
+#include <locale.h>
+#endif
+
 #ifdef HAVE_SCHED_H
 #include <sched.h>
 #endif
@@ -55,6 +58,10 @@
 #include <sys/capability.h>
 #endif
 
+#ifdef HAVE_SYS_MMAN_H
+#include <sys/mman.h>
+#endif
+
 #ifdef HAVE_PTHREAD
 #include <pthread.h>
 #endif
@@ -75,14 +82,19 @@
 #include <grp.h>
 #endif
 
+#ifdef HAVE_LIBSAMPLERATE
 #include <samplerate.h>
+#endif
 
 #include <pulse/xmalloc.h>
 #include <pulse/util.h>
+#include <pulse/utf8.h>
 
 #include <pulsecore/core-error.h>
 #include <pulsecore/winsock.h>
 #include <pulsecore/log.h>
+#include <pulsecore/macro.h>
+#include <pulsecore/thread.h>
 
 #include "core-util.h"
 
@@ -93,10 +105,8 @@
 
 #ifndef OS_IS_WIN32
 #define PA_USER_RUNTIME_PATH_PREFIX "/tmp/pulse-"
-#define PATH_SEP '/'
 #else
 #define PA_USER_RUNTIME_PATH_PREFIX "%TEMP%\\pulse-"
-#define PATH_SEP '\\'
 #endif
 
 #ifdef OS_IS_WIN32
@@ -111,7 +121,7 @@
     if (!GetModuleFileName(handle, library_path + sizeof(PULSE_ROOTENV), MAX_PATH))
         return 0;
 
-    sep = strrchr(library_path, '\\');
+    sep = strrchr(library_path, PA_PATH_SEP_CHAR);
     if (sep)
         *sep = '\0';
 
@@ -124,23 +134,42 @@
 #endif
 
 /** Make a file descriptor nonblock. Doesn't do any error checking */
-void pa_make_nonblock_fd(int fd) {
+void pa_make_fd_nonblock(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);
+    pa_assert(fd >= 0);
+
+    pa_assert_se((v = fcntl(fd, F_GETFL)) >= 0);
+
+    if (!(v & O_NONBLOCK))
+        pa_assert_se(fcntl(fd, F_SETFL, v|O_NONBLOCK) >= 0);
+
 #elif defined(OS_IS_WIN32)
     u_long arg = 1;
     if (ioctlsocket(fd, FIONBIO, &arg) < 0) {
-        if (WSAGetLastError() == WSAENOTSOCK)
-            pa_log_warn("WARNING: Only sockets can be made non-blocking!");
+        pa_assert_se(WSAGetLastError() == WSAENOTSOCK);
+        pa_log_warn("Only sockets can be made non-blocking!");
     }
 #else
-    pa_log_warn("WARNING: Non-blocking I/O not supported.!");
-#endif
+    pa_log_warn("Non-blocking I/O not supported.!");
+#endif
+
+}
+
+/* Set the FD_CLOEXEC flag for a fd */
+void pa_make_fd_cloexec(int fd) {
+
+#ifdef FD_CLOEXEC
+    int v;
+    pa_assert(fd >= 0);
+
+    pa_assert_se((v = fcntl(fd, F_GETFD, 0)) >= 0);
+
+    if (!(v & FD_CLOEXEC))
+        pa_assert_se(fcntl(fd, F_SETFD, v|FD_CLOEXEC) >= 0);
+#endif
+
 }
 
 /** Creates a directory securely */
@@ -148,7 +177,7 @@
     struct stat st;
     int r;
 
-    assert(dir);
+    pa_assert(dir);
 
 #ifdef OS_IS_WIN32
     r = mkdir(dir);
@@ -169,7 +198,7 @@
         uid = getuid();
     if (gid == (gid_t)-1)
         gid = getgid();
-    chown(dir, uid, gid);
+    (void) chown(dir, uid, gid);
 #endif
 
 #ifdef HAVE_CHMOD
@@ -295,9 +324,9 @@
     ssize_t ret = 0;
     int _type;
 
-    assert(fd >= 0);
-    assert(data);
-    assert(size);
+    pa_assert(fd >= 0);
+    pa_assert(data);
+    pa_assert(size);
 
     if (!type) {
         _type = 0;
@@ -326,9 +355,9 @@
     ssize_t ret = 0;
     int _type;
 
-    assert(fd >= 0);
-    assert(data);
-    assert(size);
+    pa_assert(fd >= 0);
+    pa_assert(data);
+    pa_assert(size);
 
     if (!type) {
         _type = 0;
@@ -354,13 +383,12 @@
 
 /** Platform independent read function. Necessary since not all
  * systems treat all file descriptors equal. */
-int pa_close(int fd)
-{
+int pa_close(int fd) {
+
 #ifdef OS_IS_WIN32
     int ret;
 
-    ret = closesocket(fd);
-    if (ret == 0)
+    if ((ret = closesocket(fd)) == 0)
         return 0;
 
     if (WSAGetLastError() != WSAENOTSOCK) {
@@ -407,9 +435,9 @@
     if (sa.sa_handler != SIG_DFL)
         return;
 
-    pa_log("WARNING: %s is not trapped. This might cause malfunction!", pa_strsignal(sig));
+    pa_log_warn("%s is not trapped. This might cause malfunction!", pa_sig2str(sig));
 #else /* HAVE_SIGACTION */
-    pa_log("WARNING: %s might not be trapped. This might cause malfunction!", pa_strsignal(sig));
+    pa_log_warn("%s might not be trapped. This might cause malfunction!", pa_sig2str(sig));
 #endif
 }
 
@@ -419,7 +447,7 @@
     int  size = 100;
     char *c = NULL;
 
-    assert(format);
+    pa_assert(format);
 
     for(;;) {
         int r;
@@ -430,6 +458,8 @@
         va_start(ap, format);
         r = vsnprintf(c, size, format, ap);
         va_end(ap);
+
+        c[size-1] = 0;
 
         if (r > -1 && r < size)
             return c;
@@ -447,18 +477,19 @@
     int  size = 100;
     char *c = NULL;
 
-    assert(format);
+    pa_assert(format);
 
     for(;;) {
         int r;
         va_list aq;
 
+        c = pa_xrealloc(c, size);
+
         va_copy(aq, ap);
-
-        c = pa_xrealloc(c, size);
         r = vsnprintf(c, size, format, aq);
-
         va_end(aq);
+
+        c[size-1] = 0;
 
         if (r > -1 && r < size)
             return c;
@@ -472,35 +503,46 @@
 
 /* Similar to OpenBSD's strlcpy() function */
 char *pa_strlcpy(char *b, const char *s, size_t l) {
-    assert(b && s && l > 0);
+    pa_assert(b);
+    pa_assert(s);
+    pa_assert(l > 0);
 
     strncpy(b, s, l);
     b[l-1] = 0;
     return b;
 }
 
-#define NICE_LEVEL (-15)
+/* Make the current thread a realtime thread*/
+void pa_make_realtime(void) {
+
+#ifdef _POSIX_PRIORITY_SCHEDULING
+    struct sched_param sp;
+    int r, policy;
+
+    memset(&sp, 0, sizeof(sp));
+    policy = 0;
+
+    if ((r = pthread_getschedparam(pthread_self(), &policy, &sp)) != 0) {
+        pa_log("pthread_getschedgetparam(): %s", pa_cstrerror(r));
+        return;
+    }
+
+    sp.sched_priority = 1;
+    if ((r = pthread_setschedparam(pthread_self(), SCHED_FIFO, &sp)) != 0) {
+        pa_log_warn("pthread_setschedparam(): %s", pa_cstrerror(r));
+        return;
+    }
+
+    pa_log_info("Successfully enabled SCHED_FIFO scheduling for thread.");
+#endif
+
+}
+
+#define NICE_LEVEL (-11)
 
 /* Raise the priority of the current process as much as possible and
-sensible: set the nice level to -15 and enable realtime scheduling if
-supported.*/
+sensible: set the nice level to -15.*/
 void pa_raise_priority(void) {
-#if defined(HAVE_SYS_CAPABILITY_H)
-    cap_t caps;
-
-    /* Temporarily acquire CAP_SYS_NICE in the effective set */
-    if ((caps = cap_get_proc())) {
-        cap_t caps_new;
-        cap_value_t nice_cap = CAP_SYS_NICE;
-
-        if ((caps_new = cap_dup(caps))) {
-            cap_set_flag(caps_new, CAP_EFFECTIVE, 1, &nice_cap, CAP_SET);
-            cap_set_flag(caps_new, CAP_PERMITTED, 1, &nice_cap, CAP_SET);
-            cap_set_proc(caps_new);
-            cap_free(caps_new);
-        }
-    }
-#endif
 
 #ifdef HAVE_SYS_RESOURCE_H
     if (setpriority(PRIO_PROCESS, 0, NICE_LEVEL) < 0)
@@ -509,84 +551,24 @@
         pa_log_info("Successfully gained nice level %i.", NICE_LEVEL);
 #endif
 
-#ifdef _POSIX_PRIORITY_SCHEDULING
-    {
-        struct sched_param sp;
-
-        if (sched_getparam(0, &sp) < 0) {
-            pa_log("sched_getparam(): %s", pa_cstrerror(errno));
-            goto fail;
-        }
-
-        sp.sched_priority = 1;
-        if (sched_setscheduler(0, SCHED_FIFO, &sp) < 0) {
-            pa_log_warn("sched_setscheduler(): %s", pa_cstrerror(errno));
-            goto fail;
-        }
-
-        pa_log_info("Successfully enabled SCHED_FIFO scheduling.");
-    }
-#endif
-
 #ifdef OS_IS_WIN32
     if (!SetPriorityClass(GetCurrentProcess(), HIGH_PRIORITY_CLASS))
         pa_log_warn("SetPriorityClass() failed: 0x%08X", GetLastError());
     else
         pa_log_info("Successfully gained high priority class.");
 #endif
-
-fail:
-
-#if defined(HAVE_SYS_CAPABILITY_H)
-    if (caps) {
-        /* Restore original caps */
-        cap_set_proc(caps);
-        cap_free(caps);
-    }
-#endif
-
-    ; /* We put this here to get the code to compile when
-       * HAVE_SYS_CAPABILITY_H is not defined. Don't remove unless you
-       * know what you do */
-}
-
-/* Reset the priority to normal, inverting the changes made by pa_raise_priority() */
+}
+
+/* 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;
-        sched_getparam(0, &sp);
-        sp.sched_priority = 0;
-        sched_setscheduler(0, SCHED_OTHER, &sp);
-    }
-#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);
-
-    if ((v = fcntl(fd, F_GETFD, 0)) < 0)
-        return -1;
-
-    v = (v & ~FD_CLOEXEC) | (b ? FD_CLOEXEC : 0);
-
-    if (fcntl(fd, F_SETFD, v) < 0)
-        return -1;
-#endif
-
-    return 0;
 }
 
 /* Try to parse a boolean string value.*/
@@ -639,31 +621,134 @@
     return pa_xstrndup(current, l);
 }
 
-/* Return the name of an UNIX signal. Similar to GNU's strsignal() */
-const char *pa_strsignal(int sig) {
+PA_STATIC_TLS_DECLARE(signame, pa_xfree);
+
+/* Return the name of an UNIX signal. Similar to Solaris sig2str() */
+const char *pa_sig2str(int sig) {
+    char *t;
+
+    if (sig <= 0)
+        goto fail;
+
+#ifdef NSIG
+    if (sig >= NSIG)
+        goto fail;
+#endif
+
+#ifdef HAVE_SIG2STR
+    {
+        char buf[SIG2STR_MAX];
+
+        if (sig2str(sig, buf) == 0) {
+            pa_xfree(PA_STATIC_TLS_GET(signame));
+            t = pa_sprintf_malloc("SIG%s", buf);
+            PA_STATIC_TLS_SET(signame, t);
+            return t;
+        }
+    }
+#else
+
     switch(sig) {
-        case SIGINT: return "SIGINT";
-        case SIGTERM: return "SIGTERM";
+#ifdef SIGHUP
+        case SIGHUP:    return "SIGHUP";
+#endif
+        case SIGINT:    return "SIGINT";
+#ifdef SIGQUIT
+        case SIGQUIT:   return "SIGQUIT";
+#endif
+        case SIGILL:    return "SIGULL";
+#ifdef SIGTRAP
+        case SIGTRAP:   return "SIGTRAP";
+#endif
+        case SIGABRT:   return "SIGABRT";
+#ifdef SIGBUS
+        case SIGBUS:    return "SIGBUS";
+#endif
+        case SIGFPE:    return "SIGFPE";
+#ifdef SIGKILL
+        case SIGKILL:   return "SIGKILL";
+#endif
 #ifdef SIGUSR1
-        case SIGUSR1: return "SIGUSR1";
-#endif
+        case SIGUSR1:   return "SIGUSR1";
+#endif
+        case SIGSEGV:   return "SIGSEGV";
 #ifdef SIGUSR2
-        case SIGUSR2: return "SIGUSR2";
+        case SIGUSR2:   return "SIGUSR2";
+#endif
+#ifdef SIGPIPE
+        case SIGPIPE:   return "SIGPIPE";
+#endif
+#ifdef SIGALRM
+        case SIGALRM:   return "SIGALRM";
+#endif
+        case SIGTERM:   return "SIGTERM";
+#ifdef SIGSTKFLT
+        case SIGSTKFLT: return "SIGSTKFLT";
+#endif
+#ifdef SIGCHLD
+        case SIGCHLD:   return "SIGCHLD";
+#endif
+#ifdef SIGCONT
+        case SIGCONT:   return "SIGCONT";
+#endif
+#ifdef SIGSTOP
+        case SIGSTOP:   return "SIGSTOP";
+#endif
+#ifdef SIGTSTP
+        case SIGTSTP:   return "SIGTSTP";
+#endif
+#ifdef SIGTTIN
+        case SIGTTIN:   return "SIGTTIN";
+#endif
+#ifdef SIGTTOU
+        case SIGTTOU:   return "SIGTTOU";
+#endif
+#ifdef SIGURG
+        case SIGURG:    return "SIGURG";
 #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";
-    }
+        case SIGXCPU:   return "SIGXCPU";
+#endif
+#ifdef SIGXFSZ
+        case SIGXFSZ:   return "SIGXFSZ";
+#endif
+#ifdef SIGVTALRM
+        case SIGVTALRM: return "SIGVTALRM";
+#endif
+#ifdef SIGPROF
+        case SIGPROF:   return "SIGPROF";
+#endif
+#ifdef SIGWINCH
+        case SIGWINCH:  return "SIGWINCH";
+#endif
+#ifdef SIGIO
+        case SIGIO:     return "SIGIO";
+#endif
+#ifdef SIGPWR
+        case SIGPWR:    return "SIGPWR";
+#endif
+#ifdef SIGSYS
+        case SIGSYS:    return "SIGSYS";
+#endif
+    }
+
+#ifdef SIGRTMIN
+    if (sig >= SIGRTMIN && sig <= SIGRTMAX) {
+        pa_xfree(PA_STATIC_TLS_GET(signame));
+        t = pa_sprintf_malloc("SIGRTMIN+%i", sig - SIGRTMIN);
+        PA_STATIC_TLS_SET(signame, t);
+        return t;
+    }
+#endif
+
+#endif
+
+fail:
+
+    pa_xfree(PA_STATIC_TLS_GET(signame));
+    t = pa_sprintf_malloc("SIG%i", sig);
+    PA_STATIC_TLS_SET(signame, t);
+    return t;
 }
 
 #ifdef HAVE_GRP_H
@@ -715,7 +800,7 @@
     int n = sysconf(_SC_NGROUPS_MAX);
     int r = -1, i;
 
-    assert(n > 0);
+    pa_assert(n > 0);
 
     gids = pa_xmalloc(sizeof(GETGROUPS_T)*n);
 
@@ -861,8 +946,7 @@
             return 0;
     }
 
-    pa_log("%slock: %s", !b? "un" : "",
-        pa_cstrerror(errno));
+    pa_log("%slock: %s", !b? "un" : "", pa_cstrerror(errno));
 #endif
 
 #ifdef OS_IS_WIN32
@@ -881,7 +965,7 @@
 
 /* Remove trailing newlines from a string */
 char* pa_strip_nl(char *s) {
-    assert(s);
+    pa_assert(s);
 
     s[strcspn(s, "\r\n")] = 0;
     return s;
@@ -890,38 +974,46 @@
 /* Create a temporary lock file and lock it. */
 int pa_lock_lockfile(const char *fn) {
     int fd = -1;
-    assert(fn);
+    pa_assert(fn);
 
     for (;;) {
         struct stat st;
 
-        if ((fd = open(fn, O_CREAT|O_RDWR, S_IRUSR|S_IWUSR)) < 0) {
-            pa_log("failed to create lock file '%s': %s", fn,
-                pa_cstrerror(errno));
+        if ((fd = open(fn, O_CREAT|O_RDWR
+#ifdef O_NOCTTY
+                       |O_NOCTTY
+#endif
+#ifdef O_NOFOLLOW
+                       |O_NOFOLLOW
+#endif
+                       , S_IRUSR|S_IWUSR)) < 0) {
+            pa_log_warn("Failed to create lock file '%s': %s", fn, pa_cstrerror(errno));
             goto fail;
         }
 
         if (pa_lock_fd(fd, 1) < 0) {
-            pa_log("failed to lock file '%s'.", fn);
+            pa_log_warn("Failed to lock file '%s'.", fn);
             goto fail;
         }
 
         if (fstat(fd, &st) < 0) {
-            pa_log("failed to fstat() file '%s'.", fn);
+            pa_log_warn("Failed to fstat() file '%s': %s", fn, pa_cstrerror(errno));
             goto fail;
         }
 
-        /* Check wheter the file has been removed meanwhile. When yes, restart this loop, otherwise, we're done */
+        /* Check wheter the file has been removed meanwhile. When yes,
+         * restart this loop, otherwise, we're done */
         if (st.st_nlink >= 1)
             break;
 
         if (pa_lock_fd(fd, 0) < 0) {
-            pa_log("failed to unlock file '%s'.", fn);
+            pa_log_warn("Failed to unlock file '%s'.", fn);
             goto fail;
         }
 
-        if (close(fd) < 0) {
-            pa_log("failed to close file '%s'.", fn);
+        if (pa_close(fd) < 0) {
+            pa_log_warn("Failed to close file '%s': %s", fn, pa_cstrerror(errno));
+            fd = -1;
             goto fail;
         }
 
@@ -933,7 +1025,7 @@
 fail:
 
     if (fd >= 0)
-        close(fd);
+        pa_close(fd);
 
     return -1;
 }
@@ -941,22 +1033,21 @@
 /* Unlock a temporary lcok file */
 int pa_unlock_lockfile(const char *fn, int fd) {
     int r = 0;
-    assert(fn && fd >= 0);
+    pa_assert(fn);
+    pa_assert(fd >= 0);
 
     if (unlink(fn) < 0) {
-        pa_log_warn("WARNING: unable to remove lock file '%s': %s",
-            fn, pa_cstrerror(errno));
+        pa_log_warn("Unable to remove lock file '%s': %s", fn, pa_cstrerror(errno));
         r = -1;
     }
 
     if (pa_lock_fd(fd, 0) < 0) {
-        pa_log_warn("WARNING: failed to unlock file '%s'.", fn);
+        pa_log_warn("Failed to unlock file '%s'.", fn);
         r = -1;
     }
 
-    if (close(fd) < 0) {
-        pa_log_warn("WARNING: failed to close lock file '%s': %s",
-            fn, pa_cstrerror(errno));
+    if (pa_close(fd) < 0) {
+        pa_log_warn("Failed to close '%s': %s", fn, pa_cstrerror(errno));
         r = -1;
     }
 
@@ -1019,10 +1110,8 @@
                 return f;
             }
 
-            if (errno != ENOENT) {
-                pa_log_warn("WARNING: failed to open configuration file '%s': %s",
-                    lfn, pa_cstrerror(errno));
-            }
+            if (errno != ENOENT)
+                pa_log_warn("Failed to open configuration file '%s': %s", lfn, pa_cstrerror(errno));
 
             pa_xfree(lfn);
         }
@@ -1051,7 +1140,10 @@
 char *pa_hexstr(const uint8_t* d, size_t dlength, char *s, size_t slength) {
     size_t i = 0, j = 0;
     const char hex[] = "0123456789abcdef";
-    assert(d && s && slength > 0);
+
+    pa_assert(d);
+    pa_assert(s);
+    pa_assert(slength > 0);
 
     while (i < dlength && j+3 <= slength) {
         s[j++] = hex[*d >> 4];
@@ -1082,7 +1174,9 @@
 /* Parse a hexadecimal string as created by pa_hexstr() to a BLOB */
 size_t pa_parsehex(const char *p, uint8_t *d, size_t dlength) {
     size_t j = 0;
-    assert(p && d);
+
+    pa_assert(p);
+    pa_assert(d);
 
     while (j < dlength && *p) {
         int b;
@@ -1109,8 +1203,8 @@
 int pa_startswith(const char *s, const char *pfx) {
     size_t l;
 
-    assert(s);
-    assert(pfx);
+    pa_assert(s);
+    pa_assert(pfx);
 
     l = strlen(pfx);
 
@@ -1121,8 +1215,8 @@
 int pa_endswith(const char *s, const char *sfx) {
     size_t l1, l2;
 
-    assert(s);
-    assert(sfx);
+    pa_assert(s);
+    pa_assert(sfx);
 
     l1 = strlen(s);
     l2 = strlen(sfx);
@@ -1146,17 +1240,17 @@
     if ((e = getenv("PULSE_RUNTIME_PATH"))) {
 
         if (fn)
-            snprintf(s, l, "%s%c%s", e, PATH_SEP, fn);
+            pa_snprintf(s, l, "%s%c%s", e, PA_PATH_SEP_CHAR, fn);
         else
-            snprintf(s, l, "%s", e);
+            pa_snprintf(s, l, "%s", e);
 
     } else {
         char u[256];
 
         if (fn)
-            snprintf(s, l, "%s%s%c%s", PA_USER_RUNTIME_PATH_PREFIX, pa_get_user_name(u, sizeof(u)), PATH_SEP, fn);
+            pa_snprintf(s, l, "%s%s%c%s", PA_USER_RUNTIME_PATH_PREFIX, pa_get_user_name(u, sizeof(u)), PA_PATH_SEP_CHAR, fn);
         else
-            snprintf(s, l, "%s%s", PA_USER_RUNTIME_PATH_PREFIX, pa_get_user_name(u, sizeof(u)));
+            pa_snprintf(s, l, "%s%s", PA_USER_RUNTIME_PATH_PREFIX, pa_get_user_name(u, sizeof(u)));
     }
 
 
@@ -1175,11 +1269,17 @@
 int pa_atoi(const char *s, int32_t *ret_i) {
     char *x = NULL;
     long l;
-    assert(s && ret_i);
-
+
+    pa_assert(s);
+    pa_assert(ret_i);
+
+    errno = 0;
     l = strtol(s, &x, 0);
 
-    if (!x || *x)
+    if (!x || *x || errno != 0)
+        return -1;
+
+    if ((int32_t) l != l)
         return -1;
 
     *ret_i = (int32_t) l;
@@ -1191,14 +1291,219 @@
 int pa_atou(const char *s, uint32_t *ret_u) {
     char *x = NULL;
     unsigned long l;
-    assert(s && ret_u);
-
+
+    pa_assert(s);
+    pa_assert(ret_u);
+
+    errno = 0;
     l = strtoul(s, &x, 0);
 
-    if (!x || *x)
+    if (!x || *x || errno != 0)
         return -1;
 
+    if ((uint32_t) l != l)
+        return -1;
+
     *ret_u = (uint32_t) l;
 
     return 0;
 }
+
+#ifdef HAVE_STRTOF_L
+static locale_t c_locale = NULL;
+
+static void c_locale_destroy(void) {
+    freelocale(c_locale);
+}
+#endif
+
+int pa_atof(const char *s, float *ret_f) {
+    char *x = NULL;
+    float f;
+    int r = 0;
+
+    pa_assert(s);
+    pa_assert(ret_f);
+
+    /* This should be locale independent */
+
+#ifdef HAVE_STRTOF_L
+
+    PA_ONCE_BEGIN {
+
+        if ((c_locale = newlocale(LC_ALL_MASK, "C", NULL)))
+            atexit(c_locale_destroy);
+
+    } PA_ONCE_END;
+
+    if (c_locale) {
+        errno = 0;
+        f = strtof_l(s, &x, c_locale);
+    } else
+#endif
+    {
+        errno = 0;
+#ifdef HAVE_STRTOF
+        f = strtof(s, &x);
+#else
+        f = strtod(s, &x);
+#endif
+    }
+
+    if (!x || *x || errno != 0)
+        r =  -1;
+    else
+        *ret_f = f;
+
+    return r;
+}
+
+/* Same as snprintf, but guarantees NUL-termination on every platform */
+int pa_snprintf(char *str, size_t size, const char *format, ...) {
+    int ret;
+    va_list ap;
+
+    pa_assert(str);
+    pa_assert(size > 0);
+    pa_assert(format);
+
+    va_start(ap, format);
+    ret = vsnprintf(str, size, format, ap);
+    va_end(ap);
+
+    str[size-1] = 0;
+
+    return ret;
+}
+
+/* Truncate the specified string, but guarantee that the string
+ * returned still validates as UTF8 */
+char *pa_truncate_utf8(char *c, size_t l) {
+    pa_assert(c);
+    pa_assert(pa_utf8_valid(c));
+
+    if (strlen(c) <= l)
+        return c;
+
+    c[l] = 0;
+
+    while (l > 0 && !pa_utf8_valid(c))
+        c[--l] = 0;
+
+    return c;
+}
+
+char *pa_getcwd(void) {
+    size_t l = 128;
+
+    for (;;) {
+        char *p = pa_xnew(char, l);
+        if (getcwd(p, l))
+            return p;
+
+        if (errno != ERANGE)
+            return NULL;
+
+        pa_xfree(p);
+        l *= 2;
+    }
+}
+
+char *pa_make_path_absolute(const char *p) {
+    char *r;
+    char *cwd;
+
+    pa_assert(p);
+
+    if (p[0] == '/')
+        return pa_xstrdup(p);
+
+    if (!(cwd = pa_getcwd()))
+        return pa_xstrdup(p);
+
+    r = pa_sprintf_malloc("%s/%s", cwd, p);
+    pa_xfree(cwd);
+    return r;
+}
+
+void *pa_will_need(const void *p, size_t l) {
+#ifdef RLIMIT_MEMLOCK
+    struct rlimit rlim;
+#endif
+    const void *a;
+    size_t size;
+    int r;
+    size_t bs;
+
+    pa_assert(p);
+    pa_assert(l > 0);
+
+    a = PA_PAGE_ALIGN_PTR(p);
+    size = (const uint8_t*) p + l - (const uint8_t*) a;
+
+#ifdef HAVE_POSIX_MADVISE
+    if ((r = posix_madvise((void*) a, size, POSIX_MADV_WILLNEED)) == 0) {
+        pa_log_debug("posix_madvise() worked fine!");
+        return (void*) p;
+    }
+#endif
+
+    /* Most likely the memory was not mmap()ed from a file and thus
+     * madvise() didn't work, so let's misuse mlock() do page this
+     * stuff back into RAM. Yeah, let's fuck with the MM!  It's so
+     * inviting, the man page of mlock() tells us: "All pages that
+     * contain a part of the specified address range are guaranteed to
+     * be resident in RAM when the call returns successfully." */
+
+#ifdef RLIMIT_MEMLOCK
+    pa_assert_se(getrlimit(RLIMIT_MEMLOCK, &rlim) == 0);
+
+    if (rlim.rlim_cur < PA_PAGE_SIZE) {
+        pa_log_debug("posix_madvise() failed (or doesn't exist), resource limits don't allow mlock(), can't page in data: %s", pa_cstrerror(r));
+        return (void*) p;
+    }
+
+    bs = PA_PAGE_ALIGN(rlim.rlim_cur);
+#else
+    bs = PA_PAGE_SIZE*4;
+#endif
+
+    pa_log_debug("posix_madvise() failed (or doesn't exist), trying mlock(): %s", pa_cstrerror(r));
+
+#ifdef HAVE_MLOCK
+    while (size > 0 && bs > 0) {
+
+        if (bs > size)
+            bs = size;
+
+        if (mlock(a, bs) < 0) {
+            bs = PA_PAGE_ALIGN(bs / 2);
+            continue;
+        }
+
+        pa_assert_se(munlock(a, bs) == 0);
+
+        a = (const uint8_t*) a + bs;
+        size -= bs;
+    }
+#endif
+
+    if (bs <= 0)
+        pa_log_debug("mlock() failed too (or doesn't exist), giving up: %s", pa_cstrerror(errno));
+    else
+        pa_log_debug("mlock() worked fine!");
+
+    return (void*) p;
+}
+
+void pa_close_pipe(int fds[2]) {
+    pa_assert(fds);
+
+    if (fds[0] >= 0)
+        pa_assert_se(pa_close(fds[0]) == 0);
+
+    if (fds[1] >= 0)
+        pa_assert_se(pa_close(fds[1]) == 0);
+
+    fds[0] = fds[1] = -1;
+}

Modified: trunk/src/pulsecore/core-util.h
URL: http://0pointer.de/cgi-bin/viewcvs.cgi/trunk/src/pulsecore/core-util.h?rev=1971&root=pulseaudio&r1=1970&r2=1971&view=diff
==============================================================================
--- trunk/src/pulsecore/core-util.h (original)
+++ trunk/src/pulsecore/core-util.h Sun Oct 28 20:13:50 2007
@@ -34,7 +34,8 @@
 
 struct timeval;
 
-void pa_make_nonblock_fd(int fd);
+void pa_make_fd_nonblock(int fd);
+void pa_make_fd_cloexec(int fd);
 
 int pa_make_secure_dir(const char* dir, mode_t m, uid_t uid, gid_t gid);
 int pa_make_secure_parent_dir(const char *fn, mode_t, uid_t uid, gid_t gid);
@@ -55,19 +56,18 @@
 
 char *pa_parent_dir(const char *fn);
 
+void pa_make_realtime(void);
 void pa_raise_priority(void);
 void pa_reset_priority(void);
 
-int pa_fd_set_cloexec(int fd, int b);
-
-int pa_parse_boolean(const char *s);
+int pa_parse_boolean(const char *s) PA_GCC_PURE;
 
 char *pa_split(const char *c, const char*delimiters, const char **state);
 char *pa_split_spaces(const char *c, const char **state);
 
 char *pa_strip_nl(char *s);
 
-const char *pa_strsignal(int sig);
+const char *pa_sig2str(int sig) PA_GCC_PURE;
 
 int pa_own_uid_in_group(const char *name, gid_t *gid);
 int pa_uid_in_group(uid_t uid, const char *name);
@@ -84,12 +84,42 @@
 char *pa_hexstr(const uint8_t* d, size_t dlength, char *s, size_t slength);
 size_t pa_parsehex(const char *p, uint8_t *d, size_t dlength);
 
-int pa_startswith(const char *s, const char *pfx);
-int pa_endswith(const char *s, const char *sfx);
+int pa_startswith(const char *s, const char *pfx) PA_GCC_PURE;
+int pa_endswith(const char *s, const char *sfx) PA_GCC_PURE;
 
 char *pa_runtime_path(const char *fn, char *s, size_t l);
 
 int pa_atoi(const char *s, int32_t *ret_i);
 int pa_atou(const char *s, uint32_t *ret_u);
+int pa_atof(const char *s, float *ret_f);
+
+int pa_snprintf(char *str, size_t size, const char *format, ...);
+
+char *pa_truncate_utf8(char *c, size_t l);
+
+char *pa_getcwd(void);
+char *pa_make_path_absolute(const char *p);
+
+void *pa_will_need(const void *p, size_t l);
+
+static inline int pa_is_power_of_two(unsigned n) {
+    return !(n & (n - 1));
+}
+
+static inline unsigned pa_make_power_of_two(unsigned n) {
+    unsigned j = n;
+
+    if (pa_is_power_of_two(n))
+        return n;
+
+    while (j) {
+        j = j >> 1;
+        n = n | j;
+    }
+
+    return n + 1;
+}
+
+void pa_close_pipe(int fds[2]);
 
 #endif

Modified: trunk/src/pulsecore/core.c
URL: http://0pointer.de/cgi-bin/viewcvs.cgi/trunk/src/pulsecore/core.c?rev=1971&root=pulseaudio&r1=1970&r2=1971&view=diff
==============================================================================
--- trunk/src/pulsecore/core.c (original)
+++ trunk/src/pulsecore/core.c Sun Oct 28 20:13:50 2007
@@ -27,7 +27,6 @@
 #endif
 
 #include <stdlib.h>
-#include <assert.h>
 #include <stdio.h>
 #include <signal.h>
 
@@ -45,12 +44,36 @@
 #include <pulsecore/props.h>
 #include <pulsecore/random.h>
 #include <pulsecore/log.h>
+#include <pulsecore/macro.h>
 
 #include "core.h"
+
+static PA_DEFINE_CHECK_TYPE(pa_core, pa_msgobject);
+
+static int core_process_msg(pa_msgobject *o, int code, void *userdata, int64_t offset, 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 core_free(pa_object *o);
 
 pa_core* pa_core_new(pa_mainloop_api *m, int shared) {
     pa_core* c;
     pa_mempool *pool;
+    int j;
+
+    pa_assert(m);
 
     if (shared) {
         if (!(pool = pa_mempool_new(shared))) {
@@ -66,7 +89,9 @@
         }
     }
 
-    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);
@@ -87,6 +112,8 @@
     c->default_sample_spec.format = PA_SAMPLE_S16NE;
     c->default_sample_spec.rate = 44100;
     c->default_sample_spec.channels = 2;
+    c->default_n_fragments = 4;
+    c->default_fragment_size_msec = 25;
 
     c->module_auto_unload_event = NULL;
     c->module_defer_unload_event = NULL;
@@ -99,22 +126,21 @@
 
     c->mempool = pool;
 
-    c->disallow_module_loading = 0;
-
     c->quit_event = NULL;
 
     c->exit_idle_time = -1;
     c->module_idle_time = 20;
     c->scache_idle_time = 20;
 
-    c->resample_method = PA_RESAMPLER_SRC_SINC_FASTEST;
+    c->resample_method = PA_RESAMPLER_SPEEX_FLOAT_BASE;
 
     c->is_system_instance = 0;
-
-    pa_hook_init(&c->hook_sink_input_new, c);
-    pa_hook_init(&c->hook_sink_disconnect, c);
-    pa_hook_init(&c->hook_source_output_new, c);
-    pa_hook_init(&c->hook_source_disconnect, c);
+    c->disallow_module_loading = 0;
+    c->high_priority = 0;
+
+
+    for (j = 0; j < PA_CORE_HOOK_MAX; j++)
+        pa_hook_init(&c->hooks[j], c);
 
     pa_property_init(c);
 
@@ -123,28 +149,31 @@
 #ifdef SIGPIPE
     pa_check_signal_is_blocked(SIGPIPE);
 #endif
+
     return c;
 }
 
-void pa_core_free(pa_core *c) {
-    assert(c);
+static void core_free(pa_object *o) {
+    pa_core *c = PA_CORE(o);
+    int j;
+    pa_assert(c);
 
     pa_module_unload_all(c);
-    assert(!c->modules);
-
-    assert(pa_idxset_isempty(c->clients));
+    pa_assert(!c->modules);
+
+    pa_assert(pa_idxset_isempty(c->clients));
     pa_idxset_free(c->clients, NULL, NULL);
 
-    assert(pa_idxset_isempty(c->sinks));
+    pa_assert(pa_idxset_isempty(c->sinks));
     pa_idxset_free(c->sinks, NULL, NULL);
 
-    assert(pa_idxset_isempty(c->sources));
+    pa_assert(pa_idxset_isempty(c->sources));
     pa_idxset_free(c->sources, NULL, NULL);
 
-    assert(pa_idxset_isempty(c->source_outputs));
+    pa_assert(pa_idxset_isempty(c->source_outputs));
     pa_idxset_free(c->source_outputs, NULL, NULL);
 
-    assert(pa_idxset_isempty(c->sink_inputs));
+    pa_assert(pa_idxset_isempty(c->sink_inputs));
     pa_idxset_free(c->sink_inputs, NULL, NULL);
 
     pa_scache_free(c);
@@ -162,23 +191,21 @@
 
     pa_property_cleanup(c);
 
-    pa_hook_free(&c->hook_sink_input_new);
-    pa_hook_free(&c->hook_sink_disconnect);
-    pa_hook_free(&c->hook_source_output_new);
-    pa_hook_free(&c->hook_source_disconnect);
+    for (j = 0; j < PA_CORE_HOOK_MAX; j++)
+        pa_hook_free(&c->hooks[j]);
 
     pa_xfree(c);
 }
 
 static void quit_callback(pa_mainloop_api*m, pa_time_event *e, PA_GCC_UNUSED const struct timeval *tv, void *userdata) {
     pa_core *c = userdata;
-    assert(c->quit_event = e);
+    pa_assert(c->quit_event == e);
 
     m->quit(m, 0);
 }
 
 void pa_core_check_quit(pa_core *c) {
-    assert(c);
+    pa_assert(c);
 
     if (!c->quit_event && c->exit_idle_time >= 0 && pa_idxset_size(c->clients) == 0) {
         struct timeval tv;

Modified: trunk/src/pulsecore/core.h
URL: http://0pointer.de/cgi-bin/viewcvs.cgi/trunk/src/pulsecore/core.h?rev=1971&root=pulseaudio&r1=1970&r2=1971&view=diff
==============================================================================
--- trunk/src/pulsecore/core.h (original)
+++ trunk/src/pulsecore/core.h Sun Oct 28 20:13:50 2007
@@ -34,17 +34,51 @@
 #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>
+
+typedef enum pa_core_hook {
+    PA_CORE_HOOK_SINK_NEW_POST,
+    PA_CORE_HOOK_SINK_UNLINK,
+    PA_CORE_HOOK_SINK_UNLINK_POST,
+    PA_CORE_HOOK_SINK_STATE_CHANGED,
+    PA_CORE_HOOK_SINK_DESCRIPTION_CHANGED,
+    PA_CORE_HOOK_SOURCE_NEW_POST,
+    PA_CORE_HOOK_SOURCE_UNLINK,
+    PA_CORE_HOOK_SOURCE_UNLINK_POST,
+    PA_CORE_HOOK_SOURCE_STATE_CHANGED,
+    PA_CORE_HOOK_SOURCE_DESCRIPTION_CHANGED,
+    PA_CORE_HOOK_SINK_INPUT_NEW,
+    PA_CORE_HOOK_SINK_INPUT_PUT,
+    PA_CORE_HOOK_SINK_INPUT_UNLINK,
+    PA_CORE_HOOK_SINK_INPUT_UNLINK_POST,
+    PA_CORE_HOOK_SINK_INPUT_MOVE,
+    PA_CORE_HOOK_SINK_INPUT_MOVE_POST,
+    PA_CORE_HOOK_SINK_INPUT_NAME_CHANGED,
+    PA_CORE_HOOK_SINK_INPUT_STATE_CHANGED,
+    PA_CORE_HOOK_SOURCE_OUTPUT_NEW,
+    PA_CORE_HOOK_SOURCE_OUTPUT_PUT,
+    PA_CORE_HOOK_SOURCE_OUTPUT_UNLINK,
+    PA_CORE_HOOK_SOURCE_OUTPUT_UNLINK_POST,
+    PA_CORE_HOOK_SOURCE_OUTPUT_MOVE,
+    PA_CORE_HOOK_SOURCE_OUTPUT_MOVE_POST,
+    PA_CORE_HOOK_SOURCE_OUTPUT_NAME_CHANGED,
+    PA_CORE_HOOK_SOURCE_OUTPUT_STATE_CHANGED,
+    PA_CORE_HOOK_MAX
+} pa_core_hook_t;
 
 /* 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;
@@ -61,6 +95,8 @@
     char *default_source_name, *default_sink_name;
 
     pa_sample_spec default_sample_spec;
+    unsigned default_n_fragments, default_fragment_size_msec;
+
     pa_time_event *module_auto_unload_event;
     pa_defer_event *module_defer_unload_event;
 
@@ -71,27 +107,30 @@
 
     pa_mempool *mempool;
 
-    int disallow_module_loading, running_as_daemon;
     int exit_idle_time, module_idle_time, scache_idle_time;
 
     pa_time_event *quit_event;
 
     pa_time_event *scache_auto_unload_event;
 
+    int disallow_module_loading, running_as_daemon;
     pa_resample_method_t resample_method;
-
     int is_system_instance;
+    int high_priority;
 
     /* hooks */
-    pa_hook
-        hook_sink_input_new,
-        hook_sink_disconnect,
-        hook_source_output_new,
-        hook_source_disconnect;
+    pa_hook hooks[PA_CORE_HOOK_MAX];
+};
+
+PA_DECLARE_CLASS(pa_core);
+#define PA_CORE(o) pa_core_cast(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);

Modified: trunk/src/pulsecore/creds.h
URL: http://0pointer.de/cgi-bin/viewcvs.cgi/trunk/src/pulsecore/creds.h?rev=1971&root=pulseaudio&r1=1970&r2=1971&view=diff
==============================================================================
--- trunk/src/pulsecore/creds.h (original)
+++ trunk/src/pulsecore/creds.h Sun Oct 28 20:13:50 2007
@@ -26,7 +26,9 @@
 
 #include <sys/types.h>
 
-/* config.h must be included before this file */
+#ifndef PACKAGE
+#error "Please include config.h before including this file!"
+#endif
 
 #ifdef HAVE_SYS_SOCKET_H
 #include <sys/socket.h>

Modified: trunk/src/pulsecore/dynarray.c
URL: http://0pointer.de/cgi-bin/viewcvs.cgi/trunk/src/pulsecore/dynarray.c?rev=1971&root=pulseaudio&r1=1970&r2=1971&view=diff
==============================================================================
--- trunk/src/pulsecore/dynarray.c (original)
+++ trunk/src/pulsecore/dynarray.c Sun Oct 28 20:13:50 2007
@@ -26,10 +26,10 @@
 #endif
 
 #include <string.h>
-#include <assert.h>
 #include <stdlib.h>
 
 #include <pulse/xmalloc.h>
+#include <pulsecore/macro.h>
 
 #include "dynarray.h"
 
@@ -52,7 +52,7 @@
 
 void pa_dynarray_free(pa_dynarray* a, void (*func)(void *p, void *userdata), void *userdata) {
     unsigned i;
-    assert(a);
+    pa_assert(a);
 
     if (func)
         for (i = 0; i < a->n_entries; i++)
@@ -64,7 +64,7 @@
 }
 
 void pa_dynarray_put(pa_dynarray*a, unsigned i, void *p) {
-    assert(a);
+    pa_assert(a);
 
     if (i >= a->n_allocated) {
         unsigned n;
@@ -85,21 +85,27 @@
 }
 
 unsigned pa_dynarray_append(pa_dynarray*a, void *p) {
-    unsigned i = a->n_entries;
+    unsigned i;
+
+    pa_assert(a);
+
+    i = a->n_entries;
     pa_dynarray_put(a, i, p);
     return i;
 }
 
 void *pa_dynarray_get(pa_dynarray*a, unsigned i) {
-    assert(a);
+    pa_assert(a);
+
     if (i >= a->n_entries)
         return NULL;
 
-    assert(a->data);
+    pa_assert(a->data);
     return a->data[i];
 }
 
 unsigned pa_dynarray_size(pa_dynarray*a) {
-    assert(a);
+    pa_assert(a);
+
     return a->n_entries;
 }

Modified: trunk/src/pulsecore/endianmacros.h
URL: http://0pointer.de/cgi-bin/viewcvs.cgi/trunk/src/pulsecore/endianmacros.h?rev=1971&root=pulseaudio&r1=1970&r2=1971&view=diff
==============================================================================
--- trunk/src/pulsecore/endianmacros.h (original)
+++ trunk/src/pulsecore/endianmacros.h Sun Oct 28 20:13:50 2007
@@ -27,54 +27,68 @@
 
 #include <inttypes.h>
 
-#ifdef HAVE_CONFIG_H
-#include <config.h>
+#ifndef PACKAGE
+#error "Please include config.h before including this file!"
 #endif
 
-#define INT16_SWAP(x) ( (int16_t) ( ((uint16_t) x >> 8) | ((uint16_t) x << 8) ) )
-#define UINT16_SWAP(x) ( (uint16_t) ( ((uint16_t) x >> 8) | ((uint16_t) x << 8) ) )
-#define INT32_SWAP(x) ( (int32_t) ( ((uint32_t) x >> 24) | ((uint32_t) x << 24) | (((uint32_t) x & 0xFF00) << 8) | ((((uint32_t) x) >> 8) & 0xFF00) ) )
-#define UINT32_SWAP(x) ( (uint32_t) ( ((uint32_t) x >> 24) | ((uint32_t) x << 24) | (((uint32_t) x & 0xFF00) << 8) | ((((uint32_t) x) >> 8) & 0xFF00) ) )
+#ifdef HAVE_BYTESWAP_H
+#include <byteswap.h>
+#endif
 
-#define MAYBE_INT32_SWAP(c,x) ((c) ? INT32_SWAP(x) : x)
-#define MAYBE_UINT32_SWAP(c,x) ((c) ? UINT32_SWAP(x) : x)
+#ifdef HAVE_BYTESWAP_H
+#define PA_INT16_SWAP(x) ((int16_t) bswap_16((uint16_t) x))
+#define PA_UINT16_SWAP(x) ((uint16_t) bswap_16((uint16_t) x))
+#define PA_INT32_SWAP(x) ((int32_t) bswap_32((uint32_t) x))
+#define PA_UINT32_SWAP(x) ((uint32_t) bswap_32((uint32_t) x))
+#else
+#define PA_INT16_SWAP(x) ( (int16_t) ( ((uint16_t) x >> 8) | ((uint16_t) x << 8) ) )
+#define PA_UINT16_SWAP(x) ( (uint16_t) ( ((uint16_t) x >> 8) | ((uint16_t) x << 8) ) )
+#define PA_INT32_SWAP(x) ( (int32_t) ( ((uint32_t) x >> 24) | ((uint32_t) x << 24) | (((uint32_t) x & 0xFF00) << 8) | ((((uint32_t) x) >> 8) & 0xFF00) ) )
+#define PA_UINT32_SWAP(x) ( (uint32_t) ( ((uint32_t) x >> 24) | ((uint32_t) x << 24) | (((uint32_t) x & 0xFF00) << 8) | ((((uint32_t) x) >> 8) & 0xFF00) ) )
+#endif
+
+#define PA_MAYBE_INT16_SWAP(c,x) ((c) ? PA_INT32_SWAP(x) : x)
+#define PA_MAYBE_UINT16_SWAP(c,x) ((c) ? PA_UINT32_SWAP(x) : x)
+
+#define PA_MAYBE_INT32_SWAP(c,x) ((c) ? PA_INT32_SWAP(x) : x)
+#define PA_MAYBE_UINT32_SWAP(c,x) ((c) ? PA_UINT32_SWAP(x) : x)
 
 #ifdef WORDS_BIGENDIAN
- #define INT16_FROM_LE(x) INT16_SWAP(x)
- #define INT16_FROM_BE(x) ((int16_t)(x))
+ #define PA_INT16_FROM_LE(x) PA_INT16_SWAP(x)
+ #define PA_INT16_FROM_BE(x) ((int16_t)(x))
 
- #define INT16_TO_LE(x) INT16_SWAP(x)
- #define INT16_TO_BE(x) ((int16_t)(x))
+ #define PA_INT16_TO_LE(x) PA_INT16_SWAP(x)
+ #define PA_INT16_TO_BE(x) ((int16_t)(x))
 
- #define UINT16_FROM_LE(x) UINT16_SWAP(x)
- #define UINT16_FROM_BE(x) ((uint16_t)(x))
+ #define PA_UINT16_FROM_LE(x) PA_UINT16_SWAP(x)
+ #define PA_UINT16_FROM_BE(x) ((uint16_t)(x))
 
- #define INT32_FROM_LE(x) INT32_SWAP(x)
- #define INT32_FROM_BE(x) ((int32_t)(x))
+ #define PA_INT32_FROM_LE(x) PA_INT32_SWAP(x)
+ #define PA_INT32_FROM_BE(x) ((int32_t)(x))
 
- #define UINT32_FROM_LE(x) UINT32_SWAP(x)
- #define UINT32_FROM_BE(x) ((uint32_t)(x))
+ #define PA_UINT32_FROM_LE(x) PA_UINT32_SWAP(x)
+ #define PA_UINT32_FROM_BE(x) ((uint32_t)(x))
 
- #define UINT32_TO_LE(x) UINT32_SWAP(x)
- #define UINT32_TO_BE(x) ((uint32_t)(x))
+ #define PA_UINT32_TO_LE(x) PA_UINT32_SWAP(x)
+ #define PA_UINT32_TO_BE(x) ((uint32_t)(x))
 #else
- #define INT16_FROM_LE(x) ((int16_t)(x))
- #define INT16_FROM_BE(x) INT16_SWAP(x)
+ #define PA_INT16_FROM_LE(x) ((int16_t)(x))
+ #define PA_INT16_FROM_BE(x) PA_INT16_SWAP(x)
 
- #define INT16_TO_LE(x) ((int16_t)(x))
- #define INT16_TO_BE(x) INT16_SWAP(x)
+ #define PA_INT16_TO_LE(x) ((int16_t)(x))
+ #define PA_INT16_TO_BE(x) PA_INT16_SWAP(x)
 
- #define UINT16_FROM_LE(x) ((uint16_t)(x))
- #define UINT16_FROM_BE(x) UINT16_SWAP(x)
+ #define PA_UINT16_FROM_LE(x) ((uint16_t)(x))
+ #define PA_UINT16_FROM_BE(x) PA_UINT16_SWAP(x)
 
- #define INT32_FROM_LE(x) ((int32_t)(x))
- #define INT32_FROM_BE(x) INT32_SWAP(x)
+ #define PA_INT32_FROM_LE(x) ((int32_t)(x))
+ #define PA_INT32_FROM_BE(x) PA_INT32_SWAP(x)
 
- #define UINT32_FROM_LE(x) ((uint32_t)(x))
- #define UINT32_FROM_BE(x) UINT32_SWAP(x)
+ #define PA_UINT32_FROM_LE(x) ((uint32_t)(x))
+ #define PA_UINT32_FROM_BE(x) PA_UINT32_SWAP(x)
 
- #define UINT32_TO_LE(x) ((uint32_t)(x))
- #define UINT32_TO_BE(x) UINT32_SWAP(x)
+ #define PA_UINT32_TO_LE(x) ((uint32_t)(x))
+ #define PA_UINT32_TO_BE(x) PA_UINT32_SWAP(x)
 #endif
 
 #endif

Modified: trunk/src/pulsecore/esound.h
URL: http://0pointer.de/cgi-bin/viewcvs.cgi/trunk/src/pulsecore/esound.h?rev=1971&root=pulseaudio&r1=1970&r2=1971&view=diff
==============================================================================
--- trunk/src/pulsecore/esound.h (original)
+++ trunk/src/pulsecore/esound.h Sun Oct 28 20:13:50 2007
@@ -205,7 +205,7 @@
 /* the endian key is transferred in binary, if it's read into int, */
 /* and matches ESD_ENDIAN_KEY (ENDN), then the endianness of the */
 /* server and the client match; if it's SWAP_ENDIAN_KEY, swap data */
-#define ESD_SWAP_ENDIAN_KEY (UINT32_SWAP(ESD_ENDIAN_KEY))
+#define ESD_SWAP_ENDIAN_KEY (PA_UINT32_SWAP(ESD_ENDIAN_KEY))
 
 
 #endif

Modified: trunk/src/pulsecore/ffmpeg/avcodec.h
URL: http://0pointer.de/cgi-bin/viewcvs.cgi/trunk/src/pulsecore/ffmpeg/avcodec.h?rev=1971&root=pulseaudio&r1=1970&r2=1971&view=diff
==============================================================================
--- trunk/src/pulsecore/ffmpeg/avcodec.h (original)
+++ trunk/src/pulsecore/ffmpeg/avcodec.h Sun Oct 28 20:13:50 2007
@@ -43,7 +43,7 @@
 
 static inline void av_freep(void *k) {
     void **p = k;
-    
+
     if (p) {
         free(*p);
         *p = NULL;

Modified: trunk/src/pulsecore/flist.c
URL: http://0pointer.de/cgi-bin/viewcvs.cgi/trunk/src/pulsecore/flist.c?rev=1971&root=pulseaudio&r1=1970&r2=1971&view=diff
==============================================================================
--- trunk/src/pulsecore/flist.c (original)
+++ trunk/src/pulsecore/flist.c Sun Oct 28 20:13:50 2007
@@ -25,12 +25,14 @@
 #include <config.h>
 #endif
 
-#include <assert.h>
+#include <pulse/xmalloc.h>
 
 #include <pulsecore/atomic.h>
 #include <pulsecore/log.h>
 #include <pulsecore/thread.h>
-#include <pulse/xmalloc.h>
+#include <pulsecore/macro.h>
+#include <pulsecore/core-util.h>
+#include <pulsecore/macro.h>
 
 #include "flist.h"
 
@@ -90,21 +92,18 @@
 };
 
 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;
 };
 
-static int is_power_of_two(unsigned size) {
-    return !(size & (size - 1));
-}
+#define PA_FLIST_CELLS(x) ((struct cell*) ((uint8_t*) (x) + PA_ALIGN(sizeof(struct pa_flist))))
 
 pa_flist *pa_flist_new(unsigned size) {
     pa_flist *l;
@@ -112,12 +111,11 @@
     if (!size)
         size = FLIST_SIZE;
 
-    assert(is_power_of_two(size));
-
-    l = pa_xnew(pa_flist, 1);
+    pa_assert(pa_is_power_of_two(size));
+
+    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);
@@ -131,32 +129,37 @@
 }
 
 void pa_flist_free(pa_flist *l, pa_free_cb_t free_cb) {
-    assert(l);
+    pa_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;
-
-    assert(l);
-    assert(p);
+    struct cell *cells;
+
+    pa_assert(l);
+    pa_assert(p);
+
+    cells = PA_FLIST_CELLS(l);
 
     n = len = (int) l->size - pa_atomic_load(&l->length) + N_EXTRA_SCAN;
     _Y;
@@ -165,13 +168,13 @@
     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;
-            _Y;
-            pa_atomic_store(&l->cells[idx].state, STATE_USED);
+            cells[idx].data = p;
+            _Y;
+            pa_atomic_store(&cells[idx].state, STATE_USED);
             _Y;
             pa_atomic_inc(&l->length);
             return 0;
@@ -183,7 +186,7 @@
 
 #ifdef PROFILE
     if (len > N_EXTRA_SCAN)
-        pa_log("WARNING: Didn't  find free cell after %u iterations.", len);
+        pa_log_warn("Didn't  find free cell after %u iterations.", len);
 #endif
 
     return -1;
@@ -191,8 +194,11 @@
 
 void* pa_flist_pop(pa_flist*l) {
     int idx, len, n;
-
-    assert(l);
+    struct cell *cells;
+
+    pa_assert(l);
+
+    cells = PA_FLIST_CELLS(l);
 
     n = len = pa_atomic_load(&l->length) + N_EXTRA_SCAN;
     _Y;
@@ -201,14 +207,14 @@
     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;
-            _Y;
-            pa_atomic_store(&l->cells[idx].state, STATE_UNUSED);
+            p = cells[idx].data;
+            _Y;
+            pa_atomic_store(&cells[idx].state, STATE_UNUSED);
             _Y;
 
             pa_atomic_dec(&l->length);
@@ -221,7 +227,7 @@
 
 #ifdef PROFILE
     if (len > N_EXTRA_SCAN)
-        pa_log("WARNING: Didn't find used cell after %u iterations.", len);
+        pa_log_warn("Didn't find used cell after %u iterations.", len);
 #endif
 
     return NULL;

Modified: trunk/src/pulsecore/flist.h
URL: http://0pointer.de/cgi-bin/viewcvs.cgi/trunk/src/pulsecore/flist.h?rev=1971&root=pulseaudio&r1=1970&r2=1971&view=diff
==============================================================================
--- trunk/src/pulsecore/flist.h (original)
+++ trunk/src/pulsecore/flist.h Sun Oct 28 20:13:50 2007
@@ -26,6 +26,9 @@
 
 #include <pulse/def.h>
 
+#include <pulsecore/once.h>
+#include <pulsecore/gccmacro.h>
+
 /* A multiple-reader multipler-write lock-free free list implementation */
 
 typedef struct pa_flist pa_flist;
@@ -38,4 +41,28 @@
 int pa_flist_push(pa_flist*l, void *p);
 void* pa_flist_pop(pa_flist*l);
 
+/* Please not that the destructor stuff is not really necesary, we do
+ * this just to make valgrind output more useful. */
+
+#define PA_STATIC_FLIST_DECLARE(name, size, free_cb)                    \
+    static struct {                                                     \
+        pa_flist *flist;                                                \
+        pa_once once;                                                   \
+    } name##_flist = { NULL, PA_ONCE_INIT };                            \
+    static void name##_flist_init(void) {                               \
+        name##_flist.flist = pa_flist_new(size);                        \
+    }                                                                   \
+    static inline pa_flist* name##_flist_get(void) {                    \
+        pa_run_once(&name##_flist.once, name##_flist_init);             \
+        return name##_flist.flist;                                      \
+    }                                                                   \
+    static void name##_flist_destructor(void) PA_GCC_DESTRUCTOR;        \
+    static void name##_flist_destructor(void) {                         \
+        if (name##_flist.flist)                                         \
+            pa_flist_free(name##_flist.flist, (free_cb));               \
+    }                                                                   \
+    struct __stupid_useless_struct_to_allow_trailing_semicolon
+
+#define PA_STATIC_FLIST_GET(name) (name##_flist_get())
+
 #endif

Modified: trunk/src/pulsecore/g711.c
URL: http://0pointer.de/cgi-bin/viewcvs.cgi/trunk/src/pulsecore/g711.c?rev=1971&root=pulseaudio&r1=1970&r2=1971&view=diff
==============================================================================
--- trunk/src/pulsecore/g711.c (original)
+++ trunk/src/pulsecore/g711.c Sun Oct 28 20:13:50 2007
@@ -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;
-
-	for (i = 0; i < size; i++) {
-		if (val <= *table++)
-			return (i);
-	}
-	return (size);
+        int i;
+
+        for (i = 0; i < size; i++) {
+                if (val <= *table++)
+                        return (i);
+        }
+        return (size);
 }
 #endif /* !FAST_*_CONVERSION */
 
@@ -77,55 +77,55 @@
  * 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;
-
-	/* 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;
-	}
-
-	/* Convert the scaled magnitude to segment number. */
-	seg = search(pcm_val, seg_aend, 8);
-
-	/* 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);
-	}
+        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; */
+
+        /* 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);
+
+        /* 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);
+        }
 }
 
 /*
@@ -133,31 +133,31 @@
  *
  */
 int16_t st_alaw2linear16(
-	unsigned char	a_val)
+        unsigned char        a_val)
 {
-	int16_t t;
-	int16_t seg;
-
-	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);
+        int16_t t;
+        int16_t seg;
+
+        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);
 }
 #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 @@
  * 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 @@
  * 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;
-
-	/* 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);
-
-	/* 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);
-	}
+        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; */
+
+        /* 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);
+
+        /*
+         * 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 @@
  * 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;
-
-	/* 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;
-
-	return ((u_val & SIGN_BIT) ? (BIAS - t) : (t - BIAS));
+        int16_t                t;
+
+        /* 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;
+
+        return ((u_val & SIGN_BIT) ? (BIAS - t) : (t - BIAS));
 }
 #endif /* !FAST_ULAW_CONVERSION */
 
@@ -2413,52 +2413,52 @@
     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 @@
 /* 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};
-
-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,
+        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,
 /* 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,
-
-	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};
+        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};
 
 /* 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

Modified: trunk/src/pulsecore/gccmacro.h
URL: http://0pointer.de/cgi-bin/viewcvs.cgi/trunk/src/pulsecore/gccmacro.h?rev=1971&root=pulseaudio&r1=1970&r2=1971&view=diff
==============================================================================
--- trunk/src/pulsecore/gccmacro.h (original)
+++ trunk/src/pulsecore/gccmacro.h Sun Oct 28 20:13:50 2007
@@ -52,4 +52,29 @@
 #define PA_GCC_UNUSED
 #endif
 
+#ifdef __GNUC__
+#define PA_GCC_DESTRUCTOR __attribute__ ((destructor))
+#else
+/** Call this function when process terminates */
+#define PA_GCC_DESTRUCTOR
 #endif
+
+#ifndef PA_GCC_PURE
+#ifdef __GNUCC__
+#define PA_GCC_PURE __attribute__ ((pure))
+#else
+/** This function's return value depends only the arguments list and global state **/
+#define PA_GCC_PURE
+#endif
+#endif
+
+#ifndef PA_GCC_CONST
+#ifdef __GNUCC__
+#define PA_GCC_CONST __attribute__ ((const))
+#else
+/** This function's return value depends only the arguments list (stricter version of PA_GCC_PURE) **/
+#define PA_GCC_CONST
+#endif
+#endif
+
+#endif

Modified: trunk/src/pulsecore/hashmap.c
URL: http://0pointer.de/cgi-bin/viewcvs.cgi/trunk/src/pulsecore/hashmap.c?rev=1971&root=pulseaudio&r1=1970&r2=1971&view=diff
==============================================================================
--- trunk/src/pulsecore/hashmap.c (original)
+++ trunk/src/pulsecore/hashmap.c Sun Oct 28 20:13:50 2007
@@ -26,13 +26,14 @@
 #endif
 
 #include <stdlib.h>
-#include <assert.h>
 #include <string.h>
 
 #include <pulse/xmalloc.h>
 
 #include <pulsecore/idxset.h>
 #include <pulsecore/log.h>
+#include <pulsecore/flist.h>
+#include <pulsecore/macro.h>
 
 #include "hashmap.h"
 
@@ -54,6 +55,8 @@
     pa_hash_func_t hash_func;
     pa_compare_func_t compare_func;
 };
+
+PA_STATIC_FLIST_DECLARE(entries, 0, pa_xfree);
 
 pa_hashmap *pa_hashmap_new(pa_hash_func_t hash_func, pa_compare_func_t compare_func) {
     pa_hashmap *h;
@@ -69,8 +72,8 @@
 }
 
 static void remove(pa_hashmap *h, struct hashmap_entry *e) {
-    assert(h);
-    assert(e);
+    pa_assert(h);
+    pa_assert(e);
 
     if (e->next)
         e->next->previous = e->previous;
@@ -84,16 +87,18 @@
     if (e->bucket_previous)
         e->bucket_previous->bucket_next = e->bucket_next;
     else {
-        assert(e->hash < h->size);
+        pa_assert(e->hash < h->size);
         h->data[e->hash] = e->bucket_next;
     }
 
-    pa_xfree(e);
+    if (pa_flist_push(PA_STATIC_FLIST_GET(entries), e) < 0)
+        pa_xfree(e);
+
     h->n_entries--;
 }
 
 void pa_hashmap_free(pa_hashmap*h, void (*free_func)(void *p, void *userdata), void *userdata) {
-    assert(h);
+    pa_assert(h);
 
     while (h->first_entry) {
         if (free_func)
@@ -107,8 +112,8 @@
 
 static struct hashmap_entry *get(pa_hashmap *h, unsigned hash, const void *key) {
     struct hashmap_entry *e;
-    assert(h);
-    assert(hash < h->size);
+    pa_assert(h);
+    pa_assert(hash < h->size);
 
     for (e = h->data[hash]; e; e = e->bucket_next)
         if (h->compare_func(e->key, key) == 0)
@@ -120,14 +125,16 @@
 int pa_hashmap_put(pa_hashmap *h, const void *key, void *value) {
     struct hashmap_entry *e;
     unsigned hash;
-    assert(h);
+    pa_assert(h);
 
     hash = h->hash_func(key) % h->size;
 
     if ((e = get(h, hash, key)))
         return -1;
 
-    e = pa_xnew(struct hashmap_entry, 1);
+    if (!(e = pa_flist_pop(PA_STATIC_FLIST_GET(entries))))
+        e = pa_xnew(struct hashmap_entry, 1);
+
     e->hash = hash;
     e->key = key;
     e->value = value;
@@ -152,7 +159,7 @@
     unsigned hash;
     struct hashmap_entry *e;
 
-    assert(h);
+    pa_assert(h);
 
     hash = h->hash_func(key) % h->size;
 
@@ -167,7 +174,7 @@
     unsigned hash;
     void *data;
 
-    assert(h);
+    pa_assert(h);
 
     hash = h->hash_func(key) % h->size;
 
@@ -184,8 +191,8 @@
 }
 
 void *pa_hashmap_iterate(pa_hashmap *h, void **state, const void **key) {
-    assert(h);
-    assert(state);
+    pa_assert(h);
+    pa_assert(state);
 
     if (!*state)
         *state = h->first_entry;
@@ -207,7 +214,7 @@
 void* pa_hashmap_steal_first(pa_hashmap *h) {
     void *data;
 
-    assert(h);
+    pa_assert(h);
 
     if (!h->first_entry)
         return NULL;
@@ -218,7 +225,7 @@
 }
 
 void *pa_hashmap_get_first(pa_hashmap *h) {
-    assert(h);
+    pa_assert(h);
 
     if (!h->first_entry)
         return NULL;

Modified: trunk/src/pulsecore/hashmap.h
URL: http://0pointer.de/cgi-bin/viewcvs.cgi/trunk/src/pulsecore/hashmap.h?rev=1971&root=pulseaudio&r1=1970&r2=1971&view=diff
==============================================================================
--- trunk/src/pulsecore/hashmap.h (original)
+++ trunk/src/pulsecore/hashmap.h Sun Oct 28 20:13:50 2007
@@ -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);

Modified: trunk/src/pulsecore/hook-list.c
URL: http://0pointer.de/cgi-bin/viewcvs.cgi/trunk/src/pulsecore/hook-list.c?rev=1971&root=pulseaudio&r1=1970&r2=1971&view=diff
==============================================================================
--- trunk/src/pulsecore/hook-list.c (original)
+++ trunk/src/pulsecore/hook-list.c Sun Oct 28 20:13:50 2007
@@ -21,10 +21,16 @@
   USA.
 ***/
 
-#include <pulsecore/hook-list.h>
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <pulsecore/macro.h>
+
+#include "hook-list.h"
 
 void pa_hook_init(pa_hook *hook, void *data) {
-    assert(hook);
+    pa_assert(hook);
 
     PA_LLIST_HEAD_INIT(pa_hook_slot, hook->slots);
     hook->last = NULL;
@@ -33,8 +39,8 @@
 }
 
 static void slot_free(pa_hook *hook, pa_hook_slot *slot) {
-    assert(hook);
-    assert(slot);
+    pa_assert(hook);
+    pa_assert(slot);
 
     if (hook->last == slot)
         hook->last = slot->prev;
@@ -45,8 +51,8 @@
 }
 
 void pa_hook_free(pa_hook *hook) {
-    assert(hook);
-    assert(!hook->firing);
+    pa_assert(hook);
+    pa_assert(!hook->firing);
 
     while (hook->slots)
         slot_free(hook, hook->slots);
@@ -57,7 +63,7 @@
 pa_hook_slot* pa_hook_connect(pa_hook *hook, pa_hook_cb_t cb, void *data) {
     pa_hook_slot *slot;
 
-    assert(cb);
+    pa_assert(cb);
 
     slot = pa_xnew(pa_hook_slot, 1);
     slot->hook = hook;
@@ -72,8 +78,8 @@
 }
 
 void pa_hook_slot_free(pa_hook_slot *slot) {
-    assert(slot);
-    assert(!slot->dead);
+    pa_assert(slot);
+    pa_assert(!slot->dead);
 
     if (slot->hook->firing > 0) {
         slot->dead = 1;
@@ -86,7 +92,7 @@
     pa_hook_slot *slot, *next;
     pa_hook_result_t result = PA_HOOK_OK;
 
-    assert(hook);
+    pa_assert(hook);
 
     hook->firing ++;
 

Modified: trunk/src/pulsecore/idxset.c
URL: http://0pointer.de/cgi-bin/viewcvs.cgi/trunk/src/pulsecore/idxset.c?rev=1971&root=pulseaudio&r1=1970&r2=1971&view=diff
==============================================================================
--- trunk/src/pulsecore/idxset.c (original)
+++ trunk/src/pulsecore/idxset.c Sun Oct 28 20:13:50 2007
@@ -27,31 +27,34 @@
 #endif
 
 #include <stdio.h>
-#include <assert.h>
 #include <stdlib.h>
 #include <string.h>
 
 #include <pulse/xmalloc.h>
+#include <pulsecore/macro.h>
+#include <pulsecore/flist.h>
 
 #include "idxset.h"
 
-typedef struct idxset_entry {
+struct idxset_entry {
     void *data;
     uint32_t index;
     unsigned hash_value;
 
     struct idxset_entry *hash_prev, *hash_next;
     struct idxset_entry* iterate_prev, *iterate_next;
-} idxset_entry;
+};
 
 struct pa_idxset {
     pa_hash_func_t hash_func;
     pa_compare_func_t compare_func;
 
     unsigned hash_table_size, n_entries;
-    idxset_entry **hash_table, **array, *iterate_list_head, *iterate_list_tail;
+    struct idxset_entry **hash_table, **array, *iterate_list_head, *iterate_list_tail;
     uint32_t index, start_index, array_size;
 };
+
+PA_STATIC_FLIST_DECLARE(entries, 0, pa_xfree);
 
 unsigned pa_idxset_string_hash_func(const void *p) {
     unsigned hash = 0;
@@ -82,7 +85,7 @@
     s->hash_func = hash_func ? hash_func : pa_idxset_trivial_hash_func;
     s->compare_func = compare_func ? compare_func : pa_idxset_trivial_compare_func;
     s->hash_table_size = 127;
-    s->hash_table = pa_xnew0(idxset_entry*, s->hash_table_size);
+    s->hash_table = pa_xnew0(struct idxset_entry*, s->hash_table_size);
     s->array = NULL;
     s->array_size = 0;
     s->index = 0;
@@ -95,15 +98,17 @@
 }
 
 void pa_idxset_free(pa_idxset *s, void (*free_func) (void *p, void *userdata), void *userdata) {
-    assert(s);
+    pa_assert(s);
 
     while (s->iterate_list_head) {
-        idxset_entry *e = s->iterate_list_head;
+        struct idxset_entry *e = s->iterate_list_head;
         s->iterate_list_head = s->iterate_list_head->iterate_next;
 
         if (free_func)
             free_func(e->data, userdata);
-        pa_xfree(e);
+
+        if (pa_flist_push(PA_STATIC_FLIST_GET(entries), e) < 0)
+            pa_xfree(e);
     }
 
     pa_xfree(s->hash_table);
@@ -111,10 +116,10 @@
     pa_xfree(s);
 }
 
-static idxset_entry* hash_scan(pa_idxset *s, idxset_entry* e, const void *p) {
-    assert(p);
-
-    assert(s->compare_func);
+static struct idxset_entry* hash_scan(pa_idxset *s, struct idxset_entry* e, const void *p) {
+    pa_assert(p);
+
+    pa_assert(s->compare_func);
     for (; e; e = e->hash_next)
         if (s->compare_func(e->data, p) == 0)
             return e;
@@ -124,8 +129,10 @@
 
 static void extend_array(pa_idxset *s, uint32_t idx) {
     uint32_t i, j, l;
-    idxset_entry** n;
-    assert(idx >= s->start_index);
+    struct idxset_entry** n;
+
+    pa_assert(s);
+    pa_assert(idx >= s->start_index);
 
     if (idx < s->start_index + s->array_size)
         return;
@@ -135,7 +142,7 @@
             break;
 
     l = idx - s->start_index - i + 100;
-    n = pa_xnew0(idxset_entry*, l);
+    n = pa_xnew0(struct idxset_entry*, l);
 
     for (j = 0; j < s->array_size-i; j++)
         n[j] = s->array[i+j];
@@ -147,7 +154,9 @@
     s->start_index += i;
 }
 
-static idxset_entry** array_index(pa_idxset*s, uint32_t idx) {
+static struct idxset_entry** array_index(pa_idxset*s, uint32_t idx) {
+    pa_assert(s);
+
     if (idx >= s->start_index + s->array_size)
         return NULL;
 
@@ -159,15 +168,15 @@
 
 int pa_idxset_put(pa_idxset*s, void *p, uint32_t *idx) {
     unsigned h;
-    idxset_entry *e, **a;
-
-    assert(s);
-    assert(p);
-
-    assert(s->hash_func);
+    struct idxset_entry *e, **a;
+
+    pa_assert(s);
+    pa_assert(p);
+
+    pa_assert(s->hash_func);
     h = s->hash_func(p) % s->hash_table_size;
 
-    assert(s->hash_table);
+    pa_assert(s->hash_table);
     if ((e = hash_scan(s, s->hash_table[h], p))) {
         if (idx)
             *idx = e->index;
@@ -175,7 +184,8 @@
         return -1;
     }
 
-    e = pa_xmalloc(sizeof(idxset_entry));
+    if (!(e = pa_flist_pop(PA_STATIC_FLIST_GET(entries))))
+        e = pa_xnew(struct idxset_entry, 1);
     e->data = p;
     e->index = s->index++;
     e->hash_value = h;
@@ -190,23 +200,23 @@
     /* Insert into array */
     extend_array(s, e->index);
     a = array_index(s, e->index);
-    assert(a && !*a);
+    pa_assert(a && !*a);
     *a = e;
 
     /* Insert into linked list */
     e->iterate_next = NULL;
     e->iterate_prev = s->iterate_list_tail;
     if (s->iterate_list_tail) {
-        assert(s->iterate_list_head);
+        pa_assert(s->iterate_list_head);
         s->iterate_list_tail->iterate_next = e;
     } else {
-        assert(!s->iterate_list_head);
+        pa_assert(!s->iterate_list_head);
         s->iterate_list_head = e;
     }
     s->iterate_list_tail = e;
 
     s->n_entries++;
-    assert(s->n_entries >= 1);
+    pa_assert(s->n_entries >= 1);
 
     if (idx)
         *idx = e->index;
@@ -215,8 +225,8 @@
 }
 
 void* pa_idxset_get_by_index(pa_idxset*s, uint32_t idx) {
-    idxset_entry **a;
-    assert(s);
+    struct idxset_entry **a;
+    pa_assert(s);
 
     if (!(a = array_index(s, idx)))
         return NULL;
@@ -229,13 +239,15 @@
 
 void* pa_idxset_get_by_data(pa_idxset*s, const void *p, uint32_t *idx) {
     unsigned h;
-    idxset_entry *e;
-    assert(s && p);
-
-    assert(s->hash_func);
+    struct idxset_entry *e;
+
+    pa_assert(s);
+    pa_assert(p);
+
+    pa_assert(s->hash_func);
     h = s->hash_func(p) % s->hash_table_size;
 
-    assert(s->hash_table);
+    pa_assert(s->hash_table);
     if (!(e = hash_scan(s, s->hash_table[h], p)))
         return NULL;
 
@@ -245,13 +257,15 @@
     return e->data;
 }
 
-static void remove_entry(pa_idxset *s, idxset_entry *e) {
-    idxset_entry **a;
-    assert(s && e);
+static void remove_entry(pa_idxset *s, struct idxset_entry *e) {
+    struct idxset_entry **a;
+
+    pa_assert(s);
+    pa_assert(e);
 
     /* Remove from array */
     a = array_index(s, e->index);
-    assert(a && *a && *a == e);
+    pa_assert(a && *a && *a == e);
     *a = NULL;
 
     /* Remove from linked list */
@@ -274,17 +288,18 @@
     else
         s->hash_table[e->hash_value] = e->hash_next;
 
-    pa_xfree(e);
-
-    assert(s->n_entries >= 1);
+    if (pa_flist_push(PA_STATIC_FLIST_GET(entries), e) < 0)
+        pa_xfree(e);
+
+    pa_assert(s->n_entries >= 1);
     s->n_entries--;
 }
 
 void* pa_idxset_remove_by_index(pa_idxset*s, uint32_t idx) {
-    idxset_entry **a;
+    struct idxset_entry **a;
     void *data;
 
-    assert(s);
+    pa_assert(s);
 
     if (!(a = array_index(s, idx)))
         return NULL;
@@ -299,14 +314,16 @@
 }
 
 void* pa_idxset_remove_by_data(pa_idxset*s, const void *data, uint32_t *idx) {
-    idxset_entry *e;
+    struct idxset_entry *e;
     unsigned h;
     void *r;
 
-    assert(s->hash_func);
+    pa_assert(s);
+
+    pa_assert(s->hash_func);
     h = s->hash_func(data) % s->hash_table_size;
 
-    assert(s->hash_table);
+    pa_assert(s->hash_table);
     if (!(e = hash_scan(s, s->hash_table[h], data)))
         return NULL;
 
@@ -320,8 +337,10 @@
 }
 
 void* pa_idxset_rrobin(pa_idxset *s, uint32_t *idx) {
-    idxset_entry **a, *e = NULL;
-    assert(s && idx);
+    struct idxset_entry **a, *e = NULL;
+
+    pa_assert(s);
+    pa_assert(idx);
 
     if ((a = array_index(s, *idx)) && *a)
         e = (*a)->iterate_next;
@@ -337,7 +356,7 @@
 }
 
 void* pa_idxset_first(pa_idxset *s, uint32_t *idx) {
-    assert(s);
+    pa_assert(s);
 
     if (!s->iterate_list_head)
         return NULL;
@@ -348,9 +367,10 @@
 }
 
 void *pa_idxset_next(pa_idxset *s, uint32_t *idx) {
-    idxset_entry **a, *e = NULL;
-    assert(s);
-    assert(idx);
+    struct idxset_entry **a, *e = NULL;
+
+    pa_assert(s);
+    pa_assert(idx);
 
     if ((a = array_index(s, *idx)) && *a)
         e = (*a)->iterate_next;
@@ -365,13 +385,15 @@
 }
 
 int pa_idxset_foreach(pa_idxset*s, int (*func)(void *p, uint32_t idx, int *del, void*userdata), void *userdata) {
-    idxset_entry *e;
-    assert(s && func);
+    struct idxset_entry *e;
+
+    pa_assert(s);
+    pa_assert(func);
 
     e = s->iterate_list_head;
     while (e) {
         int del = 0, r;
-        idxset_entry *n = e->iterate_next;
+        struct idxset_entry *n = e->iterate_next;
 
         r = func(e->data, e->index, &del, userdata);
 
@@ -388,12 +410,14 @@
 }
 
 unsigned pa_idxset_size(pa_idxset*s) {
-    assert(s);
+    pa_assert(s);
+
     return s->n_entries;
 }
 
 int pa_idxset_isempty(pa_idxset *s) {
-    assert(s);
+    pa_assert(s);
+
     return s->n_entries == 0;
 }
 

Modified: trunk/src/pulsecore/idxset.h
URL: http://0pointer.de/cgi-bin/viewcvs.cgi/trunk/src/pulsecore/idxset.h?rev=1971&root=pulseaudio&r1=1970&r2=1971&view=diff
==============================================================================
--- trunk/src/pulsecore/idxset.h (original)
+++ trunk/src/pulsecore/idxset.h Sun Oct 28 20:13:50 2007
@@ -43,11 +43,6 @@
 /* Generic implementations for hash and comparison functions for strings. */
 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);

Modified: trunk/src/pulsecore/inet_ntop.c
URL: http://0pointer.de/cgi-bin/viewcvs.cgi/trunk/src/pulsecore/inet_ntop.c?rev=1971&root=pulseaudio&r1=1970&r2=1971&view=diff
==============================================================================
--- trunk/src/pulsecore/inet_ntop.c (original)
+++ trunk/src/pulsecore/inet_ntop.c Sun Oct 28 20:13:50 2007
@@ -47,7 +47,7 @@
 
     switch (af) {
     case AF_INET:
-        snprintf(dst, cnt, "%d.%d.%d.%d",
+        pa_snprintf(dst, cnt, "%d.%d.%d.%d",
 #ifdef WORDS_BIGENDIAN
             (int)(in->s_addr >> 24) & 0xff,
             (int)(in->s_addr >> 16) & 0xff,
@@ -61,7 +61,7 @@
 #endif
         break;
     case AF_INET6:
-        snprintf(dst, cnt, "%x:%x:%x:%x:%x:%x:%x:%x",
+        pa_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],

Modified: trunk/src/pulsecore/iochannel.c
URL: http://0pointer.de/cgi-bin/viewcvs.cgi/trunk/src/pulsecore/iochannel.c?rev=1971&root=pulseaudio&r1=1970&r2=1971&view=diff
==============================================================================
--- trunk/src/pulsecore/iochannel.c (original)
+++ trunk/src/pulsecore/iochannel.c Sun Oct 28 20:13:50 2007
@@ -27,7 +27,6 @@
 #endif
 
 #include <stdlib.h>
-#include <assert.h>
 #include <fcntl.h>
 #include <unistd.h>
 #include <errno.h>
@@ -47,6 +46,7 @@
 #include <pulsecore/core-util.h>
 #include <pulsecore/socket-util.h>
 #include <pulsecore/log.h>
+#include <pulsecore/macro.h>
 
 #include "iochannel.h"
 
@@ -58,21 +58,21 @@
     pa_iochannel_cb_t callback;
     void*userdata;
 
-    int readable;
-    int writable;
-    int hungup;
-
-    int no_close;
+    pa_bool_t readable;
+    pa_bool_t writable;
+    pa_bool_t hungup;
+
+    pa_bool_t no_close;
 
     pa_io_event* input_event, *output_event;
 };
 
 static void enable_mainloop_sources(pa_iochannel *io) {
-    assert(io);
+    pa_assert(io);
 
     if (io->input_event == io->output_event && io->input_event) {
         pa_io_event_flags_t f = PA_IO_EVENT_NULL;
-        assert(io->input_event);
+        pa_assert(io->input_event);
 
         if (!io->readable)
             f |= PA_IO_EVENT_INPUT;
@@ -90,28 +90,28 @@
 
 static void callback(pa_mainloop_api* m, pa_io_event *e, int fd, pa_io_event_flags_t f, void *userdata) {
     pa_iochannel *io = userdata;
-    int changed = 0;
-
-    assert(m);
-    assert(e);
-    assert(fd >= 0);
-    assert(userdata);
+    pa_bool_t changed = FALSE;
+
+    pa_assert(m);
+    pa_assert(e);
+    pa_assert(fd >= 0);
+    pa_assert(userdata);
 
     if ((f & (PA_IO_EVENT_HANGUP|PA_IO_EVENT_ERROR)) && !io->hungup) {
-        io->hungup = 1;
-        changed = 1;
+        io->hungup = TRUE;
+        changed = TRUE;
     }
 
     if ((f & PA_IO_EVENT_INPUT) && !io->readable) {
-        io->readable = 1;
-        changed = 1;
-        assert(e == io->input_event);
+        io->readable = TRUE;
+        changed = TRUE;
+        pa_assert(e == io->input_event);
     }
 
     if ((f & PA_IO_EVENT_OUTPUT) && !io->writable) {
-        io->writable = 1;
-        changed = 1;
-        assert(e == io->output_event);
+        io->writable = TRUE;
+        changed = TRUE;
+        pa_assert(e == io->output_event);
     }
 
     if (changed) {
@@ -125,8 +125,8 @@
 pa_iochannel* pa_iochannel_new(pa_mainloop_api*m, int ifd, int ofd) {
     pa_iochannel *io;
 
-    assert(m);
-    assert(ifd >= 0 || ofd >= 0);
+    pa_assert(m);
+    pa_assert(ifd >= 0 || ofd >= 0);
 
     io = pa_xnew(pa_iochannel, 1);
     io->ifd = ifd;
@@ -136,26 +136,26 @@
 
     io->userdata = NULL;
     io->callback = NULL;
-    io->readable = 0;
-    io->writable = 0;
-    io->hungup = 0;
-    io->no_close = 0;
+    io->readable = FALSE;
+    io->writable = FALSE;
+    io->hungup = FALSE;
+    io->no_close = FALSE;
 
     io->input_event = io->output_event = NULL;
 
     if (ifd == ofd) {
-        assert(ifd >= 0);
-        pa_make_nonblock_fd(io->ifd);
+        pa_assert(ifd >= 0);
+        pa_make_fd_nonblock(io->ifd);
         io->input_event = io->output_event = m->io_new(m, ifd, PA_IO_EVENT_INPUT|PA_IO_EVENT_OUTPUT, callback, io);
     } else {
 
         if (ifd >= 0) {
-            pa_make_nonblock_fd(io->ifd);
+            pa_make_fd_nonblock(io->ifd);
             io->input_event = m->io_new(m, ifd, PA_IO_EVENT_INPUT, callback, io);
         }
 
         if (ofd >= 0) {
-            pa_make_nonblock_fd(io->ofd);
+            pa_make_fd_nonblock(io->ofd);
             io->output_event = m->io_new(m, ofd, PA_IO_EVENT_OUTPUT, callback, io);
         }
     }
@@ -164,7 +164,7 @@
 }
 
 void pa_iochannel_free(pa_iochannel*io) {
-    assert(io);
+    pa_assert(io);
 
     if (io->input_event)
         io->mainloop->io_free(io->input_event);
@@ -182,20 +182,20 @@
     pa_xfree(io);
 }
 
-int pa_iochannel_is_readable(pa_iochannel*io) {
-    assert(io);
+pa_bool_t pa_iochannel_is_readable(pa_iochannel*io) {
+    pa_assert(io);
 
     return io->readable || io->hungup;
 }
 
-int pa_iochannel_is_writable(pa_iochannel*io) {
-    assert(io);
+pa_bool_t pa_iochannel_is_writable(pa_iochannel*io) {
+    pa_assert(io);
 
     return io->writable && !io->hungup;
 }
 
-int pa_iochannel_is_hungup(pa_iochannel*io) {
-    assert(io);
+pa_bool_t pa_iochannel_is_hungup(pa_iochannel*io) {
+    pa_assert(io);
 
     return io->hungup;
 }
@@ -203,14 +203,13 @@
 ssize_t pa_iochannel_write(pa_iochannel*io, const void*data, size_t l) {
     ssize_t r;
 
-    assert(io);
-    assert(data);
-    assert(l);
-    assert(io->ofd >= 0);
-
-    r = pa_write(io->ofd, data, l, &io->ofd_type);
-    if (r >= 0) {
-        io->writable = 0;
+    pa_assert(io);
+    pa_assert(data);
+    pa_assert(l);
+    pa_assert(io->ofd >= 0);
+
+    if ((r = pa_write(io->ofd, data, l, &io->ofd_type)) >= 0) {
+        io->writable = FALSE;
         enable_mainloop_sources(io);
     }
 
@@ -220,13 +219,12 @@
 ssize_t pa_iochannel_read(pa_iochannel*io, void*data, size_t l) {
     ssize_t r;
 
-    assert(io);
-    assert(data);
-    assert(io->ifd >= 0);
-
-    r = pa_read(io->ifd, data, l, &io->ifd_type);
-    if (r >= 0) {
-        io->readable = 0;
+    pa_assert(io);
+    pa_assert(data);
+    pa_assert(io->ifd >= 0);
+
+    if ((r = pa_read(io->ifd, data, l, &io->ifd_type)) >= 0) {
+        io->readable = FALSE;
         enable_mainloop_sources(io);
     }
 
@@ -235,13 +233,13 @@
 
 #ifdef HAVE_CREDS
 
-int pa_iochannel_creds_supported(pa_iochannel *io) {
+pa_bool_t pa_iochannel_creds_supported(pa_iochannel *io) {
     struct sockaddr_un sa;
     socklen_t l;
 
-    assert(io);
-    assert(io->ifd >= 0);
-    assert(io->ofd == io->ifd);
+    pa_assert(io);
+    pa_assert(io->ifd >= 0);
+    pa_assert(io->ofd == io->ifd);
 
     l = sizeof(sa);
 
@@ -254,8 +252,8 @@
 int pa_iochannel_creds_enable(pa_iochannel *io) {
     int t = 1;
 
-    assert(io);
-    assert(io->ifd >= 0);
+    pa_assert(io);
+    pa_assert(io->ifd >= 0);
 
     if (setsockopt(io->ifd, SOL_SOCKET, SO_PASSCRED, &t, sizeof(t)) < 0) {
         pa_log_error("setsockopt(SOL_SOCKET, SO_PASSCRED): %s", pa_cstrerror(errno));
@@ -273,10 +271,10 @@
     struct ucred *u;
     struct cmsghdr *cmsg;
 
-    assert(io);
-    assert(data);
-    assert(l);
-    assert(io->ofd >= 0);
+    pa_assert(io);
+    pa_assert(data);
+    pa_assert(l);
+    pa_assert(io->ofd >= 0);
 
     memset(&iov, 0, sizeof(iov));
     iov.iov_base = (void*) data;
@@ -309,25 +307,25 @@
     mh.msg_flags = 0;
 
     if ((r = sendmsg(io->ofd, &mh, MSG_NOSIGNAL)) >= 0) {
-        io->writable = 0;
+        io->writable = FALSE;
         enable_mainloop_sources(io);
     }
 
     return r;
 }
 
-ssize_t pa_iochannel_read_with_creds(pa_iochannel*io, void*data, size_t l, pa_creds *creds, int *creds_valid) {
+ssize_t pa_iochannel_read_with_creds(pa_iochannel*io, void*data, size_t l, pa_creds *creds, pa_bool_t *creds_valid) {
     ssize_t r;
     struct msghdr mh;
     struct iovec iov;
     uint8_t cmsg_data[CMSG_SPACE(sizeof(struct ucred))];
 
-    assert(io);
-    assert(data);
-    assert(l);
-    assert(io->ifd >= 0);
-    assert(creds);
-    assert(creds_valid);
+    pa_assert(io);
+    pa_assert(data);
+    pa_assert(l);
+    pa_assert(io->ifd >= 0);
+    pa_assert(creds);
+    pa_assert(creds_valid);
 
     memset(&iov, 0, sizeof(iov));
     iov.iov_base = data;
@@ -353,17 +351,17 @@
 
             if (cmsg->cmsg_level == SOL_SOCKET && cmsg->cmsg_type == SCM_CREDENTIALS) {
                 struct ucred u;
-                assert(cmsg->cmsg_len == CMSG_LEN(sizeof(struct ucred)));
+                pa_assert(cmsg->cmsg_len == CMSG_LEN(sizeof(struct ucred)));
                 memcpy(&u, CMSG_DATA(cmsg), sizeof(struct ucred));
 
                 creds->gid = u.gid;
                 creds->uid = u.uid;
-                *creds_valid = 1;
+                *creds_valid = TRUE;
                 break;
             }
         }
 
-        io->readable = 0;
+        io->readable = FALSE;
         enable_mainloop_sources(io);
     }
 
@@ -373,46 +371,52 @@
 #endif /* HAVE_CREDS */
 
 void pa_iochannel_set_callback(pa_iochannel*io, pa_iochannel_cb_t _callback, void *userdata) {
-    assert(io);
+    pa_assert(io);
 
     io->callback = _callback;
     io->userdata = userdata;
 }
 
-void pa_iochannel_set_noclose(pa_iochannel*io, int b) {
-    assert(io);
-
-    io->no_close = b;
+void pa_iochannel_set_noclose(pa_iochannel*io, pa_bool_t b) {
+    pa_assert(io);
+
+    io->no_close = !!b;
 }
 
 void pa_iochannel_socket_peer_to_string(pa_iochannel*io, char*s, size_t l) {
-    assert(io);
-    assert(s);
-    assert(l);
+    pa_assert(io);
+    pa_assert(s);
+    pa_assert(l);
 
     pa_socket_peer_to_string(io->ifd, s, l);
 }
 
 int pa_iochannel_socket_set_rcvbuf(pa_iochannel *io, size_t l) {
-    assert(io);
+    pa_assert(io);
 
     return pa_socket_set_rcvbuf(io->ifd, l);
 }
 
 int pa_iochannel_socket_set_sndbuf(pa_iochannel *io, size_t l) {
-    assert(io);
+    pa_assert(io);
 
     return pa_socket_set_sndbuf(io->ofd, l);
 }
 
 pa_mainloop_api* pa_iochannel_get_mainloop_api(pa_iochannel *io) {
-    assert(io);
+    pa_assert(io);
 
     return io->mainloop;
 }
 
 int pa_iochannel_get_recv_fd(pa_iochannel *io) {
-    assert(io);
+    pa_assert(io);
 
     return io->ifd;
 }
+
+int pa_iochannel_get_send_fd(pa_iochannel *io) {
+    pa_assert(io);
+
+    return io->ofd;
+}

Modified: trunk/src/pulsecore/iochannel.h
URL: http://0pointer.de/cgi-bin/viewcvs.cgi/trunk/src/pulsecore/iochannel.h?rev=1971&root=pulseaudio&r1=1970&r2=1971&view=diff
==============================================================================
--- trunk/src/pulsecore/iochannel.h (original)
+++ trunk/src/pulsecore/iochannel.h Sun Oct 28 20:13:50 2007
@@ -25,10 +25,15 @@
   USA.
 ***/
 
+#ifndef PACKAGE
+#error "Please include config.h before including this file!"
+#endif
+
 #include <sys/types.h>
 
 #include <pulse/mainloop-api.h>
 #include <pulsecore/creds.h>
+#include <pulsecore/macro.h>
 
 /* A wrapper around UNIX file descriptors for attaching them to the a
    main event loop. Everytime new data may be read or be written to
@@ -54,20 +59,20 @@
 ssize_t pa_iochannel_read(pa_iochannel*io, void*data, size_t l);
 
 #ifdef HAVE_CREDS
-int pa_iochannel_creds_supported(pa_iochannel *io);
+pa_bool_t pa_iochannel_creds_supported(pa_iochannel *io);
 int pa_iochannel_creds_enable(pa_iochannel *io);
 
 ssize_t pa_iochannel_write_with_creds(pa_iochannel*io, const void*data, size_t l, const pa_creds *ucred);
-ssize_t pa_iochannel_read_with_creds(pa_iochannel*io, void*data, size_t l, pa_creds *ucred, int *creds_valid);
+ssize_t pa_iochannel_read_with_creds(pa_iochannel*io, void*data, size_t l, pa_creds *ucred, pa_bool_t *creds_valid);
 #endif
 
-int pa_iochannel_is_readable(pa_iochannel*io);
-int pa_iochannel_is_writable(pa_iochannel*io);
-int pa_iochannel_is_hungup(pa_iochannel*io);
+pa_bool_t pa_iochannel_is_readable(pa_iochannel*io);
+pa_bool_t pa_iochannel_is_writable(pa_iochannel*io);
+pa_bool_t pa_iochannel_is_hungup(pa_iochannel*io);
 
 /* Don't close the file descirptors when the io channel is freed. By
  * default the file descriptors are closed. */
-void pa_iochannel_set_noclose(pa_iochannel*io, int b);
+void pa_iochannel_set_noclose(pa_iochannel*io, pa_bool_t b);
 
 /* Set the callback function that is called whenever data becomes available for read or write */
 typedef void (*pa_iochannel_cb_t)(pa_iochannel*io, void *userdata);
@@ -83,5 +88,6 @@
 pa_mainloop_api* pa_iochannel_get_mainloop_api(pa_iochannel *io);
 
 int pa_iochannel_get_recv_fd(pa_iochannel *io);
+int pa_iochannel_get_send_fd(pa_iochannel *io);
 
 #endif

Modified: trunk/src/pulsecore/ioline.c
URL: http://0pointer.de/cgi-bin/viewcvs.cgi/trunk/src/pulsecore/ioline.c?rev=1971&root=pulseaudio&r1=1970&r2=1971&view=diff
==============================================================================
--- trunk/src/pulsecore/ioline.c (original)
+++ trunk/src/pulsecore/ioline.c Sun Oct 28 20:13:50 2007
@@ -27,14 +27,16 @@
 
 #include <errno.h>
 #include <stdio.h>
-#include <assert.h>
 #include <stdlib.h>
 #include <string.h>
 
 #include <pulse/xmalloc.h>
 
+#include <pulsecore/winsock.h>
 #include <pulsecore/core-error.h>
 #include <pulsecore/log.h>
+#include <pulsecore/macro.h>
+#include <pulsecore/refcnt.h>
 
 #include "ioline.h"
 
@@ -42,10 +44,11 @@
 #define READ_SIZE (1024)
 
 struct pa_ioline {
+    PA_REFCNT_DECLARE;
+
     pa_iochannel *io;
     pa_defer_event *defer_event;
     pa_mainloop_api *mainloop;
-    int ref;
     int dead;
 
     char *wbuf;
@@ -65,9 +68,10 @@
 
 pa_ioline* pa_ioline_new(pa_iochannel *io) {
     pa_ioline *l;
-    assert(io);
+    pa_assert(io);
 
     l = pa_xnew(pa_ioline, 1);
+    PA_REFCNT_INIT(l);
     l->io = io;
     l->dead = 0;
 
@@ -79,7 +83,6 @@
 
     l->callback = NULL;
     l->userdata = NULL;
-    l->ref = 1;
 
     l->mainloop = pa_iochannel_get_mainloop_api(io);
 
@@ -94,7 +97,7 @@
 }
 
 static void ioline_free(pa_ioline *l) {
-    assert(l);
+    pa_assert(l);
 
     if (l->io)
         pa_iochannel_free(l->io);
@@ -108,24 +111,24 @@
 }
 
 void pa_ioline_unref(pa_ioline *l) {
-    assert(l);
-    assert(l->ref >= 1);
-
-    if ((--l->ref) <= 0)
+    pa_assert(l);
+    pa_assert(PA_REFCNT_VALUE(l) >= 1);
+
+    if (PA_REFCNT_DEC(l) <= 0)
         ioline_free(l);
 }
 
 pa_ioline* pa_ioline_ref(pa_ioline *l) {
-    assert(l);
-    assert(l->ref >= 1);
-
-    l->ref++;
+    pa_assert(l);
+    pa_assert(PA_REFCNT_VALUE(l) >= 1);
+
+    PA_REFCNT_INC(l);
     return l;
 }
 
 void pa_ioline_close(pa_ioline *l) {
-    assert(l);
-    assert(l->ref >= 1);
+    pa_assert(l);
+    pa_assert(PA_REFCNT_VALUE(l) >= 1);
 
     l->dead = 1;
 
@@ -146,9 +149,9 @@
 void pa_ioline_puts(pa_ioline *l, const char *c) {
     size_t len;
 
-    assert(l);
-    assert(l->ref >= 1);
-    assert(c);
+    pa_assert(l);
+    pa_assert(PA_REFCNT_VALUE(l) >= 1);
+    pa_assert(c);
 
     if (l->dead)
         return;
@@ -158,7 +161,7 @@
         len = BUFFER_LIMIT - l->wbuf_valid_length;
 
     if (len) {
-        assert(l->wbuf_length >= l->wbuf_valid_length);
+        pa_assert(l->wbuf_length >= l->wbuf_valid_length);
 
         /* In case the allocated buffer is too small, enlarge it. */
         if (l->wbuf_valid_length + len > l->wbuf_length) {
@@ -178,7 +181,7 @@
             l->wbuf_index = 0;
         }
 
-        assert(l->wbuf_index + l->wbuf_valid_length + len <= l->wbuf_length);
+        pa_assert(l->wbuf_index + l->wbuf_valid_length + len <= l->wbuf_length);
 
         /* Append the new string */
         memcpy(l->wbuf + l->wbuf_index + l->wbuf_valid_length, c, len);
@@ -189,17 +192,17 @@
 }
 
 void pa_ioline_set_callback(pa_ioline*l, void (*callback)(pa_ioline*io, const char *s, void *userdata), void *userdata) {
-    assert(l);
-    assert(l->ref >= 1);
+    pa_assert(l);
+    pa_assert(PA_REFCNT_VALUE(l) >= 1);
 
     l->callback = callback;
     l->userdata = userdata;
 }
 
 static void failure(pa_ioline *l, int process_leftover) {
-    assert(l);
-    assert(l->ref >= 1);
-    assert(!l->dead);
+    pa_assert(l);
+    pa_assert(PA_REFCNT_VALUE(l) >= 1);
+    pa_assert(!l->dead);
 
     if (process_leftover && l->rbuf_valid_length > 0) {
         /* Pass the last missing bit to the client */
@@ -220,7 +223,9 @@
 }
 
 static void scan_for_lines(pa_ioline *l, size_t skip) {
-    assert(l && l->ref >= 1 && skip < l->rbuf_valid_length);
+    pa_assert(l);
+    pa_assert(PA_REFCNT_VALUE(l) >= 1);
+    pa_assert(skip < l->rbuf_valid_length);
 
     while (!l->dead && l->rbuf_valid_length > skip) {
         char *e, *p;
@@ -255,7 +260,8 @@
 static int do_write(pa_ioline *l);
 
 static int do_read(pa_ioline *l) {
-    assert(l && l->ref >= 1);
+    pa_assert(l);
+    pa_assert(PA_REFCNT_VALUE(l) >= 1);
 
     while (!l->dead && pa_iochannel_is_readable(l->io)) {
         ssize_t r;
@@ -289,11 +295,11 @@
 
         len = l->rbuf_length - l->rbuf_index - l->rbuf_valid_length;
 
-        assert(len >= READ_SIZE);
+        pa_assert(len >= READ_SIZE);
 
         /* Read some data */
         if ((r = pa_iochannel_read(l->io, l->rbuf+l->rbuf_index+l->rbuf_valid_length, len)) <= 0) {
-            if (r < 0) {
+            if (r < 0 && errno != ECONNRESET) {
                 pa_log("read(): %s", pa_cstrerror(errno));
                 failure(l, 0);
             } else
@@ -314,13 +320,19 @@
 /* Try to flush the buffer */
 static int do_write(pa_ioline *l) {
     ssize_t r;
-    assert(l && l->ref >= 1);
+
+    pa_assert(l);
+    pa_assert(PA_REFCNT_VALUE(l) >= 1);
 
     while (!l->dead && pa_iochannel_is_writable(l->io) && l->wbuf_valid_length) {
 
-        if ((r = pa_iochannel_write(l->io, l->wbuf+l->wbuf_index, l->wbuf_valid_length)) < 0) {
-            pa_log("write(): %s", r < 0 ? pa_cstrerror(errno) : "EOF");
+        if ((r = pa_iochannel_write(l->io, l->wbuf+l->wbuf_index, l->wbuf_valid_length)) <= 0) {
+
+            if (r < 0 && errno != EPIPE)
+                pa_log("write(): %s", pa_cstrerror(errno));
+
             failure(l, 0);
+
             return -1;
         }
 
@@ -337,8 +349,8 @@
 
 /* Try to flush read/write data */
 static void do_work(pa_ioline *l) {
-    assert(l);
-    assert(l->ref >= 1);
+    pa_assert(l);
+    pa_assert(PA_REFCNT_VALUE(l) >= 1);
 
     pa_ioline_ref(l);
 
@@ -358,21 +370,28 @@
 
 static void io_callback(pa_iochannel*io, void *userdata) {
     pa_ioline *l = userdata;
-    assert(io && l && l->ref >= 1);
+
+    pa_assert(io);
+    pa_assert(l);
+    pa_assert(PA_REFCNT_VALUE(l) >= 1);
 
     do_work(l);
 }
 
 static void defer_callback(pa_mainloop_api*m, pa_defer_event*e, void *userdata) {
     pa_ioline *l = userdata;
-    assert(l && l->ref >= 1 && l->mainloop == m && l->defer_event == e);
+
+    pa_assert(l);
+    pa_assert(PA_REFCNT_VALUE(l) >= 1);
+    pa_assert(l->mainloop == m);
+    pa_assert(l->defer_event == e);
 
     do_work(l);
 }
 
 void pa_ioline_defer_close(pa_ioline *l) {
-    assert(l);
-    assert(l->ref >= 1);
+    pa_assert(l);
+    pa_assert(PA_REFCNT_VALUE(l) >= 1);
 
     l->defer_close = 1;
 
@@ -384,8 +403,8 @@
     char *t;
     va_list ap;
 
-    assert(l);
-    assert(l->ref >= 1);
+    pa_assert(l);
+    pa_assert(PA_REFCNT_VALUE(l) >= 1);
 
     va_start(ap, format);
     t = pa_vsprintf_malloc(format, ap);

Modified: trunk/src/pulsecore/ipacl.c
URL: http://0pointer.de/cgi-bin/viewcvs.cgi/trunk/src/pulsecore/ipacl.c?rev=1971&root=pulseaudio&r1=1970&r2=1971&view=diff
==============================================================================
--- trunk/src/pulsecore/ipacl.c (original)
+++ trunk/src/pulsecore/ipacl.c Sun Oct 28 20:13:50 2007
@@ -46,13 +46,13 @@
 #include <arpa/inet.h>
 #endif
 
-#include "winsock.h"
-
 #include <pulse/xmalloc.h>
 
 #include <pulsecore/core-util.h>
 #include <pulsecore/llist.h>
 #include <pulsecore/log.h>
+#include <pulsecore/macro.h>
+#include <pulsecore/winsock.h>
 
 #ifndef HAVE_INET_PTON
 #include "inet_pton.h"
@@ -77,7 +77,7 @@
     char *a;
     pa_ip_acl *acl;
 
-    assert(s);
+    pa_assert(s);
 
     acl = pa_xnew(pa_ip_acl, 1);
     PA_LLIST_HEAD_INIT(struct acl_entry, acl->entries);
@@ -91,7 +91,7 @@
             *slash = 0;
             slash++;
             if (pa_atou(slash, &bits) < 0) {
-                pa_log("failed to parse number of bits: %s", slash);
+                pa_log_warn("Failed to parse number of bits: %s", slash);
                 goto fail;
             }
         } else
@@ -102,21 +102,21 @@
             e.bits = bits == (uint32_t) -1 ? 32 : (int) bits;
 
             if (e.bits > 32) {
-                pa_log("number of bits out of range: %i", e.bits);
+                pa_log_warn("Number of bits out of range: %i", e.bits);
                 goto fail;
             }
 
             e.family = AF_INET;
 
             if (e.bits < 32 && (uint32_t) (ntohl(e.address_ipv4.s_addr) << e.bits) != 0)
-                pa_log_warn("WARNING: Host part of ACL entry '%s/%u' is not zero!", a, e.bits);
+                pa_log_warn("Host part of ACL entry '%s/%u' is not zero!", a, e.bits);
 
         } else if (inet_pton(AF_INET6, a, &e.address_ipv6) > 0) {
 
             e.bits = bits == (uint32_t) -1 ? 128 : (int) bits;
 
             if (e.bits > 128) {
-                pa_log("number of bits out of range: %i", e.bits);
+                pa_log_warn("Number of bits out of range: %i", e.bits);
                 goto fail;
             }
             e.family = AF_INET6;
@@ -138,11 +138,11 @@
                 }
 
                 if (t)
-                    pa_log_warn("WARNING: Host part of ACL entry '%s/%u' is not zero!", a, e.bits);
+                    pa_log_warn("Host part of ACL entry '%s/%u' is not zero!", a, e.bits);
             }
 
         } else {
-            pa_log("failed to parse address: %s", a);
+            pa_log_warn("Failed to parse address: %s", a);
             goto fail;
         }
 
@@ -162,7 +162,7 @@
 }
 
 void pa_ip_acl_free(pa_ip_acl *acl) {
-    assert(acl);
+    pa_assert(acl);
 
     while (acl->entries) {
         struct acl_entry *e = acl->entries;
@@ -178,8 +178,8 @@
     struct acl_entry *e;
     socklen_t  salen;
 
-    assert(acl);
-    assert(fd >= 0);
+    pa_assert(acl);
+    pa_assert(fd >= 0);
 
     salen = sizeof(sa);
     if (getpeername(fd, (struct sockaddr*) &sa, &salen) < 0)

Modified: trunk/src/pulsecore/llist.h
URL: http://0pointer.de/cgi-bin/viewcvs.cgi/trunk/src/pulsecore/llist.h?rev=1971&root=pulseaudio&r1=1970&r2=1971&view=diff
==============================================================================
--- trunk/src/pulsecore/llist.h (original)
+++ trunk/src/pulsecore/llist.h Sun Oct 28 20:13:50 2007
@@ -24,77 +24,86 @@
   USA.
 ***/
 
-#include <assert.h>
+#include <pulsecore/macro.h>
 
 /* Some macros for maintaining doubly linked lists */
 
 /* The head of the linked list. Use this in the structure that shall
  * contain the head of the linked list */
-#define PA_LLIST_HEAD(t,name) t *name
+#define PA_LLIST_HEAD(t,name)                                           \
+    t *name
 
 /* The pointers in the linked list's items. Use this in the item structure */
-#define PA_LLIST_FIELDS(t) t *next, *prev
+#define PA_LLIST_FIELDS(t)                                              \
+    t *next, *prev
 
 /* Initialize the list's head */
-#define PA_LLIST_HEAD_INIT(t,item) do { (item) = (t*) NULL; } while(0)
+#define PA_LLIST_HEAD_INIT(t,item)                                      \
+    do {                                                                \
+        (item) = (t*) NULL; }                                           \
+    while(0)
 
 /* Initialize a list item */
-#define PA_LLIST_INIT(t,item) do { \
-                               t *_item = (item); \
-                               assert(_item); \
-                               _item->prev = _item->next = NULL; \
-                               } while(0)
+#define PA_LLIST_INIT(t,item)                                           \
+    do {                                                                \
+        t *_item = (item);                                              \
+        pa_assert(_item);                                               \
+        _item->prev = _item->next = NULL;                               \
+    } while(0)
 
 /* Prepend an item to the list */
-#define PA_LLIST_PREPEND(t,head,item) do { \
-                                        t **_head = &(head), *_item = (item); \
-                                        assert(_item); \
-                                        if ((_item->next = *_head)) \
-                                           _item->next->prev = _item; \
-                                        _item->prev = NULL; \
-                                        *_head = _item; \
-                                        } while (0)
+#define PA_LLIST_PREPEND(t,head,item)                                   \
+    do {                                                                \
+        t **_head = &(head), *_item = (item);                           \
+        pa_assert(_item);                                               \
+        if ((_item->next = *_head))                                     \
+            _item->next->prev = _item;                                  \
+        _item->prev = NULL;                                             \
+        *_head = _item;                                                 \
+    } while (0)
 
 /* Remove an item from the list */
-#define PA_LLIST_REMOVE(t,head,item) do { \
-                                    t **_head = &(head), *_item = (item); \
-                                    assert(_item); \
-                                    if (_item->next) \
-                                       _item->next->prev = _item->prev; \
-                                    if (_item->prev) \
-                                       _item->prev->next = _item->next; \
-                                    else {\
-                                       assert(*_head == _item); \
-                                       *_head = _item->next; \
-                                    } \
-                                    _item->next = _item->prev = NULL; \
-                                    } while(0)
+#define PA_LLIST_REMOVE(t,head,item)                                    \
+    do {                                                                \
+        t **_head = &(head), *_item = (item);                           \
+        pa_assert(_item);                                               \
+        if (_item->next)                                                \
+            _item->next->prev = _item->prev;                            \
+        if (_item->prev)                                                \
+            _item->prev->next = _item->next;                            \
+        else {                                                          \
+            pa_assert(*_head == _item);                                 \
+            *_head = _item->next;                                       \
+        }                                                               \
+        _item->next = _item->prev = NULL;                               \
+    } while(0)
 
-#define PA_LLIST_FIND_HEAD(t,item,head) \
-do { \
-    t **_head = (head), *_item = (item); \
-    *_head = _item; \
-    assert(_head); \
-    while ((*_head)->prev) \
-        *_head = (*_head)->prev; \
-} while (0)
+/* Find the head of the list */
+#define PA_LLIST_FIND_HEAD(t,item,head)                                 \
+    do {                                                                \
+        t **_head = (head), *_item = (item);                            \
+        *_head = _item;                                                 \
+        pa_assert(_head);                                               \
+        while ((*_head)->prev)                                          \
+            *_head = (*_head)->prev;                                    \
+    } while (0)
 
-#define PA_LLIST_INSERT_AFTER(t,head,a,b) \
-do { \
-    t **_head = &(head), *_a = (a), *_b = (b); \
-    assert(_b); \
-    if (!_a) { \
-        if ((_b->next = *_head)) \
-            _b->next->prev = _b; \
-        _b->prev = NULL; \
-        *_head = _b; \
-    } else { \
-        if ((_b->next = _a->next)) \
-            _b->next->prev = _b; \
-        _b->prev = _a; \
-        _a->next = _b; \
-    } \
-} while (0)
-
+/* Insert an item after another one (a = where, b = what) */
+#define PA_LLIST_INSERT_AFTER(t,head,a,b)                               \
+    do {                                                                \
+        t **_head = &(head), *_a = (a), *_b = (b);                      \
+        pa_assert(_b);                                                  \
+        if (!_a) {                                                      \
+            if ((_b->next = *_head))                                    \
+                _b->next->prev = _b;                                    \
+            _b->prev = NULL;                                            \
+            *_head = _b;                                                \
+        } else {                                                        \
+            if ((_b->next = _a->next))                                  \
+                _b->next->prev = _b;                                    \
+            _b->prev = _a;                                              \
+            _a->next = _b;                                              \
+        }                                                               \
+    } while (0)
 
 #endif

Modified: trunk/src/pulsecore/log.c
URL: http://0pointer.de/cgi-bin/viewcvs.cgi/trunk/src/pulsecore/log.c?rev=1971&root=pulseaudio&r1=1970&r2=1971&view=diff
==============================================================================
--- trunk/src/pulsecore/log.c (original)
+++ trunk/src/pulsecore/log.c Sun Oct 28 20:13:50 2007
@@ -26,7 +26,6 @@
 #include <config.h>
 #endif
 
-#include <assert.h>
 #include <stdarg.h>
 #include <stdio.h>
 #include <unistd.h>
@@ -40,6 +39,7 @@
 #include <pulse/xmalloc.h>
 #include <pulse/util.h>
 
+#include <pulsecore/macro.h>
 #include <pulsecore/core-util.h>
 
 #include "log.h"
@@ -71,24 +71,30 @@
 };
 
 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);
 }
 
+/* To make valgrind shut up. */
+static void ident_destructor(void) PA_GCC_DESTRUCTOR;
+static void ident_destructor(void) {
+    pa_xfree(log_ident);
+    pa_xfree(log_ident_local);
+}
+
 void pa_log_set_maximal_level(pa_log_level_t l) {
-    assert(l < PA_LOG_LEVEL_MAX);
+    pa_assert(l < PA_LOG_LEVEL_MAX);
+
     maximal_level = l;
 }
 
 void pa_log_set_target(pa_log_target_t t, void (*func)(pa_log_level_t l, const char*s)) {
-    assert(t == PA_LOG_USER || !func);
+    pa_assert(t == PA_LOG_USER || !func);
+
     log_target = t;
     user_log_func = func;
 }
@@ -104,8 +110,8 @@
     const char *e;
     char *text, *t, *n, *location;
 
-    assert(level < PA_LOG_LEVEL_MAX);
-    assert(format);
+    pa_assert(level < PA_LOG_LEVEL_MAX);
+    pa_assert(format);
 
     if ((e = getenv(ENV_LOGLEVEL)))
         maximal_level = atoi(e);
@@ -221,6 +227,7 @@
 
 void pa_log_level(pa_log_level_t level, const char *format, ...) {
     va_list ap;
+
     va_start(ap, format);
     pa_log_levelv_meta(level, NULL, 0, NULL, format, ap);
     va_end(ap);

Copied: trunk/src/pulsecore/ltdl-helper.c (from r1970, branches/lennart/src/pulsecore/ltdl-helper.c)
URL: http://0pointer.de/cgi-bin/viewcvs.cgi/trunk/src/pulsecore/ltdl-helper.c?p2=trunk/src/pulsecore/ltdl-helper.c&p1=branches/lennart/src/pulsecore/ltdl-helper.c&r1=1970&r2=1971&rev=1971&root=pulseaudio&view=diff
==============================================================================
--- branches/lennart/src/pulsecore/ltdl-helper.c (original)
+++ trunk/src/pulsecore/ltdl-helper.c Sun Oct 28 20:13:50 2007
@@ -44,7 +44,7 @@
     pa_assert(handle);
     pa_assert(module);
     pa_assert(symbol);
-    
+
     if ((f = ((pa_void_func_t) (long) lt_dlsym(handle, symbol))))
         return f;
 

Modified: trunk/src/pulsecore/mcalign.c
URL: http://0pointer.de/cgi-bin/viewcvs.cgi/trunk/src/pulsecore/mcalign.c?rev=1971&root=pulseaudio&r1=1970&r2=1971&view=diff
==============================================================================
--- trunk/src/pulsecore/mcalign.c (original)
+++ trunk/src/pulsecore/mcalign.c Sun Oct 28 20:13:50 2007
@@ -27,10 +27,10 @@
 
 #include <stdio.h>
 #include <stdlib.h>
-#include <assert.h>
 #include <string.h>
 
 #include <pulse/xmalloc.h>
+#include <pulsecore/macro.h>
 
 #include "mcalign.h"
 
@@ -41,7 +41,7 @@
 
 pa_mcalign *pa_mcalign_new(size_t base) {
     pa_mcalign *m;
-    assert(base);
+    pa_assert(base);
 
     m = pa_xnew(pa_mcalign, 1);
 
@@ -53,7 +53,7 @@
 }
 
 void pa_mcalign_free(pa_mcalign *m) {
-    assert(m);
+    pa_assert(m);
 
     if (m->leftover.memblock)
         pa_memblock_unref(m->leftover.memblock);
@@ -65,13 +65,13 @@
 }
 
 void pa_mcalign_push(pa_mcalign *m, const pa_memchunk *c) {
-    assert(m);
-    assert(c);
-
-    assert(c->memblock);
-    assert(c->length > 0);
-
-    assert(!m->current.memblock);
+    pa_assert(m);
+    pa_assert(c);
+
+    pa_assert(c->memblock);
+    pa_assert(c->length > 0);
+
+    pa_assert(!m->current.memblock);
 
     /* Append to the leftover memory block */
     if (m->leftover.memblock) {
@@ -91,9 +91,10 @@
 
         } else {
             size_t l;
+            void *lo_data, *m_data;
 
             /* We have to copy */
-            assert(m->leftover.length < m->base);
+            pa_assert(m->leftover.length < m->base);
             l = m->base - m->leftover.length;
 
             if (l > c->length)
@@ -102,10 +103,15 @@
             /* 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);
+            pa_assert(m->leftover.length <= m->base);
+            pa_assert(m->leftover.length <= pa_memblock_get_length(m->leftover.memblock));
 
             if (c->length > l) {
                 /* Save the remainder of the memory block */
@@ -128,12 +134,13 @@
 }
 
 int pa_mcalign_pop(pa_mcalign *m, pa_memchunk *c) {
-    assert(m);
-    assert(c);
+    pa_assert(m);
+    pa_assert(c);
 
     /* First test if there's a leftover memory block available */
     if (m->leftover.memblock) {
-        assert(m->leftover.length > 0 && m->leftover.length <= m->base);
+        pa_assert(m->leftover.length > 0);
+        pa_assert(m->leftover.length <= m->base);
 
         /* The leftover memory block is not yet complete */
         if (m->leftover.length < m->base)
@@ -155,13 +162,13 @@
     /* Now let's see if there is other data available */
     if (m->current.memblock) {
         size_t l;
-        assert(m->current.length >= m->base);
+        pa_assert(m->current.length >= m->base);
 
         /* The length of the returned memory block */
         l = m->current.length;
         l /= m->base;
         l *= m->base;
-        assert(l > 0);
+        pa_assert(l > 0);
 
         /* Prepare the returned block */
         *c = m->current;
@@ -169,7 +176,7 @@
         c->length = l;
 
         /* Drop that from the current memory block */
-        assert(l <= m->current.length);
+        pa_assert(l <= m->current.length);
         m->current.index += l;
         m->current.length -= l;
 
@@ -178,7 +185,7 @@
             pa_memblock_unref(m->current.memblock);
         else {
             /* Move the raimainder to leftover */
-            assert(m->current.length < m->base && !m->leftover.memblock);
+            pa_assert(m->current.length < m->base && !m->leftover.memblock);
 
             m->leftover = m->current;
         }
@@ -194,10 +201,10 @@
 }
 
 size_t pa_mcalign_csize(pa_mcalign *m, size_t l) {
-    assert(m);
-    assert(l > 0);
-
-    assert(!m->current.memblock);
+    pa_assert(m);
+    pa_assert(l > 0);
+
+    pa_assert(!m->current.memblock);
 
     if (m->leftover.memblock)
         l += m->leftover.length;

Modified: trunk/src/pulsecore/memblock.c
URL: http://0pointer.de/cgi-bin/viewcvs.cgi/trunk/src/pulsecore/memblock.c?rev=1971&root=pulseaudio&r1=1970&r2=1971&view=diff
==============================================================================
--- trunk/src/pulsecore/memblock.c (original)
+++ trunk/src/pulsecore/memblock.c Sun Oct 28 20:13:50 2007
@@ -14,7 +14,7 @@
   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.
+  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
@@ -28,15 +28,21 @@
 
 #include <stdio.h>
 #include <stdlib.h>
-#include <assert.h>
 #include <string.h>
 #include <unistd.h>
+#include <signal.h>
+#include <errno.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 <pulsecore/core-util.h>
 
 #include "memblock.h"
 
@@ -47,6 +53,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;
@@ -55,6 +87,8 @@
 };
 
 struct pa_memimport {
+    pa_mutex *mutex;
+
     pa_mempool *pool;
     pa_hashmap *segments;
     pa_hashmap *blocks;
@@ -73,9 +107,11 @@
 };
 
 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,24 +131,32 @@
 };
 
 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);
 
+PA_STATIC_FLIST_DECLARE(unused_memblocks, 0, pa_xfree);
+
+/* No lock necessary */
 static void stat_add(pa_memblock*b) {
-    assert(b);
-    assert(b->pool);
+    pa_assert(b);
+    pa_assert(b->pool);
 
     pa_atomic_inc(&b->pool->stat.n_allocated);
     pa_atomic_add(&b->pool->stat.allocated_size, b->length);
@@ -129,19 +173,20 @@
     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);
-
-    assert(pa_atomic_load(&b->pool->stat.n_allocated) > 0);
-    assert(pa_atomic_load(&b->pool->stat.allocated_size) >= (int) b->length);
+    pa_assert(b);
+    pa_assert(b->pool);
+
+    pa_assert(pa_atomic_load(&b->pool->stat.n_allocated) > 0);
+    pa_assert(pa_atomic_load(&b->pool->stat.allocated_size) >= (int) b->length);
 
     pa_atomic_dec(&b->pool->stat.n_allocated);
     pa_atomic_sub(&b->pool->stat.allocated_size,  b->length);
 
     if (b->type == PA_MEMBLOCK_IMPORTED) {
-        assert(pa_atomic_load(&b->pool->stat.n_imported) > 0);
-        assert(pa_atomic_load(&b->pool->stat.imported_size) >= (int) b->length);
+        pa_assert(pa_atomic_load(&b->pool->stat.n_imported) > 0);
+        pa_assert(pa_atomic_load(&b->pool->stat.imported_size) >= (int) b->length);
 
         pa_atomic_dec(&b->pool->stat.n_imported);
         pa_atomic_sub(&b->pool->stat.imported_size, b->length);
@@ -152,11 +197,12 @@
 
 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;
 
-    assert(p);
-    assert(length > 0);
+    pa_assert(p);
+    pa_assert(length > 0);
 
     if (!(b = pa_memblock_new_pool(p, length)))
         b = memblock_new_appended(p, length);
@@ -164,56 +210,75 @@
     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);
+    pa_assert(p);
+    pa_assert(length > 0);
+
+    /* If -1 is passed as length we choose the size for the caller. */
+
+    if (length == (size_t) -1)
+        length = p->block_size - PA_ALIGN(sizeof(struct mempool_slot)) - PA_ALIGN(sizeof(pa_memblock));
+
+    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;
+    pa_assert(p);
+
+    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);
-}
-
+    pa_assert(slot);
+
+    return (uint8_t*) slot + PA_ALIGN(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);
+    pa_assert(p);
+
+    pa_assert((uint8_t*) ptr >= (uint8_t*) p->memory.ptr);
+    pa_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,189 +288,321 @@
     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;
 
-    assert(p);
-    assert(length > 0);
-
-    if (p->block_size - sizeof(struct mempool_slot) >= sizeof(pa_memblock) + length) {
+    pa_assert(p);
+    pa_assert(length > 0);
+
+    /* If -1 is passed as length we choose the size for the caller: we
+     * take the largest size that fits in one of our slots. */
+
+    if (length == (size_t) -1)
+        length = pa_mempool_block_size_max(p);
+
+    if (p->block_size - PA_ALIGN(sizeof(struct mempool_slot)) >= PA_ALIGN(sizeof(pa_memblock)) + length) {
 
         if (!(slot = mempool_allocate_slot(p)))
             return NULL;
 
         b = mempool_slot_data(slot);
         b->type = PA_MEMBLOCK_POOL;
-        b->data = (uint8_t*) b + sizeof(pa_memblock);
-
-    } else if (p->block_size - sizeof(struct mempool_slot) >= length) {
+        pa_atomic_ptr_store(&b->data, (uint8_t*) b + PA_ALIGN(sizeof(pa_memblock)));
+
+    } else if (p->block_size - PA_ALIGN(sizeof(struct mempool_slot)) >= length) {
 
         if (!(slot = mempool_allocate_slot(p)))
             return NULL;
 
-        b = pa_xnew(pa_memblock, 1);
+        if (!(b = pa_flist_pop(PA_STATIC_FLIST_GET(unused_memblocks))))
+            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_log_debug("Memory block too large for pool: %lu > %lu", (unsigned long) length, (unsigned long) (p->block_size - PA_ALIGN(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;
 
-    assert(p);
-    assert(d);
-    assert(length > 0);
-
-    b = pa_xnew(pa_memblock, 1);
+    pa_assert(p);
+    pa_assert(d);
+    pa_assert(length != (size_t) -1);
+    pa_assert(length > 0);
+
+    if (!(b = pa_flist_pop(PA_STATIC_FLIST_GET(unused_memblocks))))
+        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;
 
-    assert(p);
-    assert(d);
-    assert(length > 0);
-    assert(free_cb);
-
-    b = pa_xnew(pa_memblock, 1);
+    pa_assert(p);
+    pa_assert(d);
+    pa_assert(length > 0);
+    pa_assert(length != (size_t) -1);
+    pa_assert(free_cb);
+
+    if (!(b = pa_flist_pop(PA_STATIC_FLIST_GET(unused_memblocks))))
+        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) {
+    pa_assert(b);
+    pa_assert(PA_REFCNT_VALUE(b) > 0);
+
+    return b->read_only && PA_REFCNT_VALUE(b) == 1;
+}
+
+/* No lock necessary */
+int pa_memblock_ref_is_one(pa_memblock *b) {
+    int r;
+
+    pa_assert(b);
+
+    r = PA_REFCNT_VALUE(b);
+    pa_assert(r > 0);
+
+    return r == 1;
+}
+
+/* No lock necessary */
+void* pa_memblock_acquire(pa_memblock *b) {
+    pa_assert(b);
+    pa_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;
+    pa_assert(b);
+    pa_assert(PA_REFCNT_VALUE(b) > 0);
+
+    r = pa_atomic_dec(&b->n_acquired);
+    pa_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) {
+    pa_assert(b);
+    pa_assert(PA_REFCNT_VALUE(b) > 0);
+
+    return b->length;
+}
+
+pa_mempool* pa_memblock_get_pool(pa_memblock *b) {
+    pa_assert(b);
+    pa_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);
+    pa_assert(b);
+    pa_assert(PA_REFCNT_VALUE(b) > 0);
 
     PA_REFCNT_INC(b);
     return b;
 }
 
-void pa_memblock_unref(pa_memblock*b) {
-    assert(b);
-    assert(PA_REFCNT_VALUE(b) > 0);
-
-    if (PA_REFCNT_DEC(b) > 0)
-        return;
+static void memblock_free(pa_memblock *b) {
+    pa_assert(b);
+
+    pa_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);
+            pa_assert(b->per_type.user.free_cb);
+            b->per_type.user.free_cb(pa_atomic_ptr_load(&b->data));
 
             /* Fall through */
 
         case PA_MEMBLOCK_FIXED:
         case PA_MEMBLOCK_APPENDED :
-            pa_xfree(b);
+            if (pa_flist_push(PA_STATIC_FLIST_GET(unused_memblocks), b) < 0)
+                pa_xfree(b);
+
             break;
 
         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);
-
+            pa_assert(segment);
+            import = segment->import;
+            pa_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_xfree(b);
+            pa_mutex_unlock(import->mutex);
+
+            import->release_cb(import, b->per_type.imported.id, import->userdata);
+
+            if (pa_flist_push(PA_STATIC_FLIST_GET(unused_memblocks), b) < 0)
+                pa_xfree(b);
             break;
         }
 
         case PA_MEMBLOCK_POOL_EXTERNAL:
         case PA_MEMBLOCK_POOL: {
             struct mempool_slot *slot;
-
-            slot = mempool_slot_by_ptr(b->pool, b->data);
-            assert(slot);
-
-            PA_LLIST_PREPEND(struct mempool_slot, b->pool->free_slots, slot);
-
-            if (b->type == PA_MEMBLOCK_POOL_EXTERNAL)
-                pa_xfree(b);
+            int call_free;
+
+            slot = mempool_slot_by_ptr(b->pool, pa_atomic_ptr_load(&b->data));
+            pa_assert(slot);
+
+            call_free = 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)
+                if (pa_flist_push(PA_STATIC_FLIST_GET(unused_memblocks), b) < 0)
+                    pa_xfree(b);
 
             break;
         }
 
         case PA_MEMBLOCK_TYPE_MAX:
         default:
-            abort();
-    }
-}
-
+            pa_assert_not_reached();
+    }
+}
+
+/* No lock necessary */
+void pa_memblock_unref(pa_memblock*b) {
+    pa_assert(b);
+    pa_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) {
+    pa_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);
+    pa_assert(b);
 
     pa_atomic_dec(&b->pool->stat.n_allocated_by_type[b->type]);
 
-    if (b->length <= b->pool->block_size - sizeof(struct mempool_slot)) {
+    if (b->length <= b->pool->block_size - PA_ALIGN(sizeof(struct mempool_slot))) {
         struct mempool_slot *slot;
 
         if ((slot = mempool_allocate_slot(b->pool))) {
             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->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->per_type.user.free_cb = pa_xfree;
     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);
+    pa_assert(b);
+    pa_assert(PA_REFCNT_VALUE(b) > 0);
+    pa_assert(b->type == PA_MEMBLOCK_FIXED);
 
     if (PA_REFCNT_VALUE(b) > 1)
         memblock_make_local(b);
@@ -413,20 +610,37 @@
     pa_memblock_unref(b);
 }
 
+/* No lock necessary. */
+pa_memblock *pa_memblock_will_need(pa_memblock *b) {
+    void *p;
+
+    pa_assert(b);
+    pa_assert(PA_REFCNT_VALUE(b) > 0);
+
+    p = pa_memblock_acquire(b);
+    pa_will_need(p, b->length);
+    pa_memblock_release(b);
+
+    return b;
+}
+
+/* Self-locked. This function is not multiple-caller safe */
 static void memblock_replace_import(pa_memblock *b) {
     pa_memimport_segment *seg;
 
-    assert(b);
-    assert(b->type == PA_MEMBLOCK_IMPORTED);
-
-    assert(pa_atomic_load(&b->pool->stat.n_imported) > 0);
-    assert(pa_atomic_load(&b->pool->stat.imported_size) >= (int) b->length);
+    pa_assert(b);
+    pa_assert(b->type == PA_MEMBLOCK_IMPORTED);
+
+    pa_assert(pa_atomic_load(&b->pool->stat.n_imported) > 0);
+    pa_assert(pa_atomic_load(&b->pool->stat.imported_size) >= (int) b->length);
     pa_atomic_dec(&b->pool->stat.n_imported);
     pa_atomic_sub(&b->pool->stat.imported_size, b->length);
 
     seg = b->per_type.imported.segment;
-    assert(seg);
-    assert(seg->import);
+    pa_assert(seg);
+    pa_assert(seg->import);
+
+    pa_mutex_lock(seg->import->mutex);
 
     pa_hashmap_remove(
             seg->import->blocks,
@@ -434,51 +648,49 @@
 
     memblock_make_local(b);
 
-    if (-- seg->n_blocks <= 0)
+    if (-- seg->n_blocks <= 0) {
+        pa_mutex_unlock(seg->import->mutex);
         segment_detach(seg);
+    } else
+        pa_mutex_unlock(seg->import->mutex);
 }
 
 pa_mempool* pa_mempool_new(int shared) {
-    size_t ps;
     pa_mempool *p;
 
     p = pa_xnew(pa_mempool, 1);
 
-#ifdef HAVE_SYSCONF
-    ps = (size_t) sysconf(_SC_PAGESIZE);
-#elif defined(PAGE_SIZE)
-	ps = (size_t) PAGE_SIZE;
-#else
-	ps = 4096; /* Let's hope it's like x86. */
-#endif
-
-    p->block_size = (PA_MEMPOOL_SLOT_SIZE/ps)*ps;
-
-    if (p->block_size < ps)
-        p->block_size = ps;
+    p->mutex = pa_mutex_new(TRUE, TRUE);
+    p->semaphore = pa_semaphore_new(0);
+
+    p->block_size = PA_PAGE_ALIGN(PA_MEMPOOL_SLOT_SIZE);
+    if (p->block_size < PA_PAGE_SIZE)
+        p->block_size = PA_PAGE_SIZE;
 
     p->n_blocks = PA_MEMPOOL_SLOTS_MAX;
 
-    assert(p->block_size > sizeof(struct mempool_slot));
+    pa_assert(p->block_size > PA_ALIGN(sizeof(struct mempool_slot)));
 
     if (pa_shm_create_rw(&p->memory, p->n_blocks * p->block_size, shared, 0700) < 0) {
         pa_xfree(p);
         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;
 }
 
 void pa_mempool_free(pa_mempool *p) {
-    assert(p);
+    pa_assert(p);
+
+    pa_mutex_lock(p->mutex);
 
     while (p->imports)
         pa_memimport_free(p->imports);
@@ -486,30 +698,65 @@
     while (p->exports)
         pa_memexport_free(p->exports);
 
-    if (pa_atomic_load(&p->stat.n_allocated) > 0)
-        pa_log_warn("WARNING! Memory pool destroyed but not all memory blocks freed!");
+    pa_mutex_unlock(p->mutex);
+
+    pa_flist_free(p->free_slots, NULL);
+
+    if (pa_atomic_load(&p->stat.n_allocated) > 0) {
+/*         raise(SIGTRAP);  */
+        pa_log_warn("Memory pool destroyed but not all memory blocks freed! %u remain.", pa_atomic_load(&p->stat.n_allocated));
+    }
 
     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);
+    pa_assert(p);
 
     return &p->stat;
 }
 
+/* No lock necessary */
+size_t pa_mempool_block_size_max(pa_mempool *p) {
+    pa_assert(p);
+
+    return p->block_size - PA_ALIGN(sizeof(struct mempool_slot)) - PA_ALIGN(sizeof(pa_memblock));
+}
+
+/* No lock necessary */
 void pa_mempool_vacuum(pa_mempool *p) {
     struct mempool_slot *slot;
-
-    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));
-}
-
+    pa_flist *list;
+
+    pa_assert(p);
+
+    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 + PA_ALIGN(sizeof(struct mempool_slot)),
+                     p->block_size - PA_ALIGN(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);
+    pa_assert(p);
 
     if (!p->memory.shared)
         return -1;
@@ -519,8 +766,9 @@
     return 0;
 }
 
+/* No lock necessary */
 int pa_mempool_is_shared(pa_mempool *p) {
-    assert(p);
+    pa_assert(p);
 
     return !!p->memory.shared;
 }
@@ -529,22 +777,27 @@
 pa_memimport* pa_memimport_new(pa_mempool *p, pa_memimport_release_cb_t cb, void *userdata) {
     pa_memimport *i;
 
-    assert(p);
-    assert(cb);
+    pa_assert(p);
+    pa_assert(cb);
 
     i = pa_xnew(pa_memimport, 1);
+    i->mutex = pa_mutex_new(TRUE, TRUE);
     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,59 +818,79 @@
     return seg;
 }
 
+/* Should be called locked */
 static void segment_detach(pa_memimport_segment *seg) {
-    assert(seg);
+    pa_assert(seg);
 
     pa_hashmap_remove(seg->import->segments, PA_UINT32_TO_PTR(seg->memory.id));
     pa_shm_free(&seg->memory);
     pa_xfree(seg);
 }
 
+/* Self-locked. Not multiple-caller safe */
 void pa_memimport_free(pa_memimport *i) {
     pa_memexport *e;
     pa_memblock *b;
 
-    assert(i);
+    pa_assert(i);
+
+    pa_mutex_lock(i->mutex);
+
+    while ((b = pa_hashmap_get_first(i->blocks)))
+        memblock_replace_import(b);
+
+    pa_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);
 
-    while ((b = pa_hashmap_get_first(i->blocks)))
-        memblock_replace_import(b);
-
-    assert(pa_hashmap_size(i->segments) == 0);
+    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_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;
-
-    b = pa_xnew(pa_memblock, 1);
+        goto finish;
+
+    if (!(b = pa_flist_pop(PA_STATIC_FLIST_GET(unused_memblocks))))
+        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 +898,10 @@
 
     seg->n_blocks++;
 
+finish:
+    pa_mutex_unlock(i->mutex);
+
+    if (b)
     stat_add(b);
 
     return b;
@@ -632,26 +909,36 @@
 
 int pa_memimport_process_revoke(pa_memimport *i, uint32_t id) {
     pa_memblock *b;
-    assert(i);
-
-    if (!(b = pa_hashmap_get(i->blocks, PA_UINT32_TO_PTR(id))))
-        return -1;
+    int ret = 0;
+    pa_assert(i);
+
+    pa_mutex_lock(i->mutex);
+
+    if (!(b = pa_hashmap_get(i->blocks, PA_UINT32_TO_PTR(id)))) {
+        ret = -1;
+        goto finish;
+    }
 
     memblock_replace_import(b);
-    return 0;
+
+finish:
+    pa_mutex_unlock(i->mutex);
+
+    return ret;
 }
 
 /* For sending blocks to other nodes */
 pa_memexport* pa_memexport_new(pa_mempool *p, pa_memexport_revoke_cb_t cb, void *userdata) {
     pa_memexport *e;
 
-    assert(p);
-    assert(cb);
+    pa_assert(p);
+    pa_assert(cb);
 
     if (!p->memory.shared)
         return NULL;
 
     e = pa_xnew(pa_memexport, 1);
+    e->mutex = pa_mutex_new(TRUE, TRUE);
     e->pool = p;
     PA_LLIST_HEAD_INIT(struct memexport_slot, e->free_slots);
     PA_LLIST_HEAD_INIT(struct memexport_slot, e->used_slots);
@@ -659,50 +946,75 @@
     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_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_mutex_free(e->mutex);
     pa_xfree(e);
 }
 
+/* Self-locked */
 int pa_memexport_process_release(pa_memexport *e, uint32_t id) {
-    assert(e);
+    pa_memblock *b;
+
+    pa_assert(e);
+
+    pa_mutex_lock(e->mutex);
 
     if (id >= e->n_init)
-        return -1;
+        goto fail;
 
     if (!e->slots[id].block)
-        return -1;
-
-/*     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);
-
-    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);
+        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); */
+
+    pa_assert(pa_atomic_load(&e->pool->stat.n_exported) > 0);
+    pa_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, b->length);
+
+    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_assert(e);
+    pa_assert(i);
+
+    pa_mutex_lock(e->mutex);
 
     for (slot = e->used_slots; slot; slot = next) {
         uint32_t idx;
@@ -716,49 +1028,57 @@
         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;
 
-    assert(p);
-    assert(b);
+    pa_assert(p);
+    pa_assert(b);
 
     if (b->type == PA_MEMBLOCK_IMPORTED ||
         b->type == PA_MEMBLOCK_POOL ||
         b->type == PA_MEMBLOCK_POOL_EXTERNAL) {
-        assert(b->pool == p);
+        pa_assert(b->pool == p);
         return pa_memblock_ref(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;
-
-    assert(e);
-    assert(b);
-    assert(block_id);
-    assert(shm_id);
-    assert(offset);
-    assert(size);
-    assert(b->pool == e->pool);
+    void *data;
+
+    pa_assert(e);
+    pa_assert(b);
+    pa_assert(block_id);
+    pa_assert(shm_id);
+    pa_assert(offset);
+    pa_assert(size);
+    pa_assert(b->pool == e->pool);
 
     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,23 +1087,28 @@
     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);
+        pa_assert(b->per_type.imported.segment);
         memory = &b->per_type.imported.segment->memory;
     } else {
-        assert(b->type == PA_MEMBLOCK_POOL || b->type == PA_MEMBLOCK_POOL_EXTERNAL);
-        assert(b->pool);
+        pa_assert(b->type == PA_MEMBLOCK_POOL || b->type == PA_MEMBLOCK_POOL_EXTERNAL);
+        pa_assert(b->pool);
         memory = &b->pool->memory;
     }
 
-    assert(b->data >= memory->ptr);
-    assert((uint8_t*) b->data + b->length <= (uint8_t*) memory->ptr + memory->size);
+    pa_assert(data >= memory->ptr);
+    pa_assert((uint8_t*) data + b->length <= (uint8_t*) memory->ptr + memory->size);
 
     *shm_id = memory->id;
-    *offset = (uint8_t*) b->data - (uint8_t*) memory->ptr;
+    *offset = (uint8_t*) data - (uint8_t*) memory->ptr;
     *size = b->length;
+
+    pa_memblock_release(b);
 
     pa_atomic_inc(&e->pool->stat.n_exported);
     pa_atomic_add(&e->pool->stat.exported_size, b->length);

Modified: trunk/src/pulsecore/memblock.h
URL: http://0pointer.de/cgi-bin/viewcvs.cgi/trunk/src/pulsecore/memblock.h?rev=1971&root=pulseaudio&r1=1970&r2=1971&view=diff
==============================================================================
--- trunk/src/pulsecore/memblock.h (original)
+++ trunk/src/pulsecore/memblock.h Sun Oct 28 20:13:50 2007
@@ -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 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_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_int_t n_too_large_for_pool;
-    pa_atomic_int_t n_pool_full;
+    pa_atomic_t n_too_large_for_pool;
+    pa_atomic_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_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,8 +101,19 @@
 /* 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);
+int pa_memblock_ref_is_one(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);
+
+pa_memblock *pa_memblock_will_need(pa_memblock *b);
 
 /* The memory block manager */
 pa_mempool* pa_mempool_new(int shared);
@@ -130,6 +122,7 @@
 void pa_mempool_vacuum(pa_mempool *p);
 int pa_mempool_get_shm_id(pa_mempool *p, uint32_t *id);
 int pa_mempool_is_shared(pa_mempool *p);
+size_t pa_mempool_block_size_max(pa_mempool *p);
 
 /* For recieving blocks from other nodes */
 pa_memimport* pa_memimport_new(pa_mempool *p, pa_memimport_release_cb_t cb, void *userdata);

Modified: trunk/src/pulsecore/memblockq.c
URL: http://0pointer.de/cgi-bin/viewcvs.cgi/trunk/src/pulsecore/memblockq.c?rev=1971&root=pulseaudio&r1=1970&r2=1971&view=diff
==============================================================================
--- trunk/src/pulsecore/memblockq.c (original)
+++ trunk/src/pulsecore/memblockq.c Sun Oct 28 20:13:50 2007
@@ -28,7 +28,6 @@
 #include <sys/time.h>
 #include <time.h>
 #include <stdio.h>
-#include <assert.h>
 #include <stdlib.h>
 #include <string.h>
 
@@ -36,23 +35,29 @@
 
 #include <pulsecore/log.h>
 #include <pulsecore/mcalign.h>
+#include <pulsecore/macro.h>
+#include <pulsecore/flist.h>
 
 #include "memblockq.h"
 
-struct memblock_list {
-    struct memblock_list *next, *prev;
+struct list_item {
+    struct list_item *next, *prev;
     int64_t index;
     pa_memchunk chunk;
 };
 
+PA_STATIC_FLIST_DECLARE(list_items, 0, pa_xfree);
+
 struct pa_memblockq {
-    struct memblock_list *blocks, *blocks_tail;
+    struct list_item *blocks, *blocks_tail;
     unsigned n_blocks;
     size_t maxlength, tlength, base, prebuf, minreq;
     int64_t read_index, write_index;
-    enum { PREBUF, RUNNING } state;
+    pa_bool_t in_prebuf;
     pa_memblock *silence;
     pa_mcalign *mcalign;
+    int64_t missing;
+    size_t requested;
 };
 
 pa_memblockq* pa_memblockq_new(
@@ -66,8 +71,8 @@
 
     pa_memblockq* bq;
 
-    assert(base > 0);
-    assert(maxlength >= base);
+    pa_assert(base > 0);
+    pa_assert(maxlength >= base);
 
     bq = pa_xnew(pa_memblockq, 1);
     bq->blocks = bq->blocks_tail = NULL;
@@ -77,13 +82,13 @@
     bq->read_index = bq->write_index = idx;
 
     pa_log_debug("memblockq requested: maxlength=%lu, tlength=%lu, base=%lu, prebuf=%lu, minreq=%lu",
-        (unsigned long)maxlength, (unsigned long)tlength, (unsigned long)base, (unsigned long)prebuf, (unsigned long)minreq);
+        (unsigned long) maxlength, (unsigned long) tlength, (unsigned long) base, (unsigned long) prebuf, (unsigned long) minreq);
 
     bq->maxlength = ((maxlength+base-1)/base)*base;
-    assert(bq->maxlength >= base);
+    pa_assert(bq->maxlength >= base);
 
     bq->tlength = ((tlength+base-1)/base)*base;
-    if (!bq->tlength || bq->tlength >= bq->maxlength)
+    if (bq->tlength <= 0 || bq->tlength > bq->maxlength)
         bq->tlength = bq->maxlength;
 
     bq->prebuf = (prebuf == (size_t) -1) ? bq->tlength/2 : prebuf;
@@ -102,15 +107,18 @@
     pa_log_debug("memblockq sanitized: maxlength=%lu, tlength=%lu, base=%lu, prebuf=%lu, minreq=%lu",
         (unsigned long)bq->maxlength, (unsigned long)bq->tlength, (unsigned long)bq->base, (unsigned long)bq->prebuf, (unsigned long)bq->minreq);
 
-    bq->state = bq->prebuf ? PREBUF : RUNNING;
+    bq->in_prebuf = bq->prebuf > 0;
     bq->silence = silence ? pa_memblock_ref(silence) : NULL;
     bq->mcalign = NULL;
 
+    bq->missing = bq->tlength;
+    bq->requested = 0;
+
     return bq;
 }
 
 void pa_memblockq_free(pa_memblockq* bq) {
-    assert(bq);
+    pa_assert(bq);
 
     pa_memblockq_flush(bq);
 
@@ -123,11 +131,11 @@
     pa_xfree(bq);
 }
 
-static void drop_block(pa_memblockq *bq, struct memblock_list *q) {
-    assert(bq);
-    assert(q);
-
-    assert(bq->n_blocks >= 1);
+static void drop_block(pa_memblockq *bq, struct list_item *q) {
+    pa_assert(bq);
+    pa_assert(q);
+
+    pa_assert(bq->n_blocks >= 1);
 
     if (q->prev)
         q->prev->next = q->next;
@@ -140,15 +148,17 @@
         bq->blocks_tail = q->prev;
 
     pa_memblock_unref(q->chunk.memblock);
-    pa_xfree(q);
+
+    if (pa_flist_push(PA_STATIC_FLIST_GET(list_items), q) < 0)
+        pa_xfree(q);
 
     bq->n_blocks--;
 }
 
-static int can_push(pa_memblockq *bq, size_t l) {
+static pa_bool_t can_push(pa_memblockq *bq, size_t l) {
     int64_t end;
 
-    assert(bq);
+    pa_assert(bq);
 
     if (bq->read_index > bq->write_index) {
         size_t d =  bq->read_index - bq->write_index;
@@ -156,7 +166,7 @@
         if (l > d)
             l -= d;
         else
-            return 1;
+            return TRUE;
     }
 
     end = bq->blocks_tail ? bq->blocks_tail->index + bq->blocks_tail->chunk.length : 0;
@@ -164,21 +174,21 @@
     /* Make sure that the list doesn't get too long */
     if (bq->write_index + (int64_t)l > end)
         if (bq->write_index + l - bq->read_index > bq->maxlength)
-            return 0;
-
-    return 1;
+            return FALSE;
+
+    return TRUE;
 }
 
 int pa_memblockq_push(pa_memblockq* bq, const pa_memchunk *uchunk) {
-
-    struct memblock_list *q, *n;
+    struct list_item *q, *n;
     pa_memchunk chunk;
-
-    assert(bq);
-    assert(uchunk);
-    assert(uchunk->memblock);
-    assert(uchunk->length > 0);
-    assert(uchunk->index + uchunk->length <= uchunk->memblock->length);
+    int64_t old, delta;
+
+    pa_assert(bq);
+    pa_assert(uchunk);
+    pa_assert(uchunk->memblock);
+    pa_assert(uchunk->length > 0);
+    pa_assert(uchunk->index + uchunk->length <= pa_memblock_get_length(uchunk->memblock));
 
     if (uchunk->length % bq->base)
         return -1;
@@ -186,6 +196,7 @@
     if (!can_push(bq, uchunk->length))
         return -1;
 
+    old = bq->write_index;
     chunk = *uchunk;
 
     if (bq->read_index > bq->write_index) {
@@ -198,11 +209,11 @@
         if (chunk.length > d) {
             chunk.index += d;
             chunk.length -= d;
-            bq->write_index = bq->read_index;
+            bq->write_index += d;
         } else {
             /* We drop the incoming data completely */
             bq->write_index += chunk.length;
-            return 0;
+            goto finish;
         }
     }
 
@@ -212,10 +223,10 @@
     q = bq->blocks_tail;
     while (q) {
 
-        if (bq->write_index >= q->index + (int64_t)q->chunk.length)
+        if (bq->write_index >= q->index + (int64_t) q->chunk.length)
             /* We found the entry where we need to place the new entry immediately after */
             break;
-        else if (bq->write_index + (int64_t)chunk.length <= q->index) {
+        else if (bq->write_index + (int64_t) chunk.length <= q->index) {
             /* This entry isn't touched at all, let's skip it */
             q = q->prev;
         } else if (bq->write_index <= q->index &&
@@ -223,7 +234,7 @@
 
             /* This entry is fully replaced by the new entry, so let's drop it */
 
-            struct memblock_list *p;
+            struct list_item *p;
             p = q;
             q = q->prev;
             drop_block(bq, p);
@@ -234,17 +245,19 @@
             if (bq->write_index + chunk.length < q->index + q->chunk.length) {
 
                 /* We need to save the end of this memchunk */
-                struct memblock_list *p;
+                struct list_item *p;
                 size_t d;
 
                 /* Create a new list entry for the end of thie memchunk */
-                p = pa_xnew(struct memblock_list, 1);
+                if (!(p = pa_flist_pop(PA_STATIC_FLIST_GET(list_items))))
+                    p = pa_xnew(struct list_item, 1);
+
                 p->chunk = q->chunk;
                 pa_memblock_ref(p->chunk.memblock);
 
                 /* Calculate offset */
                 d = bq->write_index + chunk.length - q->index;
-                assert(d > 0);
+                pa_assert(d > 0);
 
                 /* Drop it from the new entry */
                 p->index = q->index + d;
@@ -263,7 +276,7 @@
 
             /* Truncate the chunk */
             if (!(q->chunk.length = bq->write_index - q->index)) {
-                struct memblock_list *p;
+                struct list_item *p;
                 p = q;
                 q = q->prev;
                 drop_block(bq, p);
@@ -274,7 +287,7 @@
         } else {
             size_t d;
 
-            assert(bq->write_index + (int64_t)chunk.length > q->index &&
+            pa_assert(bq->write_index + (int64_t)chunk.length > q->index &&
                    bq->write_index + (int64_t)chunk.length < q->index + (int64_t)q->chunk.length &&
                    bq->write_index < q->index);
 
@@ -287,12 +300,11 @@
 
             q = q->prev;
         }
-
     }
 
     if (q) {
-        assert(bq->write_index >=  q->index + (int64_t)q->chunk.length);
-        assert(!q->next || (bq->write_index + (int64_t)chunk.length <= q->next->index));
+        pa_assert(bq->write_index >=  q->index + (int64_t)q->chunk.length);
+        pa_assert(!q->next || (bq->write_index + (int64_t)chunk.length <= q->next->index));
 
         /* Try to merge memory blocks */
 
@@ -302,13 +314,14 @@
 
             q->chunk.length += chunk.length;
             bq->write_index += chunk.length;
-            return 0;
+            goto finish;
         }
     } else
-        assert(!bq->blocks || (bq->write_index + (int64_t)chunk.length <= bq->blocks->index));
-
-
-    n = pa_xnew(struct memblock_list, 1);
+        pa_assert(!bq->blocks || (bq->write_index + (int64_t)chunk.length <= bq->blocks->index));
+
+    if (!(n = pa_flist_pop(PA_STATIC_FLIST_GET(list_items))))
+        n = pa_xnew(struct list_item, 1);
+
     n->chunk = chunk;
     pa_memblock_ref(n->chunk.memblock);
     n->index = bq->write_index;
@@ -328,27 +341,52 @@
         bq->blocks = n;
 
     bq->n_blocks++;
+
+finish:
+
+    delta = bq->write_index - old;
+
+    if (delta >= bq->requested) {
+        delta -= bq->requested;
+        bq->requested = 0;
+    } else {
+        bq->requested -= delta;
+        delta = 0;
+    }
+
+    bq->missing -= delta;
+
     return 0;
 }
 
+static pa_bool_t memblockq_check_prebuf(pa_memblockq *bq) {
+    pa_assert(bq);
+
+    if (bq->in_prebuf) {
+
+        if (pa_memblockq_get_length(bq) < bq->prebuf)
+            return TRUE;
+
+        bq->in_prebuf = FALSE;
+        return FALSE;
+    } else {
+
+        if (bq->prebuf > 0 && bq->read_index >= bq->write_index) {
+            bq->in_prebuf = TRUE;
+            return TRUE;
+        }
+
+        return FALSE;
+    }
+}
+
 int pa_memblockq_peek(pa_memblockq* bq, pa_memchunk *chunk) {
-    assert(bq);
-    assert(chunk);
-
-    if (bq->state == PREBUF) {
-
-        /* We need to pre-buffer */
-        if (pa_memblockq_get_length(bq) < bq->prebuf)
-            return -1;
-
-        bq->state = RUNNING;
-
-    } else if (bq->prebuf > 0 && bq->read_index >= bq->write_index) {
-
-        /* Buffer underflow protection */
-        bq->state = PREBUF;
+    pa_assert(bq);
+    pa_assert(chunk);
+
+    /* We need to pre-buffer */
+    if (memblockq_check_prebuf(bq))
         return -1;
-    }
 
     /* Do we need to spit out silence? */
     if (!bq->blocks || bq->blocks->index > bq->read_index) {
@@ -362,8 +400,8 @@
         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 {
@@ -382,7 +420,7 @@
     }
 
     /* Ok, let's pass real data to the caller */
-    assert(bq->blocks->index == bq->read_index);
+    pa_assert(bq->blocks->index == bq->read_index);
 
     *chunk = bq->blocks->chunk;
     pa_memblock_ref(chunk->memblock);
@@ -390,48 +428,23 @@
     return 0;
 }
 
-void pa_memblockq_drop(pa_memblockq *bq, const pa_memchunk *chunk, size_t length) {
-    assert(bq);
-    assert(length % bq->base == 0);
-
-    assert(!chunk || length <= chunk->length);
-
-    if (chunk) {
-
-        if (bq->blocks && bq->blocks->index == bq->read_index) {
-            /* The first item in queue is valid */
-
-            /* Does the chunk match with what the user supplied us? */
-            if (memcmp(chunk, &bq->blocks->chunk, sizeof(pa_memchunk)) != 0)
-                return;
-
-        } else {
-            size_t l;
-
-            /* The first item in the queue is not yet relevant */
-
-            assert(!bq->blocks || bq->blocks->index > bq->read_index);
-            l = bq->blocks ? bq->blocks->index - bq->read_index : 0;
-
-            if (bq->silence) {
-
-                if (!l || l > bq->silence->length)
-                    l = bq->silence->length;
-
-            }
-
-            /* Do the entries still match? */
-            if (chunk->index != 0 || chunk->length != l || chunk->memblock != bq->silence)
-                return;
-        }
-    }
+void pa_memblockq_drop(pa_memblockq *bq, size_t length) {
+    int64_t old, delta;
+    pa_assert(bq);
+    pa_assert(length % bq->base == 0);
+
+    old = bq->read_index;
 
     while (length > 0) {
+
+        /* Do not drop any data when we are in prebuffering mode */
+        if (memblockq_check_prebuf(bq))
+            break;
 
         if (bq->blocks) {
             size_t d;
 
-            assert(bq->blocks->index >= bq->read_index);
+            pa_assert(bq->blocks->index >= bq->read_index);
 
             d = (size_t) (bq->blocks->index - bq->read_index);
 
@@ -446,7 +459,7 @@
                 bq->read_index += d;
             }
 
-            assert(bq->blocks->index == bq->read_index);
+            pa_assert(bq->blocks->index == bq->read_index);
 
             if (bq->blocks->chunk.length <= length) {
                 /* We need to drop the full block */
@@ -472,35 +485,25 @@
             break;
         }
     }
+
+    delta = bq->read_index - old;
+    bq->missing += delta;
 }
 
 int pa_memblockq_is_readable(pa_memblockq *bq) {
-    assert(bq);
-
-    if (bq->prebuf > 0) {
-        size_t l = pa_memblockq_get_length(bq);
-
-        if (bq->state == PREBUF && l < bq->prebuf)
-            return 0;
-
-        if (l <= 0)
-            return 0;
-    }
+    pa_assert(bq);
+
+    if (memblockq_check_prebuf(bq))
+        return 0;
+
+    if (pa_memblockq_get_length(bq) <= 0)
+        return 0;
 
     return 1;
 }
 
-int pa_memblockq_is_writable(pa_memblockq *bq, size_t length) {
-    assert(bq);
-
-    if (length % bq->base)
-        return 0;
-
-    return pa_memblockq_get_length(bq) + length <= bq->tlength;
-}
-
 size_t pa_memblockq_get_length(pa_memblockq *bq) {
-    assert(bq);
+    pa_assert(bq);
 
     if (bq->write_index <= bq->read_index)
         return 0;
@@ -510,76 +513,106 @@
 
 size_t pa_memblockq_missing(pa_memblockq *bq) {
     size_t l;
-    assert(bq);
+    pa_assert(bq);
 
     if ((l = pa_memblockq_get_length(bq)) >= bq->tlength)
         return 0;
 
     l = bq->tlength - l;
-    return (l >= bq->minreq) ? l : 0;
+
+    return l >= bq->minreq ? l : 0;
 }
 
 size_t pa_memblockq_get_minreq(pa_memblockq *bq) {
-    assert(bq);
+    pa_assert(bq);
 
     return bq->minreq;
 }
 
 void pa_memblockq_seek(pa_memblockq *bq, int64_t offset, pa_seek_mode_t seek) {
-    assert(bq);
+    int64_t old, delta;
+    pa_assert(bq);
+
+    old = bq->write_index;
 
     switch (seek) {
         case PA_SEEK_RELATIVE:
             bq->write_index += offset;
-            return;
+            break;
         case PA_SEEK_ABSOLUTE:
             bq->write_index = offset;
-            return;
+            break;
         case PA_SEEK_RELATIVE_ON_READ:
             bq->write_index = bq->read_index + offset;
-            return;
+            break;
         case PA_SEEK_RELATIVE_END:
-            bq->write_index = (bq->blocks_tail ? bq->blocks_tail->index + (int64_t)bq->blocks_tail->chunk.length : bq->read_index) + offset;
-            return;
-    }
-
-    assert(0);
+            bq->write_index = (bq->blocks_tail ? bq->blocks_tail->index + (int64_t) bq->blocks_tail->chunk.length : bq->read_index) + offset;
+            break;
+        default:
+            pa_assert_not_reached();
+    }
+
+    delta = bq->write_index - old;
+
+    if (delta >= bq->requested) {
+        delta -= bq->requested;
+        bq->requested = 0;
+    } else if (delta >= 0) {
+        bq->requested -= delta;
+        delta = 0;
+    }
+
+    bq->missing -= delta;
 }
 
 void pa_memblockq_flush(pa_memblockq *bq) {
-    assert(bq);
+    int64_t old, delta;
+    pa_assert(bq);
 
     while (bq->blocks)
         drop_block(bq, bq->blocks);
 
-    assert(bq->n_blocks == 0);
-
+    pa_assert(bq->n_blocks == 0);
+
+    old = bq->write_index;
     bq->write_index = bq->read_index;
 
     pa_memblockq_prebuf_force(bq);
+
+    delta = bq->write_index - old;
+
+    if (delta > bq->requested) {
+        delta -= bq->requested;
+        bq->requested = 0;
+    } else if (delta >= 0) {
+        bq->requested -= delta;
+        delta = 0;
+    }
+
+    bq->missing -= delta;
 }
 
 size_t pa_memblockq_get_tlength(pa_memblockq *bq) {
-    assert(bq);
+    pa_assert(bq);
 
     return bq->tlength;
 }
 
 int64_t pa_memblockq_get_read_index(pa_memblockq *bq) {
-    assert(bq);
+    pa_assert(bq);
     return bq->read_index;
 }
 
 int64_t pa_memblockq_get_write_index(pa_memblockq *bq) {
-    assert(bq);
+    pa_assert(bq);
     return bq->write_index;
 }
 
 int pa_memblockq_push_align(pa_memblockq* bq, const pa_memchunk *chunk) {
     pa_memchunk rchunk;
 
-    assert(bq);
-    assert(chunk && bq->base);
+    pa_assert(bq);
+    pa_assert(chunk);
 
     if (bq->base == 1)
         return pa_memblockq_push(bq, chunk);
@@ -606,36 +639,52 @@
 
 void pa_memblockq_shorten(pa_memblockq *bq, size_t length) {
     size_t l;
-    assert(bq);
+    pa_assert(bq);
 
     l = pa_memblockq_get_length(bq);
 
     if (l > length)
-        pa_memblockq_drop(bq, NULL, l - length);
+        pa_memblockq_drop(bq, l - length);
 }
 
 void pa_memblockq_prebuf_disable(pa_memblockq *bq) {
-    assert(bq);
-
-    if (bq->state == PREBUF)
-        bq->state = RUNNING;
+    pa_assert(bq);
+
+    bq->in_prebuf = FALSE;
 }
 
 void pa_memblockq_prebuf_force(pa_memblockq *bq) {
-    assert(bq);
-
-    if (bq->state == RUNNING && bq->prebuf > 0)
-        bq->state = PREBUF;
+    pa_assert(bq);
+
+    if (!bq->in_prebuf && bq->prebuf > 0)
+        bq->in_prebuf = TRUE;
 }
 
 size_t pa_memblockq_get_maxlength(pa_memblockq *bq) {
-    assert(bq);
+    pa_assert(bq);
 
     return bq->maxlength;
 }
 
 size_t pa_memblockq_get_prebuf(pa_memblockq *bq) {
-    assert(bq);
+    pa_assert(bq);
 
     return bq->prebuf;
 }
+
+size_t pa_memblockq_pop_missing(pa_memblockq *bq) {
+    size_t l;
+
+    pa_assert(bq);
+
+/*     pa_log("pop: %lli", bq->missing); */
+
+    if (bq->missing <= 0)
+        return 0;
+
+    l = (size_t) bq->missing;
+    bq->missing = 0;
+    bq->requested += l;
+
+    return l;
+}

Modified: trunk/src/pulsecore/memblockq.h
URL: http://0pointer.de/cgi-bin/viewcvs.cgi/trunk/src/pulsecore/memblockq.h?rev=1971&root=pulseaudio&r1=1970&r2=1971&view=diff
==============================================================================
--- trunk/src/pulsecore/memblockq.h (original)
+++ trunk/src/pulsecore/memblockq.h Sun Oct 28 20:13:50 2007
@@ -62,7 +62,7 @@
    - minreq:    pa_memblockq_missing() will only return values greater
                 than this value. Pass 0 for the default.
 
-   - silence:   return this memblock whzen reading unitialized data
+   - silence:   return this memblock when reading unitialized data
 */
 pa_memblockq* pa_memblockq_new(
         int64_t idx,
@@ -83,25 +83,29 @@
  * you know what you do. */
 int pa_memblockq_push_align(pa_memblockq* bq, const pa_memchunk *chunk);
 
-/* Return a copy of the next memory chunk in the queue. It is not removed from the queue */
+/* Return a copy of the next memory chunk in the queue. It is not
+ * removed from the queue. There are two reasons this function might
+ * fail: 1. prebuffering is active, 2. queue is empty and no silence
+ * memblock was passed at initialization. If the queue is not empty,
+ * but we're currently at a hole in the queue and no silence memblock
+ * was passed we return the length of the hole in chunk->length. */
 int pa_memblockq_peek(pa_memblockq* bq, pa_memchunk *chunk);
 
-/* Drop the specified bytes from the queue, but only if the first
- * chunk in the queue matches the one passed here. If NULL is passed,
- * this check isn't done. */
-void pa_memblockq_drop(pa_memblockq *bq, const pa_memchunk *chunk, size_t length);
+/* Drop the specified bytes from the queue. */
+void pa_memblockq_drop(pa_memblockq *bq, size_t length);
 
 /* Test if the pa_memblockq is currently readable, that is, more data than base */
 int pa_memblockq_is_readable(pa_memblockq *bq);
-
-/* Test if the pa_memblockq is currently writable for the specified amount of bytes */
-int pa_memblockq_is_writable(pa_memblockq *bq, size_t length);
 
 /* Return the length of the queue in bytes */
 size_t pa_memblockq_get_length(pa_memblockq *bq);
 
 /* Return how many bytes are missing in queue to the specified fill amount */
 size_t pa_memblockq_missing(pa_memblockq *bq);
+
+/* Return the number of bytes that are missing since the last call to
+ * this function, reset the internal counter to 0. */
+size_t pa_memblockq_pop_missing(pa_memblockq *bq);
 
 /* Returns the minimal request value */
 size_t pa_memblockq_get_minreq(pa_memblockq *bq);

Modified: trunk/src/pulsecore/memchunk.c
URL: http://0pointer.de/cgi-bin/viewcvs.cgi/trunk/src/pulsecore/memchunk.c?rev=1971&root=pulseaudio&r1=1970&r2=1971&view=diff
==============================================================================
--- trunk/src/pulsecore/memchunk.c (original)
+++ trunk/src/pulsecore/memchunk.c Sun Oct 28 20:13:50 2007
@@ -27,40 +27,66 @@
 
 #include <stdio.h>
 #include <stdlib.h>
-#include <assert.h>
 #include <string.h>
+#include <errno.h>
 
 #include <pulse/xmalloc.h>
+#include <pulsecore/macro.h>
+#include <pulsecore/core-util.h>
 
 #include "memchunk.h"
 
-void pa_memchunk_make_writable(pa_memchunk *c, size_t min) {
+pa_memchunk* 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);
+    pa_assert(c);
+    pa_assert(c->memblock);
 
-    if (PA_REFCNT_VALUE(c->memblock) == 1 &&
-        !c->memblock->read_only &&
-        c->memblock->length >= c->index+min)
-        return;
+    if (pa_memblock_ref_is_one(c->memblock) &&
+        !pa_memblock_is_read_only(c->memblock) &&
+        pa_memblock_get_length(c->memblock) >= c->index+min)
+        return c;
 
     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;
+
+    return c;
 }
 
-void pa_memchunk_reset(pa_memchunk *c) {
-    assert(c);
+pa_memchunk* pa_memchunk_reset(pa_memchunk *c) {
+    pa_assert(c);
 
     c->memblock = NULL;
     c->length = c->index = 0;
+
+    return c;
 }
+
+pa_memchunk *pa_memchunk_will_need(const pa_memchunk *c) {
+    void *p;
+
+    pa_assert(c);
+    pa_assert(c->memblock);
+
+    /* A version of pa_memblock_will_need() that works on memchunks
+     * instead of memblocks */
+
+    p = (uint8_t*) pa_memblock_acquire(c->memblock) + c->index;
+    pa_will_need(p, c->length);
+    pa_memblock_release(c->memblock);
+
+    return (pa_memchunk*) c;
+}

Modified: trunk/src/pulsecore/memchunk.h
URL: http://0pointer.de/cgi-bin/viewcvs.cgi/trunk/src/pulsecore/memchunk.h?rev=1971&root=pulseaudio&r1=1970&r2=1971&view=diff
==============================================================================
--- trunk/src/pulsecore/memchunk.h (original)
+++ trunk/src/pulsecore/memchunk.h Sun Oct 28 20:13:50 2007
@@ -37,11 +37,16 @@
 
 /* Make a memchunk writable, i.e. make sure that the caller may have
  * exclusive access to the memblock and it is not read_only. If needed
- * the memblock in the structure is replaced by a copy. */
-void pa_memchunk_make_writable(pa_memchunk *c, size_t min);
+ * the memblock in the structure is replaced by a copy. If min is not
+ * 0 it is made sure that the returned memblock is at least of the
+ * specified size, i.e. is enlarged if necessary. */
+pa_memchunk* pa_memchunk_make_writable(pa_memchunk *c, size_t min);
 
 /* Invalidate a memchunk. This does not free the cotaining memblock,
  * but sets all members to zero. */
-void pa_memchunk_reset(pa_memchunk *c);
+pa_memchunk* pa_memchunk_reset(pa_memchunk *c);
+
+/* Map a memory chunk back into memory if it was swapped out */
+pa_memchunk *pa_memchunk_will_need(const pa_memchunk *c);
 
 #endif

Modified: trunk/src/pulsecore/modargs.c
URL: http://0pointer.de/cgi-bin/viewcvs.cgi/trunk/src/pulsecore/modargs.c?rev=1971&root=pulseaudio&r1=1970&r2=1971&view=diff
==============================================================================
--- trunk/src/pulsecore/modargs.c (original)
+++ trunk/src/pulsecore/modargs.c Sun Oct 28 20:13:50 2007
@@ -26,7 +26,6 @@
 #endif
 
 #include <ctype.h>
-#include <assert.h>
 #include <stdlib.h>
 #include <string.h>
 
@@ -39,6 +38,7 @@
 #include <pulsecore/sink.h>
 #include <pulsecore/source.h>
 #include <pulsecore/core-util.h>
+#include <pulsecore/macro.h>
 
 #include "modargs.h"
 
@@ -48,7 +48,10 @@
 
 static int add_key_value(pa_hashmap *map, char *key, char *value, const char* const valid_keys[]) {
     struct entry *e;
-    assert(map && key && value);
+
+    pa_assert(map);
+    pa_assert(key);
+    pa_assert(value);
 
     if (valid_keys) {
         const char*const* v;
@@ -63,10 +66,11 @@
         }
     }
 
-    e = pa_xmalloc(sizeof(struct entry));
+    e = pa_xnew(struct entry, 1);
     e->key = key;
     e->value = value;
     pa_hashmap_put(map, key, e);
+
     return 0;
 }
 
@@ -74,7 +78,6 @@
     pa_hashmap *map = NULL;
 
     map = pa_hashmap_new(pa_idxset_string_hash_func, pa_idxset_string_compare_func);
-    assert(map);
 
     if (args) {
         enum { WHITESPACE, KEY, VALUE_START, VALUE_SIMPLE, VALUE_DOUBLE_QUOTES, VALUE_TICKS } state;
@@ -166,10 +169,10 @@
     return NULL;
 }
 
-
 static void free_func(void *p, PA_GCC_UNUSED void*userdata) {
     struct entry *e = p;
-    assert(e);
+    pa_assert(e);
+
     pa_xfree(e->key);
     pa_xfree(e->value);
     pa_xfree(e);
@@ -192,7 +195,10 @@
 
 int pa_modargs_get_value_u32(pa_modargs *ma, const char *key, uint32_t *value) {
     const char *v;
-    assert(ma && key && value);
+
+    pa_assert(ma);
+    pa_assert(key);
+    pa_assert(value);
 
     if (!(v = pa_modargs_get_value(ma, key, NULL)))
         return 0;
@@ -205,7 +211,10 @@
 
 int pa_modargs_get_value_s32(pa_modargs *ma, const char *key, int32_t *value) {
     const char *v;
-    assert(ma && key && value);
+
+    pa_assert(ma);
+    pa_assert(key);
+    pa_assert(value);
 
     if (!(v = pa_modargs_get_value(ma, key, NULL)))
         return 0;
@@ -219,7 +228,10 @@
 int pa_modargs_get_value_boolean(pa_modargs *ma, const char *key, int *value) {
     const char *v;
     int r;
-    assert(ma && key && value);
+
+    pa_assert(ma);
+    pa_assert(key);
+    pa_assert(value);
 
     if (!(v = pa_modargs_get_value(ma, key, NULL)))
         return 0;
@@ -238,9 +250,9 @@
     const char *format;
     uint32_t channels;
     pa_sample_spec ss;
-    assert(ma && rss);
-
-/*    DEBUG_TRAP;*/
+
+    pa_assert(ma);
+    pa_assert(rss);
 
     ss = *rss;
     if ((pa_modargs_get_value_u32(ma, "rate", &ss.rate)) < 0)
@@ -263,16 +275,16 @@
     return 0;
 }
 
-int pa_modargs_get_channel_map(pa_modargs *ma, pa_channel_map *rmap) {
+int pa_modargs_get_channel_map(pa_modargs *ma, const char *name, pa_channel_map *rmap) {
     pa_channel_map map;
     const char *cm;
 
-    assert(ma);
-    assert(rmap);
+    pa_assert(ma);
+    pa_assert(rmap);
 
     map = *rmap;
 
-    if ((cm = pa_modargs_get_value(ma, "channel_map", NULL)))
+    if ((cm = pa_modargs_get_value(ma, name ? name : "channel_map", NULL)))
         if (!pa_channel_map_parse(&map, cm))
             return -1;
 
@@ -287,9 +299,9 @@
     pa_sample_spec ss;
     pa_channel_map map;
 
-    assert(ma);
-    assert(rss);
-    assert(rmap);
+    pa_assert(ma);
+    pa_assert(rss);
+    pa_assert(rmap);
 
     ss = *rss;
 
@@ -299,7 +311,7 @@
     if (!pa_channel_map_init_auto(&map, ss.channels, def))
         map.channels = 0;
 
-    if (pa_modargs_get_channel_map(ma, &map) < 0)
+    if (pa_modargs_get_channel_map(ma, NULL, &map) < 0)
         return -1;
 
     if (map.channels != ss.channels)

Modified: trunk/src/pulsecore/modargs.h
URL: http://0pointer.de/cgi-bin/viewcvs.cgi/trunk/src/pulsecore/modargs.h?rev=1971&root=pulseaudio&r1=1970&r2=1971&view=diff
==============================================================================
--- trunk/src/pulsecore/modargs.h (original)
+++ trunk/src/pulsecore/modargs.h Sun Oct 28 20:13:50 2007
@@ -49,8 +49,8 @@
 /* Return sample spec data from the three arguments "rate", "format" and "channels" */
 int pa_modargs_get_sample_spec(pa_modargs *ma, pa_sample_spec *ss);
 
-/* Return channel map data from the argument "channel_map" */
-int pa_modargs_get_channel_map(pa_modargs *ma, pa_channel_map *map);
+/* Return channel map data from the argument "channel_map" if name is NULL, otherwise read from the specified argument */
+int pa_modargs_get_channel_map(pa_modargs *ma, const char *name, pa_channel_map *map);
 
 /* Combination of pa_modargs_get_sample_spec() and
 pa_modargs_get_channel_map(). Not always suitable, since this routine

Modified: trunk/src/pulsecore/modinfo.c
URL: http://0pointer.de/cgi-bin/viewcvs.cgi/trunk/src/pulsecore/modinfo.c?rev=1971&root=pulseaudio&r1=1970&r2=1971&view=diff
==============================================================================
--- trunk/src/pulsecore/modinfo.c (original)
+++ trunk/src/pulsecore/modinfo.c Sun Oct 28 20:13:50 2007
@@ -26,12 +26,13 @@
 #endif
 
 #include <ltdl.h>
-#include <assert.h>
 
 #include <pulse/xmalloc.h>
 
 #include <pulsecore/core-util.h>
 #include <pulsecore/log.h>
+#include <pulsecore/macro.h>
+#include <pulsecore/ltdl-helper.h>
 
 #include "modinfo.h"
 
@@ -40,30 +41,24 @@
 #define PA_SYMBOL_USAGE "pa__get_usage"
 #define PA_SYMBOL_VERSION "pa__get_version"
 
-/* lt_dlsym() violates ISO C, so confide the breakage into this function to
- * avoid warnings. */
-typedef void (*fnptr)(void);
-static inline fnptr lt_dlsym_fn(lt_dlhandle handle, const char *symbol) {
-    return (fnptr) (long) lt_dlsym(handle, symbol);
-}
-
-pa_modinfo *pa_modinfo_get_by_handle(lt_dlhandle dl) {
+pa_modinfo *pa_modinfo_get_by_handle(lt_dlhandle dl, const char *module_name) {
     pa_modinfo *i;
     const char* (*func)(void);
-    assert(dl);
+
+    pa_assert(dl);
 
     i = pa_xnew0(pa_modinfo, 1);
 
-    if ((func = (const char* (*)(void)) lt_dlsym_fn(dl, PA_SYMBOL_AUTHOR)))
+    if ((func = (const char* (*)(void)) pa_load_sym(dl, module_name, PA_SYMBOL_AUTHOR)))
         i->author = pa_xstrdup(func());
 
-    if ((func = (const char* (*)(void)) lt_dlsym_fn(dl, PA_SYMBOL_DESCRIPTION)))
+    if ((func = (const char* (*)(void)) pa_load_sym(dl, module_name, PA_SYMBOL_DESCRIPTION)))
         i->description = pa_xstrdup(func());
 
-    if ((func = (const char* (*)(void)) lt_dlsym_fn(dl, PA_SYMBOL_USAGE)))
+    if ((func = (const char* (*)(void)) pa_load_sym(dl, module_name, PA_SYMBOL_USAGE)))
         i->usage = pa_xstrdup(func());
 
-    if ((func = (const char* (*)(void)) lt_dlsym_fn(dl, PA_SYMBOL_VERSION)))
+    if ((func = (const char* (*)(void)) pa_load_sym(dl, module_name, PA_SYMBOL_VERSION)))
         i->version = pa_xstrdup(func());
 
     return i;
@@ -72,21 +67,23 @@
 pa_modinfo *pa_modinfo_get_by_name(const char *name) {
     lt_dlhandle dl;
     pa_modinfo *i;
-    assert(name);
+
+    pa_assert(name);
 
     if (!(dl = lt_dlopenext(name))) {
         pa_log("Failed to open module \"%s\": %s", name, lt_dlerror());
         return NULL;
     }
 
-    i = pa_modinfo_get_by_handle(dl);
+    i = pa_modinfo_get_by_handle(dl, name);
     lt_dlclose(dl);
 
     return i;
 }
 
 void pa_modinfo_free(pa_modinfo *i) {
-    assert(i);
+    pa_assert(i);
+
     pa_xfree(i->author);
     pa_xfree(i->description);
     pa_xfree(i->usage);

Modified: trunk/src/pulsecore/modinfo.h
URL: http://0pointer.de/cgi-bin/viewcvs.cgi/trunk/src/pulsecore/modinfo.h?rev=1971&root=pulseaudio&r1=1970&r2=1971&view=diff
==============================================================================
--- trunk/src/pulsecore/modinfo.h (original)
+++ trunk/src/pulsecore/modinfo.h Sun Oct 28 20:13:50 2007
@@ -34,7 +34,7 @@
 } pa_modinfo;
 
 /* Read meta data from an libtool handle */
-pa_modinfo *pa_modinfo_get_by_handle(lt_dlhandle dl);
+pa_modinfo *pa_modinfo_get_by_handle(lt_dlhandle dl, const char *module_name);
 
 /* Read meta data from a module file */
 pa_modinfo *pa_modinfo_get_by_name(const char *name);

Modified: trunk/src/pulsecore/module.c
URL: http://0pointer.de/cgi-bin/viewcvs.cgi/trunk/src/pulsecore/module.c?rev=1971&root=pulseaudio&r1=1970&r2=1971&view=diff
==============================================================================
--- trunk/src/pulsecore/module.c (original)
+++ trunk/src/pulsecore/module.c Sun Oct 28 20:13:50 2007
@@ -29,7 +29,6 @@
 #include <limits.h>
 #include <stdio.h>
 #include <stdlib.h>
-#include <assert.h>
 #include <string.h>
 #include <errno.h>
 #include <ctype.h>
@@ -40,6 +39,8 @@
 #include <pulsecore/core-subscribe.h>
 #include <pulsecore/log.h>
 #include <pulsecore/core-util.h>
+#include <pulsecore/macro.h>
+#include <pulsecore/ltdl-helper.h>
 
 #include "module.h"
 
@@ -48,69 +49,31 @@
 
 #define UNLOAD_POLL_TIME 2
 
-/* lt_dlsym() violates ISO C, so confide the breakage into this function to
- * avoid warnings. */
-typedef void (*fnptr)(void);
-static inline fnptr lt_dlsym_fn(lt_dlhandle handle, const char *symbol) {
-    return (fnptr) (long) lt_dlsym(handle, symbol);
-}
-
 static void timeout_callback(pa_mainloop_api *m, pa_time_event*e, PA_GCC_UNUSED const struct timeval *tv, void *userdata) {
-    pa_core *c = userdata;
+    pa_core *c = PA_CORE(userdata);
     struct timeval ntv;
-    assert(c && c->mainloop == m && c->module_auto_unload_event == e);
+
+    pa_core_assert_ref(c);
+    pa_assert(c->mainloop == m);
+    pa_assert(c->module_auto_unload_event == e);
 
     pa_module_unload_unused(c);
 
     pa_gettimeofday(&ntv);
-    ntv.tv_sec += UNLOAD_POLL_TIME;
+    pa_timeval_add(&ntv, UNLOAD_POLL_TIME*1000000);
     m->time_restart(e, &ntv);
-}
-
-static inline fnptr load_sym(lt_dlhandle handle, const char *module, const char *symbol) {
-    char *buffer, *ch;
-    size_t buflen;
-    fnptr res;
-
-    res = lt_dlsym_fn(handle, symbol);
-    if (res)
-        return res;
-
-    /* As the .la files might have been cleansed from the system, we should
-     * try with the ltdl prefix as well. */
-
-    buflen = strlen(symbol) + strlen(module) + strlen("_LTX_") + 1;
-    buffer = pa_xmalloc(buflen);
-    assert(buffer);
-
-    strcpy(buffer, module);
-
-    for (ch = buffer;*ch != '\0';ch++) {
-        if (!isalnum(*ch))
-            *ch = '_';
-    }
-
-    strcat(buffer, "_LTX_");
-    strcat(buffer, symbol);
-
-    res = lt_dlsym_fn(handle, buffer);
-
-    pa_xfree(buffer);
-
-    return res;
 }
 
 pa_module* pa_module_load(pa_core *c, const char *name, const char *argument) {
     pa_module *m = NULL;
-    int r;
-
-    assert(c && name);
+
+    pa_assert(c);
+    pa_assert(name);
 
     if (c->disallow_module_loading)
         goto fail;
 
-    m = pa_xmalloc(sizeof(pa_module));
-
+    m = pa_xnew(pa_module, 1);
     m->name = pa_xstrdup(name);
     m->argument = pa_xstrdup(argument);
 
@@ -119,24 +82,19 @@
         goto fail;
     }
 
-    if (!(m->init = (int (*)(pa_core *_c, pa_module*_m)) load_sym(m->dl, name, PA_SYMBOL_INIT))) {
+    if (!(m->init = (int (*)(pa_module*_m)) pa_load_sym(m->dl, name, PA_SYMBOL_INIT))) {
         pa_log("Failed to load module \"%s\": symbol \""PA_SYMBOL_INIT"\" not found.", name);
         goto fail;
     }
 
-    if (!(m->done = (void (*)(pa_core *_c, pa_module*_m)) load_sym(m->dl, name, PA_SYMBOL_DONE))) {
-        pa_log("Failed to load module \"%s\": symbol \""PA_SYMBOL_DONE"\" not found.", name);
-        goto fail;
-    }
-
+    m->done = (void (*)(pa_module*_m)) pa_load_sym(m->dl, name, PA_SYMBOL_DONE);
     m->userdata = NULL;
     m->core = c;
     m->n_used = -1;
     m->auto_unload = 0;
     m->unload_requested = 0;
 
-    assert(m->init);
-    if (m->init(c, m) < 0) {
+    if (m->init(m) < 0) {
         pa_log_error("Failed to load  module \"%s\" (argument: \"%s\"): initialization failed.", name, argument ? argument : "");
         goto fail;
     }
@@ -147,14 +105,12 @@
     if (!c->module_auto_unload_event) {
         struct timeval ntv;
         pa_gettimeofday(&ntv);
-        ntv.tv_sec += UNLOAD_POLL_TIME;
+        pa_timeval_add(&ntv, UNLOAD_POLL_TIME*1000000);
         c->module_auto_unload_event = c->mainloop->time_new(c->mainloop, &ntv, timeout_callback, c);
     }
-    assert(c->module_auto_unload_event);
-
-    assert(c->modules);
-    r = pa_idxset_put(c->modules, m, &m->index);
-    assert(r >= 0 && m->index != PA_IDXSET_INVALID);
+
+    pa_assert_se(pa_idxset_put(c->modules, m, &m->index) >= 0);
+    pa_assert(m->index != PA_IDXSET_INVALID);
 
     pa_log_info("Loaded \"%s\" (index: #%u; argument: \"%s\").", m->name, m->index, m->argument ? m->argument : "");
 
@@ -178,14 +134,16 @@
 }
 
 static void pa_module_free(pa_module *m) {
-    assert(m && m->done && m->core);
+    pa_assert(m);
+    pa_assert(m->core);
 
     if (m->core->disallow_module_loading)
         return;
 
     pa_log_info("Unloading \"%s\" (index: #%u).", m->name, m->index);
 
-    m->done(m->core, m);
+    if (m->done)
+        m->done(m);
 
     lt_dlclose(m->dl);
 
@@ -199,9 +157,10 @@
 }
 
 void pa_module_unload(pa_core *c, pa_module *m) {
-    assert(c && m);
-
-    assert(c->modules);
+    pa_assert(c);
+    pa_assert(m);
+
+    pa_assert(c->modules);
     if (!(m = pa_idxset_remove_by_data(c->modules, m, NULL)))
         return;
 
@@ -210,9 +169,9 @@
 
 void pa_module_unload_by_index(pa_core *c, uint32_t idx) {
     pa_module *m;
-    assert(c && idx != PA_IDXSET_INVALID);
-
-    assert(c->modules);
+    pa_assert(c);
+    pa_assert(idx != PA_IDXSET_INVALID);
+
     if (!(m = pa_idxset_remove_by_index(c->modules, idx)))
         return;
 
@@ -221,13 +180,14 @@
 
 static void free_callback(void *p, PA_GCC_UNUSED void *userdata) {
     pa_module *m = p;
-    assert(m);
+    pa_assert(m);
     pa_module_free(m);
 }
 
 void pa_module_unload_all(pa_core *c) {
     pa_module *m;
-    assert(c);
+
+    pa_assert(c);
 
     if (!c->modules)
         return;
@@ -252,7 +212,10 @@
 static int unused_callback(void *p, PA_GCC_UNUSED uint32_t idx, int *del, void *userdata) {
     pa_module *m = p;
     time_t *now = userdata;
-    assert(p && del && now);
+
+    pa_assert(m);
+    pa_assert(del);
+    pa_assert(now);
 
     if (m->n_used == 0 && m->auto_unload && m->last_used_time+m->core->module_idle_time <= *now) {
         pa_module_free(m);
@@ -264,7 +227,7 @@
 
 void pa_module_unload_unused(pa_core *c) {
     time_t now;
-    assert(c);
+    pa_assert(c);
 
     if (!c->modules)
         return;
@@ -275,7 +238,7 @@
 
 static int unload_callback(void *p, PA_GCC_UNUSED uint32_t idx, int *del, PA_GCC_UNUSED void *userdata) {
     pa_module *m = p;
-    assert(m);
+    pa_assert(m);
 
     if (m->unload_requested) {
         pa_module_free(m);
@@ -286,18 +249,19 @@
 }
 
 static void defer_cb(pa_mainloop_api*api, pa_defer_event *e, void *userdata) {
-    pa_core *core = userdata;
+    pa_core *core = PA_CORE(userdata);
+
+    pa_core_assert_ref(core);
     api->defer_enable(e, 0);
 
     if (!core->modules)
         return;
 
     pa_idxset_foreach(core->modules, unload_callback, NULL);
-
 }
 
 void pa_module_unload_request(pa_module *m) {
-    assert(m);
+    pa_assert(m);
 
     m->unload_requested = 1;
 
@@ -308,19 +272,19 @@
 }
 
 void pa_module_set_used(pa_module*m, int used) {
-    assert(m);
+    pa_assert(m);
 
     if (m->n_used != used)
         pa_subscription_post(m->core, PA_SUBSCRIPTION_EVENT_MODULE|PA_SUBSCRIPTION_EVENT_CHANGE, m->index);
 
-    if (m->n_used != used && used == 0)
+    if (used == 0 && m->n_used > 0)
         time(&m->last_used_time);
 
     m->n_used = used;
 }
 
 pa_modinfo *pa_module_get_info(pa_module *m) {
-    assert(m);
-
-    return pa_modinfo_get_by_handle(m->dl);
-}
+    pa_assert(m);
+
+    return pa_modinfo_get_by_handle(m->dl, m->name);
+}

Modified: trunk/src/pulsecore/module.h
URL: http://0pointer.de/cgi-bin/viewcvs.cgi/trunk/src/pulsecore/module.h?rev=1971&root=pulseaudio&r1=1970&r2=1971&view=diff
==============================================================================
--- trunk/src/pulsecore/module.h (original)
+++ trunk/src/pulsecore/module.h Sun Oct 28 20:13:50 2007
@@ -39,8 +39,8 @@
 
     lt_dlhandle dl;
 
-    int (*init)(pa_core *c, pa_module*m);
-    void (*done)(pa_core *c, pa_module*m);
+    int (*init)(pa_module*m);
+    void (*done)(pa_module*m);
 
     void *userdata;
 
@@ -62,9 +62,9 @@
 
 void pa_module_set_used(pa_module*m, int used);
 
-#define PA_MODULE_AUTHOR(s) const char * pa__get_author(void) { return s; }
-#define PA_MODULE_DESCRIPTION(s) const char * pa__get_description(void) { return s; }
-#define PA_MODULE_USAGE(s) const char * pa__get_usage(void) { return s; }
+#define PA_MODULE_AUTHOR(s) const char *pa__get_author(void) { return s; }
+#define PA_MODULE_DESCRIPTION(s) const char *pa__get_description(void) { return s; }
+#define PA_MODULE_USAGE(s) const char *pa__get_usage(void) { return s; }
 #define PA_MODULE_VERSION(s) const char * pa__get_version(void) { return s; }
 
 pa_modinfo *pa_module_get_info(pa_module *m);

Modified: trunk/src/pulsecore/mutex-posix.c
URL: http://0pointer.de/cgi-bin/viewcvs.cgi/trunk/src/pulsecore/mutex-posix.c?rev=1971&root=pulseaudio&r1=1970&r2=1971&view=diff
==============================================================================
--- trunk/src/pulsecore/mutex-posix.c (original)
+++ trunk/src/pulsecore/mutex-posix.c Sun Oct 28 20:13:50 2007
@@ -25,19 +25,15 @@
 #include <config.h>
 #endif
 
-#include <assert.h>
 #include <pthread.h>
-
-#include <atomic_ops.h>
+#include <errno.h>
 
 #include <pulse/xmalloc.h>
+#include <pulsecore/macro.h>
+#include <pulsecore/log.h>
+#include <pulsecore/core-error.h>
 
 #include "mutex.h"
-
-#define ASSERT_SUCCESS(x) do { \
-    int _r = (x); \
-    assert(_r == 0); \
-} while(0)
 
 struct pa_mutex {
     pthread_mutex_t mutex;
@@ -47,68 +43,88 @@
     pthread_cond_t cond;
 };
 
-pa_mutex* pa_mutex_new(int recursive) {
+pa_mutex* pa_mutex_new(pa_bool_t recursive, pa_bool_t inherit_priority) {
     pa_mutex *m;
     pthread_mutexattr_t attr;
+    int r;
 
-    pthread_mutexattr_init(&attr);
+    pa_assert_se(pthread_mutexattr_init(&attr) == 0);
 
     if (recursive)
-        ASSERT_SUCCESS(pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE));
+        pa_assert_se(pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE) == 0);
+
+#ifdef HAVE_PTHREAD_PRIO_INHERIT
+    if (inherit_priority)
+        pa_assert_se(pthread_mutexattr_setprotocol(&attr, PTHREAD_PRIO_INHERIT) == 0);
+#endif
 
     m = pa_xnew(pa_mutex, 1);
 
-    ASSERT_SUCCESS(pthread_mutex_init(&m->mutex, &attr));
+#ifndef HAVE_PTHREAD_PRIO_INHERIT
+    pa_assert_se(pthread_mutex_init(&m->mutex, &attr) == 0);
+
+#else
+    if ((r = pthread_mutex_init(&m->mutex, &attr))) {
+
+        /* If this failed, then this was probably due to non-available
+         * priority inheritance. In which case we fall back to normal
+         * mutexes. */
+        pa_assert(r == ENOTSUP && inherit_priority);
+
+        pa_assert_se(pthread_mutexattr_setprotocol(&attr, PTHREAD_PRIO_NONE) == 0);
+        pa_assert_se(pthread_mutex_init(&m->mutex, &attr) == 0);
+    }
+#endif
+
     return m;
 }
 
 void pa_mutex_free(pa_mutex *m) {
-    assert(m);
+    pa_assert(m);
 
-    ASSERT_SUCCESS(pthread_mutex_destroy(&m->mutex));
+    pa_assert_se(pthread_mutex_destroy(&m->mutex) == 0);
     pa_xfree(m);
 }
 
 void pa_mutex_lock(pa_mutex *m) {
-    assert(m);
+    pa_assert(m);
 
-    ASSERT_SUCCESS(pthread_mutex_lock(&m->mutex));
+    pa_assert_se(pthread_mutex_lock(&m->mutex) == 0);
 }
 
 void pa_mutex_unlock(pa_mutex *m) {
-    assert(m);
+    pa_assert(m);
 
-    ASSERT_SUCCESS(pthread_mutex_unlock(&m->mutex));
+    pa_assert_se(pthread_mutex_unlock(&m->mutex) == 0);
 }
 
 pa_cond *pa_cond_new(void) {
     pa_cond *c;
 
     c = pa_xnew(pa_cond, 1);
-
-    ASSERT_SUCCESS(pthread_cond_init(&c->cond, NULL));
+    pa_assert_se(pthread_cond_init(&c->cond, NULL) == 0);
     return c;
 }
 
 void pa_cond_free(pa_cond *c) {
-    assert(c);
+    pa_assert(c);
 
-    ASSERT_SUCCESS(pthread_cond_destroy(&c->cond));
+    pa_assert_se(pthread_cond_destroy(&c->cond) == 0);
     pa_xfree(c);
 }
 
 void pa_cond_signal(pa_cond *c, int broadcast) {
-    assert(c);
+    pa_assert(c);
 
     if (broadcast)
-        ASSERT_SUCCESS(pthread_cond_broadcast(&c->cond));
+        pa_assert_se(pthread_cond_broadcast(&c->cond) == 0);
     else
-        ASSERT_SUCCESS(pthread_cond_signal(&c->cond));
+        pa_assert_se(pthread_cond_signal(&c->cond) == 0);
 }
 
 int pa_cond_wait(pa_cond *c, pa_mutex *m) {
-    assert(c);
-    assert(m);
+    pa_assert(c);
+    pa_assert(m);
 
     return pthread_cond_wait(&c->cond, &m->mutex);
 }

Modified: trunk/src/pulsecore/mutex-win32.c
URL: http://0pointer.de/cgi-bin/viewcvs.cgi/trunk/src/pulsecore/mutex-win32.c?rev=1971&root=pulseaudio&r1=1970&r2=1971&view=diff
==============================================================================
--- trunk/src/pulsecore/mutex-win32.c (original)
+++ trunk/src/pulsecore/mutex-win32.c Sun Oct 28 20:13:50 2007
@@ -40,7 +40,7 @@
     pa_hashmap *wait_events;
 };
 
-pa_mutex* pa_mutex_new(int recursive) {
+pa_mutex* pa_mutex_new(pa_bool_t recursive, pa_bool_t inherit_priority) {
     pa_mutex *m;
 
     m = pa_xnew(pa_mutex, 1);

Modified: trunk/src/pulsecore/mutex.h
URL: http://0pointer.de/cgi-bin/viewcvs.cgi/trunk/src/pulsecore/mutex.h?rev=1971&root=pulseaudio&r1=1970&r2=1971&view=diff
==============================================================================
--- trunk/src/pulsecore/mutex.h (original)
+++ trunk/src/pulsecore/mutex.h Sun Oct 28 20:13:50 2007
@@ -24,9 +24,17 @@
   USA.
 ***/
 
+#include <pulsecore/macro.h>
+
 typedef struct pa_mutex pa_mutex;
 
-pa_mutex* pa_mutex_new(int recursive);
+/* Please think twice before enabling priority inheritance. This is no
+ * magic wand! Use it only when the potentially priorized threads are
+ * good candidates for it. Don't use this blindly! Also, note that
+ * only very few operating systems actually implement this, hence this
+ * is merely a hint. */
+pa_mutex* pa_mutex_new(pa_bool_t recursive, pa_bool_t inherit_priority);
+
 void pa_mutex_free(pa_mutex *m);
 void pa_mutex_lock(pa_mutex *m);
 void pa_mutex_unlock(pa_mutex *m);

Modified: trunk/src/pulsecore/namereg.c
URL: http://0pointer.de/cgi-bin/viewcvs.cgi/trunk/src/pulsecore/namereg.c?rev=1971&root=pulseaudio&r1=1970&r2=1971&view=diff
==============================================================================
--- trunk/src/pulsecore/namereg.c (original)
+++ trunk/src/pulsecore/namereg.c Sun Oct 28 20:13:50 2007
@@ -27,7 +27,6 @@
 
 #include <stdlib.h>
 #include <string.h>
-#include <assert.h>
 #include <string.h>
 #include <stdio.h>
 
@@ -38,6 +37,7 @@
 #include <pulsecore/sink.h>
 #include <pulsecore/core-subscribe.h>
 #include <pulsecore/core-util.h>
+#include <pulsecore/macro.h>
 
 #include "namereg.h"
 
@@ -90,23 +90,22 @@
 }
 
 void pa_namereg_free(pa_core *c) {
-    assert(c);
+    pa_assert(c);
 
     if (!c->namereg)
         return;
 
-    assert(pa_hashmap_size(c->namereg) == 0);
+    pa_assert(pa_hashmap_size(c->namereg) == 0);
     pa_hashmap_free(c->namereg, NULL, NULL);
 }
 
 const char *pa_namereg_register(pa_core *c, const char *name, pa_namereg_type_t type, void *data, int fail) {
     struct namereg_entry *e;
     char *n = NULL;
-    int r;
-
-    assert(c);
-    assert(name);
-    assert(data);
+
+    pa_assert(c);
+    pa_assert(name);
+    pa_assert(data);
 
     if (!*name)
         return NULL;
@@ -142,7 +141,7 @@
         k = pa_xnew(char, l+4);
 
         for (i = 2; i <= 99; i++) {
-            snprintf(k, l+4, "%s.%u", name, i);
+            pa_snprintf(k, l+4, "%s.%u", name, i);
 
             if (!(e = pa_hashmap_get(c->namereg, k)))
                 break;
@@ -163,8 +162,7 @@
     e->name = n ? n : pa_xstrdup(name);
     e->data = data;
 
-    r = pa_hashmap_put(c->namereg, e->name, e);
-    assert (r >= 0);
+    pa_assert_se(pa_hashmap_put(c->namereg, e->name, e) >= 0);
 
     return e->name;
 }
@@ -172,11 +170,10 @@
 void pa_namereg_unregister(pa_core *c, const char *name) {
     struct namereg_entry *e;
 
-    assert(c);
-    assert(name);
-
-    e = pa_hashmap_remove(c->namereg, name);
-    assert(e);
+    pa_assert(c);
+    pa_assert(name);
+
+    pa_assert_se(e = pa_hashmap_remove(c->namereg, name));
 
     pa_xfree(e->name);
     pa_xfree(e);
@@ -185,7 +182,7 @@
 void* pa_namereg_get(pa_core *c, const char *name, pa_namereg_type_t type, int autoload) {
     struct namereg_entry *e;
     uint32_t idx;
-    assert(c);
+    pa_assert(c);
 
     if (!name) {
 
@@ -245,8 +242,8 @@
 int pa_namereg_set_default(pa_core*c, const char *name, pa_namereg_type_t type) {
     char **s;
 
-    assert(c);
-    assert(type == PA_NAMEREG_SINK || type == PA_NAMEREG_SOURCE);
+    pa_assert(c);
+    pa_assert(type == PA_NAMEREG_SINK || type == PA_NAMEREG_SOURCE);
 
     s = type == PA_NAMEREG_SINK ? &c->default_sink_name : &c->default_source_name;
 
@@ -269,7 +266,7 @@
 const char *pa_namereg_get_default_sink_name(pa_core *c) {
     pa_sink *s;
 
-    assert(c);
+    pa_assert(c);
 
     if (c->default_sink_name)
         return c->default_sink_name;
@@ -284,7 +281,7 @@
     pa_source *s;
     uint32_t idx;
 
-    assert(c);
+    pa_assert(c);
 
     if (c->default_source_name)
         return c->default_source_name;

Modified: trunk/src/pulsecore/native-common.h
URL: http://0pointer.de/cgi-bin/viewcvs.cgi/trunk/src/pulsecore/native-common.h?rev=1971&root=pulseaudio&r1=1970&r2=1971&view=diff
==============================================================================
--- trunk/src/pulsecore/native-common.h (original)
+++ trunk/src/pulsecore/native-common.h Sun Oct 28 20:13:50 2007
@@ -115,6 +115,11 @@
     PA_COMMAND_MOVE_SINK_INPUT,
     PA_COMMAND_MOVE_SOURCE_OUTPUT,
 
+    PA_COMMAND_SET_SINK_INPUT_MUTE,
+
+    PA_COMMAND_SUSPEND_SINK,
+    PA_COMMAND_SUSPEND_SOURCE,
+
     PA_COMMAND_MAX
 };
 

Copied: trunk/src/pulsecore/object.c (from r1970, branches/lennart/src/pulsecore/object.c)
URL: http://0pointer.de/cgi-bin/viewcvs.cgi/trunk/src/pulsecore/object.c?p2=trunk/src/pulsecore/object.c&p1=branches/lennart/src/pulsecore/object.c&r1=1970&r2=1971&rev=1971&root=pulseaudio&view=diff
==============================================================================
--- branches/lennart/src/pulsecore/object.c (original)
+++ trunk/src/pulsecore/object.c Sun Oct 28 20:13:50 2007
@@ -39,7 +39,7 @@
 
     pa_assert(check_type(type_name));
     pa_assert(check_type("pa_object"));
-    
+
     o = pa_xmalloc(size);
     PA_REFCNT_INIT(o);
     o->type_name = type_name;
@@ -67,6 +67,6 @@
 
 int pa_object_check_type(const char *type_name) {
     pa_assert(type_name);
-    
+
     return strcmp(type_name, "pa_object") == 0;
 }

Copied: trunk/src/pulsecore/once.c (from r1970, branches/lennart/src/pulsecore/once.c)
URL: http://0pointer.de/cgi-bin/viewcvs.cgi/trunk/src/pulsecore/once.c?p2=trunk/src/pulsecore/once.c&p1=branches/lennart/src/pulsecore/once.c&r1=1970&r2=1971&rev=1971&root=pulseaudio&view=diff
==============================================================================
--- branches/lennart/src/pulsecore/once.c (original)
+++ trunk/src/pulsecore/once.c Sun Oct 28 20:13:50 2007
@@ -43,7 +43,7 @@
     /* Caveat: We have to make sure that the once func has completed
      * before returning, even if the once func is not actually
      * executed by us. Hence the awkward locking. */
-    
+
     for (;;) {
 
         if ((m = pa_atomic_ptr_load(&control->mutex))) {
@@ -69,7 +69,7 @@
 
 void pa_once_end(pa_once *control) {
     pa_mutex *m;
-    
+
     pa_assert(control);
 
     pa_atomic_store(&control->done, 1);

Modified: trunk/src/pulsecore/once.h
URL: http://0pointer.de/cgi-bin/viewcvs.cgi/trunk/src/pulsecore/once.h?rev=1971&root=pulseaudio&r1=1970&r2=1971&view=diff
==============================================================================
--- trunk/src/pulsecore/once.h (original)
+++ trunk/src/pulsecore/once.h Sun Oct 28 20:13:50 2007
@@ -25,16 +25,52 @@
 ***/
 
 #include <pulsecore/mutex.h>
+#include <pulsecore/atomic.h>
 
 typedef struct pa_once {
-    unsigned int once_value;
-    pa_mutex *mutex;
-} pa_once_t;
+    pa_atomic_ptr_t mutex;
+    pa_atomic_t ref, done;
+} pa_once;
 
-#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)                                       \
+    }
 
+/* Not to be called directly, use the macros defined below instead */
+int pa_once_begin(pa_once *o);
+void pa_once_end(pa_once *o);
+
+#define PA_ONCE_BEGIN                                                   \
+    do {                                                                \
+        static pa_once _once = PA_ONCE_INIT;                            \
+        if (pa_once_begin(&_once)) {{
+
+#define PA_ONCE_END                                                     \
+            }                                                           \
+            pa_once_end(&_once);                                        \
+        }                                                               \
+    } while(0)
+
+/*
+
+  Usage of these macros is like this:
+
+  void foo() {
+
+      PA_ONCE_BEGIN {
+
+          ... stuff to be called just once ...
+
+      } PA_ONCE_END;
+  }
+
+*/
+
+/* Same API but calls a function */
 typedef void (*pa_once_func_t) (void);
-
-void pa_once(pa_once_t *o, pa_once_func_t f);
+void pa_run_once(pa_once *o, pa_once_func_t f);
 
 #endif

Modified: trunk/src/pulsecore/packet.c
URL: http://0pointer.de/cgi-bin/viewcvs.cgi/trunk/src/pulsecore/packet.c?rev=1971&root=pulseaudio&r1=1970&r2=1971&view=diff
==============================================================================
--- trunk/src/pulsecore/packet.c (original)
+++ trunk/src/pulsecore/packet.c Sun Oct 28 20:13:50 2007
@@ -25,22 +25,22 @@
 #include <config.h>
 #endif
 
-#include <assert.h>
 #include <stdlib.h>
 
 #include <pulse/xmalloc.h>
+#include <pulsecore/macro.h>
 
 #include "packet.h"
 
 pa_packet* pa_packet_new(size_t length) {
     pa_packet *p;
 
-    assert(length);
+    pa_assert(length > 0);
 
-    p = pa_xmalloc(sizeof(pa_packet)+length);
-    p->ref = 1;
+    p = pa_xmalloc(PA_ALIGN(sizeof(pa_packet)) + length);
+    PA_REFCNT_INIT(p);
     p->length = length;
-    p->data = (uint8_t*) (p+1);
+    p->data = (uint8_t*) p + PA_ALIGN(sizeof(pa_packet));
     p->type = PA_PACKET_APPENDED;
 
     return p;
@@ -49,11 +49,11 @@
 pa_packet* pa_packet_new_dynamic(void* data, size_t length) {
     pa_packet *p;
 
-    assert(data);
-    assert(length);
+    pa_assert(data);
+    pa_assert(length > 0);
 
     p = pa_xnew(pa_packet, 1);
-    p->ref = 1;
+    PA_REFCNT_INIT(p);
     p->length = length;
     p->data = data;
     p->type = PA_PACKET_DYNAMIC;
@@ -62,18 +62,18 @@
 }
 
 pa_packet* pa_packet_ref(pa_packet *p) {
-    assert(p);
-    assert(p->ref >= 1);
+    pa_assert(p);
+    pa_assert(PA_REFCNT_VALUE(p) >= 1);
 
-    p->ref++;
+    PA_REFCNT_INC(p);
     return p;
 }
 
 void pa_packet_unref(pa_packet *p) {
-    assert(p);
-    assert(p->ref >= 1);
+    pa_assert(p);
+    pa_assert(PA_REFCNT_VALUE(p) >= 1);
 
-    if (--p->ref == 0) {
+    if (PA_REFCNT_DEC(p) <= 0) {
         if (p->type == PA_PACKET_DYNAMIC)
             pa_xfree(p->data);
         pa_xfree(p);

Modified: trunk/src/pulsecore/packet.h
URL: http://0pointer.de/cgi-bin/viewcvs.cgi/trunk/src/pulsecore/packet.h?rev=1971&root=pulseaudio&r1=1970&r2=1971&view=diff
==============================================================================
--- trunk/src/pulsecore/packet.h (original)
+++ trunk/src/pulsecore/packet.h Sun Oct 28 20:13:50 2007
@@ -27,9 +27,11 @@
 #include <sys/types.h>
 #include <inttypes.h>
 
+#include <pulsecore/refcnt.h>
+
 typedef struct pa_packet {
+    PA_REFCNT_DECLARE;
     enum { PA_PACKET_APPENDED, PA_PACKET_DYNAMIC } type;
-    unsigned ref;
     size_t length;
     uint8_t *data;
 } pa_packet;

Modified: trunk/src/pulsecore/parseaddr.c
URL: http://0pointer.de/cgi-bin/viewcvs.cgi/trunk/src/pulsecore/parseaddr.c?rev=1971&root=pulseaudio&r1=1970&r2=1971&view=diff
==============================================================================
--- trunk/src/pulsecore/parseaddr.c (original)
+++ trunk/src/pulsecore/parseaddr.c Sun Oct 28 20:13:50 2007
@@ -26,13 +26,13 @@
 #endif
 
 #include <string.h>
-#include <assert.h>
 #include <stdlib.h>
 
 #include <pulse/xmalloc.h>
+#include <pulse/util.h>
 
-#include <pulse/util.h>
 #include <pulsecore/core-util.h>
+#include <pulsecore/macro.h>
 
 #include "parseaddr.h"
 
@@ -45,7 +45,9 @@
  *  Return a newly allocated string of the hostname and fill in *ret_port if specified  */
 
 static char *parse_host(const char *s, uint16_t *ret_port) {
-    assert(s && ret_port);
+    pa_assert(s);
+    pa_assert(ret_port);
+
     if (*s == '[') {
         char *e;
         if (!(e = strchr(s+1, ']')))
@@ -70,7 +72,10 @@
 
 int pa_parse_address(const char *name, pa_parsed_address *ret_p) {
     const char *p;
-    assert(name && ret_p);
+
+    pa_assert(name);
+    pa_assert(ret_p);
+
     memset(ret_p, 0, sizeof(pa_parsed_address));
     ret_p->type = PA_PARSED_ADDRESS_TCP_AUTO;
 
@@ -112,6 +117,5 @@
         if (!(ret_p->path_or_host = parse_host(p, &ret_p->port)))
             return -1;
 
-
     return 0;
 }

Modified: trunk/src/pulsecore/pdispatch.c
URL: http://0pointer.de/cgi-bin/viewcvs.cgi/trunk/src/pulsecore/pdispatch.c?rev=1971&root=pulseaudio&r1=1970&r2=1971&view=diff
==============================================================================
--- trunk/src/pulsecore/pdispatch.c (original)
+++ trunk/src/pulsecore/pdispatch.c Sun Oct 28 20:13:50 2007
@@ -28,7 +28,6 @@
 
 #include <stdio.h>
 #include <stdlib.h>
-#include <assert.h>
 
 #include <pulse/timeval.h>
 #include <pulse/xmalloc.h>
@@ -37,6 +36,8 @@
 #include <pulsecore/llist.h>
 #include <pulsecore/log.h>
 #include <pulsecore/core-util.h>
+#include <pulsecore/macro.h>
+#include <pulsecore/refcnt.h>
 
 #include "pdispatch.h"
 
@@ -108,7 +109,7 @@
 };
 
 struct pa_pdispatch {
-    int ref;
+    PA_REFCNT_DECLARE;
     pa_mainloop_api *mainloop;
     const pa_pdispatch_cb_t *callback_table;
     unsigned n_commands;
@@ -119,7 +120,9 @@
 };
 
 static void reply_info_free(struct reply_info *r) {
-    assert(r && r->pdispatch && r->pdispatch->mainloop);
+    pa_assert(r);
+    pa_assert(r->pdispatch);
+    pa_assert(r->pdispatch->mainloop);
 
     if (r->time_event)
         r->pdispatch->mainloop->time_free(r->time_event);
@@ -131,12 +134,12 @@
 
 pa_pdispatch* pa_pdispatch_new(pa_mainloop_api *mainloop, const pa_pdispatch_cb_t*table, unsigned entries) {
     pa_pdispatch *pd;
-    assert(mainloop);
-
-    assert((entries && table) || (!entries && !table));
-
-    pd = pa_xmalloc(sizeof(pa_pdispatch));
-    pd->ref = 1;
+    pa_assert(mainloop);
+
+    pa_assert((entries && table) || (!entries && !table));
+
+    pd = pa_xnew(pa_pdispatch, 1);
+    PA_REFCNT_INIT(pd);
     pd->mainloop = mainloop;
     pd->callback_table = table;
     pd->n_commands = entries;
@@ -149,7 +152,7 @@
 }
 
 static void pdispatch_free(pa_pdispatch *pd) {
-    assert(pd);
+    pa_assert(pd);
 
     while (pd->replies) {
         if (pd->replies->free_cb)
@@ -165,7 +168,7 @@
     pa_pdispatch_cb_t callback;
     void *userdata;
     uint32_t tag;
-    assert(r);
+    pa_assert(r);
 
     pa_pdispatch_ref(pd);
 
@@ -187,7 +190,12 @@
     uint32_t tag, command;
     pa_tagstruct *ts = NULL;
     int ret = -1;
-    assert(pd && packet && packet->data);
+
+    pa_assert(pd);
+    pa_assert(PA_REFCNT_VALUE(pd) >= 1);
+    pa_assert(packet);
+    pa_assert(PA_REFCNT_VALUE(packet) >= 1);
+    pa_assert(packet->data);
 
     pa_pdispatch_ref(pd);
 
@@ -195,7 +203,6 @@
         goto finish;
 
     ts = pa_tagstruct_new(packet->data, packet->length);
-    assert(ts);
 
     if (pa_tagstruct_getu32(ts, &command) < 0 ||
         pa_tagstruct_getu32(ts, &tag) < 0)
@@ -206,7 +213,7 @@
     char t[256];
     char const *p;
     if (!(p = command_names[command]))
-        snprintf((char*) (p = t), sizeof(t), "%u", command);
+        pa_snprintf((char*) (p = t), sizeof(t), "%u", command);
 
     pa_log("Recieved opcode <%s>", p);
 }
@@ -248,7 +255,12 @@
 
 static void timeout_callback(pa_mainloop_api*m, pa_time_event*e, PA_GCC_UNUSED const struct timeval *tv, void *userdata) {
     struct reply_info*r = userdata;
-    assert(r && r->time_event == e && r->pdispatch && r->pdispatch->mainloop == m && r->callback);
+
+    pa_assert(r);
+    pa_assert(r->time_event == e);
+    pa_assert(r->pdispatch);
+    pa_assert(r->pdispatch->mainloop == m);
+    pa_assert(r->callback);
 
     run_action(r->pdispatch, r, PA_COMMAND_TIMEOUT, NULL);
 }
@@ -256,7 +268,10 @@
 void pa_pdispatch_register_reply(pa_pdispatch *pd, uint32_t tag, int timeout, pa_pdispatch_cb_t cb, void *userdata, pa_free_cb_t free_cb) {
     struct reply_info *r;
     struct timeval tv;
-    assert(pd && pd->ref >= 1 && cb);
+
+    pa_assert(pd);
+    pa_assert(PA_REFCNT_VALUE(pd) >= 1);
+    pa_assert(cb);
 
     r = pa_xnew(struct reply_info, 1);
     r->pdispatch = pd;
@@ -268,21 +283,22 @@
     pa_gettimeofday(&tv);
     tv.tv_sec += timeout;
 
-    r->time_event = pd->mainloop->time_new(pd->mainloop, &tv, timeout_callback, r);
-    assert(r->time_event);
+    pa_assert_se(r->time_event = pd->mainloop->time_new(pd->mainloop, &tv, timeout_callback, r));
 
     PA_LLIST_PREPEND(struct reply_info, pd->replies, r);
 }
 
 int pa_pdispatch_is_pending(pa_pdispatch *pd) {
-    assert(pd);
+    pa_assert(pd);
+    pa_assert(PA_REFCNT_VALUE(pd) >= 1);
 
     return !!pd->replies;
 }
 
 void pa_pdispatch_set_drain_callback(pa_pdispatch *pd, void (*cb)(pa_pdispatch *pd, void *userdata), void *userdata) {
-    assert(pd);
-    assert(!cb || pa_pdispatch_is_pending(pd));
+    pa_assert(pd);
+    pa_assert(PA_REFCNT_VALUE(pd) >= 1);
+    pa_assert(!cb || pa_pdispatch_is_pending(pd));
 
     pd->drain_callback = cb;
     pd->drain_userdata = userdata;
@@ -290,7 +306,9 @@
 
 void pa_pdispatch_unregister_reply(pa_pdispatch *pd, void *userdata) {
     struct reply_info *r, *n;
-    assert(pd);
+
+    pa_assert(pd);
+    pa_assert(PA_REFCNT_VALUE(pd) >= 1);
 
     for (r = pd->replies; r; r = n) {
         n = r->next;
@@ -301,21 +319,24 @@
 }
 
 void pa_pdispatch_unref(pa_pdispatch *pd) {
-    assert(pd && pd->ref >= 1);
-
-    if (!(--(pd->ref)))
+    pa_assert(pd);
+    pa_assert(PA_REFCNT_VALUE(pd) >= 1);
+
+    if (PA_REFCNT_DEC(pd) <= 0)
         pdispatch_free(pd);
 }
 
 pa_pdispatch* pa_pdispatch_ref(pa_pdispatch *pd) {
-    assert(pd && pd->ref >= 1);
-    pd->ref++;
+    pa_assert(pd);
+    pa_assert(PA_REFCNT_VALUE(pd) >= 1);
+
+    PA_REFCNT_INC(pd);
     return pd;
 }
 
 const pa_creds * pa_pdispatch_creds(pa_pdispatch *pd) {
-    assert(pd);
-    assert(pd->ref >= 1);
+    pa_assert(pd);
+    pa_assert(PA_REFCNT_VALUE(pd) >= 1);
 
     return pd->creds;
 }

Modified: trunk/src/pulsecore/pid.c
URL: http://0pointer.de/cgi-bin/viewcvs.cgi/trunk/src/pulsecore/pid.c?rev=1971&root=pulseaudio&r1=1970&r2=1971&view=diff
==============================================================================
--- trunk/src/pulsecore/pid.c (original)
+++ trunk/src/pulsecore/pid.c Sun Oct 28 20:13:50 2007
@@ -33,7 +33,6 @@
 #include <sys/stat.h>
 #include <string.h>
 #include <stdio.h>
-#include <assert.h>
 #include <stdlib.h>
 #include <limits.h>
 #include <signal.h>
@@ -47,6 +46,7 @@
 #include <pulsecore/core-error.h>
 #include <pulsecore/core-util.h>
 #include <pulsecore/log.h>
+#include <pulsecore/macro.h>
 
 #include "pid.h"
 
@@ -57,11 +57,11 @@
     char t[20], *e;
     uint32_t pid;
 
-    assert(fn && fd >= 0);
+    pa_assert(fn);
+    pa_assert(fd >= 0);
 
     if ((r = pa_loop_read(fd, t, sizeof(t)-1, NULL)) < 0) {
-        pa_log_warn("WARNING: failed to read PID file '%s': %s",
-            fn, pa_cstrerror(errno));
+        pa_log_warn("Failed to read PID file '%s': %s", fn, pa_cstrerror(errno));
         return (pid_t) -1;
     }
 
@@ -73,7 +73,7 @@
         *e = 0;
 
     if (pa_atou(t, &pid) < 0) {
-        pa_log("WARNING: failed to parse PID file '%s'", fn);
+        pa_log_warn("Failed to parse PID file '%s'", fn);
         return (pid_t) -1;
     }
 
@@ -83,13 +83,22 @@
 static int open_pid_file(const char *fn, int mode) {
     int fd = -1;
 
+    pa_assert(fn);
+
     for (;;) {
         struct stat st;
 
-        if ((fd = open(fn, mode, S_IRUSR|S_IWUSR)) < 0) {
+        if ((fd = open(fn, mode
+#ifdef O_NOCTTY
+                       |O_NOCTTY
+#endif
+#ifdef O_NOFOLLOW
+                       |O_NOFOLLOW
+#endif
+                       , S_IRUSR|S_IWUSR
+             )) < 0) {
             if (mode != O_RDONLY || errno != ENOENT)
-                pa_log_warn("WARNING: failed to open PID file '%s': %s",
-                    fn, pa_cstrerror(errno));
+                pa_log_warn("Failed to open PID file '%s': %s", fn, pa_cstrerror(errno));
             goto fail;
         }
 
@@ -98,8 +107,7 @@
             goto fail;
 
         if (fstat(fd, &st) < 0) {
-            pa_log_warn("WARNING: failed to fstat() PID file '%s': %s",
-                fn, pa_cstrerror(errno));
+            pa_log_warn("Failed to fstat() PID file '%s': %s", fn, pa_cstrerror(errno));
             goto fail;
         }
 
@@ -110,9 +118,9 @@
         if (pa_lock_fd(fd, 0) < 0)
             goto fail;
 
-        if (close(fd) < 0) {
-            pa_log_warn("WARNING: failed to close file '%s': %s",
-                fn, pa_cstrerror(errno));
+        if (pa_close(fd) < 0) {
+            pa_log_warn("Failed to close file '%s': %s", fn, pa_cstrerror(errno));
+            fd = -1;
             goto fail;
         }
 
@@ -125,7 +133,7 @@
 
     if (fd >= 0) {
         pa_lock_fd(fd, 0);
-        close(fd);
+        pa_close(fd);
     }
 
     return -1;
@@ -150,7 +158,7 @@
         goto fail;
 
     if ((pid = read_pid(fn, fd)) == (pid_t) -1)
-        pa_log("corrupt PID file, overwriting.");
+        pa_log_warn("Corrupt PID file, overwriting.");
     else if (pid > 0) {
 #ifdef OS_IS_WIN32
         if ((process = OpenProcess(PROCESS_QUERY_INFORMATION, FALSE, pid)) != NULL) {
@@ -158,25 +166,24 @@
 #else
         if (kill(pid, 0) >= 0 || errno != ESRCH) {
 #endif
-            pa_log("daemon already running.");
-            goto fail;
-        }
-
-        pa_log("stale PID file, overwriting.");
+            pa_log("Daemon already running.");
+            goto fail;
+        }
+
+        pa_log_warn("Stale PID file, overwriting.");
     }
 
     /* Overwrite the current PID file */
     if (lseek(fd, 0, SEEK_SET) == (off_t) -1 || ftruncate(fd, 0) < 0) {
-        pa_log("failed to truncate PID file '%s': %s",
-            fn, pa_cstrerror(errno));
-        goto fail;
-    }
-
-    snprintf(t, sizeof(t), "%lu\n", (unsigned long) getpid());
+        pa_log("Failed to truncate PID file '%s': %s", fn, pa_cstrerror(errno));
+        goto fail;
+    }
+
+    pa_snprintf(t, sizeof(t), "%lu\n", (unsigned long) getpid());
     l = strlen(t);
 
     if (pa_loop_write(fd, t, l, NULL) != (ssize_t) l) {
-        pa_log("failed to write PID file.");
+        pa_log("Failed to write PID file.");
         goto fail;
     }
 
@@ -185,7 +192,11 @@
 fail:
     if (fd >= 0) {
         pa_lock_fd(fd, 0);
-        close(fd);
+
+        if (pa_close(fd) < 0) {
+            pa_log("Failed to close PID file '%s': %s", fn, pa_cstrerror(errno));
+            ret = -1;
+        }
     }
 
     return ret;
@@ -201,8 +212,7 @@
     pa_runtime_path("pid", fn, sizeof(fn));
 
     if ((fd = open_pid_file(fn, O_RDWR)) < 0) {
-        pa_log_warn("WARNING: failed to open PID file '%s': %s",
-            fn, pa_cstrerror(errno));
+        pa_log_warn("Failed to open PID file '%s': %s", fn, pa_cstrerror(errno));
         goto fail;
     }
 
@@ -210,13 +220,12 @@
         goto fail;
 
     if (pid != getpid()) {
-        pa_log("WARNING: PID file '%s' not mine!", fn);
+        pa_log("PID file '%s' not mine!", fn);
         goto fail;
     }
 
     if (ftruncate(fd, 0) < 0) {
-        pa_log_warn("WARNING: failed to truncate PID file '%s': %s",
-            fn, pa_cstrerror(errno));
+        pa_log_warn("Failed to truncate PID file '%s': %s", fn, pa_cstrerror(errno));
         goto fail;
     }
 
@@ -227,8 +236,7 @@
 #endif
 
     if (unlink(fn) < 0) {
-        pa_log_warn("WARNING: failed to remove PID file '%s': %s",
-            fn, pa_cstrerror(errno));
+        pa_log_warn("Failed to remove PID file '%s': %s", fn, pa_cstrerror(errno));
         goto fail;
     }
 
@@ -238,7 +246,11 @@
 
     if (fd >= 0) {
         pa_lock_fd(fd, 0);
-        close(fd);
+
+        if (pa_close(fd) < 0) {
+            pa_log_warn("Failed to close PID file '%s': %s", fn, pa_cstrerror(errno));
+            ret = -1;
+        }
     }
 
     return ret;
@@ -280,7 +292,7 @@
 
     if (fd >= 0) {
         pa_lock_fd(fd, 0);
-        close(fd);
+        pa_close(fd);
     }
 
     return ret;

Modified: trunk/src/pulsecore/pipe.c
URL: http://0pointer.de/cgi-bin/viewcvs.cgi/trunk/src/pulsecore/pipe.c?rev=1971&root=pulseaudio&r1=1970&r2=1971&view=diff
==============================================================================
--- trunk/src/pulsecore/pipe.c (original)
+++ trunk/src/pulsecore/pipe.c Sun Oct 28 20:13:50 2007
@@ -149,14 +149,14 @@
     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]);
+        if (listener >= 0)
+                pa_close(listener);
+        if (filedes[0] >= 0)
+                pa_close(filedes[0]);
+        if (filedes[1] >= 0)
+                pa_close(filedes[0]);
 
-	return -1;
+        return -1;
 }
 
 #endif /* HAVE_PIPE */

Modified: trunk/src/pulsecore/play-memblockq.c
URL: http://0pointer.de/cgi-bin/viewcvs.cgi/trunk/src/pulsecore/play-memblockq.c?rev=1971&root=pulseaudio&r1=1970&r2=1971&view=diff
==============================================================================
--- trunk/src/pulsecore/play-memblockq.c (original)
+++ trunk/src/pulsecore/play-memblockq.c Sun Oct 28 20:13:50 2007
@@ -26,7 +26,6 @@
 #endif
 
 #include <stdlib.h>
-#include <assert.h>
 #include <stdio.h>
 #include <string.h>
 
@@ -34,50 +33,171 @@
 
 #include <pulsecore/sink-input.h>
 #include <pulsecore/gccmacro.h>
+#include <pulsecore/thread-mq.h>
 
 #include "play-memblockq.h"
 
-static void sink_input_kill(pa_sink_input *i) {
-    pa_memblockq *q;
-    assert(i);
-    assert(i->userdata);
-
-    q = i->userdata;
-
-    pa_sink_input_disconnect(i);
-    pa_sink_input_unref(i);
-
-    pa_memblockq_free(q);
-}
-
-static int sink_input_peek(pa_sink_input *i, pa_memchunk *chunk) {
-    pa_memblockq *q;
-    assert(i);
-    assert(chunk);
-    assert(i->userdata);
-
-    q = i->userdata;
-
-    return pa_memblockq_peek(q, chunk);
-}
-
-static void si_kill(PA_GCC_UNUSED pa_mainloop_api *m, void *i) {
-    sink_input_kill(i);
-}
-
-static void sink_input_drop(pa_sink_input *i, const pa_memchunk*chunk, size_t length) {
-    pa_memblockq *q;
-
-    assert(i);
-    assert(length > 0);
-    assert( i->userdata);
-
-    q = i->userdata;
-
-    pa_memblockq_drop(q, chunk, length);
-
-    if (pa_memblockq_get_length(q) <= 0)
-        pa_mainloop_api_once(i->sink->core->mainloop, si_kill, i);
+typedef struct memblockq_stream {
+    pa_msgobject parent;
+    pa_core *core;
+    pa_sink_input *sink_input;
+    pa_memblockq *memblockq;
+} memblockq_stream;
+
+enum {
+    MEMBLOCKQ_STREAM_MESSAGE_UNLINK,
+};
+
+PA_DECLARE_CLASS(memblockq_stream);
+#define MEMBLOCKQ_STREAM(o) (memblockq_stream_cast(o))
+static PA_DEFINE_CHECK_TYPE(memblockq_stream, pa_msgobject);
+
+static void memblockq_stream_unlink(memblockq_stream *u) {
+    pa_assert(u);
+
+    if (!u->sink_input)
+        return;
+
+    pa_sink_input_unlink(u->sink_input);
+
+    pa_sink_input_unref(u->sink_input);
+    u->sink_input = NULL;
+
+    memblockq_stream_unref(u);
+}
+
+static void memblockq_stream_free(pa_object *o) {
+    memblockq_stream *u = MEMBLOCKQ_STREAM(o);
+    pa_assert(u);
+
+    memblockq_stream_unlink(u);
+
+    if (u->memblockq)
+        pa_memblockq_free(u->memblockq);
+
+    pa_xfree(u);
+}
+
+static int memblockq_stream_process_msg(pa_msgobject *o, int code, void*userdata, int64_t offset, pa_memchunk *chunk) {
+    memblockq_stream *u = MEMBLOCKQ_STREAM(o);
+    memblockq_stream_assert_ref(u);
+
+    switch (code) {
+        case MEMBLOCKQ_STREAM_MESSAGE_UNLINK:
+            memblockq_stream_unlink(u);
+            break;
+    }
+
+    return 0;
+}
+
+static void sink_input_kill_cb(pa_sink_input *i) {
+    pa_sink_input_assert_ref(i);
+
+    memblockq_stream_unlink(MEMBLOCKQ_STREAM(i->userdata));
+}
+
+static int sink_input_peek_cb(pa_sink_input *i, size_t length, pa_memchunk *chunk) {
+    memblockq_stream *u;
+
+    pa_assert(i);
+    pa_assert(chunk);
+    u = MEMBLOCKQ_STREAM(i->userdata);
+    memblockq_stream_assert_ref(u);
+
+    if (!u->memblockq)
+        return -1;
+
+    if (pa_memblockq_peek(u->memblockq, chunk) < 0) {
+        pa_memblockq_free(u->memblockq);
+        u->memblockq = NULL;
+        pa_asyncmsgq_post(pa_thread_mq_get()->outq, PA_MSGOBJECT(u), MEMBLOCKQ_STREAM_MESSAGE_UNLINK, NULL, 0, NULL, NULL);
+        return -1;
+    }
+
+    return 0;
+}
+
+static void sink_input_drop_cb(pa_sink_input *i, size_t length) {
+    memblockq_stream *u;
+
+    pa_assert(i);
+    pa_assert(length > 0);
+    u = MEMBLOCKQ_STREAM(i->userdata);
+    memblockq_stream_assert_ref(u);
+
+    if (!u->memblockq)
+        return;
+
+    pa_memblockq_drop(u->memblockq, length);
+}
+
+pa_sink_input* pa_memblockq_sink_input_new(
+        pa_sink *sink,
+        const char *name,
+        const pa_sample_spec *ss,
+        const pa_channel_map *map,
+        pa_memblockq *q,
+        pa_cvolume *volume) {
+
+    memblockq_stream *u = NULL;
+    pa_sink_input_new_data data;
+
+    pa_assert(sink);
+    pa_assert(ss);
+
+    /* We allow creating this stream with no q set, so that it can be
+     * filled in later */
+
+    if (q && pa_memblockq_get_length(q) <= 0) {
+        pa_memblockq_free(q);
+        return NULL;
+    }
+
+    if (volume && pa_cvolume_is_muted(volume)) {
+        pa_memblockq_free(q);
+        return NULL;
+    }
+
+    u = pa_msgobject_new(memblockq_stream);
+    u->parent.parent.free = memblockq_stream_free;
+    u->parent.process_msg = memblockq_stream_process_msg;
+    u->core = sink->core;
+    u->sink_input = NULL;
+    u->memblockq = q;
+
+    pa_sink_input_new_data_init(&data);
+    data.sink = sink;
+    data.name = name;
+    data.driver = __FILE__;
+    pa_sink_input_new_data_set_sample_spec(&data, ss);
+    pa_sink_input_new_data_set_channel_map(&data, map);
+    pa_sink_input_new_data_set_volume(&data, volume);
+
+    if (!(u->sink_input = pa_sink_input_new(sink->core, &data, 0)))
+        goto fail;
+
+    u->sink_input->peek = sink_input_peek_cb;
+    u->sink_input->drop = sink_input_drop_cb;
+    u->sink_input->kill = sink_input_kill_cb;
+    u->sink_input->userdata = u;
+
+    if (q)
+        pa_memblockq_prebuf_disable(q);
+
+    /* The reference to u is dangling here, because we want
+     * to keep this stream around until it is fully played. */
+
+    /* This sink input is not "put" yet, i.e. pa_sink_input_put() has
+     * not been called! */
+
+    return pa_sink_input_ref(u->sink_input);
+
+fail:
+    if (u)
+        memblockq_stream_unref(u);
+
+    return NULL;
 }
 
 int pa_play_memblockq(
@@ -88,41 +208,29 @@
         pa_memblockq *q,
         pa_cvolume *volume) {
 
-    pa_sink_input *si;
-    pa_sink_input_new_data data;
-
-    assert(sink);
-    assert(ss);
-    assert(q);
-
-    if (pa_memblockq_get_length(q) <= 0) {
-        pa_memblockq_free(q);
-        return 0;
-    }
-
-    if (volume && pa_cvolume_is_muted(volume)) {
-        pa_memblockq_free(q);
-        return 0;
-    }
-
-    pa_sink_input_new_data_init(&data);
-    data.sink = sink;
-    data.name = name;
-    data.driver = __FILE__;
-    pa_sink_input_new_data_set_channel_map(&data, map);
-    pa_sink_input_new_data_set_sample_spec(&data, ss);
-    pa_sink_input_new_data_set_volume(&data, volume);
-
-    if (!(si = pa_sink_input_new(sink->core, &data, 0)))
+    pa_sink_input *i;
+
+    pa_assert(sink);
+    pa_assert(ss);
+    pa_assert(q);
+
+    if (!(i = pa_memblockq_sink_input_new(sink, name, ss, map, q, volume)))
         return -1;
 
-    si->peek = sink_input_peek;
-    si->drop = sink_input_drop;
-    si->kill = sink_input_kill;
-
-    si->userdata = q;
-
-    pa_sink_notify(si->sink);
+    pa_sink_input_put(i);
+    pa_sink_input_unref(i);
 
     return 0;
 }
+
+void pa_memblockq_sink_input_set_queue(pa_sink_input *i, pa_memblockq *q) {
+    memblockq_stream *u;
+
+    pa_sink_input_assert_ref(i);
+    u = MEMBLOCKQ_STREAM(i->userdata);
+    memblockq_stream_assert_ref(u);
+
+    if (u->memblockq)
+        pa_memblockq_free(u->memblockq);
+    u->memblockq = q;
+}

Modified: trunk/src/pulsecore/play-memblockq.h
URL: http://0pointer.de/cgi-bin/viewcvs.cgi/trunk/src/pulsecore/play-memblockq.h?rev=1971&root=pulseaudio&r1=1970&r2=1971&view=diff
==============================================================================
--- trunk/src/pulsecore/play-memblockq.h (original)
+++ trunk/src/pulsecore/play-memblockq.h Sun Oct 28 20:13:50 2007
@@ -27,6 +27,16 @@
 #include <pulsecore/sink.h>
 #include <pulsecore/memblockq.h>
 
+pa_sink_input* pa_memblockq_sink_input_new(
+        pa_sink *sink,
+        const char *name,
+        const pa_sample_spec *ss,
+        const pa_channel_map *map,
+        pa_memblockq *q,
+        pa_cvolume *volume);
+
+void pa_memblockq_sink_input_set_queue(pa_sink_input *i, pa_memblockq *q);
+
 int pa_play_memblockq(
     pa_sink *sink,
     const char *name,

Modified: trunk/src/pulsecore/play-memchunk.c
URL: http://0pointer.de/cgi-bin/viewcvs.cgi/trunk/src/pulsecore/play-memchunk.c?rev=1971&root=pulseaudio&r1=1970&r2=1971&view=diff
==============================================================================
--- trunk/src/pulsecore/play-memchunk.c (original)
+++ trunk/src/pulsecore/play-memchunk.c Sun Oct 28 20:13:50 2007
@@ -26,7 +26,6 @@
 #endif
 
 #include <stdlib.h>
-#include <assert.h>
 #include <stdio.h>
 #include <string.h>
 
@@ -34,53 +33,108 @@
 
 #include <pulsecore/sink-input.h>
 #include <pulsecore/gccmacro.h>
+#include <pulsecore/thread-mq.h>
 
 #include "play-memchunk.h"
 
-static void sink_input_kill(pa_sink_input *i) {
-    pa_memchunk *c;
-    assert(i && i->userdata);
-    c = i->userdata;
+typedef struct memchunk_stream {
+    pa_msgobject parent;
+    pa_core *core;
+    pa_sink_input *sink_input;
+    pa_memchunk memchunk;
+} memchunk_stream;
 
-    pa_sink_input_disconnect(i);
-    pa_sink_input_unref(i);
+enum {
+    MEMCHUNK_STREAM_MESSAGE_UNLINK,
+};
 
-    pa_memblock_unref(c->memblock);
-    pa_xfree(c);
+PA_DECLARE_CLASS(memchunk_stream);
+#define MEMCHUNK_STREAM(o) (memchunk_stream_cast(o))
+static PA_DEFINE_CHECK_TYPE(memchunk_stream, pa_msgobject);
+
+static void memchunk_stream_unlink(memchunk_stream *u) {
+    pa_assert(u);
+
+    if (!u->sink_input)
+        return;
+
+    pa_sink_input_unlink(u->sink_input);
+
+    pa_sink_input_unref(u->sink_input);
+    u->sink_input = NULL;
+
+    memchunk_stream_unref(u);
 }
 
-static int sink_input_peek(pa_sink_input *i, pa_memchunk *chunk) {
-    pa_memchunk *c;
-    assert(i && chunk && i->userdata);
-    c = i->userdata;
+static void memchunk_stream_free(pa_object *o) {
+    memchunk_stream *u = MEMCHUNK_STREAM(o);
+    pa_assert(u);
 
-    if (c->length <= 0)
-        return -1;
+    memchunk_stream_unlink(u);
 
-    assert(c->memblock && c->memblock->length);
-    *chunk = *c;
-    pa_memblock_ref(c->memblock);
+    if (u->memchunk.memblock)
+        pa_memblock_unref(u->memchunk.memblock);
+
+    pa_xfree(u);
+}
+
+static int memchunk_stream_process_msg(pa_msgobject *o, int code, void*userdata, int64_t offset, pa_memchunk *chunk) {
+    memchunk_stream *u = MEMCHUNK_STREAM(o);
+    memchunk_stream_assert_ref(u);
+
+    switch (code) {
+        case MEMCHUNK_STREAM_MESSAGE_UNLINK:
+            memchunk_stream_unlink(u);
+            break;
+    }
 
     return 0;
 }
 
-static void si_kill(PA_GCC_UNUSED pa_mainloop_api *m, void *i) {
-    sink_input_kill(i);
+static void sink_input_kill_cb(pa_sink_input *i) {
+    pa_sink_input_assert_ref(i);
+
+    memchunk_stream_unlink(MEMCHUNK_STREAM(i->userdata));
 }
 
-static void sink_input_drop(pa_sink_input *i, const pa_memchunk*chunk, size_t length) {
-    pa_memchunk *c;
-    assert(i && length && i->userdata);
-    c = i->userdata;
+static int sink_input_peek_cb(pa_sink_input *i, size_t length, pa_memchunk *chunk) {
+    memchunk_stream *u;
 
-    assert(!memcmp(chunk, c, sizeof(chunk)));
-    assert(length <= c->length);
+    pa_assert(i);
+    pa_assert(chunk);
+    u = MEMCHUNK_STREAM(i->userdata);
+    memchunk_stream_assert_ref(u);
 
-    c->length -= length;
-    c->index += length;
+    if (!u->memchunk.memblock)
+        return -1;
 
-    if (c->length <= 0)
-        pa_mainloop_api_once(i->sink->core->mainloop, si_kill, i);
+    if (u->memchunk.length <= 0) {
+        pa_memblock_unref(u->memchunk.memblock);
+        u->memchunk.memblock = NULL;
+        pa_asyncmsgq_post(pa_thread_mq_get()->outq, PA_MSGOBJECT(u), MEMCHUNK_STREAM_MESSAGE_UNLINK, NULL, 0, NULL, NULL);
+        return -1;
+    }
+
+    pa_assert(u->memchunk.memblock);
+    *chunk = u->memchunk;
+    pa_memblock_ref(chunk->memblock);
+
+    return 0;
+}
+
+static void sink_input_drop_cb(pa_sink_input *i, size_t length) {
+    memchunk_stream *u;
+
+    pa_assert(i);
+    pa_assert(length > 0);
+    u = MEMCHUNK_STREAM(i->userdata);
+    memchunk_stream_assert_ref(u);
+
+    if (length < u->memchunk.length) {
+        u->memchunk.length -= length;
+        u->memchunk.index += length;
+    } else
+        u->memchunk.length = 0;
 }
 
 int pa_play_memchunk(
@@ -91,38 +145,52 @@
         const pa_memchunk *chunk,
         pa_cvolume *volume) {
 
-    pa_sink_input *si;
-    pa_memchunk *nchunk;
+    memchunk_stream *u = NULL;
     pa_sink_input_new_data data;
 
-    assert(sink);
-    assert(ss);
-    assert(chunk);
+    pa_assert(sink);
+    pa_assert(ss);
+    pa_assert(chunk);
 
     if (volume && pa_cvolume_is_muted(volume))
         return 0;
 
+    pa_memchunk_will_need(chunk);
+
+    u = pa_msgobject_new(memchunk_stream);
+    u->parent.parent.free = memchunk_stream_free;
+    u->parent.process_msg = memchunk_stream_process_msg;
+    u->core = sink->core;
+    u->memchunk = *chunk;
+    pa_memblock_ref(u->memchunk.memblock);
+
     pa_sink_input_new_data_init(&data);
     data.sink = sink;
+    data.driver = __FILE__;
     data.name = name;
-    data.driver = __FILE__;
     pa_sink_input_new_data_set_sample_spec(&data, ss);
     pa_sink_input_new_data_set_channel_map(&data, map);
     pa_sink_input_new_data_set_volume(&data, volume);
 
-    if (!(si = pa_sink_input_new(sink->core, &data, 0)))
-        return -1;
+    if (!(u->sink_input = pa_sink_input_new(sink->core, &data, 0)))
+        goto fail;
 
-    si->peek = sink_input_peek;
-    si->drop = sink_input_drop;
-    si->kill = sink_input_kill;
+    u->sink_input->peek = sink_input_peek_cb;
+    u->sink_input->drop = sink_input_drop_cb;
+    u->sink_input->kill = sink_input_kill_cb;
+    u->sink_input->userdata = u;
 
-    si->userdata = nchunk = pa_xnew(pa_memchunk, 1);
-    *nchunk = *chunk;
+    pa_sink_input_put(u->sink_input);
 
-    pa_memblock_ref(chunk->memblock);
-
-    pa_sink_notify(si->sink);
+    /* The reference to u is dangling here, because we want to keep
+     * this stream around until it is fully played. */
 
     return 0;
+
+fail:
+    if (u)
+        memchunk_stream_unref(u);
+
+    return -1;
 }
+

Modified: trunk/src/pulsecore/poll.c
URL: http://0pointer.de/cgi-bin/viewcvs.cgi/trunk/src/pulsecore/poll.c?rev=1971&root=pulseaudio&r1=1970&r2=1971&view=diff
==============================================================================
--- trunk/src/pulsecore/poll.c (original)
+++ trunk/src/pulsecore/poll.c Sun Oct 28 20:13:50 2007
@@ -45,7 +45,7 @@
 
 #include "winsock.h"
 
-#ifndef HAVE_SYS_POLL_H
+#ifndef HAVE_POLL_H
 
 #include <pulsecore/core-util.h>
 

Modified: trunk/src/pulsecore/props.c
URL: http://0pointer.de/cgi-bin/viewcvs.cgi/trunk/src/pulsecore/props.c?rev=1971&root=pulseaudio&r1=1970&r2=1971&view=diff
==============================================================================
--- trunk/src/pulsecore/props.c (original)
+++ trunk/src/pulsecore/props.c Sun Oct 28 20:13:50 2007
@@ -21,11 +21,13 @@
   USA.
 ***/
 
-#include <assert.h>
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
 
 #include <pulse/xmalloc.h>
-
 #include <pulsecore/log.h>
+#include <pulsecore/macro.h>
 
 #include "props.h"
 
@@ -37,9 +39,11 @@
 /* Allocate a new property object */
 static pa_property* property_new(const char *name, void *data) {
     pa_property* p;
-    assert(name && data);
 
-    p = pa_xmalloc(sizeof(pa_property));
+    pa_assert(name);
+    pa_assert(data);
+
+    p = pa_xnew(pa_property, 1);
     p->name = pa_xstrdup(name);
     p->data = data;
 
@@ -48,7 +52,7 @@
 
 /* Free a property object */
 static void property_free(pa_property *p) {
-    assert(p);
+    pa_assert(p);
 
     pa_xfree(p->name);
     pa_xfree(p);
@@ -56,7 +60,10 @@
 
 void* pa_property_get(pa_core *c, const char *name) {
     pa_property *p;
-    assert(c && name && c->properties);
+
+    pa_assert(c);
+    pa_assert(name);
+    pa_assert(c->properties);
 
     if (!(p = pa_hashmap_get(c->properties, name)))
         return NULL;
@@ -66,7 +73,11 @@
 
 int pa_property_set(pa_core *c, const char *name, void *data) {
     pa_property *p;
-    assert(c && name && data && c->properties);
+
+    pa_assert(c);
+    pa_assert(name);
+    pa_assert(data);
+    pa_assert(c->properties);
 
     if (pa_hashmap_get(c->properties, name))
         return -1;
@@ -78,7 +89,10 @@
 
 int pa_property_remove(pa_core *c, const char *name) {
     pa_property *p;
-    assert(c && name && c->properties);
+
+    pa_assert(c);
+    pa_assert(name);
+    pa_assert(c->properties);
 
     if (!(p = pa_hashmap_remove(c->properties, name)))
         return -1;
@@ -88,18 +102,18 @@
 }
 
 void pa_property_init(pa_core *c) {
-    assert(c);
+    pa_assert(c);
 
     c->properties = pa_hashmap_new(pa_idxset_string_hash_func, pa_idxset_string_compare_func);
 }
 
 void pa_property_cleanup(pa_core *c) {
-    assert(c);
+    pa_assert(c);
 
     if (!c->properties)
         return;
 
-    assert(!pa_hashmap_size(c->properties));
+    pa_assert(!pa_hashmap_size(c->properties));
 
     pa_hashmap_free(c->properties, NULL, NULL);
     c->properties = NULL;
@@ -109,14 +123,17 @@
 void pa_property_dump(pa_core *c, pa_strbuf *s) {
     void *state = NULL;
     pa_property *p;
-    assert(c && s);
+
+    pa_assert(c);
+    pa_assert(s);
 
     while ((p = pa_hashmap_iterate(c->properties, &state, NULL)))
         pa_strbuf_printf(s, "[%s] -> [%p]\n", p->name, p->data);
 }
 
 int pa_property_replace(pa_core *c, const char *name, void *data) {
-    assert(c && name);
+    pa_assert(c);
+    pa_assert(name);
 
     pa_property_remove(c, name);
     return pa_property_set(c, name, data);

Modified: trunk/src/pulsecore/protocol-cli.c
URL: http://0pointer.de/cgi-bin/viewcvs.cgi/trunk/src/pulsecore/protocol-cli.c?rev=1971&root=pulseaudio&r1=1970&r2=1971&view=diff
==============================================================================
--- trunk/src/pulsecore/protocol-cli.c (original)
+++ trunk/src/pulsecore/protocol-cli.c Sun Oct 28 20:13:50 2007
@@ -25,13 +25,13 @@
 #include <config.h>
 #endif
 
-#include <assert.h>
 #include <stdlib.h>
 
 #include <pulse/xmalloc.h>
 
 #include <pulsecore/cli.h>
 #include <pulsecore/log.h>
+#include <pulsecore/macro.h>
 
 #include "protocol-cli.h"
 
@@ -47,7 +47,8 @@
 
 static void cli_eof_cb(pa_cli*c, void*userdata) {
     pa_protocol_cli *p = userdata;
-    assert(p);
+    pa_assert(p);
+
     pa_idxset_remove_by_data(p->connections, c, NULL);
     pa_cli_free(c);
 }
@@ -55,7 +56,10 @@
 static void on_connection(pa_socket_server*s, pa_iochannel *io, void *userdata) {
     pa_protocol_cli *p = userdata;
     pa_cli *c;
-    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);
@@ -64,7 +68,6 @@
     }
 
     c = pa_cli_new(p->core, io, p->module);
-    assert(c);
     pa_cli_set_eof_callback(c, cli_eof_cb, p);
 
     pa_idxset_put(p->connections, c, NULL);
@@ -72,9 +75,11 @@
 
 pa_protocol_cli* pa_protocol_cli_new(pa_core *core, pa_socket_server *server, pa_module *m, PA_GCC_UNUSED pa_modargs *ma) {
     pa_protocol_cli* p;
-    assert(core && server);
 
-    p = pa_xmalloc(sizeof(pa_protocol_cli));
+    pa_core_assert_ref(core);
+    pa_assert(server);
+
+    p = pa_xnew(pa_protocol_cli, 1);
     p->module = m;
     p->core = core;
     p->server = server;
@@ -86,12 +91,13 @@
 }
 
 static void free_connection(void *p, PA_GCC_UNUSED void *userdata) {
-    assert(p);
+    pa_assert(p);
+
     pa_cli_free(p);
 }
 
 void pa_protocol_cli_free(pa_protocol_cli *p) {
-    assert(p);
+    pa_assert(p);
 
     pa_idxset_free(p->connections, free_connection, NULL);
     pa_socket_server_unref(p->server);

Modified: trunk/src/pulsecore/protocol-esound.c
URL: http://0pointer.de/cgi-bin/viewcvs.cgi/trunk/src/pulsecore/protocol-esound.c?rev=1971&root=pulseaudio&r1=1970&r2=1971&view=diff
==============================================================================
--- trunk/src/pulsecore/protocol-esound.c (original)
+++ trunk/src/pulsecore/protocol-esound.c Sun Oct 28 20:13:50 2007
@@ -29,7 +29,6 @@
 #include <errno.h>
 #include <string.h>
 #include <stdio.h>
-#include <assert.h>
 #include <stdlib.h>
 #include <limits.h>
 
@@ -53,6 +52,8 @@
 #include <pulsecore/core-util.h>
 #include <pulsecore/core-error.h>
 #include <pulsecore/ipacl.h>
+#include <pulsecore/macro.h>
+#include <pulsecore/thread-mq.h>
 
 #include "endianmacros.h"
 
@@ -77,13 +78,15 @@
 
 /* This is heavily based on esound's code */
 
-struct connection {
+typedef struct connection {
+    pa_msgobject parent;
+
     uint32_t index;
-    int dead;
+    pa_bool_t dead;
     pa_protocol_esound *protocol;
     pa_iochannel *io;
     pa_client *client;
-    int authorized, swap_byte_order;
+    pa_bool_t authorized, swap_byte_order;
     void *write_data;
     size_t write_data_alloc, write_data_index, write_data_length;
     void *read_data;
@@ -100,6 +103,7 @@
     struct {
         pa_memblock *current_memblock;
         size_t memblock_index, fragment_size;
+        pa_atomic_t missing;
     } playback;
 
     struct {
@@ -109,46 +113,62 @@
     } scache;
 
     pa_time_event *auth_timeout_event;
-};
+} connection;
+
+PA_DECLARE_CLASS(connection);
+#define CONNECTION(o) (connection_cast(o))
+static PA_DEFINE_CHECK_TYPE(connection, pa_msgobject);
 
 struct pa_protocol_esound {
-    int public;
     pa_module *module;
     pa_core *core;
+    int public;
     pa_socket_server *server;
     pa_idxset *connections;
+
     char *sink_name, *source_name;
     unsigned n_player;
     uint8_t esd_key[ESD_KEY_LEN];
     pa_ip_acl *auth_ip_acl;
 };
 
+enum {
+    SINK_INPUT_MESSAGE_POST_DATA = PA_SINK_INPUT_MESSAGE_MAX, /* data from main loop to sink input */
+    SINK_INPUT_MESSAGE_DISABLE_PREBUF
+};
+
+enum {
+    CONNECTION_MESSAGE_REQUEST_DATA,
+    CONNECTION_MESSAGE_POST_DATA,
+    CONNECTION_MESSAGE_UNLINK_CONNECTION
+};
+
 typedef struct proto_handler {
     size_t data_length;
-    int (*proc)(struct connection *c, esd_proto_t request, const void *data, size_t length);
+    int (*proc)(connection *c, esd_proto_t request, const void *data, size_t length);
     const char *description;
 } esd_proto_handler_info_t;
 
-static void sink_input_drop_cb(pa_sink_input *i, const pa_memchunk *chunk, size_t length);
-static int sink_input_peek_cb(pa_sink_input *i, pa_memchunk *chunk);
+static void sink_input_drop_cb(pa_sink_input *i, size_t length);
+static int sink_input_peek_cb(pa_sink_input *i, size_t length, pa_memchunk *chunk);
 static void sink_input_kill_cb(pa_sink_input *i);
-static pa_usec_t sink_input_get_latency_cb(pa_sink_input *i);
+static int sink_input_process_msg(pa_msgobject *o, int code, void *userdata, int64_t offset, pa_memchunk *chunk);
 static pa_usec_t source_output_get_latency_cb(pa_source_output *o);
 
 static void source_output_push_cb(pa_source_output *o, const pa_memchunk *chunk);
 static void source_output_kill_cb(pa_source_output *o);
 
-static int esd_proto_connect(struct connection *c, esd_proto_t request, const void *data, size_t length);
-static int esd_proto_stream_play(struct connection *c, esd_proto_t request, const void *data, size_t length);
-static int esd_proto_stream_record(struct connection *c, esd_proto_t request, const void *data, size_t length);
-static int esd_proto_get_latency(struct connection *c, esd_proto_t request, const void *data, size_t length);
-static int esd_proto_server_info(struct connection *c, esd_proto_t request, const void *data, size_t length);
-static int esd_proto_all_info(struct connection *c, esd_proto_t request, const void *data, size_t length);
-static int esd_proto_stream_pan(struct connection *c, esd_proto_t request, const void *data, size_t length);
-static int esd_proto_sample_cache(struct connection *c, esd_proto_t request, const void *data, size_t length);
-static int esd_proto_sample_free_or_play(struct connection *c, esd_proto_t request, const void *data, size_t length);
-static int esd_proto_sample_get_id(struct connection *c, esd_proto_t request, const void *data, size_t length);
-static int esd_proto_standby_or_resume(struct connection *c, esd_proto_t request, const void *data, size_t length);
+static int esd_proto_connect(connection *c, esd_proto_t request, const void *data, size_t length);
+static int esd_proto_stream_play(connection *c, esd_proto_t request, const void *data, size_t length);
+static int esd_proto_stream_record(connection *c, esd_proto_t request, const void *data, size_t length);
+static int esd_proto_get_latency(connection *c, esd_proto_t request, const void *data, size_t length);
+static int esd_proto_server_info(connection *c, esd_proto_t request, const void *data, size_t length);
+static int esd_proto_all_info(connection *c, esd_proto_t request, const void *data, size_t length);
+static int esd_proto_stream_pan(connection *c, esd_proto_t request, const void *data, size_t length);
+static int esd_proto_sample_cache(connection *c, esd_proto_t request, const void *data, size_t length);
+static int esd_proto_sample_free_or_play(connection *c, esd_proto_t request, const void *data, size_t length);
+static int esd_proto_sample_get_id(connection *c, esd_proto_t request, const void *data, size_t length);
+static int esd_proto_standby_or_resume(connection *c, esd_proto_t request, const void *data, size_t length);
 
 /* the big map of protocol handler info */
 static struct proto_handler proto_map[ESD_PROTO_MAX] = {
@@ -185,24 +205,55 @@
     { 0,                              esd_proto_get_latency, "get latency" }
 };
 
-static void connection_free(struct connection *c) {
-    assert(c);
-    pa_idxset_remove_by_data(c->protocol->connections, c, NULL);
+static void connection_unlink(connection *c) {
+    pa_assert(c);
+
+    if (!c->protocol)
+        return;
+
+    if (c->sink_input) {
+        pa_sink_input_unlink(c->sink_input);
+        pa_sink_input_unref(c->sink_input);
+        c->sink_input = NULL;
+    }
+
+    if (c->source_output) {
+        pa_source_output_unlink(c->source_output);
+        pa_source_output_unref(c->source_output);
+        c->source_output = NULL;
+    }
+
+    if (c->client) {
+        pa_client_free(c->client);
+        c->client = NULL;
+    }
 
     if (c->state == ESD_STREAMING_DATA)
         c->protocol->n_player--;
 
-    pa_client_free(c->client);
-
-    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->io) {
+        pa_iochannel_free(c->io);
+        c->io = NULL;
+    }
+
+    if (c->defer_event) {
+        c->protocol->core->mainloop->defer_free(c->defer_event);
+        c->defer_event = NULL;
+    }
+
+    if (c->auth_timeout_event) {
+        c->protocol->core->mainloop->time_free(c->auth_timeout_event);
+        c->auth_timeout_event = NULL;
+    }
+
+    pa_assert_se(pa_idxset_remove_by_data(c->protocol->connections, c, NULL) == c);
+    c->protocol = NULL;
+    connection_unref(c);
+}
+
+static void connection_free(pa_object *obj) {
+    connection *c = CONNECTION(obj);
+    pa_assert(c);
 
     if (c->input_memblockq)
         pa_memblockq_free(c->input_memblockq);
@@ -215,54 +266,44 @@
     pa_xfree(c->read_data);
     pa_xfree(c->write_data);
 
-    if (c->io)
-        pa_iochannel_free(c->io);
-
-    if (c->defer_event)
-        c->protocol->core->mainloop->defer_free(c->defer_event);
-
     if (c->scache.memchunk.memblock)
         pa_memblock_unref(c->scache.memchunk.memblock);
     pa_xfree(c->scache.name);
 
-    if (c->auth_timeout_event)
-        c->protocol->core->mainloop->time_free(c->auth_timeout_event);
-
     pa_xfree(c->original_name);
     pa_xfree(c);
 }
 
-static void connection_write_prepare(struct connection *c, size_t length) {
+static void connection_write_prepare(connection *c, size_t length) {
     size_t t;
-    assert(c);
+    pa_assert(c);
 
     t = c->write_data_length+length;
 
     if (c->write_data_alloc < t)
         c->write_data = pa_xrealloc(c->write_data, c->write_data_alloc = t);
 
-    assert(c->write_data);
-}
-
-static void connection_write(struct connection *c, const void *data, size_t length) {
+    pa_assert(c->write_data);
+}
+
+static void connection_write(connection *c, const void *data, size_t length) {
     size_t i;
-    assert(c);
-
-    assert(c->protocol && c->protocol->core && c->protocol->core->mainloop && c->protocol->core->mainloop->defer_enable);
+    pa_assert(c);
+
     c->protocol->core->mainloop->defer_enable(c->defer_event, 1);
 
     connection_write_prepare(c, length);
 
-    assert(c->write_data);
+    pa_assert(c->write_data);
 
     i = c->write_data_length;
     c->write_data_length += length;
 
-    memcpy((char*)c->write_data + i, data, length);
-}
-
-static void format_esd2native(int format, int swap_bytes, pa_sample_spec *ss) {
-    assert(ss);
+    memcpy((uint8_t*) c->write_data + i, data, length);
+}
+
+static void format_esd2native(int format, pa_bool_t swap_bytes, pa_sample_spec *ss) {
+    pa_assert(ss);
 
     ss->channels = ((format & ESD_MASK_CHAN) == ESD_STEREO) ? 2 : 1;
     if ((format & ESD_MASK_BITS) == ESD_BITS16)
@@ -289,11 +330,13 @@
 
 /*** esound commands ***/
 
-static int esd_proto_connect(struct connection *c, PA_GCC_UNUSED esd_proto_t request, const void *data, size_t length) {
+static int esd_proto_connect(connection *c, PA_GCC_UNUSED esd_proto_t request, const void *data, size_t length) {
     uint32_t ekey;
     int ok;
 
-    assert(length == (ESD_KEY_LEN + sizeof(uint32_t)));
+    connection_assert_ref(c);
+    pa_assert(data);
+    pa_assert(length == (ESD_KEY_LEN + sizeof(uint32_t)));
 
     if (!c->authorized) {
         if (memcmp(data, c->protocol->esd_key, ESD_KEY_LEN) != 0) {
@@ -301,7 +344,7 @@
             return -1;
         }
 
-        c->authorized = 1;
+        c->authorized = TRUE;
         if (c->auth_timeout_event) {
             c->protocol->core->mainloop->time_free(c->auth_timeout_event);
             c->auth_timeout_event = NULL;
@@ -312,11 +355,11 @@
 
     memcpy(&ekey, data, sizeof(uint32_t));
     if (ekey == ESD_ENDIAN_KEY)
-        c->swap_byte_order = 0;
+        c->swap_byte_order = FALSE;
     else if (ekey == ESD_SWAP_ENDIAN_KEY)
-        c->swap_byte_order = 1;
+        c->swap_byte_order = TRUE;
     else {
-        pa_log("client sent invalid endian key");
+        pa_log_warn("Client sent invalid endian key");
         return -1;
     }
 
@@ -325,7 +368,7 @@
     return 0;
 }
 
-static int esd_proto_stream_play(struct connection *c, PA_GCC_UNUSED esd_proto_t request, const void *data, size_t length) {
+static int esd_proto_stream_play(connection *c, PA_GCC_UNUSED esd_proto_t request, const void *data, size_t length) {
     char name[ESD_NAME_MAX], *utf8_name;
     int32_t format, rate;
     pa_sample_spec ss;
@@ -333,15 +376,17 @@
     pa_sink *sink = NULL;
     pa_sink_input_new_data sdata;
 
-    assert(c && length == (sizeof(int32_t)*2+ESD_NAME_MAX));
+    connection_assert_ref(c);
+    pa_assert(data);
+    pa_assert(length == (sizeof(int32_t)*2+ESD_NAME_MAX));
 
     memcpy(&format, data, sizeof(int32_t));
-    format = MAYBE_INT32_SWAP(c->swap_byte_order, format);
-    data = (const char*)data + sizeof(int32_t);
+    format = PA_MAYBE_INT32_SWAP(c->swap_byte_order, format);
+    data = (const char*) data + sizeof(int32_t);
 
     memcpy(&rate, data, sizeof(int32_t));
-    rate = MAYBE_INT32_SWAP(c->swap_byte_order, rate);
-    data = (const char*)data + sizeof(int32_t);
+    rate = PA_MAYBE_INT32_SWAP(c->swap_byte_order, rate);
+    data = (const char*) data + sizeof(int32_t);
 
     ss.rate = rate;
     format_esd2native(format, c->swap_byte_order, &ss);
@@ -362,7 +407,7 @@
 
     c->original_name = pa_xstrdup(name);
 
-    assert(!c->sink_input && !c->input_memblockq);
+    pa_assert(!c->sink_input && !c->input_memblockq);
 
     pa_sink_input_new_data_init(&sdata);
     sdata.sink = sink;
@@ -385,22 +430,26 @@
             l/PLAYBACK_BUFFER_FRAGMENTS,
             NULL);
     pa_iochannel_socket_set_rcvbuf(c->io, l/PLAYBACK_BUFFER_FRAGMENTS*2);
-    c->playback.fragment_size = l/10;
-
+    c->playback.fragment_size = l/PLAYBACK_BUFFER_FRAGMENTS;
+
+    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;
 
     c->state = ESD_STREAMING_DATA;
 
     c->protocol->n_player++;
 
+    pa_atomic_store(&c->playback.missing, pa_memblockq_missing(c->input_memblockq));
+
+    pa_sink_input_put(c->sink_input);
+
     return 0;
 }
 
-static int esd_proto_stream_record(struct connection *c, esd_proto_t request, const void *data, size_t length) {
+static int esd_proto_stream_record(connection *c, esd_proto_t request, const void *data, size_t length) {
     char name[ESD_NAME_MAX], *utf8_name;
     int32_t format, rate;
     pa_source *source = NULL;
@@ -408,15 +457,17 @@
     size_t l;
     pa_source_output_new_data sdata;
 
-    assert(c && length == (sizeof(int32_t)*2+ESD_NAME_MAX));
+    connection_assert_ref(c);
+    pa_assert(data);
+    pa_assert(length == (sizeof(int32_t)*2+ESD_NAME_MAX));
 
     memcpy(&format, data, sizeof(int32_t));
-    format = MAYBE_INT32_SWAP(c->swap_byte_order, format);
-    data = (const char*)data + sizeof(int32_t);
+    format = PA_MAYBE_INT32_SWAP(c->swap_byte_order, format);
+    data = (const char*) data + sizeof(int32_t);
 
     memcpy(&rate, data, sizeof(int32_t));
-    rate = MAYBE_INT32_SWAP(c->swap_byte_order, rate);
-    data = (const char*)data + sizeof(int32_t);
+    rate = PA_MAYBE_INT32_SWAP(c->swap_byte_order, rate);
+    data = (const char*) data + sizeof(int32_t);
 
     ss.rate = rate;
     format_esd2native(format, c->swap_byte_order, &ss);
@@ -436,7 +487,7 @@
             return -1;
         }
     } else {
-        assert(request == ESD_PROTO_STREAM_REC);
+        pa_assert(request == ESD_PROTO_STREAM_REC);
 
         if (c->protocol->source_name) {
             if (!(source = pa_namereg_get(c->protocol->core, c->protocol->source_name, PA_NAMEREG_SOURCE, 1))) {
@@ -455,7 +506,7 @@
 
     c->original_name = pa_xstrdup(name);
 
-    assert(!c->output_memblockq && !c->source_output);
+    pa_assert(!c->output_memblockq && !c->source_output);
 
     pa_source_output_new_data_init(&sdata);
     sdata.source = source;
@@ -488,14 +539,18 @@
 
     c->protocol->n_player++;
 
+    pa_source_output_put(c->source_output);
+
     return 0;
 }
 
-static int esd_proto_get_latency(struct connection *c, PA_GCC_UNUSED esd_proto_t request, const void *data, size_t length) {
+static int esd_proto_get_latency(connection *c, PA_GCC_UNUSED esd_proto_t request, const void *data, size_t length) {
     pa_sink *sink;
     int32_t latency;
 
-    assert(c && !data && length == 0);
+    connection_ref(c);
+    pa_assert(!data);
+    pa_assert(length == 0);
 
     if (!(sink = pa_namereg_get(c->protocol->core, c->protocol->sink_name, PA_NAMEREG_SINK, 1)))
         latency = 0;
@@ -504,17 +559,19 @@
         latency = (int) ((usec*44100)/1000000);
     }
 
-    latency = MAYBE_INT32_SWAP(c->swap_byte_order, latency);
+    latency = PA_MAYBE_INT32_SWAP(c->swap_byte_order, latency);
     connection_write(c, &latency, sizeof(int32_t));
     return 0;
 }
 
-static int esd_proto_server_info(struct connection *c, PA_GCC_UNUSED esd_proto_t request, const void *data, size_t length) {
+static int esd_proto_server_info(connection *c, PA_GCC_UNUSED esd_proto_t request, const void *data, size_t length) {
     int32_t rate = 44100, format = ESD_STEREO|ESD_BITS16;
     int32_t response;
     pa_sink *sink;
 
-    assert(c && data && length == sizeof(int32_t));
+    connection_ref(c);
+    pa_assert(data);
+    pa_assert(length == sizeof(int32_t));
 
     if ((sink = pa_namereg_get(c->protocol->core, c->protocol->sink_name, PA_NAMEREG_SINK, 1))) {
         rate = sink->sample_spec.rate;
@@ -525,22 +582,24 @@
 
     response = 0;
     connection_write(c, &response, sizeof(int32_t));
-    rate = MAYBE_INT32_SWAP(c->swap_byte_order, rate);
+    rate = PA_MAYBE_INT32_SWAP(c->swap_byte_order, rate);
     connection_write(c, &rate, sizeof(int32_t));
-    format = MAYBE_INT32_SWAP(c->swap_byte_order, format);
+    format = PA_MAYBE_INT32_SWAP(c->swap_byte_order, format);
     connection_write(c, &format, sizeof(int32_t));
 
     return 0;
 }
 
-static int esd_proto_all_info(struct connection *c, esd_proto_t request, const void *data, size_t length) {
+static int esd_proto_all_info(connection *c, esd_proto_t request, const void *data, size_t length) {
     size_t t, k, s;
-    struct connection *conn;
+    connection *conn;
     uint32_t idx = PA_IDXSET_INVALID;
     unsigned nsamples;
     char terminator[sizeof(int32_t)*6+ESD_NAME_MAX];
 
-    assert(c && data && length == sizeof(int32_t));
+    connection_ref(c);
+    pa_assert(data);
+    pa_assert(length == sizeof(int32_t));
 
     if (esd_proto_server_info(c, request, data, length) < 0)
         return -1;
@@ -561,7 +620,7 @@
         if (conn->state != ESD_STREAMING_DATA)
             continue;
 
-        assert(t >= k*2+s);
+        pa_assert(t >= k*2+s);
 
         if (conn->sink_input) {
             pa_cvolume volume = *pa_sink_input_get_volume(conn->sink_input);
@@ -572,7 +631,7 @@
         }
 
         /* id */
-        id = MAYBE_INT32_SWAP(c->swap_byte_order, (int32_t) (conn->index+1));
+        id = PA_MAYBE_INT32_SWAP(c->swap_byte_order, (int32_t) (conn->index+1));
         connection_write(c, &id, sizeof(int32_t));
 
         /* name */
@@ -584,25 +643,25 @@
         connection_write(c, name, ESD_NAME_MAX);
 
         /* rate */
-        rate = MAYBE_INT32_SWAP(c->swap_byte_order, rate);
+        rate = PA_MAYBE_INT32_SWAP(c->swap_byte_order, rate);
         connection_write(c, &rate, sizeof(int32_t));
 
         /* left */
-        lvolume = MAYBE_INT32_SWAP(c->swap_byte_order, lvolume);
+        lvolume = PA_MAYBE_INT32_SWAP(c->swap_byte_order, lvolume);
         connection_write(c, &lvolume, sizeof(int32_t));
 
         /*right*/
-        rvolume = MAYBE_INT32_SWAP(c->swap_byte_order, rvolume);
+        rvolume = PA_MAYBE_INT32_SWAP(c->swap_byte_order, rvolume);
         connection_write(c, &rvolume, sizeof(int32_t));
 
         /*format*/
-        format = MAYBE_INT32_SWAP(c->swap_byte_order, format);
+        format = PA_MAYBE_INT32_SWAP(c->swap_byte_order, format);
         connection_write(c, &format, sizeof(int32_t));
 
         t -= k;
     }
 
-    assert(t == s*(nsamples+1)+k);
+    pa_assert(t == s*(nsamples+1)+k);
     t -= k;
 
     connection_write(c, terminator, k);
@@ -615,10 +674,10 @@
             int32_t id, rate, lvolume, rvolume, format, len;
             char name[ESD_NAME_MAX];
 
-            assert(t >= s*2);
+            pa_assert(t >= s*2);
 
             /* id */
-            id = MAYBE_INT32_SWAP(c->swap_byte_order, (int) (ce->index+1));
+            id = PA_MAYBE_INT32_SWAP(c->swap_byte_order, (int) (ce->index+1));
             connection_write(c, &id, sizeof(int32_t));
 
             /* name */
@@ -626,57 +685,59 @@
             if (strncmp(ce->name, SCACHE_PREFIX, sizeof(SCACHE_PREFIX)-1) == 0)
                 strncpy(name, ce->name+sizeof(SCACHE_PREFIX)-1, ESD_NAME_MAX);
             else
-                snprintf(name, ESD_NAME_MAX, "native.%s", ce->name);
+                pa_snprintf(name, ESD_NAME_MAX, "native.%s", ce->name);
             connection_write(c, name, ESD_NAME_MAX);
 
             /* rate */
-            rate = MAYBE_UINT32_SWAP(c->swap_byte_order, ce->sample_spec.rate);
+            rate = PA_MAYBE_UINT32_SWAP(c->swap_byte_order, ce->sample_spec.rate);
             connection_write(c, &rate, sizeof(int32_t));
 
             /* left */
-            lvolume = MAYBE_UINT32_SWAP(c->swap_byte_order, (ce->volume.values[0]*ESD_VOLUME_BASE)/PA_VOLUME_NORM);
+            lvolume = PA_MAYBE_UINT32_SWAP(c->swap_byte_order, (ce->volume.values[0]*ESD_VOLUME_BASE)/PA_VOLUME_NORM);
             connection_write(c, &lvolume, sizeof(int32_t));
 
             /*right*/
-            rvolume = MAYBE_UINT32_SWAP(c->swap_byte_order, (ce->volume.values[0]*ESD_VOLUME_BASE)/PA_VOLUME_NORM);
+            rvolume = PA_MAYBE_UINT32_SWAP(c->swap_byte_order, (ce->volume.values[0]*ESD_VOLUME_BASE)/PA_VOLUME_NORM);
             connection_write(c, &rvolume, sizeof(int32_t));
 
             /*format*/
-            format = MAYBE_INT32_SWAP(c->swap_byte_order, format_native2esd(&ce->sample_spec));
+            format = PA_MAYBE_INT32_SWAP(c->swap_byte_order, format_native2esd(&ce->sample_spec));
             connection_write(c, &format, sizeof(int32_t));
 
             /*length*/
-            len = MAYBE_INT32_SWAP(c->swap_byte_order, (int) ce->memchunk.length);
+            len = PA_MAYBE_INT32_SWAP(c->swap_byte_order, (int) ce->memchunk.length);
             connection_write(c, &len, sizeof(int32_t));
 
             t -= s;
         }
     }
 
-    assert(t == s);
+    pa_assert(t == s);
 
     connection_write(c, terminator, s);
 
     return 0;
 }
 
-static int esd_proto_stream_pan(struct connection *c, PA_GCC_UNUSED esd_proto_t request, const void *data, size_t length) {
+static int esd_proto_stream_pan(connection *c, PA_GCC_UNUSED esd_proto_t request, const void *data, size_t length) {
     int32_t ok;
     uint32_t idx, lvolume, rvolume;
-    struct connection *conn;
-
-    assert(c && data && length == sizeof(int32_t)*3);
+    connection *conn;
+
+    connection_assert_ref(c);
+    pa_assert(data);
+    pa_assert(length == sizeof(int32_t)*3);
 
     memcpy(&idx, data, sizeof(uint32_t));
-    idx = MAYBE_UINT32_SWAP(c->swap_byte_order, idx) - 1;
+    idx = PA_MAYBE_UINT32_SWAP(c->swap_byte_order, idx) - 1;
     data = (const char*)data + sizeof(uint32_t);
 
     memcpy(&lvolume, data, sizeof(uint32_t));
-    lvolume = MAYBE_UINT32_SWAP(c->swap_byte_order, lvolume);
+    lvolume = PA_MAYBE_UINT32_SWAP(c->swap_byte_order, lvolume);
     data = (const char*)data + sizeof(uint32_t);
 
     memcpy(&rvolume, data, sizeof(uint32_t));
-    rvolume = MAYBE_UINT32_SWAP(c->swap_byte_order, rvolume);
+    rvolume = PA_MAYBE_UINT32_SWAP(c->swap_byte_order, rvolume);
     data = (const char*)data + sizeof(uint32_t);
 
     if ((conn = pa_idxset_get_by_index(c->protocol->connections, idx)) && conn->sink_input) {
@@ -694,20 +755,22 @@
     return 0;
 }
 
-static int esd_proto_sample_cache(struct connection *c, PA_GCC_UNUSED esd_proto_t request, const void *data, size_t length) {
+static int esd_proto_sample_cache(connection *c, PA_GCC_UNUSED esd_proto_t request, const void *data, size_t length) {
     pa_sample_spec ss;
     int32_t format, rate, sc_length;
     uint32_t idx;
     char name[ESD_NAME_MAX+sizeof(SCACHE_PREFIX)-1];
 
-    assert(c && data && length == (ESD_NAME_MAX+3*sizeof(int32_t)));
+    connection_assert_ref(c);
+    pa_assert(data);
+    pa_assert(length == (ESD_NAME_MAX+3*sizeof(int32_t)));
 
     memcpy(&format, data, sizeof(int32_t));
-    format = MAYBE_INT32_SWAP(c->swap_byte_order, format);
+    format = PA_MAYBE_INT32_SWAP(c->swap_byte_order, format);
     data = (const char*)data + sizeof(int32_t);
 
     memcpy(&rate, data, sizeof(int32_t));
-    rate = MAYBE_INT32_SWAP(c->swap_byte_order, rate);
+    rate = PA_MAYBE_INT32_SWAP(c->swap_byte_order, rate);
     data = (const char*)data + sizeof(int32_t);
 
     ss.rate = rate;
@@ -716,7 +779,7 @@
     CHECK_VALIDITY(pa_sample_spec_valid(&ss), "Invalid sample specification.");
 
     memcpy(&sc_length, data, sizeof(int32_t));
-    sc_length = MAYBE_INT32_SWAP(c->swap_byte_order, sc_length);
+    sc_length = PA_MAYBE_INT32_SWAP(c->swap_byte_order, sc_length);
     data = (const char*)data + sizeof(int32_t);
 
     CHECK_VALIDITY(sc_length <= MAX_CACHE_SAMPLE_SIZE, "Sample too large (%d bytes).", (int)sc_length);
@@ -727,12 +790,12 @@
 
     CHECK_VALIDITY(pa_utf8_valid(name), "Invalid UTF8 in sample name.");
 
-    assert(!c->scache.memchunk.memblock);
+    pa_assert(!c->scache.memchunk.memblock);
     c->scache.memchunk.memblock = pa_memblock_new(c->protocol->core->mempool, sc_length);
     c->scache.memchunk.index = 0;
     c->scache.memchunk.length = sc_length;
     c->scache.sample_spec = ss;
-    assert(!c->scache.name);
+    pa_assert(!c->scache.name);
     c->scache.name = pa_xstrdup(name);
 
     c->state = ESD_CACHING_SAMPLE;
@@ -745,12 +808,14 @@
     return 0;
 }
 
-static int esd_proto_sample_get_id(struct connection *c, PA_GCC_UNUSED esd_proto_t request, const void *data, size_t length) {
+static int esd_proto_sample_get_id(connection *c, PA_GCC_UNUSED esd_proto_t request, const void *data, size_t length) {
     int32_t ok;
     uint32_t idx;
     char name[ESD_NAME_MAX+sizeof(SCACHE_PREFIX)-1];
 
-    assert(c && data && length == ESD_NAME_MAX);
+    connection_assert_ref(c);
+    pa_assert(data);
+    pa_assert(length == ESD_NAME_MAX);
 
     strcpy(name, SCACHE_PREFIX);
     strncpy(name+sizeof(SCACHE_PREFIX)-1, data, ESD_NAME_MAX);
@@ -767,15 +832,17 @@
     return 0;
 }
 
-static int esd_proto_sample_free_or_play(struct connection *c, esd_proto_t request, const void *data, size_t length) {
+static int esd_proto_sample_free_or_play(connection *c, esd_proto_t request, const void *data, size_t length) {
     int32_t ok;
     const char *name;
     uint32_t idx;
 
-    assert(c && data && length == sizeof(int32_t));
+    connection_assert_ref(c);
+    pa_assert(data);
+    pa_assert(length == sizeof(int32_t));
 
     memcpy(&idx, data, sizeof(uint32_t));
-    idx = MAYBE_UINT32_SWAP(c->swap_byte_order, idx) - 1;
+    idx = PA_MAYBE_UINT32_SWAP(c->swap_byte_order, idx) - 1;
 
     ok = 0;
 
@@ -787,7 +854,7 @@
                 if (pa_scache_play_item(c->protocol->core, name, sink, PA_VOLUME_NORM) >= 0)
                     ok = idx + 1;
         } else {
-            assert(request == ESD_PROTO_SAMPLE_FREE);
+            pa_assert(request == ESD_PROTO_SAMPLE_FREE);
 
             if (pa_scache_remove_item(c->protocol->core, name) >= 0)
                 ok = idx + 1;
@@ -799,8 +866,10 @@
     return 0;
 }
 
-static int esd_proto_standby_or_resume(struct connection *c, PA_GCC_UNUSED esd_proto_t request, PA_GCC_UNUSED const void *data, PA_GCC_UNUSED size_t length) {
+static int esd_proto_standby_or_resume(connection *c, PA_GCC_UNUSED esd_proto_t request, PA_GCC_UNUSED const void *data, PA_GCC_UNUSED size_t length) {
     int32_t ok;
+
+    connection_assert_ref(c);
 
     connection_write_prepare(c, sizeof(int32_t) * 2);
 
@@ -814,20 +883,21 @@
 /*** client callbacks ***/
 
 static void client_kill_cb(pa_client *c) {
-    assert(c && c->userdata);
-    connection_free(c->userdata);
+    pa_assert(c);
+
+    connection_unlink(CONNECTION(c->userdata));
 }
 
 /*** pa_iochannel callbacks ***/
 
-static int do_read(struct connection *c) {
-    assert(c && c->io);
-
-/*      pa_log("READ");  */
+static int do_read(connection *c) {
+    connection_assert_ref(c);
+
+/*     pa_log("READ"); */
 
     if (c->state == ESD_NEXT_REQUEST) {
         ssize_t r;
-        assert(c->read_data_length < sizeof(c->request));
+        pa_assert(c->read_data_length < sizeof(c->request));
 
         if ((r = pa_iochannel_read(c->io, ((uint8_t*) &c->request) + c->read_data_length, sizeof(c->request) - c->read_data_length)) <= 0) {
             pa_log_debug("read(): %s", r < 0 ? pa_cstrerror(errno) : "EOF");
@@ -837,7 +907,7 @@
         if ((c->read_data_length+= r) >= sizeof(c->request)) {
             struct proto_handler *handler;
 
-            c->request = MAYBE_INT32_SWAP(c->swap_byte_order, c->request);
+            c->request = PA_MAYBE_INT32_SWAP(c->swap_byte_order, c->request);
 
             if (c->request < ESD_PROTO_CONNECT || c->request > ESD_PROTO_MAX) {
                 pa_log("recieved invalid request.");
@@ -862,7 +932,7 @@
             } else {
                 if (c->read_data_alloc < handler->data_length)
                     c->read_data = pa_xrealloc(c->read_data, c->read_data_alloc = handler->data_length);
-                assert(c->read_data);
+                pa_assert(c->read_data);
 
                 c->state = ESD_NEEDS_REQDATA;
                 c->read_data_length = 0;
@@ -873,18 +943,21 @@
         ssize_t r;
         struct proto_handler *handler = proto_map+c->request;
 
-        assert(handler->proc);
-
-        assert(c->read_data && c->read_data_length < handler->data_length);
+        pa_assert(handler->proc);
+
+        pa_assert(c->read_data && c->read_data_length < handler->data_length);
 
         if ((r = pa_iochannel_read(c->io, (uint8_t*) c->read_data + c->read_data_length, handler->data_length - c->read_data_length)) <= 0) {
+            if (r < 0 && (errno == EINTR || errno == EAGAIN))
+                return 0;
+
             pa_log_debug("read(): %s", r < 0 ? pa_cstrerror(errno) : "EOF");
             return -1;
         }
 
         if ((c->read_data_length += r) >= handler->data_length) {
             size_t l = c->read_data_length;
-            assert(handler->proc);
+            pa_assert(handler->proc);
 
             c->state = ESD_NEXT_REQUEST;
             c->read_data_length = 0;
@@ -894,16 +967,26 @@
         }
     } else if (c->state == ESD_CACHING_SAMPLE) {
         ssize_t r;
-
-        assert(c->scache.memchunk.memblock && c->scache.name && 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) {
+        void *p;
+
+        pa_assert(c->scache.memchunk.memblock);
+        pa_assert(c->scache.name);
+        pa_assert(c->scache.memchunk.index < c->scache.memchunk.length);
+
+        p = pa_memblock_acquire(c->scache.memchunk.memblock);
+        r = pa_iochannel_read(c->io, (uint8_t*) p+c->scache.memchunk.index, c->scache.memchunk.length-c->scache.memchunk.index);
+        pa_memblock_release(c->scache.memchunk.memblock);
+
+        if (r <= 0) {
+            if (r < 0 && (errno == EINTR || errno == EAGAIN))
+                return 0;
+
             pa_log_debug("read(): %s", r < 0 ? pa_cstrerror(errno) : "EOF");
             return -1;
         }
 
         c->scache.memchunk.index += r;
-        assert(c->scache.memchunk.index <= c->scache.memchunk.length);
+        pa_assert(c->scache.memchunk.index <= c->scache.memchunk.length);
 
         if (c->scache.memchunk.index == c->scache.memchunk.length) {
             uint32_t idx;
@@ -928,31 +1011,39 @@
         pa_memchunk chunk;
         ssize_t r;
         size_t l;
-
-        assert(c->input_memblockq);
+        void *p;
+
+        pa_assert(c->input_memblockq);
 
 /*         pa_log("STREAMING_DATA"); */
 
-        if (!(l = pa_memblockq_missing(c->input_memblockq)))
+        if (!(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, c->playback.fragment_size*2));
             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 (r < 0 && (errno == EINTR || errno == EAGAIN))
+                return 0;
+
             pa_log_debug("read(): %s", r < 0 ? pa_cstrerror(errno) : "EOF");
             return -1;
         }
@@ -960,29 +1051,30 @@
         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->sink_input->sink->asyncmsgq, PA_MSGOBJECT(c->sink_input), SINK_INPUT_MESSAGE_POST_DATA, NULL, 0, &chunk, NULL);
+        pa_atomic_sub(&c->playback.missing, r);
     }
 
     return 0;
 }
 
-static int do_write(struct connection *c) {
-    assert(c && c->io);
+static int do_write(connection *c) {
+    connection_assert_ref(c);
 
 /*     pa_log("WRITE"); */
 
     if (c->write_data_length) {
         ssize_t r;
 
-        assert(c->write_data_index < c->write_data_length);
+        pa_assert(c->write_data_index < c->write_data_length);
         if ((r = pa_iochannel_write(c->io, (uint8_t*) c->write_data+c->write_data_index, c->write_data_length-c->write_data_index)) < 0) {
+
+            if (r < 0 && (errno == EINTR || errno == EAGAIN))
+                return 0;
+
             pa_log("write(): %s", pa_cstrerror(errno));
             return -1;
         }
@@ -993,32 +1085,38 @@
     } else if (c->state == ESD_STREAMING_DATA && c->source_output) {
         pa_memchunk chunk;
         ssize_t r;
-
-        assert(c->output_memblockq);
+        void *p;
+
         if (pa_memblockq_peek(c->output_memblockq, &chunk) < 0)
             return 0;
 
-        assert(chunk.memblock && chunk.length);
-
-        if ((r = pa_iochannel_write(c->io, (uint8_t*) chunk.memblock->data+chunk.index, chunk.length)) < 0) {
-            pa_memblock_unref(chunk.memblock);
+        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 (r < 0 && (errno == EINTR || errno == EAGAIN))
+                return 0;
+
             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);
+        pa_memblockq_drop(c->output_memblockq, r);
     }
 
     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);
+static void do_work(connection *c) {
+    connection_assert_ref(c);
+
     c->protocol->core->mainloop->defer_enable(c->defer_event, 0);
 
     if (c->dead)
@@ -1044,122 +1142,196 @@
 fail:
 
     if (c->state == ESD_STREAMING_DATA && c->sink_input) {
-        c->dead = 1;
+        c->dead = TRUE;
 
         pa_iochannel_free(c->io);
         c->io = NULL;
 
-        pa_memblockq_prebuf_disable(c->input_memblockq);
-        pa_sink_notify(c->sink_input->sink);
+        pa_asyncmsgq_post(c->sink_input->sink->asyncmsgq, PA_MSGOBJECT(c->sink_input), SINK_INPUT_MESSAGE_DISABLE_PREBUF, NULL, 0, NULL, NULL);
     } else
-        connection_free(c);
+        connection_unlink(c);
 }
 
 static void io_callback(pa_iochannel*io, void *userdata) {
-    struct connection *c = userdata;
-    assert(io && c && c->io == io);
+    connection *c = CONNECTION(userdata);
+
+    connection_assert_ref(c);
+    pa_assert(io);
 
     do_work(c);
 }
 
-/*** defer 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_log("DEFER"); */
+    connection *c = CONNECTION(userdata);
+
+    connection_assert_ref(c);
+    pa_assert(e);
 
     do_work(c);
 }
 
+static int connection_process_msg(pa_msgobject *o, int code, void*userdata, int64_t offset, pa_memchunk *chunk) {
+    connection *c = CONNECTION(o);
+    connection_assert_ref(c);
+
+    switch (code) {
+        case CONNECTION_MESSAGE_REQUEST_DATA:
+            do_work(c);
+            break;
+
+        case CONNECTION_MESSAGE_POST_DATA:
+/*             pa_log("got data %u", chunk->length); */
+            pa_memblockq_push_align(c->output_memblockq, chunk);
+            do_work(c);
+            break;
+
+        case CONNECTION_MESSAGE_UNLINK_CONNECTION:
+            connection_unlink(c);
+            break;
+    }
+
+    return 0;
+}
+
 /*** sink_input callbacks ***/
 
-static int sink_input_peek_cb(pa_sink_input *i, pa_memchunk *chunk) {
-    struct connection*c;
-    assert(i && i->userdata && chunk);
-    c = i->userdata;
-
-    if (pa_memblockq_peek(c->input_memblockq, chunk) < 0) {
-
-        if (c->dead)
-            connection_free(c);
-
-        return -1;
-    }
-
-    return 0;
-}
-
-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);
-
-/*     pa_log("DROP"); */
-
-    pa_memblockq_drop(c->input_memblockq, chunk, length);
-
-    /* do something */
-    assert(c->protocol && c->protocol->core && c->protocol->core->mainloop && c->protocol->core->mainloop->defer_enable);
-
-    if (!c->dead)
-        c->protocol->core->mainloop->defer_enable(c->defer_event, 1);
-
-/*     assert(pa_memblockq_get_length(c->input_memblockq) > 2048); */
+/* Called from thread context */
+static int sink_input_process_msg(pa_msgobject *o, int code, void *userdata, int64_t offset, pa_memchunk *chunk) {
+    pa_sink_input *i = PA_SINK_INPUT(o);
+    connection*c;
+
+    pa_sink_input_assert_ref(i);
+    c = CONNECTION(i->userdata);
+    connection_assert_ref(c);
+
+    switch (code) {
+
+        case SINK_INPUT_MESSAGE_POST_DATA: {
+            pa_assert(chunk);
+
+            /* New data from the main loop */
+            pa_memblockq_push_align(c->input_memblockq, chunk);
+
+/*             pa_log("got data, %u", pa_memblockq_get_length(c->input_memblockq)); */
+
+            return 0;
+        }
+
+        case SINK_INPUT_MESSAGE_DISABLE_PREBUF: {
+            pa_memblockq_prebuf_disable(c->input_memblockq);
+            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(o, code, userdata, offset, chunk);
+    }
+}
+
+/* Called from thread context */
+static int sink_input_peek_cb(pa_sink_input *i, size_t length, pa_memchunk *chunk) {
+    connection*c;
+    int r;
+
+    pa_assert(i);
+    c = CONNECTION(i->userdata);
+    connection_assert_ref(c);
+    pa_assert(chunk);
+
+    if ((r = pa_memblockq_peek(c->input_memblockq, chunk)) < 0 && c->dead)
+        pa_asyncmsgq_post(pa_thread_mq_get()->outq, PA_MSGOBJECT(c), CONNECTION_MESSAGE_UNLINK_CONNECTION, NULL, 0, NULL, NULL);
+
+    return r;
+}
+
+/* Called from thread context */
+static void sink_input_drop_cb(pa_sink_input *i, size_t length) {
+    connection*c;
+    size_t old, new;
+
+    pa_assert(i);
+    c = CONNECTION(i->userdata);
+    connection_assert_ref(c);
+    pa_assert(length);
+
+    /*     pa_log("DROP"); */
+
+    old = pa_memblockq_missing(c->input_memblockq);
+    pa_memblockq_drop(c->input_memblockq, length);
+    new = pa_memblockq_missing(c->input_memblockq);
+
+    if (new > old) {
+        if (pa_atomic_add(&c->playback.missing, new - old) <= 0)
+            pa_asyncmsgq_post(pa_thread_mq_get()->outq, PA_MSGOBJECT(c), CONNECTION_MESSAGE_REQUEST_DATA, NULL, 0, NULL, NULL);
+    }
 }
 
 static void sink_input_kill_cb(pa_sink_input *i) {
-    assert(i && 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);
+    pa_sink_input_assert_ref(i);
+
+    connection_unlink(CONNECTION(i->userdata));
 }
 
 /*** source_output callbacks ***/
 
+/* Called from thread context */
 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);
-
-    /* do something */
-    assert(c->protocol && c->protocol->core && c->protocol->core->mainloop && c->protocol->core->mainloop->defer_enable);
-
-    if (!c->dead)
-        c->protocol->core->mainloop->defer_enable(c->defer_event, 1);
+    connection *c;
+
+    pa_assert(o);
+    c = CONNECTION(o->userdata);
+    pa_assert(c);
+    pa_assert(chunk);
+
+    pa_asyncmsgq_post(pa_thread_mq_get()->outq, PA_MSGOBJECT(c), CONNECTION_MESSAGE_POST_DATA, NULL, 0, chunk, NULL);
 }
 
 static void source_output_kill_cb(pa_source_output *o) {
-    assert(o && o->userdata);
-    connection_free((struct connection *) o->userdata);
+    pa_source_output_assert_ref(o);
+
+    connection_unlink(CONNECTION(o->userdata));
 }
 
 static pa_usec_t source_output_get_latency_cb(pa_source_output *o) {
-    struct connection*c = o->userdata;
-    assert(o && c);
+    connection*c;
+
+    pa_assert(o);
+    c = CONNECTION(o->userdata);
+    pa_assert(c);
+
     return pa_bytes_to_usec(pa_memblockq_get_length(c->output_memblockq), &c->source_output->sample_spec);
 }
 
 /*** socket server callback ***/
 
 static void auth_timeout(pa_mainloop_api*m, pa_time_event *e, const struct timeval *tv, void *userdata) {
-    struct connection *c = userdata;
-    assert(m && tv && c && c->auth_timeout_event == e);
+    connection *c = CONNECTION(userdata);
+
+    pa_assert(m);
+    pa_assert(tv);
+    connection_assert_ref(c);
+    pa_assert(c->auth_timeout_event == e);
 
     if (!c->authorized)
-        connection_free(c);
+        connection_unlink(c);
 }
 
 static void on_connection(pa_socket_server*s, pa_iochannel *io, void *userdata) {
-    struct connection *c;
+    connection *c;
     pa_protocol_esound *p = userdata;
     char cname[256], pname[128];
-    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);
@@ -1167,23 +1339,23 @@
         return;
     }
 
-    c = pa_xnew(struct connection, 1);
+    c = pa_msgobject_new(connection);
+    c->parent.parent.free = connection_free;
+    c->parent.process_msg = connection_process_msg;
     c->protocol = p;
     c->io = io;
     pa_iochannel_set_callback(c->io, io_callback, c);
 
     pa_iochannel_socket_peer_to_string(io, pname, sizeof(pname));
-    snprintf(cname, sizeof(cname), "EsounD client (%s)", pname);
-    assert(p->core);
+    pa_snprintf(cname, sizeof(cname), "EsounD client (%s)", pname);
     c->client = pa_client_new(p->core, __FILE__, cname);
-    assert(c->client);
     c->client->owner = p->module;
     c->client->kill = client_kill_cb;
     c->client->userdata = c;
 
     c->authorized = !!p->public;
-    c->swap_byte_order = 0;
-    c->dead = 0;
+    c->swap_byte_order = FALSE;
+    c->dead = FALSE;
 
     c->read_data_length = 0;
     c->read_data = pa_xmalloc(c->read_data_alloc = proto_map[ESD_PROTO_CONNECT].data_length);
@@ -1203,6 +1375,7 @@
     c->playback.current_memblock = NULL;
     c->playback.memblock_index = 0;
     c->playback.fragment_size = 0;
+    pa_atomic_store(&c->playback.missing, 0);
 
     c->scache.memchunk.length = c->scache.memchunk.index = 0;
     c->scache.memchunk.memblock = NULL;
@@ -1212,7 +1385,7 @@
 
     if (!c->authorized && p->auth_ip_acl && pa_ip_acl_check(p->auth_ip_acl, pa_iochannel_get_recv_fd(io)) > 0) {
         pa_log_info("Client authenticated by IP ACL.");
-        c->authorized = 1;
+        c->authorized = TRUE;
     }
 
     if (!c->authorized) {
@@ -1224,7 +1397,6 @@
         c->auth_timeout_event = 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);
 
     pa_idxset_put(p->connections, c, &c->index);
@@ -1233,22 +1405,22 @@
 /*** entry points ***/
 
 pa_protocol_esound* pa_protocol_esound_new(pa_core*core, pa_socket_server *server, pa_module *m, pa_modargs *ma) {
-    pa_protocol_esound *p;
+    pa_protocol_esound *p = NULL;
     int public = 0;
     const char *acl;
 
-    assert(core);
-    assert(server);
-    assert(m);
-    assert(ma);
-
-    p = pa_xnew(pa_protocol_esound, 1);
+    pa_assert(core);
+    pa_assert(server);
+    pa_assert(m);
+    pa_assert(ma);
 
     if (pa_modargs_get_value_boolean(ma, "auth-anonymous", &public) < 0) {
         pa_log("auth-anonymous= expects a boolean argument.");
         goto fail;
     }
 
+    p = pa_xnew(pa_protocol_esound, 1);
+
     if (pa_authkey_load_auto(pa_modargs_get_value(ma, "cookie", DEFAULT_COOKIE_FILE), p->esd_key, sizeof(p->esd_key)) < 0)
         goto fail;
 
@@ -1261,13 +1433,12 @@
     } else
         p->auth_ip_acl = NULL;
 
+    p->core = core;
     p->module = m;
     p->public = public;
     p->server = server;
     pa_socket_server_set_callback(p->server, on_connection, p);
-    p->core = core;
     p->connections = pa_idxset_new(NULL, NULL);
-    assert(p->connections);
 
     p->sink_name = pa_xstrdup(pa_modargs_get_value(ma, "sink", NULL));
     p->source_name = pa_xstrdup(pa_modargs_get_value(ma, "source", NULL));
@@ -1281,17 +1452,20 @@
 }
 
 void pa_protocol_esound_free(pa_protocol_esound *p) {
-    struct connection *c;
-    assert(p);
+    connection *c;
+    pa_assert(p);
 
     while ((c = pa_idxset_first(p->connections, NULL)))
-        connection_free(c);
-
+        connection_unlink(c);
     pa_idxset_free(p->connections, NULL, NULL);
+
     pa_socket_server_unref(p->server);
 
     if (p->auth_ip_acl)
         pa_ip_acl_free(p->auth_ip_acl);
 
+    pa_xfree(p->sink_name);
+    pa_xfree(p->source_name);
+
     pa_xfree(p);
 }

Modified: trunk/src/pulsecore/protocol-http.c
URL: http://0pointer.de/cgi-bin/viewcvs.cgi/trunk/src/pulsecore/protocol-http.c?rev=1971&root=pulseaudio&r1=1970&r2=1971&view=diff
==============================================================================
--- trunk/src/pulsecore/protocol-http.c (original)
+++ trunk/src/pulsecore/protocol-http.c Sun Oct 28 20:13:50 2007
@@ -25,7 +25,6 @@
 #include <config.h>
 #endif
 
-#include <assert.h>
 #include <stdlib.h>
 #include <stdio.h>
 #include <string.h>
@@ -34,6 +33,7 @@
 #include <pulse/xmalloc.h>
 
 #include <pulsecore/ioline.h>
+#include <pulsecore/macro.h>
 #include <pulsecore/log.h>
 #include <pulsecore/namereg.h>
 #include <pulsecore/cli-text.h>
@@ -65,11 +65,12 @@
 
 static void http_response(struct connection *c, int code, const char *msg, const char *mime) {
     char s[256];
-    assert(c);
-    assert(msg);
-    assert(mime);
-
-    snprintf(s, sizeof(s),
+
+    pa_assert(c);
+    pa_assert(msg);
+    pa_assert(mime);
+
+    pa_snprintf(s, sizeof(s),
              "HTTP/1.0 %i %s\n"
              "Connection: close\n"
              "Content-Type: %s\n"
@@ -83,14 +84,14 @@
 
 static void http_message(struct connection *c, int code, const char *msg, const char *text) {
     char s[256];
-    assert(c);
+    pa_assert(c);
 
     http_response(c, code, msg, "text/html");
 
     if (!text)
         text = msg;
 
-    snprintf(s, sizeof(s),
+    pa_snprintf(s, sizeof(s),
              "<?xml version=\"1.0\"?>\n"
              "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Strict//EN\" \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd\">\n"
              "<html xmlns=\"http://www.w3.org/1999/xhtml\"><head><title>%s</title></head>\n"
@@ -103,21 +104,22 @@
 
 
 static void connection_free(struct connection *c, int del) {
-    assert(c);
+    pa_assert(c);
 
     if (c->url)
         pa_xfree(c->url);
 
     if (del)
         pa_idxset_remove_by_data(c->protocol->connections, c, NULL);
+
     pa_ioline_unref(c->line);
     pa_xfree(c);
 }
 
 static void line_callback(pa_ioline *line, const char *s, void *userdata) {
     struct connection *c = userdata;
-    assert(line);
-    assert(c);
+    pa_assert(line);
+    pa_assert(c);
 
     if (!s) {
         /* EOF */
@@ -223,7 +225,10 @@
 static void on_connection(pa_socket_server*s, pa_iochannel *io, void *userdata) {
     pa_protocol_http *p = userdata;
     struct connection *c;
-    assert(s && io && p);
+
+    pa_assert(s);
+    pa_assert(io);
+    pa_assert(p);
 
     if (pa_idxset_size(p->connections)+1 > MAX_CONNECTIONS) {
         pa_log_warn("Warning! Too many connections (%u), dropping incoming connection.", MAX_CONNECTIONS);
@@ -231,7 +236,7 @@
         return;
     }
 
-    c = pa_xmalloc(sizeof(struct connection));
+    c = pa_xnew(struct connection, 1);
     c->protocol = p;
     c->line = pa_ioline_new(io);
     c->state = REQUEST_LINE;
@@ -243,9 +248,11 @@
 
 pa_protocol_http* pa_protocol_http_new(pa_core *core, pa_socket_server *server, pa_module *m, PA_GCC_UNUSED pa_modargs *ma) {
     pa_protocol_http* p;
-    assert(core && server);
-
-    p = pa_xmalloc(sizeof(pa_protocol_http));
+
+    pa_core_assert_ref(core);
+    pa_assert(server);
+
+    p = pa_xnew(pa_protocol_http, 1);
     p->module = m;
     p->core = core;
     p->server = server;
@@ -257,12 +264,12 @@
 }
 
 static void free_connection(void *p, PA_GCC_UNUSED void *userdata) {
-    assert(p);
+    pa_assert(p);
     connection_free(p, 0);
 }
 
 void pa_protocol_http_free(pa_protocol_http *p) {
-    assert(p);
+    pa_assert(p);
 
     pa_idxset_free(p->connections, free_connection, NULL);
     pa_socket_server_unref(p->server);

Modified: trunk/src/pulsecore/protocol-native.c
URL: http://0pointer.de/cgi-bin/viewcvs.cgi/trunk/src/pulsecore/protocol-native.c?rev=1971&root=pulseaudio&r1=1970&r2=1971&view=diff
==============================================================================
--- trunk/src/pulsecore/protocol-native.c (original)
+++ trunk/src/pulsecore/protocol-native.c Sun Oct 28 20:13:50 2007
@@ -28,7 +28,6 @@
 
 #include <string.h>
 #include <stdio.h>
-#include <assert.h>
 #include <stdlib.h>
 #include <unistd.h>
 
@@ -61,6 +60,7 @@
 #include <pulsecore/creds.h>
 #include <pulsecore/core-util.h>
 #include <pulsecore/ipacl.h>
+#include <pulsecore/thread-mq.h>
 
 #include "protocol-native.h"
 
@@ -72,54 +72,61 @@
 
 #define MAX_MEMBLOCKQ_LENGTH (4*1024*1024) /* 4MB */
 
-struct connection;
+typedef struct connection connection;
 struct pa_protocol_native;
 
-struct record_stream {
-    struct connection *connection;
+typedef struct record_stream {
+    pa_msgobject parent;
+
+    connection *connection;
     uint32_t index;
+
     pa_source_output *source_output;
     pa_memblockq *memblockq;
     size_t fragment_size;
-};
-
-struct playback_stream {
-    int type;
-    struct connection *connection;
+} record_stream;
+
+typedef struct output_stream {
+    pa_msgobject parent;
+} output_stream;
+
+typedef struct playback_stream {
+    output_stream parent;
+
+    connection *connection;
     uint32_t index;
+
     pa_sink_input *sink_input;
     pa_memblockq *memblockq;
-    size_t requested_bytes;
     int drain_request;
     uint32_t drain_tag;
     uint32_t syncid;
     int underrun;
 
-    /* Sync group members */
-    PA_LLIST_FIELDS(struct playback_stream);
-};
-
-struct upload_stream {
-    int type;
-    struct connection *connection;
+    pa_atomic_t missing;
+    size_t minreq;
+
+    /* Only updated after SINK_INPUT_MESSAGE_UPDATE_LATENCY */
+    int64_t read_index, write_index;
+    size_t resampled_chunk_length;
+} playback_stream;
+
+typedef struct upload_stream {
+    output_stream parent;
+
+    connection *connection;
     uint32_t index;
+
     pa_memchunk memchunk;
     size_t length;
     char *name;
     pa_sample_spec sample_spec;
     pa_channel_map channel_map;
-};
-
-struct output_stream {
-    int type;
-};
-
-enum {
-    UPLOAD_STREAM,
-    PLAYBACK_STREAM
-};
+} upload_stream;
 
 struct connection {
+    pa_msgobject parent;
+
     int authorized;
     uint32_t version;
     pa_protocol_native *protocol;
@@ -132,10 +139,30 @@
     pa_time_event *auth_timeout_event;
 };
 
+PA_DECLARE_CLASS(record_stream);
+#define RECORD_STREAM(o) (record_stream_cast(o))
+static PA_DEFINE_CHECK_TYPE(record_stream, pa_msgobject);
+
+PA_DECLARE_CLASS(output_stream);
+#define OUTPUT_STREAM(o) (output_stream_cast(o))
+static PA_DEFINE_CHECK_TYPE(output_stream, pa_msgobject);
+
+PA_DECLARE_CLASS(playback_stream);
+#define PLAYBACK_STREAM(o) (playback_stream_cast(o))
+static PA_DEFINE_CHECK_TYPE(playback_stream, output_stream);
+
+PA_DECLARE_CLASS(upload_stream);
+#define UPLOAD_STREAM(o) (upload_stream_cast(o))
+static PA_DEFINE_CHECK_TYPE(upload_stream, output_stream);
+
+PA_DECLARE_CLASS(connection);
+#define CONNECTION(o) (connection_cast(o))
+static PA_DEFINE_CHECK_TYPE(connection, pa_msgobject);
+
 struct pa_protocol_native {
     pa_module *module;
+    pa_core *core;
     int public;
-    pa_core *core;
     pa_socket_server *server;
     pa_idxset *connections;
     uint8_t auth_cookie[PA_NATIVE_COOKIE_LENGTH];
@@ -146,16 +173,44 @@
     pa_ip_acl *auth_ip_acl;
 };
 
-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);
+enum {
+    SINK_INPUT_MESSAGE_POST_DATA = PA_SINK_INPUT_MESSAGE_MAX, /* data from main loop to sink input */
+    SINK_INPUT_MESSAGE_DRAIN, /* disabled prebuf, get playback started. */
+    SINK_INPUT_MESSAGE_FLUSH,
+    SINK_INPUT_MESSAGE_TRIGGER,
+    SINK_INPUT_MESSAGE_SEEK,
+    SINK_INPUT_MESSAGE_PREBUF_FORCE,
+    SINK_INPUT_MESSAGE_UPDATE_LATENCY
+};
+
+enum {
+    PLAYBACK_STREAM_MESSAGE_REQUEST_DATA,      /* data requested from sink input from the main loop */
+    PLAYBACK_STREAM_MESSAGE_UNDERFLOW,
+    PLAYBACK_STREAM_MESSAGE_OVERFLOW,
+    PLAYBACK_STREAM_MESSAGE_DRAIN_ACK
+};
+
+enum {
+    RECORD_STREAM_MESSAGE_POST_DATA         /* data from source output to main loop */
+};
+
+enum {
+    CONNECTION_MESSAGE_RELEASE,
+    CONNECTION_MESSAGE_REVOKE
+};
+
+static int sink_input_peek_cb(pa_sink_input *i, size_t length, pa_memchunk *chunk);
+static void sink_input_drop_cb(pa_sink_input *i, size_t length);
 static void sink_input_kill_cb(pa_sink_input *i);
-static pa_usec_t sink_input_get_latency_cb(pa_sink_input *i);
-
+
+static void send_memblock(connection *c);
 static void request_bytes(struct playback_stream*s);
 
 static void source_output_kill_cb(pa_source_output *o);
 static void source_output_push_cb(pa_source_output *o, const pa_memchunk *chunk);
 static pa_usec_t source_output_get_latency_cb(pa_source_output *o);
+
+static int sink_input_process_msg(pa_msgobject *o, int code, void *userdata, int64_t offset, pa_memchunk *chunk);
 
 static void command_exit(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata);
 static void command_create_playback_stream(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata);
@@ -179,8 +234,7 @@
 static void command_set_volume(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata);
 static void command_set_mute(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata);
 static void command_cork_playback_stream(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata);
-static void command_flush_playback_stream(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata);
-static void command_trigger_or_prebuf_playback_stream(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata);
+static void command_trigger_or_flush_or_prebuf_playback_stream(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata);
 static void command_set_default_sink_or_source(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata);
 static void command_set_stream_name(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata);
 static void command_kill(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata);
@@ -193,6 +247,7 @@
 static void command_cork_record_stream(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata);
 static void command_flush_record_stream(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata);
 static void command_move_stream(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata);
+static void command_suspend(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata);
 
 static const pa_pdispatch_cb_t command_table[PA_COMMAND_MAX] = {
     [PA_COMMAND_ERROR] = NULL,
@@ -239,12 +294,16 @@
     [PA_COMMAND_SET_SOURCE_VOLUME] = command_set_volume,
 
     [PA_COMMAND_SET_SINK_MUTE] = command_set_mute,
+    [PA_COMMAND_SET_SINK_INPUT_MUTE] = command_set_mute,
     [PA_COMMAND_SET_SOURCE_MUTE] = command_set_mute,
 
+    [PA_COMMAND_SUSPEND_SINK] = command_suspend,
+    [PA_COMMAND_SUSPEND_SOURCE] = command_suspend,
+
     [PA_COMMAND_CORK_PLAYBACK_STREAM] = command_cork_playback_stream,
-    [PA_COMMAND_FLUSH_PLAYBACK_STREAM] = command_flush_playback_stream,
-    [PA_COMMAND_TRIGGER_PLAYBACK_STREAM] = command_trigger_or_prebuf_playback_stream,
-    [PA_COMMAND_PREBUF_PLAYBACK_STREAM] = command_trigger_or_prebuf_playback_stream,
+    [PA_COMMAND_FLUSH_PLAYBACK_STREAM] = command_trigger_or_flush_or_prebuf_playback_stream,
+    [PA_COMMAND_TRIGGER_PLAYBACK_STREAM] = command_trigger_or_flush_or_prebuf_playback_stream,
+    [PA_COMMAND_PREBUF_PLAYBACK_STREAM] = command_trigger_or_flush_or_prebuf_playback_stream,
 
     [PA_COMMAND_CORK_RECORD_STREAM] = command_cork_record_stream,
     [PA_COMMAND_FLUSH_RECORD_STREAM] = command_flush_record_stream,
@@ -269,74 +328,146 @@
 
 /* structure management */
 
-static struct upload_stream* upload_stream_new(
-    struct connection *c,
-    const pa_sample_spec *ss,
-    const pa_channel_map *map,
-    const char *name, size_t length) {
-
-    struct upload_stream *s;
-    assert(c && ss && name && length);
-
-    s = pa_xnew(struct upload_stream, 1);
-    s->type = UPLOAD_STREAM;
+static void upload_stream_unlink(upload_stream *s) {
+    pa_assert(s);
+
+    if (!s->connection)
+        return;
+
+    pa_assert_se(pa_idxset_remove_by_data(s->connection->output_streams, s, NULL) == s);
+    s->connection = NULL;
+    upload_stream_unref(s);
+}
+
+static void upload_stream_free(pa_object *o) {
+    upload_stream *s = UPLOAD_STREAM(o);
+    pa_assert(s);
+
+    upload_stream_unlink(s);
+
+    pa_xfree(s->name);
+
+    if (s->memchunk.memblock)
+        pa_memblock_unref(s->memchunk.memblock);
+
+    pa_xfree(s);
+}
+
+static upload_stream* upload_stream_new(
+        connection *c,
+        const pa_sample_spec *ss,
+        const pa_channel_map *map,
+        const char *name, size_t length) {
+
+    upload_stream *s;
+
+    pa_assert(c);
+    pa_assert(ss);
+    pa_assert(name);
+    pa_assert(length > 0);
+
+    s = pa_msgobject_new(upload_stream);
+    s->parent.parent.parent.free = upload_stream_free;
     s->connection = c;
     s->sample_spec = *ss;
     s->channel_map = *map;
     s->name = pa_xstrdup(name);
-
-    s->memchunk.memblock = NULL;
-    s->memchunk.index = 0;
-    s->memchunk.length = 0;
-
+    pa_memchunk_reset(&s->memchunk);
     s->length = length;
 
     pa_idxset_put(c->output_streams, s, &s->index);
+
     return s;
 }
 
-static void upload_stream_free(struct upload_stream *o) {
-    assert(o && o->connection);
-
-    pa_idxset_remove_by_data(o->connection->output_streams, o, NULL);
-
-    pa_xfree(o->name);
-
-    if (o->memchunk.memblock)
-        pa_memblock_unref(o->memchunk.memblock);
-
-    pa_xfree(o);
-}
-
-static struct record_stream* record_stream_new(
-    struct connection *c,
-    pa_source *source,
-    const pa_sample_spec *ss,
-    const pa_channel_map *map,
-    const char *name,
-    size_t maxlength,
-    size_t fragment_size) {
-
-    struct record_stream *s;
+static void record_stream_unlink(record_stream *s) {
+    pa_assert(s);
+
+    if (!s->connection)
+        return;
+
+    if (s->source_output) {
+        pa_source_output_unlink(s->source_output);
+        pa_source_output_unref(s->source_output);
+        s->source_output = NULL;
+    }
+
+    pa_assert_se(pa_idxset_remove_by_data(s->connection->record_streams, s, NULL) == s);
+    s->connection = NULL;
+    record_stream_unref(s);
+}
+
+static void record_stream_free(pa_object *o) {
+    record_stream *s = RECORD_STREAM(o);
+    pa_assert(s);
+
+    record_stream_unlink(s);
+
+    pa_memblockq_free(s->memblockq);
+    pa_xfree(s);
+}
+
+static int record_stream_process_msg(pa_msgobject *o, int code, void*userdata, int64_t offset, pa_memchunk *chunk) {
+    record_stream *s = RECORD_STREAM(o);
+    record_stream_assert_ref(s);
+
+    if (!s->connection)
+        return -1;
+
+    switch (code) {
+
+        case RECORD_STREAM_MESSAGE_POST_DATA:
+
+            if (pa_memblockq_push_align(s->memblockq, chunk) < 0) {
+/*                 pa_log_warn("Failed to push data into output queue."); */
+                return -1;
+            }
+
+            if (!pa_pstream_is_pending(s->connection->pstream))
+                send_memblock(s->connection);
+
+            break;
+    }
+
+    return 0;
+}
+
+static record_stream* record_stream_new(
+        connection *c,
+        pa_source *source,
+        const pa_sample_spec *ss,
+        const pa_channel_map *map,
+        const char *name,
+        uint32_t *maxlength,
+        uint32_t fragment_size,
+        int corked) {
+
+    record_stream *s;
     pa_source_output *source_output;
     size_t base;
     pa_source_output_new_data data;
 
-    assert(c && ss && name && maxlength);
+    pa_assert(c);
+    pa_assert(ss);
+    pa_assert(name);
+    pa_assert(maxlength);
+    pa_assert(*maxlength > 0);
 
     pa_source_output_new_data_init(&data);
+    data.module = c->protocol->module;
+    data.client = c->client;
     data.source = source;
     data.driver = __FILE__;
     data.name = name;
     pa_source_output_new_data_set_sample_spec(&data, ss);
     pa_source_output_new_data_set_channel_map(&data, map);
-    data.module = c->protocol->module;
-    data.client = c->client;
-
-    if (!(source_output = pa_source_output_new(c->protocol->core, &data, 0)))
+
+    if (!(source_output = pa_source_output_new(c->protocol->core, &data, corked ? PA_SOURCE_OUTPUT_START_CORKED : 0)))
         return NULL;
 
-    s = pa_xnew(struct record_stream, 1);
+    s = pa_msgobject_new(record_stream);
+    s->parent.parent.free = record_stream_free;
+    s->parent.process_msg = record_stream_process_msg;
     s->connection = c;
     s->source_output = source_output;
     s->source_output->push = source_output_push_cb;
@@ -346,58 +477,159 @@
 
     s->memblockq = pa_memblockq_new(
             0,
-            maxlength,
+            *maxlength,
             0,
             base = pa_frame_size(ss),
             1,
             0,
             NULL);
-    assert(s->memblockq);
 
     s->fragment_size = (fragment_size/base)*base;
-    if (!s->fragment_size)
+    if (s->fragment_size <= 0)
         s->fragment_size = base;
+    *maxlength = pa_memblockq_get_maxlength(s->memblockq);
 
     pa_idxset_put(c->record_streams, s, &s->index);
+
+    pa_source_output_put(s->source_output);
     return s;
 }
 
-static void record_stream_free(struct record_stream* r) {
-    assert(r && r->connection);
-
-    pa_idxset_remove_by_data(r->connection->record_streams, r, NULL);
-    pa_source_output_disconnect(r->source_output);
-    pa_source_output_unref(r->source_output);
-    pa_memblockq_free(r->memblockq);
-    pa_xfree(r);
-}
-
-static struct playback_stream* playback_stream_new(
-        struct connection *c,
+static void playback_stream_unlink(playback_stream *s) {
+    pa_assert(s);
+
+    if (!s->connection)
+        return;
+
+    if (s->sink_input) {
+        pa_sink_input_unlink(s->sink_input);
+        pa_sink_input_unref(s->sink_input);
+        s->sink_input = NULL;
+    }
+
+    if (s->drain_request)
+        pa_pstream_send_error(s->connection->pstream, s->drain_tag, PA_ERR_NOENTITY);
+
+    pa_assert_se(pa_idxset_remove_by_data(s->connection->output_streams, s, NULL) == s);
+    s->connection = NULL;
+    playback_stream_unref(s);
+}
+
+static void playback_stream_free(pa_object* o) {
+    playback_stream *s = PLAYBACK_STREAM(o);
+    pa_assert(s);
+
+    playback_stream_unlink(s);
+
+    pa_memblockq_free(s->memblockq);
+    pa_xfree(s);
+}
+
+static int playback_stream_process_msg(pa_msgobject *o, int code, void*userdata, int64_t offset, pa_memchunk *chunk) {
+    playback_stream *s = PLAYBACK_STREAM(o);
+    playback_stream_assert_ref(s);
+
+    if (!s->connection)
+        return -1;
+
+    switch (code) {
+        case PLAYBACK_STREAM_MESSAGE_REQUEST_DATA: {
+            pa_tagstruct *t;
+            uint32_t l = 0;
+
+            for (;;) {
+                int32_t k;
+
+                if ((k = pa_atomic_load(&s->missing)) <= 0)
+                    break;
+
+                l += k;
+
+                if (l < s->minreq)
+                    break;
+
+                if (pa_atomic_sub(&s->missing, k) <= k)
+                    break;
+            }
+
+            if (l < s->minreq)
+                break;
+
+            t = pa_tagstruct_new(NULL, 0);
+            pa_tagstruct_putu32(t, PA_COMMAND_REQUEST);
+            pa_tagstruct_putu32(t, (uint32_t) -1); /* tag */
+            pa_tagstruct_putu32(t, s->index);
+            pa_tagstruct_putu32(t, l);
+            pa_pstream_send_tagstruct(s->connection->pstream, t);
+
+/*             pa_log("Requesting %u bytes", l);     */
+            break;
+        }
+
+        case PLAYBACK_STREAM_MESSAGE_UNDERFLOW: {
+            pa_tagstruct *t;
+
+            /* Report that we're empty */
+            t = pa_tagstruct_new(NULL, 0);
+            pa_tagstruct_putu32(t, PA_COMMAND_UNDERFLOW);
+            pa_tagstruct_putu32(t, (uint32_t) -1); /* tag */
+            pa_tagstruct_putu32(t, s->index);
+            pa_pstream_send_tagstruct(s->connection->pstream, t);
+            break;
+        }
+
+        case PLAYBACK_STREAM_MESSAGE_OVERFLOW: {
+            pa_tagstruct *t;
+
+            /* Notify the user we're overflowed*/
+            t = pa_tagstruct_new(NULL, 0);
+            pa_tagstruct_putu32(t, PA_COMMAND_OVERFLOW);
+            pa_tagstruct_putu32(t, (uint32_t) -1); /* tag */
+            pa_tagstruct_putu32(t, s->index);
+            pa_pstream_send_tagstruct(s->connection->pstream, t);
+            break;
+        }
+
+        case PLAYBACK_STREAM_MESSAGE_DRAIN_ACK:
+            pa_pstream_send_simple_ack(s->connection->pstream, PA_PTR_TO_UINT(userdata));
+            break;
+
+    }
+
+    return 0;
+}
+
+static playback_stream* playback_stream_new(
+        connection *c,
         pa_sink *sink,
         const pa_sample_spec *ss,
         const pa_channel_map *map,
         const char *name,
-        size_t maxlength,
-        size_t tlength,
-        size_t prebuf,
-        size_t minreq,
+        uint32_t *maxlength,
+        uint32_t *tlength,
+        uint32_t *prebuf,
+        uint32_t *minreq,
         pa_cvolume *volume,
-        uint32_t syncid) {
-
-    struct playback_stream *s, *ssync;
+        uint32_t syncid,
+        int corked,
+        uint32_t *missing) {
+
+    playback_stream *s, *ssync;
     pa_sink_input *sink_input;
     pa_memblock *silence;
     uint32_t idx;
     int64_t start_index;
     pa_sink_input_new_data data;
 
-    assert(c && ss && name && maxlength);
+    pa_assert(c);
+    pa_assert(ss);
+    pa_assert(name);
+    pa_assert(maxlength);
 
     /* Find syncid group */
     for (ssync = pa_idxset_first(c->output_streams, &idx); ssync; ssync = pa_idxset_next(c->output_streams, &idx)) {
 
-        if (ssync->type != PLAYBACK_STREAM)
+        if (!playback_stream_isinstance(ssync))
             continue;
 
         if (ssync->syncid == syncid)
@@ -405,8 +637,13 @@
     }
 
     /* Synced streams must connect to the same sink */
-    if (ssync)
-        sink = ssync->sink_input->sink;
+    if (ssync) {
+
+        if (!sink)
+            sink = ssync->sink_input->sink;
+        else if (sink != ssync->sink_input->sink)
+            return NULL;
+    }
 
     pa_sink_input_new_data_init(&data);
     data.sink = sink;
@@ -417,146 +654,158 @@
     pa_sink_input_new_data_set_volume(&data, volume);
     data.module = c->protocol->module;
     data.client = c->client;
-
-    if (!(sink_input = pa_sink_input_new(c->protocol->core, &data, 0)))
+    data.sync_base = ssync ? ssync->sink_input : NULL;
+
+    if (!(sink_input = pa_sink_input_new(c->protocol->core, &data, corked ? PA_SINK_INPUT_START_CORKED : 0)))
         return NULL;
 
-    s = pa_xnew(struct playback_stream, 1);
-    s->type = PLAYBACK_STREAM;
+    s = pa_msgobject_new(playback_stream);
+    s->parent.parent.parent.free = playback_stream_free;
+    s->parent.parent.process_msg = playback_stream_process_msg;
     s->connection = c;
     s->syncid = syncid;
     s->sink_input = sink_input;
     s->underrun = 1;
 
+    s->sink_input->parent.process_msg = sink_input_process_msg;
     s->sink_input->peek = sink_input_peek_cb;
     s->sink_input->drop = sink_input_drop_cb;
     s->sink_input->kill = sink_input_kill_cb;
-    s->sink_input->get_latency = sink_input_get_latency_cb;
     s->sink_input->userdata = s;
 
-    if (ssync) {
-        /* Sync id found, now find head of list */
-        PA_LLIST_FIND_HEAD(struct playback_stream, ssync, &ssync);
-
-        /* Prepend ourselves */
-        PA_LLIST_PREPEND(struct playback_stream, ssync, s);
-
-        /* Set our start index to the current read index of the other grozp member(s) */
-        assert(ssync->next);
-        start_index = pa_memblockq_get_read_index(ssync->next->memblockq);
-    } else {
-        /* This ia a new sync group */
-        PA_LLIST_INIT(struct playback_stream, s);
-        start_index = 0;
-    }
+    start_index = ssync ? pa_memblockq_get_read_index(ssync->memblockq) : 0;
 
     silence = pa_silence_memblock_new(c->protocol->core->mempool, ss, 0);
 
     s->memblockq = pa_memblockq_new(
             start_index,
-            maxlength,
-            tlength,
+            *maxlength,
+            *tlength,
             pa_frame_size(ss),
-            prebuf,
-            minreq,
+            *prebuf,
+            *minreq,
             silence);
 
     pa_memblock_unref(silence);
 
-    s->requested_bytes = 0;
+    *maxlength = (uint32_t) pa_memblockq_get_maxlength(s->memblockq);
+    *tlength = (uint32_t) pa_memblockq_get_tlength(s->memblockq);
+    *prebuf = (uint32_t) pa_memblockq_get_prebuf(s->memblockq);
+    *minreq = (uint32_t) pa_memblockq_get_minreq(s->memblockq);
+    *missing = (uint32_t) pa_memblockq_pop_missing(s->memblockq);
+
+    s->minreq = pa_memblockq_get_minreq(s->memblockq);
+    pa_atomic_store(&s->missing, 0);
     s->drain_request = 0;
 
     pa_idxset_put(c->output_streams, s, &s->index);
 
+    pa_sink_input_put(s->sink_input);
+
     return s;
 }
 
-static void playback_stream_free(struct playback_stream* p) {
-    struct playback_stream *head;
-    assert(p && p->connection);
-
-    if (p->drain_request)
-        pa_pstream_send_error(p->connection->pstream, p->drain_tag, PA_ERR_NOENTITY);
-
-    PA_LLIST_FIND_HEAD(struct playback_stream, p, &head);
-    PA_LLIST_REMOVE(struct playback_stream, head, p);
-
-    pa_idxset_remove_by_data(p->connection->output_streams, p, NULL);
-    pa_sink_input_disconnect(p->sink_input);
-    pa_sink_input_unref(p->sink_input);
-    pa_memblockq_free(p->memblockq);
-    pa_xfree(p);
-}
-
-static void connection_free(struct connection *c) {
-    struct record_stream *r;
-    struct output_stream *o;
-    assert(c && c->protocol);
-
-    pa_idxset_remove_by_data(c->protocol->connections, c, NULL);
+static int connection_process_msg(pa_msgobject *o, int code, void*userdata, int64_t offset, pa_memchunk *chunk) {
+    connection *c = CONNECTION(o);
+    connection_assert_ref(c);
+
+    if (!c->protocol)
+        return -1;
+
+    switch (code) {
+
+        case CONNECTION_MESSAGE_REVOKE:
+            pa_pstream_send_revoke(c->pstream, PA_PTR_TO_UINT(userdata));
+            break;
+
+        case CONNECTION_MESSAGE_RELEASE:
+            pa_pstream_send_release(c->pstream, PA_PTR_TO_UINT(userdata));
+            break;
+    }
+
+    return 0;
+}
+
+static void connection_unlink(connection *c) {
+    record_stream *r;
+    output_stream *o;
+
+    pa_assert(c);
+
+    if (!c->protocol)
+        return;
+
     while ((r = pa_idxset_first(c->record_streams, NULL)))
-        record_stream_free(r);
+        record_stream_unlink(r);
+
+    while ((o = pa_idxset_first(c->output_streams, NULL)))
+        if (playback_stream_isinstance(o))
+            playback_stream_unlink(PLAYBACK_STREAM(o));
+        else
+            upload_stream_unlink(UPLOAD_STREAM(o));
+
+    if (c->subscription)
+        pa_subscription_free(c->subscription);
+
+    if (c->pstream)
+        pa_pstream_unlink(c->pstream);
+
+    if (c->auth_timeout_event) {
+        c->protocol->core->mainloop->time_free(c->auth_timeout_event);
+        c->auth_timeout_event = NULL;
+    }
+
+    pa_assert_se(pa_idxset_remove_by_data(c->protocol->connections, c, NULL) == c);
+    c->protocol = NULL;
+    connection_unref(c);
+}
+
+static void connection_free(pa_object *o) {
+    connection *c = CONNECTION(o);
+
+    pa_assert(c);
+
+    connection_unlink(c);
+
     pa_idxset_free(c->record_streams, NULL, NULL);
-
-    while ((o = pa_idxset_first(c->output_streams, NULL)))
-        if (o->type == PLAYBACK_STREAM)
-            playback_stream_free((struct playback_stream*) o);
-        else
-            upload_stream_free((struct upload_stream*) o);
     pa_idxset_free(c->output_streams, NULL, NULL);
 
     pa_pdispatch_unref(c->pdispatch);
-    pa_pstream_close(c->pstream);
     pa_pstream_unref(c->pstream);
     pa_client_free(c->client);
 
-    if (c->subscription)
-        pa_subscription_free(c->subscription);
-
-    if (c->auth_timeout_event)
-        c->protocol->core->mainloop->time_free(c->auth_timeout_event);
-
     pa_xfree(c);
 }
 
-static void request_bytes(struct playback_stream *s) {
-    pa_tagstruct *t;
-    size_t l;
-    assert(s);
-
-    if (!(l = pa_memblockq_missing(s->memblockq)))
-        return;
-
-    if (l <= s->requested_bytes)
-        return;
-
-    l -= s->requested_bytes;
-
-    if (l < pa_memblockq_get_minreq(s->memblockq))
-        return;
-
-    s->requested_bytes += l;
-
-    t = pa_tagstruct_new(NULL, 0);
-    assert(t);
-    pa_tagstruct_putu32(t, PA_COMMAND_REQUEST);
-    pa_tagstruct_putu32(t, (uint32_t) -1); /* tag */
-    pa_tagstruct_putu32(t, s->index);
-    pa_tagstruct_putu32(t, l);
-    pa_pstream_send_tagstruct(s->connection->pstream, t);
-
-/*     pa_log("Requesting %u bytes", l);  */
-}
-
-static void send_memblock(struct connection *c) {
+/* Called from thread context */
+static void request_bytes(playback_stream *s) {
+    size_t m, previous_missing;
+
+    playback_stream_assert_ref(s);
+
+    m = pa_memblockq_pop_missing(s->memblockq);
+
+    if (m <= 0)
+        return;
+
+/*     pa_log("request_bytes(%u)", m); */
+
+    previous_missing = pa_atomic_add(&s->missing, m);
+    if (previous_missing < s->minreq && previous_missing+m >= s->minreq) {
+        pa_assert(pa_thread_mq_get());
+        pa_asyncmsgq_post(pa_thread_mq_get()->outq, PA_MSGOBJECT(s), PLAYBACK_STREAM_MESSAGE_REQUEST_DATA, NULL, 0, NULL, NULL);
+    }
+}
+
+static void send_memblock(connection *c) {
     uint32_t start;
-    struct record_stream *r;
+    record_stream *r;
 
     start = PA_IDXSET_INVALID;
     for (;;) {
         pa_memchunk chunk;
 
-        if (!(r = pa_idxset_rrobin(c->record_streams, &c->rrobin_index)))
+        if (!(r = RECORD_STREAM(pa_idxset_rrobin(c->record_streams, &c->rrobin_index))))
             return;
 
         if (start == PA_IDXSET_INVALID)
@@ -571,7 +820,8 @@
                 schunk.length = r->fragment_size;
 
             pa_pstream_send_memblock(c->pstream, r->index, 0, PA_SEEK_RELATIVE, &schunk);
-            pa_memblockq_drop(r->memblockq, &chunk, schunk.length);
+
+            pa_memblockq_drop(r->memblockq, schunk.length);
             pa_memblock_unref(schunk.memblock);
 
             return;
@@ -579,9 +829,9 @@
     }
 }
 
-static void send_playback_stream_killed(struct playback_stream *p) {
+static void send_playback_stream_killed(playback_stream *p) {
     pa_tagstruct *t;
-    assert(p);
+    playback_stream_assert_ref(p);
 
     t = pa_tagstruct_new(NULL, 0);
     pa_tagstruct_putu32(t, PA_COMMAND_PLAYBACK_STREAM_KILLED);
@@ -590,9 +840,9 @@
     pa_pstream_send_tagstruct(p->connection->pstream, t);
 }
 
-static void send_record_stream_killed(struct record_stream *r) {
+static void send_record_stream_killed(record_stream *r) {
     pa_tagstruct *t;
-    assert(r);
+    record_stream_assert_ref(r);
 
     t = pa_tagstruct_new(NULL, 0);
     pa_tagstruct_putu32(t, PA_COMMAND_RECORD_STREAM_KILLED);
@@ -601,107 +851,230 @@
     pa_pstream_send_tagstruct(r->connection->pstream, t);
 }
 
-/*** sinkinput callbacks ***/
-
-static int sink_input_peek_cb(pa_sink_input *i, pa_memchunk *chunk) {
-    struct playback_stream *s;
-    assert(i && i->userdata && chunk);
-    s = i->userdata;
+/*** sink input callbacks ***/
+
+/* Called from thread context */
+static int sink_input_process_msg(pa_msgobject *o, int code, void *userdata, int64_t offset, pa_memchunk *chunk) {
+    pa_sink_input *i = PA_SINK_INPUT(o);
+    playback_stream *s;
+
+    pa_sink_input_assert_ref(i);
+    s = PLAYBACK_STREAM(i->userdata);
+    playback_stream_assert_ref(s);
+
+    switch (code) {
+
+        case SINK_INPUT_MESSAGE_SEEK:
+            pa_memblockq_seek(s->memblockq, offset, PA_PTR_TO_UINT(userdata));
+            request_bytes(s);
+            return 0;
+
+        case SINK_INPUT_MESSAGE_POST_DATA: {
+            pa_assert(chunk);
+
+/*             pa_log("sink input post: %u", chunk->length); */
+
+            if (pa_memblockq_push_align(s->memblockq, chunk) < 0) {
+
+                pa_log_warn("Failed to push data into queue");
+                pa_asyncmsgq_post(pa_thread_mq_get()->outq, PA_MSGOBJECT(s), PLAYBACK_STREAM_MESSAGE_OVERFLOW, NULL, 0, NULL, NULL);
+                pa_memblockq_seek(s->memblockq, chunk->length, PA_SEEK_RELATIVE);
+            }
+
+            request_bytes(s);
+
+            s->underrun = 0;
+            return 0;
+        }
+
+        case SINK_INPUT_MESSAGE_DRAIN: {
+
+            pa_memblockq_prebuf_disable(s->memblockq);
+
+            if (!pa_memblockq_is_readable(s->memblockq))
+                pa_asyncmsgq_post(pa_thread_mq_get()->outq, PA_MSGOBJECT(s), PLAYBACK_STREAM_MESSAGE_DRAIN_ACK, userdata, 0, NULL, NULL);
+            else {
+                s->drain_tag = PA_PTR_TO_UINT(userdata);
+                s->drain_request = 1;
+            }
+            request_bytes(s);
+
+            return 0;
+        }
+
+        case SINK_INPUT_MESSAGE_FLUSH:
+        case SINK_INPUT_MESSAGE_PREBUF_FORCE:
+        case SINK_INPUT_MESSAGE_TRIGGER: {
+
+            pa_sink_input *isync;
+            void (*func)(pa_memblockq *bq);
+
+            switch  (code) {
+                case SINK_INPUT_MESSAGE_FLUSH:
+                    func = pa_memblockq_flush;
+                    break;
+
+                case SINK_INPUT_MESSAGE_PREBUF_FORCE:
+                    func = pa_memblockq_prebuf_force;
+                    break;
+
+                case SINK_INPUT_MESSAGE_TRIGGER:
+                    func = pa_memblockq_prebuf_disable;
+                    break;
+
+                default:
+                    pa_assert_not_reached();
+            }
+
+            func(s->memblockq);
+            s->underrun = 0;
+            request_bytes(s);
+
+            /* Do the same for all other members in the sync group */
+            for (isync = i->sync_prev; isync; isync = isync->sync_prev) {
+                playback_stream *ssync = PLAYBACK_STREAM(isync->userdata);
+                func(ssync->memblockq);
+                ssync->underrun = 0;
+                request_bytes(ssync);
+            }
+
+            for (isync = i->sync_next; isync; isync = isync->sync_next) {
+                playback_stream *ssync = PLAYBACK_STREAM(isync->userdata);
+                func(ssync->memblockq);
+                ssync->underrun = 0;
+                request_bytes(ssync);
+            }
+
+            return 0;
+        }
+
+        case SINK_INPUT_MESSAGE_UPDATE_LATENCY:
+
+            s->read_index = pa_memblockq_get_read_index(s->memblockq);
+            s->write_index = pa_memblockq_get_write_index(s->memblockq);
+            s->resampled_chunk_length = s->sink_input->thread_info.resampled_chunk.memblock ? s->sink_input->thread_info.resampled_chunk.length : 0;
+            return 0;
+
+        case PA_SINK_INPUT_MESSAGE_SET_STATE:
+
+            pa_memblockq_prebuf_force(s->memblockq);
+            request_bytes(s);
+            break;
+
+        case PA_SINK_INPUT_MESSAGE_GET_LATENCY: {
+            pa_usec_t *r = userdata;
+
+            *r = pa_bytes_to_usec(pa_memblockq_get_length(s->memblockq), &i->sample_spec);
+
+            /* Fall through, the default handler will add in the extra
+             * latency added by the resampler */
+            break;
+        }
+    }
+
+    return pa_sink_input_process_msg(o, code, userdata, offset, chunk);
+}
+
+/* Called from thread context */
+static int sink_input_peek_cb(pa_sink_input *i, size_t length, pa_memchunk *chunk) {
+    playback_stream *s;
+
+    pa_sink_input_assert_ref(i);
+    s = PLAYBACK_STREAM(i->userdata);
+    playback_stream_assert_ref(s);
+    pa_assert(chunk);
 
     if (pa_memblockq_get_length(s->memblockq) <= 0 && !s->underrun) {
-        pa_tagstruct *t;
-
-        /* Report that we're empty */
-
-        t = pa_tagstruct_new(NULL, 0);
-        pa_tagstruct_putu32(t, PA_COMMAND_UNDERFLOW);
-        pa_tagstruct_putu32(t, (uint32_t) -1); /* tag */
-        pa_tagstruct_putu32(t, s->index);
-        pa_pstream_send_tagstruct(s->connection->pstream, t);
-
+        pa_asyncmsgq_post(pa_thread_mq_get()->outq, PA_MSGOBJECT(s), PLAYBACK_STREAM_MESSAGE_UNDERFLOW, NULL, 0, NULL, NULL);
         s->underrun = 1;
     }
 
     if (pa_memblockq_peek(s->memblockq, chunk) < 0) {
-/*         pa_log("peek: failure");    */
+/*         pa_log("peek: failure");     */
         return -1;
     }
 
-/*     pa_log("peek: %u", chunk->length);    */
+/*     pa_log("peek: %u", chunk->length); */
+
+    request_bytes(s);
 
     return 0;
 }
 
-static void sink_input_drop_cb(pa_sink_input *i, const pa_memchunk *chunk, size_t length) {
-    struct playback_stream *s;
-    assert(i && i->userdata && length);
-    s = i->userdata;
-
-    pa_memblockq_drop(s->memblockq, chunk, length);
+/* Called from thread context */
+static void sink_input_drop_cb(pa_sink_input *i, size_t length) {
+    playback_stream *s;
+
+    pa_sink_input_assert_ref(i);
+    s = PLAYBACK_STREAM(i->userdata);
+    playback_stream_assert_ref(s);
+    pa_assert(length > 0);
+
+    pa_memblockq_drop(s->memblockq, length);
+
+    if (s->drain_request && !pa_memblockq_is_readable(s->memblockq)) {
+        s->drain_request = 0;
+        pa_asyncmsgq_post(pa_thread_mq_get()->outq, PA_MSGOBJECT(s), PLAYBACK_STREAM_MESSAGE_DRAIN_ACK, PA_UINT_TO_PTR(s->drain_tag), 0, NULL, NULL);
+    }
 
     request_bytes(s);
 
-    if (s->drain_request && !pa_memblockq_is_readable(s->memblockq)) {
-        pa_pstream_send_simple_ack(s->connection->pstream, s->drain_tag);
-        s->drain_request = 0;
-    }
-
-/*     pa_log("after_drop: %u %u", pa_memblockq_get_length(s->memblockq), pa_memblockq_is_readable(s->memblockq));   */
+/*     pa_log("after_drop: %u %u", pa_memblockq_get_length(s->memblockq), pa_memblockq_is_readable(s->memblockq)); */
 }
 
 static void sink_input_kill_cb(pa_sink_input *i) {
-    assert(i && i->userdata);
-    send_playback_stream_killed((struct playback_stream *) i->userdata);
-    playback_stream_free((struct playback_stream *) i->userdata);
-}
-
-static pa_usec_t sink_input_get_latency_cb(pa_sink_input *i) {
-    struct playback_stream *s;
-    assert(i && i->userdata);
-    s = i->userdata;
+    playback_stream *s;
+
+    pa_sink_input_assert_ref(i);
+    s = PLAYBACK_STREAM(i->userdata);
+    playback_stream_assert_ref(s);
+
+    send_playback_stream_killed(s);
+    playback_stream_unlink(s);
+}
+
+/*** source_output callbacks ***/
+
+/* Called from thread context */
+static void source_output_push_cb(pa_source_output *o, const pa_memchunk *chunk) {
+    record_stream *s;
+
+    pa_source_output_assert_ref(o);
+    s = RECORD_STREAM(o->userdata);
+    record_stream_assert_ref(s);
+    pa_assert(chunk);
+
+    pa_asyncmsgq_post(pa_thread_mq_get()->outq, PA_MSGOBJECT(s), RECORD_STREAM_MESSAGE_POST_DATA, NULL, 0, chunk, NULL);
+}
+
+static void source_output_kill_cb(pa_source_output *o) {
+    record_stream *s;
+
+    pa_source_output_assert_ref(o);
+    s = RECORD_STREAM(o->userdata);
+    record_stream_assert_ref(s);
+
+    send_record_stream_killed(s);
+    record_stream_unlink(s);
+}
+
+static pa_usec_t source_output_get_latency_cb(pa_source_output *o) {
+    record_stream *s;
+
+    pa_source_output_assert_ref(o);
+    s = RECORD_STREAM(o->userdata);
+    record_stream_assert_ref(s);
 
     /*pa_log("get_latency: %u", pa_memblockq_get_length(s->memblockq));*/
 
-    return pa_bytes_to_usec(pa_memblockq_get_length(s->memblockq), &s->sink_input->sample_spec);
-}
-
-/*** source_output callbacks ***/
-
-static void source_output_push_cb(pa_source_output *o, const pa_memchunk *chunk) {
-    struct record_stream *s;
-    assert(o && o->userdata && chunk);
-    s = o->userdata;
-
-    if (pa_memblockq_push_align(s->memblockq, chunk) < 0) {
-        pa_log_warn("Failed to push data into output queue.");
-        return;
-    }
-
-    if (!pa_pstream_is_pending(s->connection->pstream))
-        send_memblock(s->connection);
-}
-
-static void source_output_kill_cb(pa_source_output *o) {
-    assert(o && o->userdata);
-    send_record_stream_killed((struct record_stream *) o->userdata);
-    record_stream_free((struct record_stream *) o->userdata);
-}
-
-static pa_usec_t source_output_get_latency_cb(pa_source_output *o) {
-    struct record_stream *s;
-    assert(o && o->userdata);
-    s = o->userdata;
-
-    /*pa_log("get_latency: %u", pa_memblockq_get_length(s->memblockq));*/
-
     return pa_bytes_to_usec(pa_memblockq_get_length(s->memblockq), &o->sample_spec);
 }
 
 /*** pdispatch callbacks ***/
 
-static void protocol_error(struct connection *c) {
+static void protocol_error(connection *c) {
     pa_log("protocol error, kicking client");
-    connection_free(c);
+    connection_unlink(c);
 }
 
 #define CHECK_VALIDITY(pstream, expression, tag, error) do { \
@@ -721,9 +1094,9 @@
 }
 
 static void command_create_playback_stream(PA_GCC_UNUSED pa_pdispatch *pd, PA_GCC_UNUSED uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
-    struct connection *c = userdata;
-    struct playback_stream *s;
-    uint32_t maxlength, tlength, prebuf, minreq, sink_index, syncid;
+    connection *c = CONNECTION(userdata);
+    playback_stream *s;
+    uint32_t maxlength, tlength, prebuf, minreq, sink_index, syncid, missing;
     const char *name, *sink_name;
     pa_sample_spec ss;
     pa_channel_map map;
@@ -732,7 +1105,8 @@
     pa_cvolume volume;
     int corked;
 
-    assert(c && t && c->protocol && c->protocol->core);
+    connection_assert_ref(c);
+    pa_assert(t);
 
     if (pa_tagstruct_get(
             t,
@@ -773,34 +1147,35 @@
         CHECK_VALIDITY(c->pstream, sink, tag, PA_ERR_NOENTITY);
     }
 
-    s = playback_stream_new(c, sink, &ss, &map, name, maxlength, tlength, prebuf, minreq, &volume, syncid);
+    s = playback_stream_new(c, sink, &ss, &map, name, &maxlength, &tlength, &prebuf, &minreq, &volume, syncid, corked, &missing);
     CHECK_VALIDITY(c->pstream, s, tag, PA_ERR_INVALID);
-
-    pa_sink_input_cork(s->sink_input, corked);
 
     reply = reply_new(tag);
     pa_tagstruct_putu32(reply, s->index);
-    assert(s->sink_input);
+    pa_assert(s->sink_input);
     pa_tagstruct_putu32(reply, s->sink_input->index);
-    pa_tagstruct_putu32(reply, s->requested_bytes = pa_memblockq_missing(s->memblockq));
+    pa_tagstruct_putu32(reply, missing);
+
+/*     pa_log("initial request is %u", missing); */
 
     if (c->version >= 9) {
         /* Since 0.9 we support sending the buffer metrics back to the client */
 
-        pa_tagstruct_putu32(reply, (uint32_t) pa_memblockq_get_maxlength(s->memblockq));
-        pa_tagstruct_putu32(reply, (uint32_t) pa_memblockq_get_tlength(s->memblockq));
-        pa_tagstruct_putu32(reply, (uint32_t) pa_memblockq_get_prebuf(s->memblockq));
-        pa_tagstruct_putu32(reply, (uint32_t) pa_memblockq_get_minreq(s->memblockq));
+        pa_tagstruct_putu32(reply, (uint32_t) maxlength);
+        pa_tagstruct_putu32(reply, (uint32_t) tlength);
+        pa_tagstruct_putu32(reply, (uint32_t) prebuf);
+        pa_tagstruct_putu32(reply, (uint32_t) minreq);
     }
 
     pa_pstream_send_tagstruct(c->pstream, reply);
-    request_bytes(s);
 }
 
 static void command_delete_stream(PA_GCC_UNUSED pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
-    struct connection *c = userdata;
+    connection *c = CONNECTION(userdata);
     uint32_t channel;
-    assert(c && t);
+
+    connection_assert_ref(c);
+    pa_assert(t);
 
     if (pa_tagstruct_getu32(t, &channel) < 0 ||
         !pa_tagstruct_eof(t)) {
@@ -810,39 +1185,52 @@
 
     CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
 
-    if (command == PA_COMMAND_DELETE_PLAYBACK_STREAM) {
-        struct playback_stream *s;
-        if (!(s = pa_idxset_get_by_index(c->output_streams, channel)) || (s->type != PLAYBACK_STREAM)) {
-            pa_pstream_send_error(c->pstream, tag, PA_ERR_EXIST);
-            return;
+    switch (command) {
+
+        case PA_COMMAND_DELETE_PLAYBACK_STREAM: {
+            playback_stream *s;
+            if (!(s = pa_idxset_get_by_index(c->output_streams, channel)) || !playback_stream_isinstance(s)) {
+                pa_pstream_send_error(c->pstream, tag, PA_ERR_EXIST);
+                return;
+            }
+
+            playback_stream_unlink(s);
+            break;
         }
 
-        playback_stream_free(s);
-    } else if (command == PA_COMMAND_DELETE_RECORD_STREAM) {
-        struct record_stream *s;
-        if (!(s = pa_idxset_get_by_index(c->record_streams, channel))) {
-            pa_pstream_send_error(c->pstream, tag, PA_ERR_EXIST);
-            return;
+        case PA_COMMAND_DELETE_RECORD_STREAM: {
+            record_stream *s;
+            if (!(s = pa_idxset_get_by_index(c->record_streams, channel))) {
+                pa_pstream_send_error(c->pstream, tag, PA_ERR_EXIST);
+                return;
+            }
+
+            record_stream_unlink(s);
+            break;
         }
 
-        record_stream_free(s);
-    } else {
-        struct upload_stream *s;
-        assert(command == PA_COMMAND_DELETE_UPLOAD_STREAM);
-        if (!(s = pa_idxset_get_by_index(c->output_streams, channel)) || (s->type != UPLOAD_STREAM)) {
-            pa_pstream_send_error(c->pstream, tag, PA_ERR_EXIST);
-            return;
+        case PA_COMMAND_DELETE_UPLOAD_STREAM: {
+            upload_stream *s;
+
+            if (!(s = pa_idxset_get_by_index(c->output_streams, channel)) || !upload_stream_isinstance(s)) {
+                pa_pstream_send_error(c->pstream, tag, PA_ERR_EXIST);
+                return;
+            }
+
+            upload_stream_unlink(s);
+            break;
         }
 
-        upload_stream_free(s);
+        default:
+            pa_assert_not_reached();
     }
 
     pa_pstream_send_simple_ack(c->pstream, tag);
 }
 
 static void command_create_record_stream(PA_GCC_UNUSED pa_pdispatch *pd, PA_GCC_UNUSED uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
-    struct connection *c = userdata;
-    struct record_stream *s;
+    connection *c = CONNECTION(userdata);
+    record_stream *s;
     uint32_t maxlength, fragment_size;
     uint32_t source_index;
     const char *name, *source_name;
@@ -851,7 +1239,9 @@
     pa_tagstruct *reply;
     pa_source *source = NULL;
     int corked;
-    assert(c && t && c->protocol && c->protocol->core);
+
+    connection_assert_ref(c);
+    pa_assert(t);
 
     if (pa_tagstruct_gets(t, &name) < 0 ||
         pa_tagstruct_get_sample_spec(t, &ss) < 0 ||
@@ -882,20 +1272,18 @@
         CHECK_VALIDITY(c->pstream, source, tag, PA_ERR_NOENTITY);
     }
 
-    s = record_stream_new(c, source, &ss, &map, name, maxlength, fragment_size);
+    s = record_stream_new(c, source, &ss, &map, name, &maxlength, fragment_size, corked);
     CHECK_VALIDITY(c->pstream, s, tag, PA_ERR_INVALID);
-
-    pa_source_output_cork(s->source_output, corked);
 
     reply = reply_new(tag);
     pa_tagstruct_putu32(reply, s->index);
-    assert(s->source_output);
+    pa_assert(s->source_output);
     pa_tagstruct_putu32(reply, s->source_output->index);
 
     if (c->version >= 9) {
         /* Since 0.9 we support sending the buffer metrics back to the client */
 
-        pa_tagstruct_putu32(reply, (uint32_t) pa_memblockq_get_maxlength(s->memblockq));
+        pa_tagstruct_putu32(reply, (uint32_t) maxlength);
         pa_tagstruct_putu32(reply, (uint32_t) s->fragment_size);
     }
 
@@ -903,8 +1291,10 @@
 }
 
 static void command_exit(PA_GCC_UNUSED pa_pdispatch *pd, PA_GCC_UNUSED uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
-    struct connection *c = userdata;
-    assert(c && t);
+    connection *c = CONNECTION(userdata);
+
+    connection_assert_ref(c);
+    pa_assert(t);
 
     if (!pa_tagstruct_eof(t)) {
         protocol_error(c);
@@ -913,16 +1303,17 @@
 
     CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
 
-    assert(c->protocol && c->protocol->core && c->protocol->core->mainloop);
     c->protocol->core->mainloop->quit(c->protocol->core->mainloop, 0);
     pa_pstream_send_simple_ack(c->pstream, tag); /* nonsense */
 }
 
 static void command_auth(PA_GCC_UNUSED pa_pdispatch *pd, PA_GCC_UNUSED uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
-    struct connection *c = userdata;
+    connection *c = CONNECTION(userdata);
     const void*cookie;
     pa_tagstruct *reply;
-    assert(c && t);
+
+    connection_assert_ref(c);
+    pa_assert(t);
 
     if (pa_tagstruct_getu32(t, &c->version) < 0 ||
         pa_tagstruct_get_arbitrary(t, &cookie, PA_NATIVE_COOKIE_LENGTH) < 0 ||
@@ -1015,9 +1406,11 @@
 }
 
 static void command_set_client_name(PA_GCC_UNUSED pa_pdispatch *pd, PA_GCC_UNUSED uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
-    struct connection *c = userdata;
+    connection *c = CONNECTION(userdata);
     const char *name;
-    assert(c && t);
+
+    connection_assert_ref(c);
+    pa_assert(t);
 
     if (pa_tagstruct_gets(t, &name) < 0 ||
         !pa_tagstruct_eof(t)) {
@@ -1032,10 +1425,12 @@
 }
 
 static void command_lookup(PA_GCC_UNUSED pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
-    struct connection *c = userdata;
+    connection *c = CONNECTION(userdata);
     const char *name;
     uint32_t idx = PA_IDXSET_INVALID;
-    assert(c && t);
+
+    connection_assert_ref(c);
+    pa_assert(t);
 
     if (pa_tagstruct_gets(t, &name) < 0 ||
         !pa_tagstruct_eof(t)) {
@@ -1052,7 +1447,7 @@
             idx = sink->index;
     } else {
         pa_source *source;
-        assert(command == PA_COMMAND_LOOKUP_SOURCE);
+        pa_assert(command == PA_COMMAND_LOOKUP_SOURCE);
         if ((source = pa_namereg_get(c->protocol->core, name, PA_NAMEREG_SOURCE, 1)))
             idx = source->index;
     }
@@ -1068,10 +1463,12 @@
 }
 
 static void command_drain_playback_stream(PA_GCC_UNUSED pa_pdispatch *pd, PA_GCC_UNUSED uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
-    struct connection *c = userdata;
+    connection *c = CONNECTION(userdata);
     uint32_t idx;
-    struct playback_stream *s;
-    assert(c && t);
+    playback_stream *s;
+
+    connection_assert_ref(c);
+    pa_assert(t);
 
     if (pa_tagstruct_getu32(t, &idx) < 0 ||
         !pa_tagstruct_eof(t)) {
@@ -1082,29 +1479,18 @@
     CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
     s = pa_idxset_get_by_index(c->output_streams, idx);
     CHECK_VALIDITY(c->pstream, s, tag, PA_ERR_NOENTITY);
-    CHECK_VALIDITY(c->pstream, s->type == PLAYBACK_STREAM, tag, PA_ERR_NOENTITY);
-
-    s->drain_request = 0;
-
-    pa_memblockq_prebuf_disable(s->memblockq);
-
-    if (!pa_memblockq_is_readable(s->memblockq)) {
-/*         pa_log("immediate drain: %u", pa_memblockq_get_length(s->memblockq));  */
-        pa_pstream_send_simple_ack(c->pstream, tag);
-    } else {
-/*         pa_log("slow drain triggered");  */
-        s->drain_request = 1;
-        s->drain_tag = tag;
-
-        pa_sink_notify(s->sink_input->sink);
-    }
+    CHECK_VALIDITY(c->pstream, playback_stream_isinstance(s), tag, PA_ERR_NOENTITY);
+
+    pa_asyncmsgq_post(s->sink_input->sink->asyncmsgq, PA_MSGOBJECT(s->sink_input), SINK_INPUT_MESSAGE_DRAIN, PA_UINT_TO_PTR(tag), 0, NULL, NULL);
 }
 
 static void command_stat(PA_GCC_UNUSED pa_pdispatch *pd, PA_GCC_UNUSED uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
-    struct connection *c = userdata;
+    connection *c = CONNECTION(userdata);
     pa_tagstruct *reply;
     const pa_mempool_stat *stat;
-    assert(c && t);
+
+    connection_assert_ref(c);
+    pa_assert(t);
 
     if (!pa_tagstruct_eof(t)) {
         protocol_error(c);
@@ -1125,13 +1511,15 @@
 }
 
 static void command_get_playback_latency(PA_GCC_UNUSED pa_pdispatch *pd, PA_GCC_UNUSED uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
-    struct connection *c = userdata;
+    connection *c = CONNECTION(userdata);
     pa_tagstruct *reply;
-    struct playback_stream *s;
+    playback_stream *s;
     struct timeval tv, now;
     uint32_t idx;
     pa_usec_t latency;
-    assert(c && t);
+
+    connection_assert_ref(c);
+    pa_assert(t);
 
     if (pa_tagstruct_getu32(t, &idx) < 0 ||
         pa_tagstruct_get_timeval(t, &tv) < 0 ||
@@ -1143,31 +1531,34 @@
     CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
     s = pa_idxset_get_by_index(c->output_streams, idx);
     CHECK_VALIDITY(c->pstream, s, tag, PA_ERR_NOENTITY);
-    CHECK_VALIDITY(c->pstream, s->type == PLAYBACK_STREAM, tag, PA_ERR_NOENTITY);
+    CHECK_VALIDITY(c->pstream, playback_stream_isinstance(s), tag, PA_ERR_NOENTITY);
+    CHECK_VALIDITY(c->pstream, pa_asyncmsgq_send(s->sink_input->sink->asyncmsgq, PA_MSGOBJECT(s->sink_input), SINK_INPUT_MESSAGE_UPDATE_LATENCY, s, 0, NULL) == 0, tag, PA_ERR_NOENTITY)
 
     reply = reply_new(tag);
 
     latency = pa_sink_get_latency(s->sink_input->sink);
-    if (s->sink_input->resampled_chunk.memblock)
-        latency += pa_bytes_to_usec(s->sink_input->resampled_chunk.length, &s->sink_input->sample_spec);
+    latency += pa_bytes_to_usec(s->resampled_chunk_length, &s->sink_input->sample_spec);
+
     pa_tagstruct_put_usec(reply, latency);
 
     pa_tagstruct_put_usec(reply, 0);
-    pa_tagstruct_put_boolean(reply, s->sink_input->state == PA_SINK_INPUT_RUNNING);
+    pa_tagstruct_put_boolean(reply, pa_sink_input_get_state(s->sink_input) == PA_SINK_INPUT_RUNNING);
     pa_tagstruct_put_timeval(reply, &tv);
     pa_tagstruct_put_timeval(reply, pa_gettimeofday(&now));
-    pa_tagstruct_puts64(reply, pa_memblockq_get_write_index(s->memblockq));
-    pa_tagstruct_puts64(reply, pa_memblockq_get_read_index(s->memblockq));
+    pa_tagstruct_puts64(reply, s->write_index);
+    pa_tagstruct_puts64(reply, s->read_index);
     pa_pstream_send_tagstruct(c->pstream, reply);
 }
 
 static void command_get_record_latency(PA_GCC_UNUSED pa_pdispatch *pd, PA_GCC_UNUSED uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
-    struct connection *c = userdata;
+    connection *c = CONNECTION(userdata);
     pa_tagstruct *reply;
-    struct record_stream *s;
+    record_stream *s;
     struct timeval tv, now;
     uint32_t idx;
-    assert(c && t);
+
+    connection_assert_ref(c);
+    pa_assert(t);
 
     if (pa_tagstruct_getu32(t, &idx) < 0 ||
         pa_tagstruct_get_timeval(t, &tv) < 0 ||
@@ -1192,14 +1583,16 @@
 }
 
 static void command_create_upload_stream(PA_GCC_UNUSED pa_pdispatch *pd, PA_GCC_UNUSED uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
-    struct connection *c = userdata;
-    struct upload_stream *s;
+    connection *c = CONNECTION(userdata);
+    upload_stream *s;
     uint32_t length;
     const char *name;
     pa_sample_spec ss;
     pa_channel_map map;
     pa_tagstruct *reply;
-    assert(c && t && c->protocol && c->protocol->core);
+
+    connection_assert_ref(c);
+    pa_assert(t);
 
     if (pa_tagstruct_gets(t, &name) < 0 ||
         pa_tagstruct_get_sample_spec(t, &ss) < 0 ||
@@ -1228,11 +1621,13 @@
 }
 
 static void command_finish_upload_stream(PA_GCC_UNUSED pa_pdispatch *pd, PA_GCC_UNUSED uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
-    struct connection *c = userdata;
+    connection *c = CONNECTION(userdata);
     uint32_t channel;
-    struct upload_stream *s;
+    upload_stream *s;
     uint32_t idx;
-    assert(c && t);
+
+    connection_assert_ref(c);
+    pa_assert(t);
 
     if (pa_tagstruct_getu32(t, &channel) < 0 ||
         !pa_tagstruct_eof(t)) {
@@ -1244,23 +1639,25 @@
 
     s = pa_idxset_get_by_index(c->output_streams, channel);
     CHECK_VALIDITY(c->pstream, s, tag, PA_ERR_NOENTITY);
-    CHECK_VALIDITY(c->pstream, s->type == UPLOAD_STREAM, tag, PA_ERR_NOENTITY);
+    CHECK_VALIDITY(c->pstream, upload_stream_isinstance(s), tag, PA_ERR_NOENTITY);
 
     if (pa_scache_add_item(c->protocol->core, s->name, &s->sample_spec, &s->channel_map, &s->memchunk, &idx) < 0)
         pa_pstream_send_error(c->pstream, tag, PA_ERR_INTERNAL);
     else
         pa_pstream_send_simple_ack(c->pstream, tag);
 
-    upload_stream_free(s);
+    upload_stream_unlink(s);
 }
 
 static void command_play_sample(PA_GCC_UNUSED pa_pdispatch *pd, PA_GCC_UNUSED uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
-    struct connection *c = userdata;
+    connection *c = CONNECTION(userdata);
     uint32_t sink_index;
     pa_volume_t volume;
     pa_sink *sink;
     const char *name, *sink_name;
-    assert(c && t);
+
+    connection_assert_ref(c);
+    pa_assert(t);
 
     if (pa_tagstruct_getu32(t, &sink_index) < 0 ||
         pa_tagstruct_gets(t, &sink_name) < 0 ||
@@ -1291,9 +1688,11 @@
 }
 
 static void command_remove_sample(PA_GCC_UNUSED pa_pdispatch *pd, PA_GCC_UNUSED uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
-    struct connection *c = userdata;
+    connection *c = CONNECTION(userdata);
     const char *name;
-    assert(c && t);
+
+    connection_assert_ref(c);
+    pa_assert(t);
 
     if (pa_tagstruct_gets(t, &name) < 0 ||
         !pa_tagstruct_eof(t)) {
@@ -1313,7 +1712,9 @@
 }
 
 static void sink_fill_tagstruct(pa_tagstruct *t, pa_sink *sink) {
-    assert(t && sink);
+    pa_assert(t);
+    pa_sink_assert_ref(sink);
+
     pa_tagstruct_put(
         t,
         PA_TAG_U32, sink->index,
@@ -1321,22 +1722,21 @@
         PA_TAG_STRING, sink->description,
         PA_TAG_SAMPLE_SPEC, &sink->sample_spec,
         PA_TAG_CHANNEL_MAP, &sink->channel_map,
-        PA_TAG_U32, sink->owner ? sink->owner->index : PA_INVALID_INDEX,
-        PA_TAG_CVOLUME, pa_sink_get_volume(sink, PA_MIXER_HARDWARE),
-        PA_TAG_BOOLEAN, pa_sink_get_mute(sink, PA_MIXER_HARDWARE),
+        PA_TAG_U32, sink->module ? sink->module->index : PA_INVALID_INDEX,
+        PA_TAG_CVOLUME, pa_sink_get_volume(sink),
+        PA_TAG_BOOLEAN, pa_sink_get_mute(sink),
         PA_TAG_U32, sink->monitor_source ? sink->monitor_source->index : PA_INVALID_INDEX,
         PA_TAG_STRING, sink->monitor_source ? sink->monitor_source->name : NULL,
         PA_TAG_USEC, pa_sink_get_latency(sink),
         PA_TAG_STRING, sink->driver,
-        PA_TAG_U32,
-        (sink->get_hw_volume ? PA_SINK_HW_VOLUME_CTRL : 0) |
-        (sink->get_latency ? PA_SINK_LATENCY : 0) |
-        (sink->is_hardware ? PA_SINK_HARDWARE : 0),
+        PA_TAG_U32, sink->flags,
         PA_TAG_INVALID);
 }
 
 static void source_fill_tagstruct(pa_tagstruct *t, pa_source *source) {
-    assert(t && source);
+    pa_assert(t);
+    pa_source_assert_ref(source);
+
     pa_tagstruct_put(
         t,
         PA_TAG_U32, source->index,
@@ -1344,22 +1744,21 @@
         PA_TAG_STRING, source->description,
         PA_TAG_SAMPLE_SPEC, &source->sample_spec,
         PA_TAG_CHANNEL_MAP, &source->channel_map,
-        PA_TAG_U32, source->owner ? source->owner->index : PA_INVALID_INDEX,
-        PA_TAG_CVOLUME, pa_source_get_volume(source, PA_MIXER_HARDWARE),
-        PA_TAG_BOOLEAN, pa_source_get_mute(source, PA_MIXER_HARDWARE),
+        PA_TAG_U32, source->module ? source->module->index : PA_INVALID_INDEX,
+        PA_TAG_CVOLUME, pa_source_get_volume(source),
+        PA_TAG_BOOLEAN, pa_source_get_mute(source),
         PA_TAG_U32, source->monitor_of ? source->monitor_of->index : PA_INVALID_INDEX,
         PA_TAG_STRING, source->monitor_of ? source->monitor_of->name : NULL,
         PA_TAG_USEC, pa_source_get_latency(source),
         PA_TAG_STRING, source->driver,
-        PA_TAG_U32,
-        (source->get_hw_volume ? PA_SOURCE_HW_VOLUME_CTRL : 0) |
-        (source->get_latency ? PA_SOURCE_LATENCY : 0) |
-        (source->is_hardware ? PA_SOURCE_HARDWARE : 0),
+        PA_TAG_U32, source->flags,
         PA_TAG_INVALID);
 }
 
 static void client_fill_tagstruct(pa_tagstruct *t, pa_client *client) {
-    assert(t && client);
+    pa_assert(t);
+    pa_assert(client);
+
     pa_tagstruct_putu32(t, client->index);
     pa_tagstruct_puts(t, client->name);
     pa_tagstruct_putu32(t, client->owner ? client->owner->index : PA_INVALID_INDEX);
@@ -1367,7 +1766,9 @@
 }
 
 static void module_fill_tagstruct(pa_tagstruct *t, pa_module *module) {
-    assert(t && module);
+    pa_assert(t);
+    pa_assert(module);
+
     pa_tagstruct_putu32(t, module->index);
     pa_tagstruct_puts(t, module->name);
     pa_tagstruct_puts(t, module->argument);
@@ -1375,8 +1776,10 @@
     pa_tagstruct_put_boolean(t, module->auto_unload);
 }
 
-static void sink_input_fill_tagstruct(pa_tagstruct *t, pa_sink_input *s) {
-    assert(t && s);
+static void sink_input_fill_tagstruct(connection *c, pa_tagstruct *t, pa_sink_input *s) {
+    pa_assert(t);
+    pa_sink_input_assert_ref(s);
+
     pa_tagstruct_putu32(t, s->index);
     pa_tagstruct_puts(t, s->name);
     pa_tagstruct_putu32(t, s->module ? s->module->index : PA_INVALID_INDEX);
@@ -1389,10 +1792,14 @@
     pa_tagstruct_put_usec(t, pa_sink_get_latency(s->sink));
     pa_tagstruct_puts(t, pa_resample_method_to_string(pa_sink_input_get_resample_method(s)));
     pa_tagstruct_puts(t, s->driver);
+    if (c->version >= 11)
+        pa_tagstruct_put_boolean(t, pa_sink_input_get_mute(s));
 }
 
 static void source_output_fill_tagstruct(pa_tagstruct *t, pa_source_output *s) {
-    assert(t && s);
+    pa_assert(t);
+    pa_source_output_assert_ref(s);
+
     pa_tagstruct_putu32(t, s->index);
     pa_tagstruct_puts(t, s->name);
     pa_tagstruct_putu32(t, s->module ? s->module->index : PA_INVALID_INDEX);
@@ -1407,7 +1814,9 @@
 }
 
 static void scache_fill_tagstruct(pa_tagstruct *t, pa_scache_entry *e) {
-    assert(t && e);
+    pa_assert(t);
+    pa_assert(e);
+
     pa_tagstruct_putu32(t, e->index);
     pa_tagstruct_puts(t, e->name);
     pa_tagstruct_put_cvolume(t, &e->volume);
@@ -1420,7 +1829,7 @@
 }
 
 static void command_get_info(PA_GCC_UNUSED pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
-    struct connection *c = userdata;
+    connection *c = CONNECTION(userdata);
     uint32_t idx;
     pa_sink *sink = NULL;
     pa_source *source = NULL;
@@ -1431,7 +1840,9 @@
     pa_scache_entry *sce = NULL;
     const char *name;
     pa_tagstruct *reply;
-    assert(c && t);
+
+    connection_assert_ref(c);
+    pa_assert(t);
 
     if (pa_tagstruct_getu32(t, &idx) < 0 ||
         (command != PA_COMMAND_GET_CLIENT_INFO &&
@@ -1466,7 +1877,7 @@
     else if (command == PA_COMMAND_GET_SOURCE_OUTPUT_INFO)
         so = pa_idxset_get_by_index(c->protocol->core->source_outputs, idx);
     else {
-        assert(command == PA_COMMAND_GET_SAMPLE_INFO);
+        pa_assert(command == PA_COMMAND_GET_SAMPLE_INFO);
         if (idx != PA_INVALID_INDEX)
             sce = pa_idxset_get_by_index(c->protocol->core->scache, idx);
         else
@@ -1488,7 +1899,7 @@
     else if (module)
         module_fill_tagstruct(reply, module);
     else if (si)
-        sink_input_fill_tagstruct(reply, si);
+        sink_input_fill_tagstruct(c, reply, si);
     else if (so)
         source_output_fill_tagstruct(reply, so);
     else
@@ -1497,12 +1908,14 @@
 }
 
 static void command_get_info_list(PA_GCC_UNUSED pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
-    struct connection *c = userdata;
+    connection *c = CONNECTION(userdata);
     pa_idxset *i;
     uint32_t idx;
     void *p;
     pa_tagstruct *reply;
-    assert(c && t);
+
+    connection_assert_ref(c);
+    pa_assert(t);
 
     if (!pa_tagstruct_eof(t)) {
         protocol_error(c);
@@ -1526,7 +1939,7 @@
     else if (command == PA_COMMAND_GET_SOURCE_OUTPUT_INFO_LIST)
         i = c->protocol->core->source_outputs;
     else {
-        assert(command == PA_COMMAND_GET_SAMPLE_INFO_LIST);
+        pa_assert(command == PA_COMMAND_GET_SAMPLE_INFO_LIST);
         i = c->protocol->core->scache;
     }
 
@@ -1541,11 +1954,11 @@
             else if (command == PA_COMMAND_GET_MODULE_INFO_LIST)
                 module_fill_tagstruct(reply, p);
             else if (command == PA_COMMAND_GET_SINK_INPUT_INFO_LIST)
-                sink_input_fill_tagstruct(reply, p);
+                sink_input_fill_tagstruct(c, reply, p);
             else if (command == PA_COMMAND_GET_SOURCE_OUTPUT_INFO_LIST)
                 source_output_fill_tagstruct(reply, p);
             else {
-                assert(command == PA_COMMAND_GET_SAMPLE_INFO_LIST);
+                pa_assert(command == PA_COMMAND_GET_SAMPLE_INFO_LIST);
                 scache_fill_tagstruct(reply, p);
             }
         }
@@ -1555,11 +1968,13 @@
 }
 
 static void command_get_server_info(PA_GCC_UNUSED pa_pdispatch *pd, PA_GCC_UNUSED uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
-    struct connection *c = userdata;
+    connection *c = CONNECTION(userdata);
     pa_tagstruct *reply;
     char txt[256];
     const char *n;
-    assert(c && t);
+
+    connection_assert_ref(c);
+    pa_assert(t);
 
     if (!pa_tagstruct_eof(t)) {
         protocol_error(c);
@@ -1587,8 +2002,9 @@
 
 static void subscription_cb(pa_core *core, pa_subscription_event_type_t e, uint32_t idx, void *userdata) {
     pa_tagstruct *t;
-    struct connection *c = userdata;
-    assert(c && core);
+    connection *c = CONNECTION(userdata);
+
+    connection_assert_ref(c);
 
     t = pa_tagstruct_new(NULL, 0);
     pa_tagstruct_putu32(t, PA_COMMAND_SUBSCRIBE_EVENT);
@@ -1599,9 +2015,11 @@
 }
 
 static void command_subscribe(PA_GCC_UNUSED pa_pdispatch *pd, PA_GCC_UNUSED uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
-    struct connection *c = userdata;
+    connection *c = CONNECTION(userdata);
     pa_subscription_mask_t m;
-    assert(c && t);
+
+    connection_assert_ref(c);
+    pa_assert(t);
 
     if (pa_tagstruct_getu32(t, &m) < 0 ||
         !pa_tagstruct_eof(t)) {
@@ -1617,7 +2035,7 @@
 
     if (m != 0) {
         c->subscription = pa_subscription_new(c->protocol->core, m, subscription_cb, c);
-        assert(c->subscription);
+        pa_assert(c->subscription);
     } else
         c->subscription = NULL;
 
@@ -1631,14 +2049,16 @@
         pa_tagstruct *t,
         void *userdata) {
 
-    struct connection *c = userdata;
+    connection *c = CONNECTION(userdata);
     uint32_t idx;
     pa_cvolume volume;
     pa_sink *sink = NULL;
     pa_source *source = NULL;
     pa_sink_input *si = NULL;
     const char *name = NULL;
-    assert(c && t);
+
+    connection_assert_ref(c);
+    pa_assert(t);
 
     if (pa_tagstruct_getu32(t, &idx) < 0 ||
         (command == PA_COMMAND_SET_SINK_VOLUME && pa_tagstruct_gets(t, &name) < 0) ||
@@ -1653,27 +2073,36 @@
     CHECK_VALIDITY(c->pstream, idx != PA_INVALID_INDEX || !name || (*name && pa_utf8_valid(name)), tag, PA_ERR_INVALID);
     CHECK_VALIDITY(c->pstream, pa_cvolume_valid(&volume), tag, PA_ERR_INVALID);
 
-    if (command == PA_COMMAND_SET_SINK_VOLUME) {
-        if (idx != PA_INVALID_INDEX)
-            sink = pa_idxset_get_by_index(c->protocol->core->sinks, idx);
-        else
-            sink = pa_namereg_get(c->protocol->core, name, PA_NAMEREG_SINK, 1);
-    } else if (command == PA_COMMAND_SET_SOURCE_VOLUME) {
-        if (idx != (uint32_t) -1)
-            source = pa_idxset_get_by_index(c->protocol->core->sources, idx);
-        else
-            source = pa_namereg_get(c->protocol->core, name, PA_NAMEREG_SOURCE, 1);
-    }  else {
-        assert(command == PA_COMMAND_SET_SINK_INPUT_VOLUME);
-        si = pa_idxset_get_by_index(c->protocol->core->sink_inputs, idx);
+    switch (command) {
+
+        case PA_COMMAND_SET_SINK_VOLUME:
+            if (idx != PA_INVALID_INDEX)
+                sink = pa_idxset_get_by_index(c->protocol->core->sinks, idx);
+            else
+                sink = pa_namereg_get(c->protocol->core, name, PA_NAMEREG_SINK, 1);
+            break;
+
+        case PA_COMMAND_SET_SOURCE_VOLUME:
+            if (idx != PA_INVALID_INDEX)
+                source = pa_idxset_get_by_index(c->protocol->core->sources, idx);
+            else
+                source = pa_namereg_get(c->protocol->core, name, PA_NAMEREG_SOURCE, 1);
+            break;
+
+        case PA_COMMAND_SET_SINK_INPUT_VOLUME:
+            si = pa_idxset_get_by_index(c->protocol->core->sink_inputs, idx);
+            break;
+
+        default:
+            pa_assert_not_reached();
     }
 
     CHECK_VALIDITY(c->pstream, si || sink || source, tag, PA_ERR_NOENTITY);
 
     if (sink)
-        pa_sink_set_volume(sink, PA_MIXER_HARDWARE, &volume);
+        pa_sink_set_volume(sink, &volume);
     else if (source)
-        pa_source_set_volume(source, PA_MIXER_HARDWARE, &volume);
+        pa_source_set_volume(source, &volume);
     else if (si)
         pa_sink_input_set_volume(si, &volume);
 
@@ -1687,16 +2116,20 @@
         pa_tagstruct *t,
         void *userdata) {
 
-    struct connection *c = userdata;
+    connection *c = CONNECTION(userdata);
     uint32_t idx;
     int mute;
     pa_sink *sink = NULL;
     pa_source *source = NULL;
+    pa_sink_input *si = NULL;
     const char *name = NULL;
-    assert(c && t);
+
+    connection_assert_ref(c);
+    pa_assert(t);
 
     if (pa_tagstruct_getu32(t, &idx) < 0 ||
-        pa_tagstruct_gets(t, &name) < 0 ||
+        (command == PA_COMMAND_SET_SINK_MUTE && pa_tagstruct_gets(t, &name) < 0) ||
+        (command == PA_COMMAND_SET_SOURCE_MUTE && pa_tagstruct_gets(t, &name) < 0) ||
         pa_tagstruct_get_boolean(t, &mute) ||
         !pa_tagstruct_eof(t)) {
         protocol_error(c);
@@ -1706,35 +2139,53 @@
     CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
     CHECK_VALIDITY(c->pstream, idx != PA_INVALID_INDEX || !name || (*name && pa_utf8_valid(name)), tag, PA_ERR_INVALID);
 
-    if (command == PA_COMMAND_SET_SINK_MUTE) {
-        if (idx != PA_INVALID_INDEX)
-            sink = pa_idxset_get_by_index(c->protocol->core->sinks, idx);
-        else
-            sink = pa_namereg_get(c->protocol->core, name, PA_NAMEREG_SINK, 1);
-    } else {
-        assert(command == PA_COMMAND_SET_SOURCE_MUTE);
-        if (idx != (uint32_t) -1)
-            source = pa_idxset_get_by_index(c->protocol->core->sources, idx);
-        else
-            source = pa_namereg_get(c->protocol->core, name, PA_NAMEREG_SOURCE, 1);
-    }
-
-    CHECK_VALIDITY(c->pstream, sink || source, tag, PA_ERR_NOENTITY);
+    switch (command) {
+
+        case PA_COMMAND_SET_SINK_MUTE:
+
+            if (idx != PA_INVALID_INDEX)
+                sink = pa_idxset_get_by_index(c->protocol->core->sinks, idx);
+            else
+                sink = pa_namereg_get(c->protocol->core, name, PA_NAMEREG_SINK, 1);
+
+            break;
+
+        case PA_COMMAND_SET_SOURCE_MUTE:
+            if (idx != PA_INVALID_INDEX)
+                source = pa_idxset_get_by_index(c->protocol->core->sources, idx);
+            else
+                source = pa_namereg_get(c->protocol->core, name, PA_NAMEREG_SOURCE, 1);
+
+            break;
+
+        case PA_COMMAND_SET_SINK_INPUT_MUTE:
+            si = pa_idxset_get_by_index(c->protocol->core->sink_inputs, idx);
+            break;
+
+        default:
+            pa_assert_not_reached();
+    }
+
+    CHECK_VALIDITY(c->pstream, si || sink || source, tag, PA_ERR_NOENTITY);
 
     if (sink)
-        pa_sink_set_mute(sink, PA_MIXER_HARDWARE, mute);
+        pa_sink_set_mute(sink, mute);
     else if (source)
-        pa_source_set_mute(source, PA_MIXER_HARDWARE, mute);
+        pa_source_set_mute(source, mute);
+    else if (si)
+        pa_sink_input_set_mute(si, mute);
 
     pa_pstream_send_simple_ack(c->pstream, tag);
 }
 
 static void command_cork_playback_stream(PA_GCC_UNUSED pa_pdispatch *pd, PA_GCC_UNUSED uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
-    struct connection *c = userdata;
+    connection *c = CONNECTION(userdata);
     uint32_t idx;
     int b;
-    struct playback_stream *s, *ssync;
-    assert(c && t);
+    playback_stream *s;
+
+    connection_assert_ref(c);
+    pa_assert(t);
 
     if (pa_tagstruct_getu32(t, &idx) < 0 ||
         pa_tagstruct_get_boolean(t, &b) < 0 ||
@@ -1747,30 +2198,19 @@
     CHECK_VALIDITY(c->pstream, idx != PA_INVALID_INDEX, tag, PA_ERR_INVALID);
     s = pa_idxset_get_by_index(c->output_streams, idx);
     CHECK_VALIDITY(c->pstream, s, tag, PA_ERR_NOENTITY);
-    CHECK_VALIDITY(c->pstream, s->type == PLAYBACK_STREAM, tag, PA_ERR_NOENTITY);
+    CHECK_VALIDITY(c->pstream, playback_stream_isinstance(s), tag, PA_ERR_NOENTITY);
 
     pa_sink_input_cork(s->sink_input, b);
-    pa_memblockq_prebuf_force(s->memblockq);
-
-    /* Do the same for all other members in the sync group */
-    for (ssync = s->prev; ssync; ssync = ssync->prev) {
-        pa_sink_input_cork(ssync->sink_input, b);
-        pa_memblockq_prebuf_force(ssync->memblockq);
-    }
-
-    for (ssync = s->next; ssync; ssync = ssync->next) {
-        pa_sink_input_cork(ssync->sink_input, b);
-        pa_memblockq_prebuf_force(ssync->memblockq);
-    }
-
     pa_pstream_send_simple_ack(c->pstream, tag);
 }
 
-static void command_flush_playback_stream(PA_GCC_UNUSED pa_pdispatch *pd, PA_GCC_UNUSED uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
-    struct connection *c = userdata;
+static void command_trigger_or_flush_or_prebuf_playback_stream(PA_GCC_UNUSED pa_pdispatch *pd, PA_GCC_UNUSED uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
+    connection *c = CONNECTION(userdata);
     uint32_t idx;
-    struct playback_stream *s, *ssync;
-    assert(c && t);
+    playback_stream *s;
+
+    connection_assert_ref(c);
+    pa_assert(t);
 
     if (pa_tagstruct_getu32(t, &idx) < 0 ||
         !pa_tagstruct_eof(t)) {
@@ -1782,75 +2222,36 @@
     CHECK_VALIDITY(c->pstream, idx != PA_INVALID_INDEX, tag, PA_ERR_INVALID);
     s = pa_idxset_get_by_index(c->output_streams, idx);
     CHECK_VALIDITY(c->pstream, s, tag, PA_ERR_NOENTITY);
-    CHECK_VALIDITY(c->pstream, s->type == PLAYBACK_STREAM, tag, PA_ERR_NOENTITY);
-
-    pa_memblockq_flush(s->memblockq);
-    s->underrun = 0;
-
-    /* Do the same for all other members in the sync group */
-    for (ssync = s->prev; ssync; ssync = ssync->prev) {
-        pa_memblockq_flush(ssync->memblockq);
-        ssync->underrun = 0;
-    }
-
-    for (ssync = s->next; ssync; ssync = ssync->next) {
-        pa_memblockq_flush(ssync->memblockq);
-        ssync->underrun = 0;
+    CHECK_VALIDITY(c->pstream, playback_stream_isinstance(s), tag, PA_ERR_NOENTITY);
+
+    switch (command) {
+        case PA_COMMAND_FLUSH_PLAYBACK_STREAM:
+            pa_asyncmsgq_send(s->sink_input->sink->asyncmsgq, PA_MSGOBJECT(s->sink_input), SINK_INPUT_MESSAGE_FLUSH, NULL, 0, NULL);
+            break;
+
+        case PA_COMMAND_PREBUF_PLAYBACK_STREAM:
+            pa_asyncmsgq_send(s->sink_input->sink->asyncmsgq, PA_MSGOBJECT(s->sink_input), SINK_INPUT_MESSAGE_PREBUF_FORCE, NULL, 0, NULL);
+            break;
+
+        case PA_COMMAND_TRIGGER_PLAYBACK_STREAM:
+            pa_asyncmsgq_send(s->sink_input->sink->asyncmsgq, PA_MSGOBJECT(s->sink_input), SINK_INPUT_MESSAGE_TRIGGER, NULL, 0, NULL);
+            break;
+
+        default:
+            pa_assert_not_reached();
     }
 
     pa_pstream_send_simple_ack(c->pstream, tag);
-    pa_sink_notify(s->sink_input->sink);
-    request_bytes(s);
-
-    for (ssync = s->prev; ssync; ssync = ssync->prev)
-        request_bytes(ssync);
-
-    for (ssync = s->next; ssync; ssync = ssync->next)
-        request_bytes(ssync);
-}
-
-static void command_trigger_or_prebuf_playback_stream(PA_GCC_UNUSED pa_pdispatch *pd, PA_GCC_UNUSED uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
-    struct connection *c = userdata;
+}
+
+static void command_cork_record_stream(PA_GCC_UNUSED pa_pdispatch *pd, PA_GCC_UNUSED uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
+    connection *c = CONNECTION(userdata);
     uint32_t idx;
-    struct playback_stream *s;
-    assert(c && t);
-
-    if (pa_tagstruct_getu32(t, &idx) < 0 ||
-        !pa_tagstruct_eof(t)) {
-        protocol_error(c);
-        return;
-    }
-
-    CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
-    CHECK_VALIDITY(c->pstream, idx != PA_INVALID_INDEX, tag, PA_ERR_INVALID);
-    s = pa_idxset_get_by_index(c->output_streams, idx);
-    CHECK_VALIDITY(c->pstream, s, tag, PA_ERR_NOENTITY);
-    CHECK_VALIDITY(c->pstream, s->type == PLAYBACK_STREAM, tag, PA_ERR_NOENTITY);
-
-    switch (command) {
-        case PA_COMMAND_PREBUF_PLAYBACK_STREAM:
-            pa_memblockq_prebuf_force(s->memblockq);
-            break;
-
-        case PA_COMMAND_TRIGGER_PLAYBACK_STREAM:
-            pa_memblockq_prebuf_disable(s->memblockq);
-            break;
-
-        default:
-            abort();
-    }
-
-    pa_sink_notify(s->sink_input->sink);
-    pa_pstream_send_simple_ack(c->pstream, tag);
-    request_bytes(s);
-}
-
-static void command_cork_record_stream(PA_GCC_UNUSED pa_pdispatch *pd, PA_GCC_UNUSED uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
-    struct connection *c = userdata;
-    uint32_t idx;
-    struct record_stream *s;
+    record_stream *s;
     int b;
-    assert(c && t);
+
+    connection_assert_ref(c);
+    pa_assert(t);
 
     if (pa_tagstruct_getu32(t, &idx) < 0 ||
         pa_tagstruct_get_boolean(t, &b) < 0 ||
@@ -1869,10 +2270,12 @@
 }
 
 static void command_flush_record_stream(PA_GCC_UNUSED pa_pdispatch *pd, PA_GCC_UNUSED uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
-    struct connection *c = userdata;
+    connection *c = CONNECTION(userdata);
     uint32_t idx;
-    struct record_stream *s;
-    assert(c && t);
+    record_stream *s;
+
+    connection_assert_ref(c);
+    pa_assert(t);
 
     if (pa_tagstruct_getu32(t, &idx) < 0 ||
         !pa_tagstruct_eof(t)) {
@@ -1889,9 +2292,11 @@
 }
 
 static void command_set_default_sink_or_source(PA_GCC_UNUSED pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
-    struct connection *c = userdata;
+    connection *c = CONNECTION(userdata);
     const char *s;
-    assert(c && t);
+
+    connection_assert_ref(c);
+    pa_assert(t);
 
     if (pa_tagstruct_gets(t, &s) < 0 ||
         !pa_tagstruct_eof(t)) {
@@ -1907,10 +2312,12 @@
 }
 
 static void command_set_stream_name(PA_GCC_UNUSED pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
-    struct connection *c = userdata;
+    connection *c = CONNECTION(userdata);
     uint32_t idx;
     const char *name;
-    assert(c && t);
+
+    connection_assert_ref(c);
+    pa_assert(t);
 
     if (pa_tagstruct_getu32(t, &idx) < 0 ||
         pa_tagstruct_gets(t, &name) < 0 ||
@@ -1923,16 +2330,16 @@
     CHECK_VALIDITY(c->pstream, name && pa_utf8_valid(name), tag, PA_ERR_INVALID);
 
     if (command == PA_COMMAND_SET_PLAYBACK_STREAM_NAME) {
-        struct playback_stream *s;
+        playback_stream *s;
 
         s = pa_idxset_get_by_index(c->output_streams, idx);
         CHECK_VALIDITY(c->pstream, s, tag, PA_ERR_NOENTITY);
-        CHECK_VALIDITY(c->pstream, s->type == PLAYBACK_STREAM, tag, PA_ERR_NOENTITY);
+        CHECK_VALIDITY(c->pstream, playback_stream_isinstance(s), tag, PA_ERR_NOENTITY);
 
         pa_sink_input_set_name(s->sink_input, name);
 
     } else {
-        struct record_stream *s;
+        record_stream *s;
 
         s = pa_idxset_get_by_index(c->record_streams, idx);
         CHECK_VALIDITY(c->pstream, s, tag, PA_ERR_NOENTITY);
@@ -1944,9 +2351,11 @@
 }
 
 static void command_kill(PA_GCC_UNUSED pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
-    struct connection *c = userdata;
+    connection *c = CONNECTION(userdata);
     uint32_t idx;
-    assert(c && t);
+
+    connection_assert_ref(c);
+    pa_assert(t);
 
     if (pa_tagstruct_getu32(t, &idx) < 0 ||
         !pa_tagstruct_eof(t)) {
@@ -1961,6 +2370,8 @@
 
         client = pa_idxset_get_by_index(c->protocol->core->clients, idx);
         CHECK_VALIDITY(c->pstream, client, tag, PA_ERR_NOENTITY);
+
+        connection_ref(c);
         pa_client_kill(client);
 
     } else if (command == PA_COMMAND_KILL_SINK_INPUT) {
@@ -1969,27 +2380,32 @@
         s = pa_idxset_get_by_index(c->protocol->core->sink_inputs, idx);
         CHECK_VALIDITY(c->pstream, s, tag, PA_ERR_NOENTITY);
 
+        connection_ref(c);
         pa_sink_input_kill(s);
     } else {
         pa_source_output *s;
 
-        assert(command == PA_COMMAND_KILL_SOURCE_OUTPUT);
+        pa_assert(command == PA_COMMAND_KILL_SOURCE_OUTPUT);
 
         s = pa_idxset_get_by_index(c->protocol->core->source_outputs, idx);
         CHECK_VALIDITY(c->pstream, s, tag, PA_ERR_NOENTITY);
 
+        connection_ref(c);
         pa_source_output_kill(s);
     }
 
     pa_pstream_send_simple_ack(c->pstream, tag);
+    connection_unref(c);
 }
 
 static void command_load_module(PA_GCC_UNUSED pa_pdispatch *pd, PA_GCC_UNUSED uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
-    struct connection *c = userdata;
+    connection *c = CONNECTION(userdata);
     pa_module *m;
     const char *name, *argument;
     pa_tagstruct *reply;
-    assert(c && t);
+
+    connection_assert_ref(c);
+    pa_assert(t);
 
     if (pa_tagstruct_gets(t, &name) < 0 ||
         pa_tagstruct_gets(t, &argument) < 0 ||
@@ -2013,10 +2429,12 @@
 }
 
 static void command_unload_module(PA_GCC_UNUSED pa_pdispatch *pd, PA_GCC_UNUSED uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
-    struct connection *c = userdata;
+    connection *c = CONNECTION(userdata);
     uint32_t idx;
     pa_module *m;
-    assert(c && t);
+
+    connection_assert_ref(c);
+    pa_assert(t);
 
     if (pa_tagstruct_getu32(t, &idx) < 0 ||
         !pa_tagstruct_eof(t)) {
@@ -2033,12 +2451,14 @@
 }
 
 static void command_add_autoload(PA_GCC_UNUSED pa_pdispatch *pd, PA_GCC_UNUSED uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
-    struct connection *c = userdata;
+    connection *c = CONNECTION(userdata);
     const char *name, *module, *argument;
     uint32_t type;
     uint32_t idx;
     pa_tagstruct *reply;
-    assert(c && t);
+
+    connection_assert_ref(c);
+    pa_assert(t);
 
     if (pa_tagstruct_gets(t, &name) < 0 ||
         pa_tagstruct_getu32(t, &type) < 0 ||
@@ -2066,11 +2486,13 @@
 }
 
 static void command_remove_autoload(PA_GCC_UNUSED pa_pdispatch *pd, PA_GCC_UNUSED uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
-    struct connection *c = userdata;
+    connection *c = CONNECTION(userdata);
     const char *name = NULL;
     uint32_t type, idx = PA_IDXSET_INVALID;
     int r;
-    assert(c && t);
+
+    connection_assert_ref(c);
+    pa_assert(t);
 
     if ((pa_tagstruct_getu32(t, &idx) < 0 &&
         (pa_tagstruct_gets(t, &name) < 0 ||
@@ -2095,7 +2517,7 @@
 }
 
 static void autoload_fill_tagstruct(pa_tagstruct *t, const pa_autoload_entry *e) {
-    assert(t && e);
+    pa_assert(t && e);
 
     pa_tagstruct_putu32(t, e->index);
     pa_tagstruct_puts(t, e->name);
@@ -2105,12 +2527,14 @@
 }
 
 static void command_get_autoload_info(PA_GCC_UNUSED pa_pdispatch *pd, PA_GCC_UNUSED uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
-    struct connection *c = userdata;
+    connection *c = CONNECTION(userdata);
     const pa_autoload_entry *a = NULL;
     uint32_t type, idx;
     const char *name;
     pa_tagstruct *reply;
-    assert(c && t);
+
+    connection_assert_ref(c);
+    pa_assert(t);
 
     if ((pa_tagstruct_getu32(t, &idx) < 0 &&
         (pa_tagstruct_gets(t, &name) < 0 ||
@@ -2137,9 +2561,11 @@
 }
 
 static void command_get_autoload_info_list(PA_GCC_UNUSED pa_pdispatch *pd, PA_GCC_UNUSED uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
-    struct connection *c = userdata;
+    connection *c = CONNECTION(userdata);
     pa_tagstruct *reply;
-    assert(c && t);
+
+    connection_assert_ref(c);
+    pa_assert(t);
 
     if (!pa_tagstruct_eof(t)) {
         protocol_error(c);
@@ -2162,12 +2588,12 @@
 }
 
 static void command_move_stream(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
-    struct connection *c = userdata;
+    connection *c = CONNECTION(userdata);
     uint32_t idx = PA_INVALID_INDEX, idx_device = PA_INVALID_INDEX;
     const char *name = NULL;
 
-    assert(c);
-    assert(t);
+    connection_assert_ref(c);
+    pa_assert(t);
 
     if (pa_tagstruct_getu32(t, &idx) < 0 ||
         pa_tagstruct_getu32(t, &idx_device) < 0 ||
@@ -2202,6 +2628,8 @@
         pa_source_output *so = NULL;
         pa_source *source;
 
+        pa_assert(command == PA_COMMAND_MOVE_SOURCE_OUTPUT);
+
         so = pa_idxset_get_by_index(c->protocol->core->source_outputs, idx);
 
         if (idx_device != PA_INVALID_INDEX)
@@ -2218,67 +2646,122 @@
     }
 
     pa_pstream_send_simple_ack(c->pstream, tag);
-
+}
+
+static void command_suspend(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
+    connection *c = CONNECTION(userdata);
+    uint32_t idx = PA_INVALID_INDEX;
+    const char *name = NULL;
+    int b;
+
+    connection_assert_ref(c);
+    pa_assert(t);
+
+    if (pa_tagstruct_getu32(t, &idx) < 0 ||
+        pa_tagstruct_gets(t, &name) < 0 ||
+        pa_tagstruct_get_boolean(t, &b) < 0 ||
+        !pa_tagstruct_eof(t)) {
+        protocol_error(c);
+        return;
+    }
+
+    CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
+    CHECK_VALIDITY(c->pstream, idx != PA_INVALID_INDEX || !name || !*name || pa_utf8_valid(name), tag, PA_ERR_INVALID);
+
+    if (command == PA_COMMAND_SUSPEND_SINK) {
+
+        if (idx == PA_INVALID_INDEX && name && !*name) {
+
+            if (pa_sink_suspend_all(c->protocol->core, b) < 0) {
+                pa_pstream_send_error(c->pstream, tag, PA_ERR_INVALID);
+                return;
+            }
+        } else {
+            pa_sink *sink = NULL;
+
+            if (idx != PA_INVALID_INDEX)
+                sink = pa_idxset_get_by_index(c->protocol->core->sinks, idx);
+            else
+                sink = pa_namereg_get(c->protocol->core, name, PA_NAMEREG_SINK, 1);
+
+            CHECK_VALIDITY(c->pstream, sink, tag, PA_ERR_NOENTITY);
+
+            if (pa_sink_suspend(sink, b) < 0) {
+                pa_pstream_send_error(c->pstream, tag, PA_ERR_INVALID);
+                return;
+            }
+        }
+    } else {
+
+        pa_assert(command == PA_COMMAND_SUSPEND_SOURCE);
+
+        if (idx == PA_INVALID_INDEX && name && !*name) {
+
+            if (pa_source_suspend_all(c->protocol->core, b) < 0) {
+                pa_pstream_send_error(c->pstream, tag, PA_ERR_INVALID);
+                return;
+            }
+
+        } else {
+            pa_source *source;
+
+            if (idx != PA_INVALID_INDEX)
+                source = pa_idxset_get_by_index(c->protocol->core->sources, idx);
+            else
+                source = pa_namereg_get(c->protocol->core, name, PA_NAMEREG_SOURCE, 1);
+
+            CHECK_VALIDITY(c->pstream, source, tag, PA_ERR_NOENTITY);
+
+            if (pa_source_suspend(source, b) < 0) {
+                pa_pstream_send_error(c->pstream, tag, PA_ERR_INVALID);
+                return;
+            }
+        }
+    }
+
+    pa_pstream_send_simple_ack(c->pstream, tag);
 }
 
 /*** pstream callbacks ***/
 
 static void pstream_packet_callback(pa_pstream *p, pa_packet *packet, const pa_creds *creds, void *userdata) {
-    struct connection *c = userdata;
-    assert(p && packet && packet->data && c);
+    connection *c = CONNECTION(userdata);
+
+    pa_assert(p);
+    pa_assert(packet);
+    connection_assert_ref(c);
 
     if (pa_pdispatch_run(c->pdispatch, packet, creds, c) < 0) {
         pa_log("invalid packet.");
-        connection_free(c);
+        connection_unlink(c);
     }
 }
 
 static void pstream_memblock_callback(pa_pstream *p, uint32_t channel, int64_t offset, pa_seek_mode_t seek, const pa_memchunk *chunk, void *userdata) {
-    struct connection *c = userdata;
-    struct output_stream *stream;
-    assert(p && chunk && userdata);
-
-    if (!(stream = pa_idxset_get_by_index(c->output_streams, channel))) {
+    connection *c = CONNECTION(userdata);
+    output_stream *stream;
+
+    pa_assert(p);
+    pa_assert(chunk);
+    connection_assert_ref(c);
+
+    if (!(stream = OUTPUT_STREAM(pa_idxset_get_by_index(c->output_streams, channel)))) {
         pa_log("client sent block for invalid stream.");
         /* Ignoring */
         return;
     }
 
-    if (stream->type == PLAYBACK_STREAM) {
-        struct playback_stream *ps = (struct playback_stream*) stream;
-        if (chunk->length >= ps->requested_bytes)
-            ps->requested_bytes = 0;
-        else
-            ps->requested_bytes -= chunk->length;
-
-        pa_memblockq_seek(ps->memblockq, offset, seek);
-
-        if (pa_memblockq_push_align(ps->memblockq, chunk) < 0) {
-            pa_tagstruct *t;
-
-            pa_log_warn("failed to push data into queue");
-
-            /* Pushing this block into the queue failed, so we simulate
-             * it by skipping ahead */
-
-            pa_memblockq_seek(ps->memblockq, chunk->length, PA_SEEK_RELATIVE);
-
-            /* Notify the user */
-            t = pa_tagstruct_new(NULL, 0);
-            pa_tagstruct_putu32(t, PA_COMMAND_OVERFLOW);
-            pa_tagstruct_putu32(t, (uint32_t) -1); /* tag */
-            pa_tagstruct_putu32(t, ps->index);
-            pa_pstream_send_tagstruct(p, t);
-        }
-
-        ps->underrun = 0;
-
-        pa_sink_notify(ps->sink_input->sink);
+    if (playback_stream_isinstance(stream)) {
+        playback_stream *ps = PLAYBACK_STREAM(stream);
+
+        if (seek != PA_SEEK_RELATIVE || offset != 0)
+            pa_asyncmsgq_post(ps->sink_input->sink->asyncmsgq, PA_MSGOBJECT(ps->sink_input), SINK_INPUT_MESSAGE_SEEK, PA_UINT_TO_PTR(seek), offset, NULL, NULL);
+
+        pa_asyncmsgq_post(ps->sink_input->sink->asyncmsgq, PA_MSGOBJECT(ps->sink_input), SINK_INPUT_MESSAGE_POST_DATA, NULL, 0, chunk, NULL);
 
     } else {
-        struct upload_stream *u = (struct upload_stream*) stream;
+        upload_stream *u = UPLOAD_STREAM(stream);
         size_t l;
-        assert(u->type == UPLOAD_STREAM);
 
         if (!u->memchunk.memblock) {
             if (u->length == chunk->length) {
@@ -2291,15 +2774,24 @@
             }
         }
 
-        assert(u->memchunk.memblock);
+        pa_assert(u->memchunk.memblock);
 
         l = u->length;
         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;
         }
@@ -2307,43 +2799,72 @@
 }
 
 static void pstream_die_callback(pa_pstream *p, void *userdata) {
-    struct connection *c = userdata;
-    assert(p && c);
-    connection_free(c);
-
-/*    pa_log("connection died.");*/
-}
-
+    connection *c = CONNECTION(userdata);
+
+    pa_assert(p);
+    connection_assert_ref(c);
+
+    connection_unlink(c);
+    pa_log_info("connection died.");
+}
 
 static void pstream_drain_callback(pa_pstream *p, void *userdata) {
-    struct connection *c = userdata;
-    assert(p && c);
+    connection *c = CONNECTION(userdata);
+
+    pa_assert(p);
+    connection_assert_ref(c);
 
     send_memblock(c);
 }
 
+static void pstream_revoke_callback(pa_pstream *p, uint32_t block_id, void *userdata) {
+    pa_thread_mq *q;
+
+    if (!(q = pa_thread_mq_get()))
+        pa_pstream_send_revoke(p, block_id);
+    else
+        pa_asyncmsgq_post(q->outq, PA_MSGOBJECT(userdata), CONNECTION_MESSAGE_REVOKE, PA_UINT_TO_PTR(block_id), 0, NULL, NULL);
+}
+
+static void pstream_release_callback(pa_pstream *p, uint32_t block_id, void *userdata) {
+    pa_thread_mq *q;
+
+    if (!(q = pa_thread_mq_get()))
+        pa_pstream_send_release(p, block_id);
+    else
+        pa_asyncmsgq_post(q->outq, PA_MSGOBJECT(userdata), CONNECTION_MESSAGE_RELEASE, PA_UINT_TO_PTR(block_id), 0, NULL, NULL);
+}
+
 /*** client callbacks ***/
 
 static void client_kill_cb(pa_client *c) {
-    assert(c && c->userdata);
-    connection_free(c->userdata);
+    pa_assert(c);
+
+    connection_unlink(CONNECTION(c->userdata));
 }
 
 /*** socket server callbacks ***/
 
 static void auth_timeout(pa_mainloop_api*m, pa_time_event *e, const struct timeval *tv, void *userdata) {
-    struct connection *c = userdata;
-    assert(m && tv && c && c->auth_timeout_event == e);
+    connection *c = CONNECTION(userdata);
+
+    pa_assert(m);
+    pa_assert(tv);
+    connection_assert_ref(c);
+    pa_assert(c->auth_timeout_event == e);
 
     if (!c->authorized)
-        connection_free(c);
+        connection_unlink(c);
 }
 
 static void on_connection(PA_GCC_UNUSED pa_socket_server*s, pa_iochannel *io, void *userdata) {
     pa_protocol_native *p = userdata;
-    struct connection *c;
+    connection *c;
     char cname[256], pname[128];
-    assert(io && p);
+
+    pa_assert(s);
+    pa_assert(io);
+    pa_assert(p);
 
     if (pa_idxset_size(p->connections)+1 > MAX_CONNECTIONS) {
         pa_log_warn("Warning! Too many connections (%u), dropping incoming connection.", MAX_CONNECTIONS);
@@ -2351,7 +2872,9 @@
         return;
     }
 
-    c = pa_xmalloc(sizeof(struct connection));
+    c = pa_msgobject_new(connection);
+    c->parent.parent.free = connection_free;
+    c->parent.process_msg = connection_process_msg;
 
     c->authorized = !!p->public;
 
@@ -2371,34 +2894,30 @@
     c->version = 8;
     c->protocol = p;
     pa_iochannel_socket_peer_to_string(io, pname, sizeof(pname));
-    snprintf(cname, sizeof(cname), "Native client (%s)", pname);
-    assert(p->core);
+    pa_snprintf(cname, sizeof(cname), "Native client (%s)", pname);
     c->client = pa_client_new(p->core, __FILE__, cname);
-    assert(c->client);
     c->client->kill = client_kill_cb;
     c->client->userdata = c;
     c->client->owner = p->module;
 
     c->pstream = pa_pstream_new(p->core->mainloop, io, p->core->mempool);
-    assert(c->pstream);
 
     pa_pstream_set_recieve_packet_callback(c->pstream, pstream_packet_callback, c);
     pa_pstream_set_recieve_memblock_callback(c->pstream, pstream_memblock_callback, c);
     pa_pstream_set_die_callback(c->pstream, pstream_die_callback, c);
     pa_pstream_set_drain_callback(c->pstream, pstream_drain_callback, c);
+    pa_pstream_set_revoke_callback(c->pstream, pstream_revoke_callback, c);
+    pa_pstream_set_release_callback(c->pstream, pstream_release_callback, c);
 
     c->pdispatch = pa_pdispatch_new(p->core->mainloop, command_table, PA_COMMAND_MAX);
-    assert(c->pdispatch);
 
     c->record_streams = pa_idxset_new(NULL, NULL);
     c->output_streams = pa_idxset_new(NULL, NULL);
-    assert(c->record_streams && c->output_streams);
 
     c->rrobin_index = PA_IDXSET_INVALID;
     c->subscription = NULL;
 
     pa_idxset_put(p->connections, c, NULL);
-
 
 #ifdef HAVE_CREDS
     if (pa_iochannel_creds_supported(io))
@@ -2410,7 +2929,7 @@
 /*** module entry points ***/
 
 static int load_key(pa_protocol_native*p, const char*fn) {
-    assert(p);
+    pa_assert(p);
 
     p->auth_cookie_in_property = 0;
 
@@ -2440,8 +2959,8 @@
     int public = 0;
     const char *acl;
 
-    assert(c);
-    assert(ma);
+    pa_assert(c);
+    pa_assert(ma);
 
     if (pa_modargs_get_value_boolean(ma, "auth-anonymous", &public) < 0) {
         pa_log("auth-anonymous= expects a boolean argument.");
@@ -2482,7 +3001,6 @@
         goto fail;
 
     p->connections = pa_idxset_new(NULL, NULL);
-    assert(p->connections);
 
     return p;
 
@@ -2517,11 +3035,11 @@
 }
 
 void pa_protocol_native_free(pa_protocol_native *p) {
-    struct connection *c;
-    assert(p);
+    connection *c;
+    pa_assert(p);
 
     while ((c = pa_idxset_first(p->connections, NULL)))
-        connection_free(c);
+        connection_unlink(c);
     pa_idxset_free(p->connections, NULL, NULL);
 
     if (p->server) {
@@ -2553,7 +3071,12 @@
     pa_xfree(p);
 }
 
-pa_protocol_native* pa_protocol_native_new_iochannel(pa_core*core, pa_iochannel *io, pa_module *m, pa_modargs *ma) {
+pa_protocol_native* pa_protocol_native_new_iochannel(
+        pa_core*core,
+        pa_iochannel *io,
+        pa_module *m,
+        pa_modargs *ma) {
+
     pa_protocol_native *p;
 
     if (!(p = protocol_new_internal(core, m, ma)))

Modified: trunk/src/pulsecore/protocol-simple.c
URL: http://0pointer.de/cgi-bin/viewcvs.cgi/trunk/src/pulsecore/protocol-simple.c?rev=1971&root=pulseaudio&r1=1970&r2=1971&view=diff
==============================================================================
--- trunk/src/pulsecore/protocol-simple.c (original)
+++ trunk/src/pulsecore/protocol-simple.c Sun Oct 28 20:13:50 2007
@@ -25,7 +25,6 @@
 #include <config.h>
 #endif
 
-#include <assert.h>
 #include <stdlib.h>
 #include <limits.h>
 #include <stdio.h>
@@ -41,101 +40,154 @@
 #include <pulsecore/namereg.h>
 #include <pulsecore/log.h>
 #include <pulsecore/core-error.h>
+#include <pulsecore/atomic.h>
+#include <pulsecore/thread-mq.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;
     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_t missing;
     } playback;
-};
+} connection;
+
+PA_DECLARE_CLASS(connection);
+#define CONNECTION(o) (connection_cast(o))
+static PA_DEFINE_CHECK_TYPE(connection, pa_msgobject);
 
 struct pa_protocol_simple {
     pa_module *module;
     pa_core *core;
     pa_socket_server*server;
     pa_idxset *connections;
+
     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 */
+    SINK_INPUT_MESSAGE_DISABLE_PREBUF /* disabled prebuf, get playback started. */
+};
+
+enum {
+    CONNECTION_MESSAGE_REQUEST_DATA,      /* data requested from sink input from the main loop */
+    CONNECTION_MESSAGE_POST_DATA,         /* data from source output to main loop */
+    CONNECTION_MESSAGE_UNLINK_CONNECTION    /* Please drop a aconnection now */
+};
+
 
 #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_idxset_remove_by_data(c->protocol->connections, c, NULL);
+static void connection_unlink(connection *c) {
+    pa_assert(c);
+
+    if (!c->protocol)
+        return;
+
+    if (c->sink_input) {
+        pa_sink_input_unlink(c->sink_input);
+        pa_sink_input_unref(c->sink_input);
+        c->sink_input = NULL;
+    }
+
+    if (c->source_output) {
+        pa_source_output_unlink(c->source_output);
+        pa_source_output_unref(c->source_output);
+        c->source_output = NULL;
+    }
+
+    if (c->client) {
+        pa_client_free(c->client);
+        c->client = NULL;
+    }
+
+    if (c->io) {
+        pa_iochannel_free(c->io);
+        c->io = NULL;
+    }
+
+    pa_assert_se(pa_idxset_remove_by_data(c->protocol->connections, c, NULL) == c);
+    c->protocol = NULL;
+    connection_unref(c);
+}
+
+static void connection_free(pa_object *o) {
+    connection *c = CONNECTION(o);
+    pa_assert(c);
+
+    connection_unref(c);
 
     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->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);
-    if (c->defer_event)
-        c->protocol->core->mainloop->defer_free(c->defer_event);
+
     pa_xfree(c);
 }
 
-static int do_read(struct connection *c) {
+static int do_read(connection *c) {
     pa_memchunk chunk;
     ssize_t r;
     size_t l;
-
-    if (!c->sink_input || !(l = pa_memblockq_missing(c->input_memblockq)))
+    void *p;
+
+    connection_assert_ref(c);
+
+    if (!c->sink_input || (l = pa_atomic_load(&c->playback.missing)) <= 0)
         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 (r < 0 && (errno == EINTR || errno == EAGAIN))
+            return 0;
+
         pa_log_debug("read(): %s", r == 0 ? "EOF" : pa_cstrerror(errno));
         return -1;
     }
@@ -143,50 +195,55 @@
     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->sink_input->sink->asyncmsgq, PA_MSGOBJECT(c->sink_input), SINK_INPUT_MESSAGE_POST_DATA, NULL, 0, &chunk, NULL);
+    pa_atomic_sub(&c->playback.missing, r);
 
     return 0;
 }
 
-static int do_write(struct connection *c) {
+static int do_write(connection *c) {
     pa_memchunk chunk;
     ssize_t r;
+    void *p;
+
+    connection_assert_ref(c);
 
     if (!c->source_output)
         return 0;
 
-    assert(c->output_memblockq);
-    if (pa_memblockq_peek(c->output_memblockq, &chunk) < 0)
+    if (pa_memblockq_peek(c->output_memblockq, &chunk) < 0) {
+/*         pa_log("peek failed"); */
         return 0;
-
-    assert(chunk.memblock && chunk.length);
-
-    if ((r = pa_iochannel_write(c->io, (uint8_t*) chunk.memblock->data+chunk.index, chunk.length)) < 0) {
-        pa_memblock_unref(chunk.memblock);
+    }
+
+    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;
+
         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);
+    pa_memblockq_drop(c->output_memblockq, r);
 
     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);
+static void do_work(connection *c) {
+    connection_assert_ref(c);
 
     if (c->dead)
         return;
@@ -207,103 +264,182 @@
 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);
+        pa_asyncmsgq_post(c->sink_input->sink->asyncmsgq, PA_MSGOBJECT(c->sink_input), SINK_INPUT_MESSAGE_DISABLE_PREBUF, NULL, 0, NULL, NULL);
     } else
-        connection_free(c);
+        connection_unlink(c);
+}
+
+static int connection_process_msg(pa_msgobject *o, int code, void*userdata, int64_t offset, pa_memchunk *chunk) {
+    connection *c = CONNECTION(o);
+    connection_assert_ref(c);
+
+    switch (code) {
+        case CONNECTION_MESSAGE_REQUEST_DATA:
+            do_work(c);
+            break;
+
+        case CONNECTION_MESSAGE_POST_DATA:
+/*             pa_log("got data %u", chunk->length); */
+            pa_memblockq_push_align(c->output_memblockq, chunk);
+            do_work(c);
+            break;
+
+        case CONNECTION_MESSAGE_UNLINK_CONNECTION:
+            connection_unlink(c);
+            break;
+    }
+
+    return 0;
 }
 
 /*** sink_input callbacks ***/
 
-static int sink_input_peek_cb(pa_sink_input *i, pa_memchunk *chunk) {
-    struct connection*c;
-    assert(i && i->userdata && chunk);
-    c = i->userdata;
-
-    if (pa_memblockq_peek(c->input_memblockq, chunk) < 0) {
-
-        if (c->dead)
-            connection_free(c);
-
-        return -1;
-    }
-
-    return 0;
-}
-
-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);
-
-    pa_memblockq_drop(c->input_memblockq, chunk, length);
-
-    /* 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);
-}
-
+/* Called from thread context */
+static int sink_input_process_msg(pa_msgobject *o, int code, void *userdata, int64_t offset, pa_memchunk *chunk) {
+    pa_sink_input *i = PA_SINK_INPUT(o);
+    connection*c;
+
+    pa_sink_input_assert_ref(i);
+    c = CONNECTION(i->userdata);
+    connection_assert_ref(c);
+
+    switch (code) {
+
+        case SINK_INPUT_MESSAGE_POST_DATA: {
+            pa_assert(chunk);
+
+            /* New data from the main loop */
+            pa_memblockq_push_align(c->input_memblockq, chunk);
+
+/*             pa_log("got data, %u", pa_memblockq_get_length(c->input_memblockq)); */
+
+            return 0;
+        }
+
+        case SINK_INPUT_MESSAGE_DISABLE_PREBUF: {
+            pa_memblockq_prebuf_disable(c->input_memblockq);
+            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(o, code, userdata, offset, chunk);
+    }
+}
+
+/* Called from thread context */
+static int sink_input_peek_cb(pa_sink_input *i, size_t length, pa_memchunk *chunk) {
+    connection *c;
+    int r;
+
+    pa_assert(i);
+    c = CONNECTION(i->userdata);
+    connection_assert_ref(c);
+    pa_assert(chunk);
+
+    r = pa_memblockq_peek(c->input_memblockq, chunk);
+
+/*     pa_log("peeked %u %i", r >= 0 ? chunk->length: 0, r); */
+
+    if (c->dead && r < 0)
+        pa_asyncmsgq_post(pa_thread_mq_get()->outq, PA_MSGOBJECT(c), CONNECTION_MESSAGE_UNLINK_CONNECTION, NULL, 0, NULL, NULL);
+
+    return r;
+}
+
+/* Called from thread context */
+static void sink_input_drop_cb(pa_sink_input *i, size_t length) {
+    connection *c;
+    size_t old, new;
+
+    pa_assert(i);
+    c = CONNECTION(i->userdata);
+    connection_assert_ref(c);
+    pa_assert(length);
+
+    old = pa_memblockq_missing(c->input_memblockq);
+    pa_memblockq_drop(c->input_memblockq, length);
+    new = pa_memblockq_missing(c->input_memblockq);
+
+    if (new > old) {
+        if (pa_atomic_add(&c->playback.missing, new - old) <= 0)
+            pa_asyncmsgq_post(pa_thread_mq_get()->outq, PA_MSGOBJECT(c), CONNECTION_MESSAGE_REQUEST_DATA, NULL, 0, NULL, NULL);
+    }
+}
+
+/* Called from main context */
 static void sink_input_kill_cb(pa_sink_input *i) {
-    assert(i && 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);
+    pa_sink_input_assert_ref(i);
+
+    connection_unlink(CONNECTION(i->userdata));
 }
 
 /*** source_output callbacks ***/
 
+/* Called from thread context */
 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);
-
-    /* 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);
-}
-
+    connection *c;
+
+    pa_assert(o);
+    c = CONNECTION(o->userdata);
+    pa_assert(c);
+    pa_assert(chunk);
+
+    pa_asyncmsgq_post(pa_thread_mq_get()->outq, PA_MSGOBJECT(c), CONNECTION_MESSAGE_POST_DATA, NULL, 0, chunk, NULL);
+}
+
+/* Called from main context */
 static void source_output_kill_cb(pa_source_output *o) {
-    assert(o && o->userdata);
-    connection_free((struct connection *) o->userdata);
-}
-
+    pa_source_output_assert_ref(o);
+
+    connection_unlink(CONNECTION(o->userdata));
+}
+
+/* Called from main context */
 static pa_usec_t source_output_get_latency_cb(pa_source_output *o) {
-    struct connection*c = o->userdata;
-    assert(o && c);
+    connection*c;
+
+    pa_assert(o);
+    c = CONNECTION(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) {
+    connection*c;
+
+    pa_assert(client);
+    c = CONNECTION(client->userdata);
+    pa_assert(c);
+
+    connection_unlink(c);
 }
 
 /*** 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);
+    connection *c = CONNECTION(userdata);
+
+    connection_assert_ref(c);
+    pa_assert(io);
 
     do_work(c);
 }
@@ -312,9 +448,12 @@
 
 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];
-    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,21 +461,22 @@
         return;
     }
 
-    c = pa_xmalloc(sizeof(struct connection));
+    c = pa_msgobject_new(connection);
+    c->parent.parent.free = connection_free;
+    c->parent.process_msg = connection_process_msg;
     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;
@@ -357,10 +497,10 @@
             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);
@@ -372,11 +512,12 @@
                 (size_t) -1,
                 l/PLAYBACK_BUFFER_FRAGMENTS,
                 NULL);
-        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);
+        c->playback.fragment_size = l/PLAYBACK_BUFFER_FRAGMENTS;
+
+        pa_atomic_store(&c->playback.missing, pa_memblockq_missing(c->input_memblockq));
+
+        pa_sink_input_put(c->sink_input);
     }
 
     if (p->mode & RECORD) {
@@ -409,29 +550,29 @@
                 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:
     if (c)
-        connection_free(c);
+        connection_unlink(c);
 }
 
 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);
-
-    p = pa_xmalloc0(sizeof(pa_protocol_simple));
+
+    pa_assert(core);
+    pa_assert(server);
+    pa_assert(ma);
+
+    p = pa_xnew0(pa_protocol_simple, 1);
     p->module = m;
     p->core = core;
     p->server = server;
@@ -472,23 +613,24 @@
 fail:
     if (p)
         pa_protocol_simple_free(p);
+
     return NULL;
 }
 
 
 void pa_protocol_simple_free(pa_protocol_simple *p) {
-    struct connection *c;
-    assert(p);
+    connection *c;
+    pa_assert(p);
 
     if (p->connections) {
         while((c = pa_idxset_first(p->connections, NULL)))
-            connection_free(c);
+            connection_unlink(c);
 
         pa_idxset_free(p->connections, NULL, NULL);
     }
 
     if (p->server)
         pa_socket_server_unref(p->server);
+
     pa_xfree(p);
 }
-

Modified: trunk/src/pulsecore/pstream-util.c
URL: http://0pointer.de/cgi-bin/viewcvs.cgi/trunk/src/pulsecore/pstream-util.c?rev=1971&root=pulseaudio&r1=1970&r2=1971&view=diff
==============================================================================
--- trunk/src/pulsecore/pstream-util.c (original)
+++ trunk/src/pulsecore/pstream-util.c Sun Oct 28 20:13:50 2007
@@ -25,9 +25,8 @@
 #include <config.h>
 #endif
 
-#include <assert.h>
-
 #include <pulsecore/native-common.h>
+#include <pulsecore/macro.h>
 
 #include "pstream-util.h"
 
@@ -35,20 +34,20 @@
     size_t length;
     uint8_t *data;
     pa_packet *packet;
-    assert(p);
-    assert(t);
 
-    data = pa_tagstruct_free_data(t, &length);
-    assert(data && length);
-    packet = pa_packet_new_dynamic(data, length);
-    assert(packet);
+    pa_assert(p);
+    pa_assert(t);
+
+    pa_assert_se(data = pa_tagstruct_free_data(t, &length));
+    pa_assert_se(packet = pa_packet_new_dynamic(data, length));
     pa_pstream_send_packet(p, packet, creds);
     pa_packet_unref(packet);
 }
 
 void pa_pstream_send_error(pa_pstream *p, uint32_t tag, uint32_t error) {
-    pa_tagstruct *t = pa_tagstruct_new(NULL, 0);
-    assert(t);
+    pa_tagstruct *t;
+
+    pa_assert_se(t = pa_tagstruct_new(NULL, 0));
     pa_tagstruct_putu32(t, PA_COMMAND_ERROR);
     pa_tagstruct_putu32(t, tag);
     pa_tagstruct_putu32(t, error);
@@ -56,8 +55,9 @@
 }
 
 void pa_pstream_send_simple_ack(pa_pstream *p, uint32_t tag) {
-    pa_tagstruct *t = pa_tagstruct_new(NULL, 0);
-    assert(t);
+    pa_tagstruct *t;
+
+    pa_assert_se(t = pa_tagstruct_new(NULL, 0));
     pa_tagstruct_putu32(t, PA_COMMAND_REPLY);
     pa_tagstruct_putu32(t, tag);
     pa_pstream_send_tagstruct(p, t);

Modified: trunk/src/pulsecore/pstream.c
URL: http://0pointer.de/cgi-bin/viewcvs.cgi/trunk/src/pulsecore/pstream.c?rev=1971&root=pulseaudio&r1=1970&r2=1971&view=diff
==============================================================================
--- trunk/src/pulsecore/pstream.c (original)
+++ trunk/src/pulsecore/pstream.c Sun Oct 28 20:13:50 2007
@@ -28,7 +28,6 @@
 
 #include <stdio.h>
 #include <stdlib.h>
-#include <assert.h>
 #include <unistd.h>
 
 #ifdef HAVE_SYS_SOCKET_H
@@ -41,16 +40,17 @@
 #include <netinet/in.h>
 #endif
 
-#include "winsock.h"
 
 #include <pulse/xmalloc.h>
 
+#include <pulsecore/winsock.h>
 #include <pulsecore/queue.h>
 #include <pulsecore/log.h>
 #include <pulsecore/core-scache.h>
 #include <pulsecore/creds.h>
-#include <pulsecore/mutex.h>
 #include <pulsecore/refcnt.h>
+#include <pulsecore/flist.h>
+#include <pulsecore/macro.h>
 
 #include "pstream.h"
 
@@ -84,7 +84,8 @@
 
 #define PA_PSTREAM_DESCRIPTOR_SIZE (PA_PSTREAM_DESCRIPTOR_MAX*sizeof(uint32_t))
 #define FRAME_SIZE_MAX_ALLOW PA_SCACHE_ENTRY_SIZE_MAX /* allow uploading a single sample in one frame at max */
-#define FRAME_SIZE_MAX_USE (1024*64)
+
+PA_STATIC_FLIST_DECLARE(items, 0, pa_xfree);
 
 struct item_info {
     enum {
@@ -94,7 +95,6 @@
         PA_PSTREAM_ITEM_SHMREVOKE
     } type;
 
-
     /* packet info */
     pa_packet *packet;
 #ifdef HAVE_CREDS
@@ -118,8 +118,8 @@
     pa_mainloop_api *mainloop;
     pa_defer_event *defer_event;
     pa_iochannel *io;
+
     pa_queue *send_queue;
-    pa_mutex *mutex;
 
     int dead;
 
@@ -129,6 +129,7 @@
         uint32_t shm_info[PA_PSTREAM_SHM_MAX];
         void *data;
         size_t index;
+        pa_memchunk memchunk;
     } write;
 
     struct {
@@ -156,6 +157,12 @@
     pa_pstream_notify_cb_t die_callback;
     void *die_callback_userdata;
 
+    pa_pstream_block_id_cb_t revoke_callback;
+    void *revoke_callback_userdata;
+
+    pa_pstream_block_id_cb_t release_callback;
+    void *release_callback_userdata;
+
     pa_mempool *mempool;
 
 #ifdef HAVE_CREDS
@@ -168,12 +175,10 @@
 static int do_read(pa_pstream *p);
 
 static void do_something(pa_pstream *p) {
-    assert(p);
-    assert(PA_REFCNT_VALUE(p) > 0);
+    pa_assert(p);
+    pa_assert(PA_REFCNT_VALUE(p) > 0);
 
     pa_pstream_ref(p);
-
-    pa_mutex_lock(p->mutex);
 
     p->mainloop->defer_enable(p->defer_event, 0);
 
@@ -188,28 +193,24 @@
             goto fail;
     }
 
-    pa_mutex_unlock(p->mutex);
-
     pa_pstream_unref(p);
     return;
 
 fail:
 
-    p->dead = 1;
-
     if (p->die_callback)
         p->die_callback(p, p->die_callback_userdata);
 
-    pa_mutex_unlock(p->mutex);
-
+    pa_pstream_unlink(p);
     pa_pstream_unref(p);
 }
 
 static void io_callback(pa_iochannel*io, void *userdata) {
     pa_pstream *p = userdata;
 
-    assert(p);
-    assert(p->io == io);
+    pa_assert(p);
+    pa_assert(PA_REFCNT_VALUE(p) > 0);
+    pa_assert(p->io == io);
 
     do_something(p);
 }
@@ -217,9 +218,10 @@
 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);
+    pa_assert(p);
+    pa_assert(PA_REFCNT_VALUE(p) > 0);
+    pa_assert(p->defer_event == e);
+    pa_assert(p->mainloop == m);
 
     do_something(p);
 }
@@ -229,9 +231,9 @@
 pa_pstream *pa_pstream_new(pa_mainloop_api *m, pa_iochannel *io, pa_mempool *pool) {
     pa_pstream *p;
 
-    assert(m);
-    assert(io);
-    assert(pool);
+    pa_assert(m);
+    pa_assert(io);
+    pa_assert(pool);
 
     p = pa_xnew(pa_pstream, 1);
     PA_REFCNT_INIT(p);
@@ -239,17 +241,15 @@
     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;
@@ -262,6 +262,10 @@
     p->drain_callback_userdata = NULL;
     p->die_callback = NULL;
     p->die_callback_userdata = NULL;
+    p->revoke_callback = NULL;
+    p->revoke_callback_userdata = NULL;
+    p->release_callback = NULL;
+    p->release_callback_userdata = NULL;
 
     p->mempool = pool;
 
@@ -281,56 +285,57 @@
     return p;
 }
 
-static void item_free(void *item, PA_GCC_UNUSED void *p) {
+static void item_free(void *item, PA_GCC_UNUSED void *q) {
     struct item_info *i = item;
-    assert(i);
+    pa_assert(i);
 
     if (i->type == PA_PSTREAM_ITEM_MEMBLOCK) {
-        assert(i->chunk.memblock);
+        pa_assert(i->chunk.memblock);
         pa_memblock_unref(i->chunk.memblock);
     } else if (i->type == PA_PSTREAM_ITEM_PACKET) {
-        assert(i->packet);
+        pa_assert(i->packet);
         pa_packet_unref(i->packet);
     }
 
-    pa_xfree(i);
+    if (pa_flist_push(PA_STATIC_FLIST_GET(items), i) < 0)
+        pa_xfree(i);
 }
 
 static void pstream_free(pa_pstream *p) {
-    assert(p);
-
-    pa_pstream_close(p);
+    pa_assert(p);
+
+    pa_pstream_unlink(p);
 
     pa_queue_free(p->send_queue, item_free, NULL);
 
     if (p->write.current)
         item_free(p->write.current, NULL);
 
+    if (p->write.memchunk.memblock)
+        pa_memblock_unref(p->write.memchunk.memblock);
+
     if (p->read.memblock)
         pa_memblock_unref(p->read.memblock);
 
     if (p->read.packet)
         pa_packet_unref(p->read.packet);
 
-    if (p->mutex)
-        pa_mutex_free(p->mutex);
-
     pa_xfree(p);
 }
 
 void pa_pstream_send_packet(pa_pstream*p, pa_packet *packet, const pa_creds *creds) {
     struct item_info *i;
 
-    assert(p);
-    assert(PA_REFCNT_VALUE(p) > 0);
-    assert(packet);
-
-    pa_mutex_lock(p->mutex);
+    pa_assert(p);
+    pa_assert(PA_REFCNT_VALUE(p) > 0);
+    pa_assert(packet);
 
     if (p->dead)
-        goto finish;
-
-    i = pa_xnew(struct item_info, 1);
+        return;
+
+    if (!(i = pa_flist_pop(PA_STATIC_FLIST_GET(items))))
+        i = pa_xnew(struct item_info, 1);
+
     i->type = PA_PSTREAM_ITEM_PACKET;
     i->packet = pa_packet_ref(packet);
 
@@ -340,37 +345,36 @@
 #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) {
     size_t length, idx;
-
-    assert(p);
-    assert(PA_REFCNT_VALUE(p) > 0);
-    assert(channel != (uint32_t) -1);
-    assert(chunk);
-
-    pa_mutex_lock(p->mutex);
+    size_t bsm;
+
+    pa_assert(p);
+    pa_assert(PA_REFCNT_VALUE(p) > 0);
+    pa_assert(channel != (uint32_t) -1);
+    pa_assert(chunk);
 
     if (p->dead)
-        goto finish;
-
+        return;
+
+    idx = 0;
     length = chunk->length;
-    idx = 0;
+
+    bsm = pa_mempool_block_size_max(p->mempool);
 
     while (length > 0) {
         struct item_info *i;
         size_t n;
 
-        i = pa_xnew(struct item_info, 1);
+        if (!(i = pa_flist_pop(PA_STATIC_FLIST_GET(items))))
+            i = pa_xnew(struct item_info, 1);
         i->type = PA_PSTREAM_ITEM_MEMBLOCK;
 
-        n = length < FRAME_SIZE_MAX_USE ? length : FRAME_SIZE_MAX_USE;
+        n = MIN(length, bsm);
         i->chunk.index = chunk->index + idx;
         i->chunk.length = n;
         i->chunk.memblock = pa_memblock_ref(chunk->memblock);
@@ -389,27 +393,20 @@
     }
 
     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) {
+}
+
+void pa_pstream_send_release(pa_pstream *p, uint32_t block_id) {
     struct item_info *item;
-    pa_pstream *p = userdata;
-
-    assert(p);
-    assert(PA_REFCNT_VALUE(p) > 0);
-
-    pa_mutex_lock(p->mutex);
+    pa_assert(p);
+    pa_assert(PA_REFCNT_VALUE(p) > 0);
 
     if (p->dead)
-        goto finish;
+        return;
 
 /*     pa_log("Releasing block %u", block_id); */
 
-    item = pa_xnew(struct item_info, 1);
+    if (!(item = pa_flist_pop(PA_STATIC_FLIST_GET(items))))
+        item = pa_xnew(struct item_info, 1);
     item->type = PA_PSTREAM_ITEM_SHMRELEASE;
     item->block_id = block_id;
 #ifdef HAVE_CREDS
@@ -418,27 +415,35 @@
 
     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) {
+}
+
+/* might be called from thread context */
+static void memimport_release_cb(pa_memimport *i, uint32_t block_id, void *userdata) {
+    pa_pstream *p = userdata;
+
+    pa_assert(p);
+    pa_assert(PA_REFCNT_VALUE(p) > 0);
+
+    if (p->dead)
+        return;
+
+    if (p->release_callback)
+        p->release_callback(p, block_id, p->release_callback_userdata);
+    else
+        pa_pstream_send_release(p, block_id);
+}
+
+void pa_pstream_send_revoke(pa_pstream *p, uint32_t block_id) {
     struct item_info *item;
-    pa_pstream *p = userdata;
-
-    assert(p);
-    assert(PA_REFCNT_VALUE(p) > 0);
-
-    pa_mutex_lock(p->mutex);
+    pa_assert(p);
+    pa_assert(PA_REFCNT_VALUE(p) > 0);
 
     if (p->dead)
-        goto finish;
-
+        return;
 /*     pa_log("Revoking block %u", block_id); */
 
-    item = pa_xnew(struct item_info, 1);
+    if (!(item = pa_flist_pop(PA_STATIC_FLIST_GET(items))))
+        item = pa_xnew(struct item_info, 1);
     item->type = PA_PSTREAM_ITEM_SHMREVOKE;
     item->block_id = block_id;
 #ifdef HAVE_CREDS
@@ -447,21 +452,33 @@
 
     pa_queue_push(p->send_queue, item);
     p->mainloop->defer_enable(p->defer_event, 1);
-
-finish:
-
-    pa_mutex_unlock(p->mutex);
+}
+
+/* might be called from thread context */
+static void memexport_revoke_cb(pa_memexport *e, uint32_t block_id, void *userdata) {
+    pa_pstream *p = userdata;
+
+    pa_assert(p);
+    pa_assert(PA_REFCNT_VALUE(p) > 0);
+
+    if (p->revoke_callback)
+        p->revoke_callback(p, block_id, p->revoke_callback_userdata);
+    else
+        pa_pstream_send_revoke(p, block_id);
 }
 
 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)))
+    pa_assert(p);
+    pa_assert(PA_REFCNT_VALUE(p) > 0);
+
+    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);
@@ -471,7 +488,7 @@
 
     if (p->write.current->type == PA_PSTREAM_ITEM_PACKET) {
 
-        assert(p->write.current->packet);
+        pa_assert(p->write.current->packet);
         p->write.data = p->write.current->packet->data;
         p->write.descriptor[PA_PSTREAM_DESCRIPTOR_LENGTH] = htonl(p->write.current->packet->length);
 
@@ -489,8 +506,8 @@
         uint32_t flags;
         int send_payload = 1;
 
-        assert(p->write.current->type == PA_PSTREAM_ITEM_MEMBLOCK);
-        assert(p->write.current->chunk.memblock);
+        pa_assert(p->write.current->type == PA_PSTREAM_ITEM_MEMBLOCK);
+        pa_assert(p->write.current->chunk.memblock);
 
         p->write.descriptor[PA_PSTREAM_DESCRIPTOR_CHANNEL] = htonl(p->write.current->channel);
         p->write.descriptor[PA_PSTREAM_DESCRIPTOR_OFFSET_HI] = htonl((uint32_t) (((uint64_t) p->write.current->offset) >> 32));
@@ -502,7 +519,7 @@
             uint32_t block_id, shm_id;
             size_t offset, length;
 
-            assert(p->export);
+            pa_assert(p->export);
 
             if (pa_memexport_put(p->export,
                                  p->write.current->chunk.memblock,
@@ -528,7 +545,9 @@
 
         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,9 +563,10 @@
     void *d;
     size_t l;
     ssize_t r;
-
-    assert(p);
-    assert(PA_REFCNT_VALUE(p) > 0);
+    pa_memblock *release_memblock = NULL;
+
+    pa_assert(p);
+    pa_assert(PA_REFCNT_VALUE(p) > 0);
 
     if (!p->write.current)
         prepare_next_write_item(p);
@@ -558,71 +578,104 @@
         d = (uint8_t*) p->write.descriptor + p->write.index;
         l = PA_PSTREAM_DESCRIPTOR_SIZE - p->write.index;
     } else {
-        assert(p->write.data);
-
-        d = (uint8_t*) p->write.data + p->write.index - PA_PSTREAM_DESCRIPTOR_SIZE;
+        pa_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*) d + p->write.index - PA_PSTREAM_DESCRIPTOR_SIZE;
         l = ntohl(p->write.descriptor[PA_PSTREAM_DESCRIPTOR_LENGTH]) - (p->write.index - PA_PSTREAM_DESCRIPTOR_SIZE);
     }
 
-    assert(l > 0);
+    pa_assert(l > 0);
 
 #ifdef HAVE_CREDS
     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;
 
     if (p->write.index >= PA_PSTREAM_DESCRIPTOR_SIZE + ntohl(p->write.descriptor[PA_PSTREAM_DESCRIPTOR_LENGTH])) {
-        assert(p->write.current);
-        item_free(p->write.current, (void *) 1);
+        pa_assert(p->write.current);
+        item_free(p->write.current, NULL);
         p->write.current = NULL;
+
+        if (p->write.memchunk.memblock)
+            pa_memblock_unref(p->write.memchunk.memblock);
+
+        pa_memchunk_reset(&p->write.memchunk);
 
         if (p->drain_callback && !pa_pstream_is_pending(p))
             p->drain_callback(p, p->drain_callback_userdata);
     }
 
     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;
-
-    assert(p);
-    assert(PA_REFCNT_VALUE(p) > 0);
+    pa_memblock *release_memblock = NULL;
+    pa_assert(p);
+    pa_assert(PA_REFCNT_VALUE(p) > 0);
 
     if (p->read.index < PA_PSTREAM_DESCRIPTOR_SIZE) {
         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;
+        pa_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);
     }
 
 #ifdef HAVE_CREDS
     {
-        int b = 0;
+        pa_bool_t 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;
-#endif
+        goto fail;
+#endif
+
+    if (release_memblock)
+        pa_memblock_release(release_memblock);
 
     p->read.index += r;
 
@@ -643,7 +696,7 @@
 
 /*             pa_log("Got release frame for %u", ntohl(p->read.descriptor[PA_PSTREAM_DESCRIPTOR_OFFSET_HI])); */
 
-            assert(p->export);
+            pa_assert(p->export);
             pa_memexport_process_release(p->export, ntohl(p->read.descriptor[PA_PSTREAM_DESCRIPTOR_OFFSET_HI]));
 
             goto frame_done;
@@ -654,7 +707,7 @@
 
 /*             pa_log("Got revoke frame for %u", ntohl(p->read.descriptor[PA_PSTREAM_DESCRIPTOR_OFFSET_HI])); */
 
-            assert(p->import);
+            pa_assert(p->import);
             pa_memimport_process_revoke(p->import, ntohl(p->read.descriptor[PA_PSTREAM_DESCRIPTOR_OFFSET_HI]));
 
             goto frame_done;
@@ -667,7 +720,7 @@
             return -1;
         }
 
-        assert(!p->read.packet && !p->read.memblock);
+        pa_assert(!p->read.packet && !p->read.memblock);
 
         channel = ntohl(p->read.descriptor[PA_PSTREAM_DESCRIPTOR_CHANNEL]);
 
@@ -704,7 +757,7 @@
                 /* 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.");
@@ -771,9 +824,9 @@
             } else {
                 pa_memblock *b;
 
-                assert((ntohl(p->read.descriptor[PA_PSTREAM_DESCRIPTOR_FLAGS]) & PA_FLAG_SHMMASK) == PA_FLAG_SHMDATA);
-
-                assert(p->import);
+                pa_assert((ntohl(p->read.descriptor[PA_PSTREAM_DESCRIPTOR_FLAGS]) & PA_FLAG_SHMMASK) == PA_FLAG_SHMDATA);
+
+                pa_assert(p->import);
 
                 if (!(b = pa_memimport_get(p->import,
                                           ntohl(p->read.shm_info[PA_PSTREAM_SHM_BLOCKID]),
@@ -791,7 +844,7 @@
 
                     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,92 +872,104 @@
     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);
+    pa_assert(p);
+    pa_assert(PA_REFCNT_VALUE(p) > 0);
+
     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);
+    pa_assert(p);
+    pa_assert(PA_REFCNT_VALUE(p) > 0);
+
     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);
+    pa_assert(p);
+    pa_assert(PA_REFCNT_VALUE(p) > 0);
+
     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);
+    pa_assert(p);
+    pa_assert(PA_REFCNT_VALUE(p) > 0);
+
     p->recieve_memblock_callback = cb;
     p->recieve_memblock_callback_userdata = userdata;
-    pa_mutex_unlock(p->mutex);
+}
+
+void pa_pstream_set_release_callback(pa_pstream *p, pa_pstream_block_id_cb_t cb, void *userdata) {
+    pa_assert(p);
+    pa_assert(PA_REFCNT_VALUE(p) > 0);
+
+    p->release_callback = cb;
+    p->release_callback_userdata = userdata;
+}
+
+void pa_pstream_set_revoke_callback(pa_pstream *p, pa_pstream_block_id_cb_t cb, void *userdata) {
+    pa_assert(p);
+    pa_assert(PA_REFCNT_VALUE(p) > 0);
+
+    p->release_callback = cb;
+    p->release_callback_userdata = userdata;
 }
 
 int pa_pstream_is_pending(pa_pstream *p) {
     int b;
 
-    assert(p);
-    assert(PA_REFCNT_VALUE(p) > 0);
-
-    pa_mutex_lock(p->mutex);
+    pa_assert(p);
+    pa_assert(PA_REFCNT_VALUE(p) > 0);
 
     if (p->dead)
         b = 0;
     else
         b = p->write.current || !pa_queue_is_empty(p->send_queue);
 
-    pa_mutex_unlock(p->mutex);
-
     return b;
 }
 
 void pa_pstream_unref(pa_pstream*p) {
-    assert(p);
-    assert(PA_REFCNT_VALUE(p) > 0);
+    pa_assert(p);
+    pa_assert(PA_REFCNT_VALUE(p) > 0);
 
     if (PA_REFCNT_DEC(p) <= 0)
         pstream_free(p);
 }
 
 pa_pstream* pa_pstream_ref(pa_pstream*p) {
-    assert(p);
-    assert(PA_REFCNT_VALUE(p) > 0);
+    pa_assert(p);
+    pa_assert(PA_REFCNT_VALUE(p) > 0);
 
     PA_REFCNT_INC(p);
     return p;
 }
 
-void pa_pstream_close(pa_pstream *p) {
-    assert(p);
-
-    pa_mutex_lock(p->mutex);
+void pa_pstream_unlink(pa_pstream *p) {
+    pa_assert(p);
+
+    if (p->dead)
+        return;
 
     p->dead = 1;
 
@@ -932,15 +997,11 @@
     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);
+    pa_assert(p);
+    pa_assert(PA_REFCNT_VALUE(p) > 0);
 
     p->use_shm = enable;
 
@@ -956,6 +1017,4 @@
             p->export = NULL;
         }
     }
-
-    pa_mutex_unlock(p->mutex);
-}
+}

Modified: trunk/src/pulsecore/pstream.h
URL: http://0pointer.de/cgi-bin/viewcvs.cgi/trunk/src/pulsecore/pstream.h?rev=1971&root=pulseaudio&r1=1970&r2=1971&view=diff
==============================================================================
--- trunk/src/pulsecore/pstream.h (original)
+++ trunk/src/pulsecore/pstream.h Sun Oct 28 20:13:50 2007
@@ -41,6 +41,7 @@
 typedef void (*pa_pstream_packet_cb_t)(pa_pstream *p, pa_packet *packet, const pa_creds *creds, void *userdata);
 typedef void (*pa_pstream_memblock_cb_t)(pa_pstream *p, uint32_t channel, int64_t offset, pa_seek_mode_t seek, const pa_memchunk *chunk, void *userdata);
 typedef void (*pa_pstream_notify_cb_t)(pa_pstream *p, void *userdata);
+typedef void (*pa_pstream_block_id_cb_t)(pa_pstream *p, uint32_t block_id, void *userdata);
 
 pa_pstream* pa_pstream_new(pa_mainloop_api *m, pa_iochannel *io, pa_mempool *p);
 void pa_pstream_unref(pa_pstream*p);
@@ -48,17 +49,20 @@
 
 void pa_pstream_send_packet(pa_pstream*p, pa_packet *packet, const pa_creds *creds);
 void pa_pstream_send_memblock(pa_pstream*p, uint32_t channel, int64_t offset, pa_seek_mode_t seek, const pa_memchunk *chunk);
+void pa_pstream_send_release(pa_pstream *p, uint32_t block_id);
+void pa_pstream_send_revoke(pa_pstream *p, uint32_t block_id);
 
 void pa_pstream_set_recieve_packet_callback(pa_pstream *p, pa_pstream_packet_cb_t cb, void *userdata);
 void pa_pstream_set_recieve_memblock_callback(pa_pstream *p, pa_pstream_memblock_cb_t cb, void *userdata);
 void pa_pstream_set_drain_callback(pa_pstream *p, pa_pstream_notify_cb_t cb, void *userdata);
-
 void pa_pstream_set_die_callback(pa_pstream *p, pa_pstream_notify_cb_t cb, void *userdata);
+void pa_pstream_set_release_callback(pa_pstream *p, pa_pstream_block_id_cb_t cb, void *userdata);
+void pa_pstream_set_revoke_callback(pa_pstream *p, pa_pstream_block_id_cb_t cb, void *userdata);
 
 int pa_pstream_is_pending(pa_pstream *p);
 
 void pa_pstream_use_shm(pa_pstream *p, int enable);
 
-void pa_pstream_close(pa_pstream *p);
+void pa_pstream_unlink(pa_pstream *p);
 
 #endif

Modified: trunk/src/pulsecore/queue.c
URL: http://0pointer.de/cgi-bin/viewcvs.cgi/trunk/src/pulsecore/queue.c?rev=1971&root=pulseaudio&r1=1970&r2=1971&view=diff
==============================================================================
--- trunk/src/pulsecore/queue.c (original)
+++ trunk/src/pulsecore/queue.c Sun Oct 28 20:13:50 2007
@@ -25,12 +25,15 @@
 #include <config.h>
 #endif
 
-#include <assert.h>
 #include <stdlib.h>
 
 #include <pulse/xmalloc.h>
+#include <pulsecore/macro.h>
+#include <pulsecore/flist.h>
 
 #include "queue.h"
+
+PA_STATIC_FLIST_DECLARE(entries, 0, pa_xfree);
 
 struct queue_entry {
     struct queue_entry *next;
@@ -44,25 +47,24 @@
 
 pa_queue* pa_queue_new(void) {
     pa_queue *q = pa_xnew(pa_queue, 1);
+
     q->front = q->back = NULL;
     q->length = 0;
+
     return q;
 }
 
 void pa_queue_free(pa_queue* q, void (*destroy)(void *p, void *userdata), void *userdata) {
-    struct queue_entry *e;
-    assert(q);
+    void *data;
+    pa_assert(q);
 
-    e = q->front;
-    while (e) {
-        struct queue_entry *n = e->next;
+    while ((data = pa_queue_pop(q)))
+        if (destroy)
+            destroy(data, userdata);
 
-        if (destroy)
-            destroy(e->data, userdata);
-
-        pa_xfree(e);
-        e = n;
-    }
+    pa_assert(!q->front);
+    pa_assert(!q->back);
+    pa_assert(q->length == 0);
 
     pa_xfree(q);
 }
@@ -70,14 +72,20 @@
 void pa_queue_push(pa_queue *q, void *p) {
     struct queue_entry *e;
 
-    e = pa_xnew(struct queue_entry, 1);
+    pa_assert(q);
+    pa_assert(p);
+
+    if (!(e = pa_flist_pop(PA_STATIC_FLIST_GET(entries))))
+        e = pa_xnew(struct queue_entry, 1);
+
     e->data = p;
     e->next = NULL;
 
-    if (q->back)
+    if (q->back) {
+        pa_assert(q->front);
         q->back->next = e;
-    else {
-        assert(!q->front);
+    } else {
+        pa_assert(!q->front);
         q->front = e;
     }
 
@@ -88,17 +96,22 @@
 void* pa_queue_pop(pa_queue *q) {
     void *p;
     struct queue_entry *e;
-    assert(q);
+    pa_assert(q);
 
     if (!(e = q->front))
         return NULL;
 
     q->front = e->next;
-    if (q->back == e)
+
+    if (q->back == e) {
+        pa_assert(!e->next);
         q->back = NULL;
+    }
 
     p = e->data;
-    pa_xfree(e);
+
+    if (pa_flist_push(PA_STATIC_FLIST_GET(entries), e) < 0)
+        pa_xfree(e);
 
     q->length--;
 
@@ -106,6 +119,7 @@
 }
 
 int pa_queue_is_empty(pa_queue *q) {
-    assert(q);
+    pa_assert(q);
+
     return q->length == 0;
 }

Modified: trunk/src/pulsecore/random.c
URL: http://0pointer.de/cgi-bin/viewcvs.cgi/trunk/src/pulsecore/random.c?rev=1971&root=pulseaudio&r1=1970&r2=1971&view=diff
==============================================================================
--- trunk/src/pulsecore/random.c (original)
+++ trunk/src/pulsecore/random.c Sun Oct 28 20:13:50 2007
@@ -31,21 +31,22 @@
 #include <errno.h>
 #include <string.h>
 #include <stdlib.h>
-#include <assert.h>
 #include <time.h>
 
 #include <pulsecore/core-util.h>
 #include <pulsecore/log.h>
+#include <pulsecore/macro.h>
 
 #include "random.h"
 
 static int has_whined = 0;
 
-static const char *devices[] = { "/dev/urandom", "/dev/random", NULL };
+static const char * const devices[] = { "/dev/urandom", "/dev/random", NULL };
 
 static int random_proper(void *ret_data, size_t length) {
 #ifdef OS_IS_WIN32
-    assert(ret_data && length);
+    pa_assert(ret_data);
+    pa_assert(length > 0);
 
     return -1;
 
@@ -53,9 +54,10 @@
 
     int fd, ret = -1;
     ssize_t r = 0;
-    const char **device;
+    const char *const * device;
 
-    assert(ret_data && length);
+    pa_assert(ret_data);
+    pa_assert(length > 0);
 
     device = devices;
 
@@ -67,7 +69,7 @@
             if ((r = pa_loop_read(fd, ret_data, length, NULL)) < 0 || (size_t) r != length)
                 ret = -1;
 
-            close(fd);
+            pa_close(fd);
         } else
             ret = -1;
 
@@ -84,7 +86,7 @@
 
     if (random_proper(&seed, sizeof(unsigned int)) < 0) {
         if (!has_whined)
-            pa_log_warn("failed to get proper entropy. Falling back to seeding with current time.");
+            pa_log_warn("Failed to get proper entropy. Falling back to seeding with current time.");
         has_whined = 1;
 
         seed = (unsigned int) time(NULL);
@@ -97,13 +99,14 @@
     uint8_t *p;
     size_t l;
 
-    assert(ret_data && length);
+    pa_assert(ret_data);
+    pa_assert(length > 0);
 
     if (random_proper(ret_data, length) >= 0)
         return;
 
     if (!has_whined)
-        pa_log_warn("failed to get proper entropy. Falling back to unsecure pseudo RNG.");
+        pa_log_warn("Failed to get proper entropy. Falling back to unsecure pseudo RNG.");
     has_whined = 1;
 
     for (p = ret_data, l = length; l > 0; p++, l--)

Modified: trunk/src/pulsecore/refcnt.h
URL: http://0pointer.de/cgi-bin/viewcvs.cgi/trunk/src/pulsecore/refcnt.h?rev=1971&root=pulseaudio&r1=1970&r2=1971&view=diff
==============================================================================
--- trunk/src/pulsecore/refcnt.h (original)
+++ trunk/src/pulsecore/refcnt.h Sun Oct 28 20:13:50 2007
@@ -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

Modified: trunk/src/pulsecore/resampler.c
URL: http://0pointer.de/cgi-bin/viewcvs.cgi/trunk/src/pulsecore/resampler.c?rev=1971&root=pulseaudio&r1=1970&r2=1971&view=diff
==============================================================================
--- trunk/src/pulsecore/resampler.c (original)
+++ trunk/src/pulsecore/resampler.c Sun Oct 28 20:13:50 2007
@@ -25,53 +25,133 @@
 #include <config.h>
 #endif
 
-#include <assert.h>
 #include <string.h>
 
+#if HAVE_LIBSAMPLERATE
 #include <samplerate.h>
+#endif
+
 #include <liboil/liboilfuncs.h>
 #include <liboil/liboil.h>
 
 #include <pulse/xmalloc.h>
-
 #include <pulsecore/sconv.h>
 #include <pulsecore/log.h>
+#include <pulsecore/macro.h>
+
+#include "speexwrap.h"
+
+#include "ffmpeg/avcodec.h"
 
 #include "resampler.h"
+
+/* Number of samples of extra space we allow the resamplers to return */
+#define EXTRA_SAMPLES 128
 
 struct pa_resampler {
     pa_resample_method_t resample_method;
     pa_sample_spec i_ss, o_ss;
     pa_channel_map i_cm, o_cm;
-    size_t i_fz, o_fz;
+    size_t i_fz, o_fz, w_sz;
     pa_mempool *mempool;
 
-    void (*impl_free)(pa_resampler *r);
-    void (*impl_update_input_rate)(pa_resampler *r, uint32_t rate);
-    void (*impl_run)(pa_resampler *r, const pa_memchunk *in, pa_memchunk *out);
-    void *impl_data;
-};
-
-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;
-    pa_convert_from_float32ne_func_t from_float32ne_func;
-    SRC_STATE *src_state;
+    pa_sample_format_t work_format;
+
+    pa_convert_func_t to_work_format_func;
+    pa_convert_func_t from_work_format_func;
 
     int map_table[PA_CHANNELS_MAX][PA_CHANNELS_MAX];
     int map_required;
+
+    void (*impl_free)(pa_resampler *r);
+    void (*impl_update_rates)(pa_resampler *r);
+    void (*impl_resample)(pa_resampler *r, const pa_memchunk *in, unsigned in_samples, pa_memchunk *out, unsigned *out_samples);
+
+    struct { /* data specific to the trivial resampler */
+        unsigned o_counter;
+        unsigned i_counter;
+    } trivial;
+
+#ifdef HAVE_LIBSAMPLERATE
+    struct { /* data specific to libsamplerate */
+        SRC_STATE *state;
+    } src;
+#endif
+
+    struct { /* data specific to speex */
+        SpeexResamplerState* state;
+    } speex;
+
+    struct { /* data specific to ffmpeg */
+        struct AVResampleContext *state;
+        pa_memchunk buf[PA_CHANNELS_MAX];
+    } ffmpeg;
 };
 
-struct impl_trivial {
-    unsigned o_counter;
-    unsigned i_counter;
+static int copy_init(pa_resampler *r);
+static int trivial_init(pa_resampler*r);
+static int speex_init(pa_resampler*r);
+static int ffmpeg_init(pa_resampler*r);
+#ifdef HAVE_LIBSAMPLERATE
+static int libsamplerate_init(pa_resampler*r);
+#endif
+
+static void calc_map_table(pa_resampler *r);
+
+static int (* const init_table[])(pa_resampler*r) = {
+#ifdef HAVE_LIBSAMPLERATE
+    [PA_RESAMPLER_SRC_SINC_BEST_QUALITY]   = libsamplerate_init,
+    [PA_RESAMPLER_SRC_SINC_MEDIUM_QUALITY] = libsamplerate_init,
+    [PA_RESAMPLER_SRC_SINC_FASTEST]        = libsamplerate_init,
+    [PA_RESAMPLER_SRC_ZERO_ORDER_HOLD]     = libsamplerate_init,
+    [PA_RESAMPLER_SRC_LINEAR]              = libsamplerate_init,
+#else
+    [PA_RESAMPLER_SRC_SINC_BEST_QUALITY]   = NULL,
+    [PA_RESAMPLER_SRC_SINC_MEDIUM_QUALITY] = NULL,
+    [PA_RESAMPLER_SRC_SINC_FASTEST]        = NULL,
+    [PA_RESAMPLER_SRC_ZERO_ORDER_HOLD]     = NULL,
+    [PA_RESAMPLER_SRC_LINEAR]              = NULL,
+#endif
+    [PA_RESAMPLER_TRIVIAL]                 = trivial_init,
+    [PA_RESAMPLER_SPEEX_FLOAT_BASE+0]      = speex_init,
+    [PA_RESAMPLER_SPEEX_FLOAT_BASE+1]      = speex_init,
+    [PA_RESAMPLER_SPEEX_FLOAT_BASE+2]      = speex_init,
+    [PA_RESAMPLER_SPEEX_FLOAT_BASE+3]      = speex_init,
+    [PA_RESAMPLER_SPEEX_FLOAT_BASE+4]      = speex_init,
+    [PA_RESAMPLER_SPEEX_FLOAT_BASE+5]      = speex_init,
+    [PA_RESAMPLER_SPEEX_FLOAT_BASE+6]      = speex_init,
+    [PA_RESAMPLER_SPEEX_FLOAT_BASE+7]      = speex_init,
+    [PA_RESAMPLER_SPEEX_FLOAT_BASE+8]      = speex_init,
+    [PA_RESAMPLER_SPEEX_FLOAT_BASE+9]      = speex_init,
+    [PA_RESAMPLER_SPEEX_FLOAT_BASE+10]     = speex_init,
+    [PA_RESAMPLER_SPEEX_FIXED_BASE+0]      = speex_init,
+    [PA_RESAMPLER_SPEEX_FIXED_BASE+1]      = speex_init,
+    [PA_RESAMPLER_SPEEX_FIXED_BASE+2]      = speex_init,
+    [PA_RESAMPLER_SPEEX_FIXED_BASE+3]      = speex_init,
+    [PA_RESAMPLER_SPEEX_FIXED_BASE+4]      = speex_init,
+    [PA_RESAMPLER_SPEEX_FIXED_BASE+5]      = speex_init,
+    [PA_RESAMPLER_SPEEX_FIXED_BASE+6]      = speex_init,
+    [PA_RESAMPLER_SPEEX_FIXED_BASE+7]      = speex_init,
+    [PA_RESAMPLER_SPEEX_FIXED_BASE+8]      = speex_init,
+    [PA_RESAMPLER_SPEEX_FIXED_BASE+9]      = speex_init,
+    [PA_RESAMPLER_SPEEX_FIXED_BASE+10]     = speex_init,
+    [PA_RESAMPLER_FFMPEG]                  = ffmpeg_init,
+    [PA_RESAMPLER_AUTO]                    = NULL,
+    [PA_RESAMPLER_COPY]                    = copy_init
 };
 
-static int libsamplerate_init(pa_resampler*r);
-static int trivial_init(pa_resampler*r);
+static inline size_t sample_size(pa_sample_format_t f) {
+    pa_sample_spec ss = {
+        .format = f,
+        .rate = 0,
+        .channels = 1
+    };
+
+    return pa_sample_size(&ss);
+}
 
 pa_resampler* pa_resampler_new(
         pa_mempool *pool,
@@ -79,25 +159,51 @@
         const pa_channel_map *am,
         const pa_sample_spec *b,
         const pa_channel_map *bm,
-        pa_resample_method_t resample_method) {
+        pa_resample_method_t resample_method,
+        int variable_rate) {
 
     pa_resampler *r = NULL;
 
-    assert(pool);
-    assert(a);
-    assert(b);
-    assert(pa_sample_spec_valid(a));
-    assert(pa_sample_spec_valid(b));
-    assert(resample_method != PA_RESAMPLER_INVALID);
+    pa_assert(pool);
+    pa_assert(a);
+    pa_assert(b);
+    pa_assert(pa_sample_spec_valid(a));
+    pa_assert(pa_sample_spec_valid(b));
+    pa_assert(resample_method >= 0);
+    pa_assert(resample_method < PA_RESAMPLER_MAX);
+
+    /* Fix method */
+
+    if (!variable_rate && a->rate == b->rate) {
+        pa_log_info("Forcing resampler 'copy', because of fixed, identical sample rates.");
+        resample_method = PA_RESAMPLER_COPY;
+    }
+
+    if (!pa_resample_method_supported(resample_method)) {
+        pa_log_warn("Support for resampler '%s' not compiled in, reverting to 'auto'.", pa_resample_method_to_string(resample_method));
+        resample_method = PA_RESAMPLER_AUTO;
+    }
+
+    if (resample_method == PA_RESAMPLER_FFMPEG && variable_rate) {
+        pa_log_info("Resampler 'ffmpeg' cannot do variable rate, reverting to resampler 'auto'.");
+        resample_method = PA_RESAMPLER_AUTO;
+    }
+
+    if (resample_method == PA_RESAMPLER_COPY && (variable_rate || a->rate != b->rate)) {
+        pa_log_info("Resampler 'copy' cannot change sampling rate, reverting to resampler 'auto'.");
+        resample_method = PA_RESAMPLER_AUTO;
+    }
+
+    if (resample_method == PA_RESAMPLER_AUTO)
+        resample_method = PA_RESAMPLER_SPEEX_FLOAT_BASE + 0;
 
     r = pa_xnew(pa_resampler, 1);
-    r->impl_data = NULL;
     r->mempool = pool;
     r->resample_method = resample_method;
 
     r->impl_free = NULL;
-    r->impl_update_input_rate = NULL;
-    r->impl_run = NULL;
+    r->impl_update_rates = NULL;
+    r->impl_resample = NULL;
 
     /* Fill sample specs */
     r->i_ss = *a;
@@ -116,24 +222,65 @@
     r->i_fz = pa_frame_size(a);
     r->o_fz = pa_frame_size(b);
 
-    /* Choose implementation */
-    if (a->channels != b->channels ||
-        a->format != b->format ||
-        !pa_channel_map_equal(&r->i_cm, &r->o_cm) ||
-        resample_method != PA_RESAMPLER_TRIVIAL) {
-
-        /* Use the libsamplerate based resampler for the complicated cases */
-        if (resample_method == PA_RESAMPLER_TRIVIAL)
-            r->resample_method = PA_RESAMPLER_SRC_ZERO_ORDER_HOLD;
-
-        if (libsamplerate_init(r) < 0)
+    pa_memchunk_reset(&r->buf1);
+    pa_memchunk_reset(&r->buf2);
+    pa_memchunk_reset(&r->buf3);
+    pa_memchunk_reset(&r->buf4);
+
+    r->buf1_samples = r->buf2_samples = r->buf3_samples = r->buf4_samples = 0;
+
+    calc_map_table(r);
+
+    pa_log_info("Using resampler '%s'", pa_resample_method_to_string(resample_method));
+
+    if ((resample_method >= PA_RESAMPLER_SPEEX_FIXED_BASE && resample_method <= PA_RESAMPLER_SPEEX_FIXED_MAX) ||
+        (resample_method == PA_RESAMPLER_FFMPEG))
+        r->work_format = PA_SAMPLE_S16NE;
+    else if (resample_method == PA_RESAMPLER_TRIVIAL || resample_method == PA_RESAMPLER_COPY) {
+
+        if (r->map_required || a->format != b->format) {
+
+            if (a->format == PA_SAMPLE_FLOAT32NE || a->format == PA_SAMPLE_FLOAT32RE ||
+                b->format == PA_SAMPLE_FLOAT32NE || b->format == PA_SAMPLE_FLOAT32RE)
+                r->work_format = PA_SAMPLE_FLOAT32NE;
+            else
+                r->work_format = PA_SAMPLE_S16NE;
+
+        } else
+            r->work_format = a->format;
+
+    } else
+        r->work_format = PA_SAMPLE_FLOAT32NE;
+
+    pa_log_info("Using %s as working format.", pa_sample_format_to_string(r->work_format));
+
+    r->w_sz = sample_size(r->work_format);
+
+    if (r->i_ss.format == r->work_format)
+        r->to_work_format_func = NULL;
+    else if (r->work_format == PA_SAMPLE_FLOAT32NE) {
+        if (!(r->to_work_format_func = pa_get_convert_to_float32ne_function(r->i_ss.format)))
             goto fail;
-
     } else {
-        /* Use our own simple non-fp resampler for the trivial cases and when the user selects it */
-        if (trivial_init(r) < 0)
+        pa_assert(r->work_format == PA_SAMPLE_S16NE);
+        if (!(r->to_work_format_func = pa_get_convert_to_s16ne_function(r->i_ss.format)))
             goto fail;
     }
+
+    if (r->o_ss.format == r->work_format)
+        r->from_work_format_func = NULL;
+    else if (r->work_format == PA_SAMPLE_FLOAT32NE) {
+        if (!(r->from_work_format_func = pa_get_convert_from_float32ne_function(r->o_ss.format)))
+            goto fail;
+    } else {
+        pa_assert(r->work_format == PA_SAMPLE_S16NE);
+        if (!(r->from_work_format_func = pa_get_convert_from_s16ne_function(r->o_ss.format)))
+            goto fail;
+    }
+
+    /* initialize implementation */
+    if (init_table[resample_method](r) < 0)
+        goto fail;
 
     return r;
 
@@ -145,41 +292,85 @@
 }
 
 void pa_resampler_free(pa_resampler *r) {
-    assert(r);
+    pa_assert(r);
 
     if (r->impl_free)
         r->impl_free(r);
 
+    if (r->buf1.memblock)
+        pa_memblock_unref(r->buf1.memblock);
+    if (r->buf2.memblock)
+        pa_memblock_unref(r->buf2.memblock);
+    if (r->buf3.memblock)
+        pa_memblock_unref(r->buf3.memblock);
+    if (r->buf4.memblock)
+        pa_memblock_unref(r->buf4.memblock);
+
     pa_xfree(r);
 }
 
 void pa_resampler_set_input_rate(pa_resampler *r, uint32_t rate) {
-    assert(r);
-    assert(rate > 0);
+    pa_assert(r);
+    pa_assert(rate > 0);
 
     if (r->i_ss.rate == rate)
         return;
 
     r->i_ss.rate = rate;
 
-    if (r->impl_update_input_rate)
-        r->impl_update_input_rate(r, rate);
-}
-
-void pa_resampler_run(pa_resampler *r, const pa_memchunk *in, pa_memchunk *out) {
-    assert(r && in && out && r->impl_run);
-
-    r->impl_run(r, in, out);
+    r->impl_update_rates(r);
+}
+
+void pa_resampler_set_output_rate(pa_resampler *r, uint32_t rate) {
+    pa_assert(r);
+    pa_assert(rate > 0);
+
+    if (r->o_ss.rate == rate)
+        return;
+
+    r->o_ss.rate = rate;
+
+    r->impl_update_rates(r);
 }
 
 size_t pa_resampler_request(pa_resampler *r, size_t out_length) {
-    assert(r);
+    pa_assert(r);
 
     return (((out_length / r->o_fz)*r->i_ss.rate)/r->o_ss.rate) * r->i_fz;
 }
 
+size_t pa_resampler_max_block_size(pa_resampler *r) {
+    size_t block_size_max;
+    pa_sample_spec ss;
+    size_t fs;
+
+    pa_assert(r);
+
+    block_size_max = pa_mempool_block_size_max(r->mempool);
+
+    /* We deduce the "largest" sample spec we're using during the
+     * conversion */
+    ss = r->i_ss;
+    if (r->o_ss.channels > ss.channels)
+        ss.channels = r->o_ss.channels;
+
+    /* We silently assume that the format enum is ordered by size */
+    if (r->o_ss.format > ss.format)
+        ss.format = r->o_ss.format;
+    if (r->work_format > ss.format)
+        ss.format = r->work_format;
+
+    if (r->o_ss.rate > ss.rate)
+        ss.rate = r->o_ss.rate;
+
+    fs = pa_frame_size(&ss);
+
+    return (((block_size_max/fs + EXTRA_SAMPLES)*r->i_ss.rate)/ss.rate)*r->i_fz;
+}
+
 pa_resample_method_t pa_resampler_get_method(pa_resampler *r) {
-    assert(r);
+    pa_assert(r);
+
     return r->resample_method;
 }
 
@@ -189,7 +380,32 @@
     "src-sinc-fastest",
     "src-zero-order-hold",
     "src-linear",
-    "trivial"
+    "trivial",
+    "speex-float-0",
+    "speex-float-1",
+    "speex-float-2",
+    "speex-float-3",
+    "speex-float-4",
+    "speex-float-5",
+    "speex-float-6",
+    "speex-float-7",
+    "speex-float-8",
+    "speex-float-9",
+    "speex-float-10",
+    "speex-fixed-0",
+    "speex-fixed-1",
+    "speex-fixed-2",
+    "speex-fixed-3",
+    "speex-fixed-4",
+    "speex-fixed-5",
+    "speex-fixed-6",
+    "speex-fixed-7",
+    "speex-fixed-8",
+    "speex-fixed-9",
+    "speex-fixed-10",
+    "ffmpeg",
+    "auto",
+    "copy"
 };
 
 const char *pa_resample_method_to_string(pa_resample_method_t m) {
@@ -200,52 +416,43 @@
     return resample_methods[m];
 }
 
+int pa_resample_method_supported(pa_resample_method_t m) {
+
+    if (m < 0 || m >= PA_RESAMPLER_MAX)
+        return 0;
+
+#ifndef HAVE_LIBSAMPLERATE
+    if (m <= PA_RESAMPLER_SRC_LINEAR)
+        return 0;
+#endif
+
+    return 1;
+}
+
 pa_resample_method_t pa_parse_resample_method(const char *string) {
     pa_resample_method_t m;
 
-    assert(string);
+    pa_assert(string);
 
     for (m = 0; m < PA_RESAMPLER_MAX; m++)
         if (!strcmp(string, resample_methods[m]))
             return m;
 
+    if (!strcmp(string, "speex-fixed"))
+        return PA_RESAMPLER_SPEEX_FIXED_BASE + 0;
+
+    if (!strcmp(string, "speex-float"))
+        return PA_RESAMPLER_SPEEX_FLOAT_BASE + 0;
+
     return PA_RESAMPLER_INVALID;
 }
 
-
-/*** libsamplerate based implementation ***/
-
-static void libsamplerate_free(pa_resampler *r) {
-    struct impl_libsamplerate *u;
-
-    assert(r);
-    assert(r->impl_data);
-
-    u = r->impl_data;
-
-    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);
-    pa_xfree(u);
-}
-
 static void calc_map_table(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)))
+
+    pa_assert(r);
+
+    if (!(r->map_required = (r->i_ss.channels != r->o_ss.channels || !pa_channel_map_equal(&r->i_cm, &r->o_cm))))
         return;
 
     for (oc = 0; oc < r->o_ss.channels; oc++) {
@@ -263,392 +470,590 @@
                 (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;
+                r->map_table[oc][i++] = ic;
         }
 
         /* Add an end marker */
         if (i < PA_CHANNELS_MAX)
-            u->map_table[oc][i] = -1;
-    }
-}
-
-static float * convert_to_float(pa_resampler *r, void *input, unsigned n_frames) {
-    struct impl_libsamplerate *u;
+            r->map_table[oc][i] = -1;
+    }
+}
+
+static pa_memchunk* convert_to_work_format(pa_resampler *r, pa_memchunk *input) {
     unsigned n_samples;
-
-    assert(r);
-    assert(input);
-    assert(r->impl_data);
-    u = r->impl_data;
-
-    /* Convert the incoming sample into floats and place them in buf1 */
-
-    if (!u->to_float32ne_func)
+    void *src, *dst;
+
+    pa_assert(r);
+    pa_assert(input);
+    pa_assert(input->memblock);
+
+    /* Convert the incoming sample into the work sample format and place them in buf1 */
+
+    if (!r->to_work_format_func || !input->length)
         return input;
 
-    n_samples = n_frames * r->i_ss.channels;
-
-    if (u->buf1_samples < n_samples) {
-        if (u->buf1_block)
-            pa_memblock_unref(u->buf1_block);
-
-        u->buf1_samples = n_samples;
-        u->buf1_block = pa_memblock_new(r->mempool, sizeof(float) * n_samples);
-        u->buf1 = u->buf1_block->data;
-    }
-
-    u->to_float32ne_func(n_samples, input, u->buf1);
-
-    return u->buf1;
-}
-
-static float *remap_channels(pa_resampler *r, float *input, unsigned n_frames) {
-    struct impl_libsamplerate *u;
-    unsigned n_samples;
+    n_samples = (input->length / r->i_fz) * r->i_ss.channels;
+
+    r->buf1.index = 0;
+    r->buf1.length = r->w_sz * n_samples;
+
+    if (!r->buf1.memblock || r->buf1_samples < n_samples) {
+        if (r->buf1.memblock)
+            pa_memblock_unref(r->buf1.memblock);
+
+        r->buf1_samples = n_samples;
+        r->buf1.memblock = pa_memblock_new(r->mempool, r->buf1.length);
+    }
+
+    src = (uint8_t*) pa_memblock_acquire(input->memblock) + input->index;
+    dst = (uint8_t*) pa_memblock_acquire(r->buf1.memblock);
+
+    r->to_work_format_func(n_samples, src, dst);
+
+    pa_memblock_release(input->memblock);
+    pa_memblock_release(r->buf1.memblock);
+
+    return &r->buf1;
+}
+
+static pa_memchunk *remap_channels(pa_resampler *r, pa_memchunk *input) {
+    unsigned in_n_samples, out_n_samples, n_frames;
     int i_skip, o_skip;
     unsigned oc;
-
-    assert(r);
-    assert(input);
-    assert(r->impl_data);
-    u = r->impl_data;
+    void *src, *dst;
+
+    pa_assert(r);
+    pa_assert(input);
+    pa_assert(input->memblock);
 
     /* Remap channels and place the result int buf2 */
 
-    if (!u->map_required)
+    if (!r->map_required || !input->length)
         return input;
 
-    n_samples = n_frames * r->o_ss.channels;
-
-    if (u->buf2_samples < n_samples) {
-        if (u->buf2_block)
-            pa_memblock_unref(u->buf2_block);
-
-        u->buf2_samples = n_samples;
-        u->buf2_block = pa_memblock_new(r->mempool, sizeof(float) * n_samples);
-        u->buf2 = u->buf2_block->data;
-    }
-
-    memset(u->buf2, 0, n_samples * sizeof(float));
-
-    o_skip = sizeof(float) * r->o_ss.channels;
-    i_skip = sizeof(float) * r->i_ss.channels;
-
-    for (oc = 0; oc < r->o_ss.channels; oc++) {
-        unsigned i;
-        static const float one = 1.0;
-
-        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,
-                n_frames,
-                &one, &one);
-    }
-
-    return u->buf2;
-}
-
-static float *resample(pa_resampler *r, float *input, unsigned *n_frames) {
-    struct impl_libsamplerate *u;
+    in_n_samples = input->length / r->w_sz;
+    n_frames = in_n_samples / r->i_ss.channels;
+    out_n_samples = n_frames * r->o_ss.channels;
+
+    r->buf2.index = 0;
+    r->buf2.length = r->w_sz * out_n_samples;
+
+    if (!r->buf2.memblock || r->buf2_samples < out_n_samples) {
+        if (r->buf2.memblock)
+            pa_memblock_unref(r->buf2.memblock);
+
+        r->buf2_samples = out_n_samples;
+        r->buf2.memblock = pa_memblock_new(r->mempool, r->buf2.length);
+    }
+
+    src = ((uint8_t*) pa_memblock_acquire(input->memblock) + input->index);
+    dst = pa_memblock_acquire(r->buf2.memblock);
+
+    memset(dst, 0, r->buf2.length);
+
+    o_skip = r->w_sz * r->o_ss.channels;
+    i_skip = r->w_sz * r->i_ss.channels;
+
+    switch (r->work_format) {
+        case PA_SAMPLE_FLOAT32NE:
+
+            for (oc = 0; oc < r->o_ss.channels; oc++) {
+                unsigned i;
+                static const float one = 1.0;
+
+                for (i = 0; i < PA_CHANNELS_MAX && r->map_table[oc][i] >= 0; i++)
+                    oil_vectoradd_f32(
+                            (float*) dst + oc, o_skip,
+                            (float*) dst + oc, o_skip,
+                            (float*) src + r->map_table[oc][i], i_skip,
+                            n_frames,
+                            &one, &one);
+            }
+
+            break;
+
+        case PA_SAMPLE_S16NE:
+
+            for (oc = 0; oc < r->o_ss.channels; oc++) {
+                unsigned i;
+                static const int16_t one = 1;
+
+                for (i = 0; i < PA_CHANNELS_MAX && r->map_table[oc][i] >= 0; i++)
+                    oil_vectoradd_s16(
+                            (int16_t*) dst + oc, o_skip,
+                            (int16_t*) dst + oc, o_skip,
+                            (int16_t*) src + r->map_table[oc][i], i_skip,
+                            n_frames,
+                            &one, &one);
+            }
+
+            break;
+
+        default:
+            pa_assert_not_reached();
+    }
+
+    pa_memblock_release(input->memblock);
+    pa_memblock_release(r->buf2.memblock);
+
+    r->buf2.length = out_n_samples * r->w_sz;
+
+    return &r->buf2;
+}
+
+static pa_memchunk *resample(pa_resampler *r, pa_memchunk *input) {
+    unsigned in_n_frames, in_n_samples;
+    unsigned out_n_frames, out_n_samples;
+
+    pa_assert(r);
+    pa_assert(input);
+
+    /* Resample the data and place the result in buf3 */
+
+    if (!r->impl_resample || !input->length)
+        return input;
+
+    in_n_samples = input->length / r->w_sz;
+    in_n_frames = in_n_samples / r->o_ss.channels;
+
+    out_n_frames = ((in_n_frames*r->o_ss.rate)/r->i_ss.rate)+EXTRA_SAMPLES;
+    out_n_samples = out_n_frames * r->o_ss.channels;
+
+    r->buf3.index = 0;
+    r->buf3.length = r->w_sz * out_n_samples;
+
+    if (!r->buf3.memblock || r->buf3_samples < out_n_samples) {
+        if (r->buf3.memblock)
+            pa_memblock_unref(r->buf3.memblock);
+
+        r->buf3_samples = out_n_samples;
+        r->buf3.memblock = pa_memblock_new(r->mempool, r->buf3.length);
+    }
+
+    r->impl_resample(r, input, in_n_frames, &r->buf3, &out_n_frames);
+    r->buf3.length = out_n_frames * r->w_sz * r->o_ss.channels;
+
+    return &r->buf3;
+}
+
+static pa_memchunk *convert_from_work_format(pa_resampler *r, pa_memchunk *input) {
+    unsigned n_samples, n_frames;
+    void *src, *dst;
+
+    pa_assert(r);
+    pa_assert(input);
+
+    /* Convert the data into the correct sample type and place the result in buf4 */
+
+    if (!r->from_work_format_func || !input->length)
+        return input;
+
+    n_samples = input->length / r->w_sz;
+    n_frames =  n_samples / r->o_ss.channels;
+
+    r->buf4.index = 0;
+    r->buf4.length = r->o_fz * n_frames;
+
+    if (!r->buf4.memblock || r->buf4_samples < n_samples) {
+        if (r->buf4.memblock)
+            pa_memblock_unref(r->buf4.memblock);
+
+        r->buf4_samples = n_samples;
+        r->buf4.memblock = pa_memblock_new(r->mempool, r->buf4.length);
+    }
+
+    src = (uint8_t*) pa_memblock_acquire(input->memblock) + input->index;
+    dst = pa_memblock_acquire(r->buf4.memblock);
+    r->from_work_format_func(n_samples, src, dst);
+    pa_memblock_release(input->memblock);
+    pa_memblock_release(r->buf4.memblock);
+
+    r->buf4.length = r->o_fz * n_frames;
+
+    return &r->buf4;
+}
+
+void pa_resampler_run(pa_resampler *r, const pa_memchunk *in, pa_memchunk *out) {
+    pa_memchunk *buf;
+
+    pa_assert(r);
+    pa_assert(in);
+    pa_assert(out);
+    pa_assert(in->length);
+    pa_assert(in->memblock);
+    pa_assert(in->length % r->i_fz == 0);
+
+    buf = (pa_memchunk*) in;
+    buf = convert_to_work_format(r, buf);
+    buf = remap_channels(r, buf);
+    buf = resample(r, buf);
+
+    if (buf->length) {
+        buf = convert_from_work_format(r, buf);
+        *out = *buf;
+
+        if (buf == in)
+            pa_memblock_ref(buf->memblock);
+        else
+            pa_memchunk_reset(buf);
+    } else
+        pa_memchunk_reset(out);
+}
+
+/*** libsamplerate based implementation ***/
+
+#ifdef HAVE_LIBSAMPLERATE
+static void libsamplerate_resample(pa_resampler *r, const pa_memchunk *input, unsigned in_n_frames, pa_memchunk *output, unsigned *out_n_frames) {
     SRC_DATA data;
-    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)
-        return input;
-
-    out_n_frames = (*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);
-
-        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;
-    }
-
-    data.data_in = input;
-    data.input_frames = *n_frames;
-
-    data.data_out = u->buf3;
-    data.output_frames = out_n_frames;
+
+    pa_assert(r);
+    pa_assert(input);
+    pa_assert(output);
+    pa_assert(out_n_frames);
+
+    memset(&data, 0, sizeof(data));
+
+    data.data_in = (float*) ((uint8_t*) pa_memblock_acquire(input->memblock) + input->index);
+    data.input_frames = in_n_frames;
+
+    data.data_out = (float*) ((uint8_t*) pa_memblock_acquire(output->memblock) + output->index);
+    data.output_frames = *out_n_frames;
 
     data.src_ratio = (double) r->o_ss.rate / r->i_ss.rate;
     data.end_of_input = 0;
 
-    ret = src_process(u->src_state, &data);
-    assert(ret == 0);
-    assert((unsigned) data.input_frames_used == *n_frames);
-
-    *n_frames = data.output_frames_gen;
-
-    return u->buf3;
-}
-
-static void *convert_from_float(pa_resampler *r, float *input, unsigned n_frames) {
-    struct impl_libsamplerate *u;
-    unsigned n_samples;
-
-    assert(r);
-    assert(input);
-    assert(r->impl_data);
-    u = r->impl_data;
-
-    /* Convert the data into the correct sample type and place the result in buf4 */
-
-    if (!u->from_float32ne_func)
-        return input;
-
-    n_samples = n_frames * r->o_ss.channels;
-
-    if (u->buf4_samples < n_samples) {
-        if (u->buf4_block)
-            pa_memblock_unref(u->buf4_block);
-
-        u->buf4_samples = n_samples;
-        u->buf4_block = pa_memblock_new(r->mempool, sizeof(float) * n_samples);
-        u->buf4 = u->buf4_block->data;
-    }
-
-    u->from_float32ne_func(n_samples, input, u->buf4);
-
-    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;
-
-    assert(r);
-    assert(in);
-    assert(out);
-    assert(in->length);
-    assert(in->memblock);
-    assert(in->length % r->i_fz == 0);
-    assert(r->impl_data);
-
-    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);
+    pa_assert_se(src_process(r->src.state, &data) == 0);
+    pa_assert((unsigned) data.input_frames_used == in_n_frames);
+
+    pa_memblock_release(input->memblock);
+    pa_memblock_release(output->memblock);
+
+    *out_n_frames = data.output_frames_gen;
+}
+
+static void libsamplerate_update_rates(pa_resampler *r) {
+    pa_assert(r);
+
+    pa_assert_se(src_set_ratio(r->src.state, (double) r->o_ss.rate / r->i_ss.rate) == 0);
+}
+
+static void libsamplerate_free(pa_resampler *r) {
+    pa_assert(r);
+
+    if (r->src.state)
+        src_delete(r->src.state);
+}
+
+static int libsamplerate_init(pa_resampler *r) {
+    int err;
+
+    pa_assert(r);
+
+    if (!(r->src.state = src_new(r->resample_method, r->o_ss.channels, &err)))
+        return -1;
+
+    r->impl_free = libsamplerate_free;
+    r->impl_update_rates = libsamplerate_update_rates;
+    r->impl_resample = libsamplerate_resample;
+
+    return 0;
+}
+#endif
+
+/*** speex based implementation ***/
+
+static void speex_resample_float(pa_resampler *r, const pa_memchunk *input, unsigned in_n_frames, pa_memchunk *output, unsigned *out_n_frames) {
+    float *in, *out;
+    uint32_t inf = in_n_frames, outf = *out_n_frames;
+
+    pa_assert(r);
+    pa_assert(input);
+    pa_assert(output);
+    pa_assert(out_n_frames);
+
+    in = (float*) ((uint8_t*) pa_memblock_acquire(input->memblock) + input->index);
+    out = (float*) ((uint8_t*) pa_memblock_acquire(output->memblock) + output->index);
+
+    pa_assert_se(paspfl_resampler_process_interleaved_float(r->speex.state, in, &inf, out, &outf) == 0);
+
+    pa_memblock_release(input->memblock);
+    pa_memblock_release(output->memblock);
+
+    pa_assert(inf == in_n_frames);
+    *out_n_frames = outf;
+}
+
+static void speex_resample_int(pa_resampler *r, const pa_memchunk *input, unsigned in_n_frames, pa_memchunk *output, unsigned *out_n_frames) {
+    int16_t *in, *out;
+    uint32_t inf = in_n_frames, outf = *out_n_frames;
+
+    pa_assert(r);
+    pa_assert(input);
+    pa_assert(output);
+    pa_assert(out_n_frames);
+
+    in = (int16_t*) ((uint8_t*) pa_memblock_acquire(input->memblock) + input->index);
+    out = (int16_t*) ((uint8_t*) pa_memblock_acquire(output->memblock) + output->index);
+
+    pa_assert_se(paspfx_resampler_process_interleaved_int(r->speex.state, in, &inf, out, &outf) == 0);
+
+    pa_memblock_release(input->memblock);
+    pa_memblock_release(output->memblock);
+
+    pa_assert(inf == in_n_frames);
+    *out_n_frames = outf;
+}
+
+static void speex_update_rates(pa_resampler *r) {
+    pa_assert(r);
+
+    if (r->resample_method >= PA_RESAMPLER_SPEEX_FIXED_BASE && r->resample_method <= PA_RESAMPLER_SPEEX_FIXED_MAX)
+        pa_assert_se(paspfx_resampler_set_rate(r->speex.state, r->i_ss.rate, r->o_ss.rate) == 0);
+    else {
+        pa_assert(r->resample_method >= PA_RESAMPLER_SPEEX_FLOAT_BASE && r->resample_method <= PA_RESAMPLER_SPEEX_FLOAT_MAX);
+        pa_assert_se(paspfl_resampler_set_rate(r->speex.state, r->i_ss.rate, r->o_ss.rate) == 0);
+    }
+}
+
+static void speex_free(pa_resampler *r) {
+    pa_assert(r);
+
+    if (!r->speex.state)
+        return;
+
+    if (r->resample_method >= PA_RESAMPLER_SPEEX_FIXED_BASE && r->resample_method <= PA_RESAMPLER_SPEEX_FIXED_MAX)
+        paspfx_resampler_destroy(r->speex.state);
+    else {
+        pa_assert(r->resample_method >= PA_RESAMPLER_SPEEX_FLOAT_BASE && r->resample_method <= PA_RESAMPLER_SPEEX_FLOAT_MAX);
+        paspfl_resampler_destroy(r->speex.state);
+    }
+}
+
+static int speex_init(pa_resampler *r) {
+    int q, err;
+
+    pa_assert(r);
+
+    r->impl_free = speex_free;
+    r->impl_update_rates = speex_update_rates;
+
+    if (r->resample_method >= PA_RESAMPLER_SPEEX_FIXED_BASE && r->resample_method <= PA_RESAMPLER_SPEEX_FIXED_MAX) {
+        q = r->resample_method - PA_RESAMPLER_SPEEX_FIXED_BASE;
+
+        pa_log_info("Choosing speex quality setting %i.", q);
+
+        if (!(r->speex.state = paspfx_resampler_init(r->o_ss.channels, r->i_ss.rate, r->o_ss.rate, q, &err)))
+            return -1;
+
+        r->impl_resample = speex_resample_int;
+    } else {
+        pa_assert(r->resample_method >= PA_RESAMPLER_SPEEX_FLOAT_BASE && r->resample_method <= PA_RESAMPLER_SPEEX_FLOAT_MAX);
+        q = r->resample_method - PA_RESAMPLER_SPEEX_FLOAT_BASE;
+
+        pa_log_info("Choosing speex quality setting %i.", q);
+
+        if (!(r->speex.state = paspfl_resampler_init(r->o_ss.channels, r->i_ss.rate, r->o_ss.rate, q, &err)))
+            return -1;
+
+        r->impl_resample = speex_resample_float;
+    }
+
+    return 0;
+}
+
+/* Trivial implementation */
+
+static void trivial_resample(pa_resampler *r, const pa_memchunk *input, unsigned in_n_frames, pa_memchunk *output, unsigned *out_n_frames) {
+    size_t fz;
+    unsigned o_index;
+    void *src, *dst;
+
+    pa_assert(r);
+    pa_assert(input);
+    pa_assert(output);
+    pa_assert(out_n_frames);
+
+    fz = r->w_sz * r->o_ss.channels;
+
+    src = (uint8_t*) pa_memblock_acquire(input->memblock) + input->index;
+    dst = (uint8_t*) pa_memblock_acquire(output->memblock) + output->index;
+
+    for (o_index = 0;; o_index++, r->trivial.o_counter++) {
+        unsigned j;
+
+        j = ((r->trivial.o_counter * r->i_ss.rate) / r->o_ss.rate);
+        j = j > r->trivial.i_counter ? j - r->trivial.i_counter : 0;
+
+        if (j >= in_n_frames)
+            break;
+
+        pa_assert(o_index * fz < pa_memblock_get_length(output->memblock));
+
+        oil_memcpy((uint8_t*) dst + fz * o_index,
+                   (uint8_t*) src + fz * j, fz);
+    }
+
+    pa_memblock_release(input->memblock);
+    pa_memblock_release(output->memblock);
+
+    *out_n_frames = o_index;
+
+    r->trivial.i_counter += in_n_frames;
+
+    /* Normalize counters */
+    while (r->trivial.i_counter >= r->i_ss.rate) {
+        pa_assert(r->trivial.o_counter >= r->o_ss.rate);
+
+        r->trivial.i_counter -= r->i_ss.rate;
+        r->trivial.o_counter -= r->o_ss.rate;
+    }
+}
+
+static void trivial_update_rates(pa_resampler *r) {
+    pa_assert(r);
+
+    r->trivial.i_counter = 0;
+    r->trivial.o_counter = 0;
+}
+
+static int trivial_init(pa_resampler*r) {
+    pa_assert(r);
+
+    r->trivial.o_counter = r->trivial.i_counter = 0;
+
+    r->impl_resample = trivial_resample;
+    r->impl_update_rates = trivial_update_rates;
+    r->impl_free = NULL;
+
+    return 0;
+}
+
+/*** ffmpeg based implementation ***/
+
+static void ffmpeg_resample(pa_resampler *r, const pa_memchunk *input, unsigned in_n_frames, pa_memchunk *output, unsigned *out_n_frames) {
+    unsigned used_frames = 0, c;
+
+    pa_assert(r);
+    pa_assert(input);
+    pa_assert(output);
+    pa_assert(out_n_frames);
+
+    for (c = 0; c < r->o_ss.channels; c++) {
+        unsigned u;
+        pa_memblock *b, *w;
+        int16_t *p, *t, *k, *q, *s;
+        int consumed_frames;
+        unsigned in, l;
+
+        /* Allocate a new block */
+        b = pa_memblock_new(r->mempool, r->ffmpeg.buf[c].length + in_n_frames * sizeof(int16_t));
+        p = pa_memblock_acquire(b);
+
+        /* Copy the remaining data into it */
+        l = r->ffmpeg.buf[c].length;
+        if (r->ffmpeg.buf[c].memblock) {
+            t = (int16_t*) ((uint8_t*) pa_memblock_acquire(r->ffmpeg.buf[c].memblock) + r->ffmpeg.buf[c].index);
+            memcpy(p, t, l);
+            pa_memblock_release(r->ffmpeg.buf[c].memblock);
+            pa_memblock_unref(r->ffmpeg.buf[c].memblock);
+            pa_memchunk_reset(&r->ffmpeg.buf[c]);
         }
-    } else {
-        out->memblock = NULL;
-        out->index = out->length = 0;
-    }
-}
-
-static void libsamplerate_update_input_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) r->o_ss.rate / rate);
-        assert(ret == 0);
-    }
-}
-
-static int libsamplerate_init(pa_resampler *r) {
-    struct impl_libsamplerate *u = NULL;
-    int err;
-
-    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;
-    u->buf1_samples = u->buf2_samples = u->buf3_samples = u->buf4_samples = 0;
-
-    if (r->i_ss.format == PA_SAMPLE_FLOAT32NE)
-        u->to_float32ne_func = NULL;
-    else if (!(u->to_float32ne_func = pa_get_convert_to_float32ne_function(r->i_ss.format)))
-        goto fail;
-
-    if (r->o_ss.format == PA_SAMPLE_FLOAT32NE)
-        u->from_float32ne_func = NULL;
-    else if (!(u->from_float32ne_func = pa_get_convert_from_float32ne_function(r->o_ss.format)))
-        goto fail;
-
-    if (r->o_ss.rate == r->i_ss.rate)
-        u->src_state = NULL;
-    else if (!(u->src_state = src_new(r->resample_method, r->o_ss.channels, &err)))
-        goto fail;
-
-    r->impl_free = libsamplerate_free;
-    r->impl_update_input_rate = libsamplerate_update_input_rate;
-    r->impl_run = libsamplerate_run;
-
-    calc_map_table(r);
+
+        /* Now append the new data, splitting up channels */
+        t = ((int16_t*) ((uint8_t*) pa_memblock_acquire(input->memblock) + input->index)) + c;
+        k = (int16_t*) ((uint8_t*) p + l);
+        for (u = 0; u < in_n_frames; u++) {
+            *k = *t;
+            t += r->o_ss.channels;
+            k ++;
+        }
+        pa_memblock_release(input->memblock);
+
+        /* Calculate the resulting number of frames */
+        in = in_n_frames + l / sizeof(int16_t);
+
+        /* Allocate buffer for the result */
+        w = pa_memblock_new(r->mempool, *out_n_frames * sizeof(int16_t));
+        q = pa_memblock_acquire(w);
+
+        /* Now, resample */
+        used_frames = av_resample(r->ffmpeg.state,
+                                  q, p,
+                                  &consumed_frames,
+                                  in, *out_n_frames,
+                                  c >= (unsigned) r->o_ss.channels-1);
+
+        pa_memblock_release(b);
+
+        /* Now store the remaining samples away */
+        pa_assert(consumed_frames <= (int) in);
+        if (consumed_frames < (int) in) {
+            r->ffmpeg.buf[c].memblock = b;
+            r->ffmpeg.buf[c].index = consumed_frames * sizeof(int16_t);
+            r->ffmpeg.buf[c].length = (in - consumed_frames) * sizeof(int16_t);
+        } else
+            pa_memblock_unref(b);
+
+        /* And place the results in the output buffer */
+        s = (short*) ((uint8_t*) pa_memblock_acquire(output->memblock) + output->index) + c;
+        for (u = 0; u < used_frames; u++) {
+            *s = *q;
+            q++;
+            s += r->o_ss.channels;
+        }
+        pa_memblock_release(output->memblock);
+        pa_memblock_release(w);
+        pa_memblock_unref(w);
+    }
+
+    *out_n_frames = used_frames;
+}
+
+static void ffmpeg_free(pa_resampler *r) {
+    unsigned c;
+
+    pa_assert(r);
+
+    if (r->ffmpeg.state)
+        av_resample_close(r->ffmpeg.state);
+
+    for (c = 0; c < PA_ELEMENTSOF(r->ffmpeg.buf); c++)
+        if (r->ffmpeg.buf[c].memblock)
+            pa_memblock_unref(r->ffmpeg.buf[c].memblock);
+}
+
+static int ffmpeg_init(pa_resampler *r) {
+    unsigned c;
+
+    pa_assert(r);
+
+    /* We could probably implement different quality levels by
+     * adjusting the filter parameters here. However, ffmpeg
+     * internally only uses these hardcoded values, so let's use them
+     * here for now as well until ffmpeg makes this configurable. */
+
+    if (!(r->ffmpeg.state = av_resample_init(r->o_ss.rate, r->i_ss.rate, 16, 10, 0, 0.8)))
+        return -1;
+
+    r->impl_free = ffmpeg_free;
+    r->impl_resample = ffmpeg_resample;
+
+    for (c = 0; c < PA_ELEMENTSOF(r->ffmpeg.buf); c++)
+        pa_memchunk_reset(&r->ffmpeg.buf[c]);
 
     return 0;
-
-fail:
-    pa_xfree(u);
-    return -1;
-}
-
-/* Trivial implementation */
-
-static void trivial_run(pa_resampler *r, const pa_memchunk *in, pa_memchunk *out) {
-    size_t fz;
-    unsigned  n_frames;
-    struct impl_trivial *u;
-
-    assert(r);
-    assert(in);
-    assert(out);
-    assert(r->impl_data);
-
-    u = r->impl_data;
-
-    fz = r->i_fz;
-    assert(fz == r->o_fz);
-
-    n_frames = in->length/fz;
-
-    if (r->i_ss.rate == r->o_ss.rate) {
-
-        /* In case there's no diefference in sample types, do nothing */
-        *out = *in;
-        pa_memblock_ref(out->memblock);
-
-        u->o_counter += n_frames;
-    } else {
-        /* Do real resampling */
-        size_t l;
-        unsigned o_index;
-
-        /* The length of the new memory block rounded up */
-        l = ((((n_frames+1) * r->o_ss.rate) / r->i_ss.rate) + 1) * fz;
-
-        out->index = 0;
-        out->memblock = pa_memblock_new(r->mempool, l);
-
-        for (o_index = 0;; o_index++, u->o_counter++) {
-            unsigned j;
-
-            j = (u->o_counter * r->i_ss.rate / r->o_ss.rate);
-            j = j > u->i_counter ? j - u->i_counter : 0;
-
-            if (j >= n_frames)
-                break;
-
-            assert(o_index*fz < out->memblock->length);
-
-            memcpy((uint8_t*) out->memblock->data + fz*o_index,
-                   (uint8_t*) in->memblock->data + in->index + fz*j, fz);
-
-        }
-
-        out->length = o_index*fz;
-    }
-
-    u->i_counter += n_frames;
-
-    /* Normalize counters */
-    while (u->i_counter >= r->i_ss.rate) {
-        u->i_counter -= r->i_ss.rate;
-        assert(u->o_counter >= r->o_ss.rate);
-        u->o_counter -= r->o_ss.rate;
-    }
-}
-
-static void trivial_free(pa_resampler *r) {
-    assert(r);
-
-    pa_xfree(r->impl_data);
-}
-
-static void trivial_update_input_rate(pa_resampler *r, uint32_t rate) {
-    struct impl_trivial *u;
-
-    assert(r);
-    assert(rate > 0);
-    assert(r->impl_data);
-
-    u = r->impl_data;
-    u->i_counter = 0;
-    u->o_counter = 0;
-}
-
-static int trivial_init(pa_resampler*r) {
-    struct impl_trivial *u;
-
-    assert(r);
-    assert(r->i_ss.format == r->o_ss.format);
-    assert(r->i_ss.channels == r->o_ss.channels);
-
-    r->impl_data = u = pa_xnew(struct impl_trivial, 1);
-    u->o_counter = u->i_counter = 0;
-
-    r->impl_run = trivial_run;
-    r->impl_free = trivial_free;
-    r->impl_update_input_rate = trivial_update_input_rate;
+}
+
+/*** copy (noop) implementation ***/
+
+static int copy_init(pa_resampler *r) {
+    pa_assert(r);
+
+    pa_assert(r->o_ss.rate == r->i_ss.rate);
+
+    r->impl_free = NULL;
+    r->impl_resample = NULL;
+    r->impl_update_rates = NULL;
 
     return 0;
 }
-
-

Modified: trunk/src/pulsecore/resampler.h
URL: http://0pointer.de/cgi-bin/viewcvs.cgi/trunk/src/pulsecore/resampler.h?rev=1971&root=pulseaudio&r1=1970&r2=1971&view=diff
==============================================================================
--- trunk/src/pulsecore/resampler.h (original)
+++ trunk/src/pulsecore/resampler.h Sun Oct 28 20:13:50 2007
@@ -24,8 +24,6 @@
   USA.
 ***/
 
-#include <samplerate.h>
-
 #include <pulse/sample.h>
 #include <pulse/channelmap.h>
 #include <pulsecore/memblock.h>
@@ -35,12 +33,19 @@
 
 typedef enum pa_resample_method {
     PA_RESAMPLER_INVALID                 = -1,
-    PA_RESAMPLER_SRC_SINC_BEST_QUALITY   = SRC_SINC_BEST_QUALITY,
-    PA_RESAMPLER_SRC_SINC_MEDIUM_QUALITY = SRC_SINC_MEDIUM_QUALITY,
-    PA_RESAMPLER_SRC_SINC_FASTEST        = SRC_SINC_FASTEST,
-    PA_RESAMPLER_SRC_ZERO_ORDER_HOLD     = SRC_ZERO_ORDER_HOLD,
-    PA_RESAMPLER_SRC_LINEAR              = SRC_LINEAR,
+    PA_RESAMPLER_SRC_SINC_BEST_QUALITY   = 0, /* = SRC_SINC_BEST_QUALITY */
+    PA_RESAMPLER_SRC_SINC_MEDIUM_QUALITY = 1, /* = SRC_SINC_MEDIUM_QUALITY */
+    PA_RESAMPLER_SRC_SINC_FASTEST        = 2, /* = SRC_SINC_FASTEST */
+    PA_RESAMPLER_SRC_ZERO_ORDER_HOLD     = 3, /* = SRC_ZERO_ORDER_HOLD */
+    PA_RESAMPLER_SRC_LINEAR              = 4, /* = SRC_LINEAR */
     PA_RESAMPLER_TRIVIAL,
+    PA_RESAMPLER_SPEEX_FLOAT_BASE,
+    PA_RESAMPLER_SPEEX_FLOAT_MAX = PA_RESAMPLER_SPEEX_FLOAT_BASE + 10,
+    PA_RESAMPLER_SPEEX_FIXED_BASE,
+    PA_RESAMPLER_SPEEX_FIXED_MAX = PA_RESAMPLER_SPEEX_FIXED_BASE + 10,
+    PA_RESAMPLER_FFMPEG,
+    PA_RESAMPLER_AUTO, /* automatic select based on sample format */
+    PA_RESAMPLER_COPY,
     PA_RESAMPLER_MAX
 } pa_resample_method_t;
 
@@ -50,18 +55,25 @@
         const pa_channel_map *am,
         const pa_sample_spec *b,
         const pa_channel_map *bm,
-        pa_resample_method_t resample_method);
+        pa_resample_method_t resample_method,
+        int variable_rate);
 
 void pa_resampler_free(pa_resampler *r);
 
 /* Returns the size of an input memory block which is required to return the specified amount of output data */
 size_t pa_resampler_request(pa_resampler *r, size_t out_length);
 
+/* Returns the maximum size of input blocks we can process without needing bounce buffers larger than the mempool tile size. */
+size_t pa_resampler_max_block_size(pa_resampler *r);
+
 /* Pass the specified memory chunk to the resampler and return the newly resampled data */
 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);
@@ -72,4 +84,7 @@
 /* return a human readable string for the specified resampling method. Inverse of pa_parse_resample_method() */
 const char *pa_resample_method_to_string(pa_resample_method_t m);
 
+/* Return 1 when the specified resampling method is supported */
+int pa_resample_method_supported(pa_resample_method_t m);
+
 #endif

Copied: trunk/src/pulsecore/rtpoll.h (from r1970, branches/lennart/src/pulsecore/rtpoll.h)
URL: http://0pointer.de/cgi-bin/viewcvs.cgi/trunk/src/pulsecore/rtpoll.h?p2=trunk/src/pulsecore/rtpoll.h&p1=branches/lennart/src/pulsecore/rtpoll.h&r1=1970&r2=1971&rev=1971&root=pulseaudio&view=diff
==============================================================================
--- branches/lennart/src/pulsecore/rtpoll.h (original)
+++ trunk/src/pulsecore/rtpoll.h Sun Oct 28 20:13:50 2007
@@ -58,7 +58,7 @@
     PA_RTPOLL_EARLY  = -100,          /* For veeery important stuff, like handling control messages */
     PA_RTPOLL_NORMAL = 0,             /* For normal stuff */
     PA_RTPOLL_LATE   = +100,          /* For housekeeping */
-    PA_RTPOLL_NEVER  = INT_MAX,       /* For stuff that doesn't register any callbacks, but only fds to listen on */ 
+    PA_RTPOLL_NEVER  = INT_MAX,       /* For stuff that doesn't register any callbacks, but only fds to listen on */
 } pa_rtpoll_priority_t;
 
 pa_rtpoll *pa_rtpoll_new(void);

Modified: trunk/src/pulsecore/sample-util.c
URL: http://0pointer.de/cgi-bin/viewcvs.cgi/trunk/src/pulsecore/sample-util.c?rev=1971&root=pulseaudio&r1=1970&r2=1971&view=diff
==============================================================================
--- trunk/src/pulsecore/sample-util.c (original)
+++ trunk/src/pulsecore/sample-util.c Sun Oct 28 20:13:50 2007
@@ -28,53 +28,71 @@
 
 #include <stdio.h>
 #include <string.h>
-#include <assert.h>
 #include <stdlib.h>
 
 #include <liboil/liboilfuncs.h>
+#include <liboil/liboil.h>
 
 #include <pulsecore/log.h>
+#include <pulsecore/macro.h>
 
 #include "sample-util.h"
 #include "endianmacros.h"
 
-#define PA_SILENCE_MAX (1024*1024*1)
+#define PA_SILENCE_MAX (PA_PAGE_SIZE*16)
 
 pa_memblock *pa_silence_memblock_new(pa_mempool *pool, const pa_sample_spec *spec, size_t length) {
     size_t fs;
-    assert(pool);
-    assert(spec);
-
-    if (length == 0)
+    pa_assert(pool);
+    pa_assert(spec);
+
+    if (length <= 0)
         length = pa_bytes_per_second(spec)/20; /* 50 ms */
 
     if (length > PA_SILENCE_MAX)
         length = PA_SILENCE_MAX;
 
     fs = pa_frame_size(spec);
-    length = ((PA_SILENCE_MAX+fs-1) / fs) * fs;
+
+    length = (length+fs-1)/fs;
 
     if (length <= 0)
-        length = fs;
+        length = 1;
+
+    length *= fs;
 
     return pa_silence_memblock(pa_memblock_new(pool, length), spec);
 }
 
 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;
+
+    pa_assert(b);
+    pa_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);
-
-    pa_silence_memory((uint8_t*) c->memblock->data+c->index, c->length, spec);
+    void *data;
+
+    pa_assert(c);
+    pa_assert(c->memblock);
+    pa_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) {
     uint8_t c = 0;
-    assert(p && length && spec);
+    pa_assert(p);
+    pa_assert(length > 0);
+    pa_assert(spec);
 
     switch (spec->format) {
         case PA_SAMPLE_U8:
@@ -87,37 +105,51 @@
             c = 0;
             break;
         case PA_SAMPLE_ALAW:
+            c = 0xd5;
+            break;
         case PA_SAMPLE_ULAW:
-            c = 80;
+            c = 0xff;
             break;
         default:
-            assert(0);
+            pa_assert_not_reached();
     }
 
     memset(p, c, length);
 }
 
 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) {
-
-    assert(streams && data && length && spec);
+        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;
+
+    pa_assert(streams);
+    pa_assert(data);
+    pa_assert(length);
+    pa_assert(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 +159,12 @@
                         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));
@@ -144,28 +176,27 @@
                     if (volume->values[channel] != PA_VOLUME_NORM)
                         sum = (int32_t) (sum * pa_sw_volume_to_linear(volume->values[channel]));
 
-                    if (sum < -0x8000) sum = -0x8000;
-                    if (sum > 0x7FFF) sum = 0x7FFF;
-
+                    sum = CLAMP(sum, -0x8000, 0x7FFF);
                 }
 
-                *((int16_t*) data) = sum;
+                *((int16_t*) data) = (int16_t) sum;
                 data = (uint8_t*) data + sizeof(int16_t);
 
                 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 +206,12 @@
                         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 = PA_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));
@@ -192,28 +223,27 @@
                     if (volume->values[channel] != PA_VOLUME_NORM)
                         sum = (int32_t) (sum * pa_sw_volume_to_linear(volume->values[channel]));
 
-                    if (sum < -0x8000) sum = -0x8000;
-                    if (sum > 0x7FFF) sum = 0x7FFF;
-
+                    sum = CLAMP(sum, -0x8000, 0x7FFF);
                 }
 
-                *((int16_t*) data) = INT16_SWAP(sum);
+                *((int16_t*) data) = PA_INT16_SWAP((int16_t) sum);
                 data = (uint8_t*) data + sizeof(int16_t);
 
                 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 +253,12 @@
                         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));
@@ -240,9 +270,7 @@
                     if (volume->values[channel] != PA_VOLUME_NORM)
                         sum = (int32_t) (sum * pa_sw_volume_to_linear(volume->values[channel]));
 
-                    if (sum < -0x80) sum = -0x80;
-                    if (sum > 0x7F) sum = 0x7F;
-
+                    sum = CLAMP(sum, -0x80, 0x7F);
                 }
 
                 *((uint8_t*) data) = (uint8_t) (sum + 0x80);
@@ -251,17 +279,18 @@
                 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 +300,12 @@
                         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,18 +324,35 @@
                 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();
     }
-}
-
-
-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));
-    assert(volume);
+
+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) {
+
+    void *ptr;
+
+    pa_assert(c);
+    pa_assert(spec);
+    pa_assert(c->length % pa_frame_size(spec) == 0);
+    pa_assert(volume);
 
     if (pa_cvolume_channels_equal_to(volume, PA_VOLUME_NORM))
         return;
@@ -316,24 +362,25 @@
         return;
     }
 
+    ptr = pa_memblock_acquire(c->memblock);
+
     switch (spec->format) {
+
         case PA_SAMPLE_S16NE: {
             int16_t *d;
             size_t n;
             unsigned channel;
-            double linear[PA_CHANNELS_MAX];
+            int32_t linear[PA_CHANNELS_MAX];
 
             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--) {
-                int32_t t = (int32_t)(*d);
-
-                t = (int32_t) (t * linear[channel]);
-
-                if (t < -0x8000) t = -0x8000;
-                if (t > 0x7FFF) t = 0x7FFF;
-
+                linear[channel] = (int32_t) (pa_sw_volume_to_linear(volume->values[channel]) * 0x10000);
+
+            for (channel = 0, d = (int16_t*) ((uint8_t*) ptr + c->index), n = c->length/sizeof(int16_t); n > 0; d++, n--) {
+                int32_t t;
+
+                t = (int32_t)(*d);
+                t = (t * linear[channel]) / 0x10000;
+                t = CLAMP(t, -0x8000, 0x7FFF);
                 *d = (int16_t) t;
 
                 if (++channel >= spec->channels)
@@ -346,20 +393,18 @@
             int16_t *d;
             size_t n;
             unsigned channel;
-            double linear[PA_CHANNELS_MAX];
+            int32_t linear[PA_CHANNELS_MAX];
 
             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--) {
-                int32_t t = (int32_t)(INT16_SWAP(*d));
-
-                t = (int32_t) (t * linear[channel]);
-
-                if (t < -0x8000) t = -0x8000;
-                if (t > 0x7FFF) t = 0x7FFF;
-
-                *d = INT16_SWAP((int16_t) t);
+                linear[channel] = (int32_t) (pa_sw_volume_to_linear(volume->values[channel]) * 0x10000);
+
+            for (channel = 0, d = (int16_t*) ((uint8_t*) ptr + c->index), n = c->length/sizeof(int16_t); n > 0; d++, n--) {
+                int32_t t;
+
+                t = (int32_t)(PA_INT16_SWAP(*d));
+                t = (t * linear[channel]) / 0x10000;
+                t = CLAMP(t, -0x8000, 0x7FFF);
+                *d = PA_INT16_SWAP((int16_t) t);
 
                 if (++channel >= spec->channels)
                     channel = 0;
@@ -371,16 +416,18 @@
         case PA_SAMPLE_U8: {
             uint8_t *d;
             size_t n;
-            unsigned channel = 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 = (int32_t) (t * pa_sw_volume_to_linear(volume->values[channel]));
-
-                if (t < -0x80) t = -0x80;
-                if (t > 0x7F) t = 0x7F;
-
+            unsigned channel;
+            int32_t linear[PA_CHANNELS_MAX];
+
+            for (channel = 0; channel < spec->channels; channel++)
+                linear[channel] = (int32_t) (pa_sw_volume_to_linear(volume->values[channel]) * 0x10000);
+
+            for (channel = 0, d = (uint8_t*) ptr + c->index, n = c->length; n > 0; d++, n--) {
+                int32_t t;
+
+                t = (int32_t) *d - 0x80;
+                t = (t * linear[channel]) / 0x10000;
+                t = CLAMP(t, -0x80, 0x7F);
                 *d = (uint8_t) (t + 0x80);
 
                 if (++channel >= spec->channels)
@@ -395,7 +442,7 @@
             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;
 
@@ -406,7 +453,6 @@
                     continue;
 
                 v = (float) pa_sw_volume_to_linear(volume->values[channel]);
-
                 t = d + channel;
                 oil_scalarmult_f32(t, skip, t, skip, &v, n);
             }
@@ -414,9 +460,85 @@
         }
 
         default:
-            pa_log_error("ERROR: Unable to change volume of format %s.",
-                pa_sample_format_to_string(spec->format));
-            abort();
+            pa_log_warn(" Unable to change volume of format %s.", pa_sample_format_to_string(spec->format));
+            /* If we cannot change the volume, we just don't do it */
     }
-}
-
+
+    pa_memblock_release(c->memblock);
+}
+
+size_t pa_frame_align(size_t l, const pa_sample_spec *ss) {
+    size_t fs;
+
+    pa_assert(ss);
+
+    fs = pa_frame_size(ss);
+
+    return (l/fs) * fs;
+}
+
+int pa_frame_aligned(size_t l, const pa_sample_spec *ss) {
+    size_t fs;
+
+    pa_assert(ss);
+
+    fs = pa_frame_size(ss);
+
+    return l % fs == 0;
+}
+
+void pa_interleave(const void *src[], unsigned channels, void *dst, size_t ss, unsigned n) {
+    unsigned c;
+    size_t fs;
+
+    pa_assert(src);
+    pa_assert(channels > 0);
+    pa_assert(dst);
+    pa_assert(ss > 0);
+    pa_assert(n > 0);
+
+    fs = ss * channels;
+
+    for (c = 0; c < channels; c++) {
+        unsigned j;
+        void *d;
+        const void *s;
+
+        s = src[c];
+        d = (uint8_t*) dst + c * ss;
+
+        for (j = 0; j < n; j ++) {
+            oil_memcpy(d, s, ss);
+            s = (uint8_t*) s + ss;
+            d = (uint8_t*) d + fs;
+        }
+    }
+}
+
+void pa_deinterleave(const void *src, void *dst[], unsigned channels, size_t ss, unsigned n) {
+    size_t fs;
+    unsigned c;
+
+    pa_assert(src);
+    pa_assert(dst);
+    pa_assert(channels > 0);
+    pa_assert(ss > 0);
+    pa_assert(n > 0);
+
+    fs = ss * channels;
+
+    for (c = 0; c < channels; c++) {
+        unsigned j;
+        const void *s;
+        void *d;
+
+        s = (uint8_t*) src + c * ss;
+        d = dst[c];
+
+        for (j = 0; j < n; j ++) {
+            oil_memcpy(d, s, ss);
+            s = (uint8_t*) s + fs;
+            d = (uint8_t*) d + ss;
+        }
+    }
+}

Modified: trunk/src/pulsecore/sample-util.h
URL: http://0pointer.de/cgi-bin/viewcvs.cgi/trunk/src/pulsecore/sample-util.h?rev=1971&root=pulseaudio&r1=1970&r2=1971&view=diff
==============================================================================
--- trunk/src/pulsecore/sample-util.h (original)
+++ trunk/src/pulsecore/sample-util.h Sun Oct 28 20:13:50 2007
@@ -39,10 +39,11 @@
     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,
@@ -55,4 +56,11 @@
     const pa_sample_spec *spec,
     const pa_cvolume *volume);
 
+size_t pa_frame_align(size_t l, const pa_sample_spec *ss) PA_GCC_PURE;
+
+int pa_frame_aligned(size_t l, const pa_sample_spec *ss) PA_GCC_PURE;
+
+void pa_interleave(const void *src[], unsigned channels, void *dst, size_t ss, unsigned n);
+void pa_deinterleave(const void *src, void *dst[], unsigned channels, size_t ss, unsigned n);
+
 #endif

Modified: trunk/src/pulsecore/sconv-s16be.c
URL: http://0pointer.de/cgi-bin/viewcvs.cgi/trunk/src/pulsecore/sconv-s16be.c?rev=1971&root=pulseaudio&r1=1970&r2=1971&view=diff
==============================================================================
--- trunk/src/pulsecore/sconv-s16be.c (original)
+++ trunk/src/pulsecore/sconv-s16be.c Sun Oct 28 20:13:50 2007
@@ -27,11 +27,14 @@
 
 #include "endianmacros.h"
 
-#define INT16_FROM INT16_FROM_BE
-#define INT16_TO INT16_TO_BE
+#define INT16_FROM PA_INT16_FROM_BE
+#define INT16_TO PA_INT16_TO_BE
 
 #define pa_sconv_s16le_to_float32ne pa_sconv_s16be_to_float32ne
 #define pa_sconv_s16le_from_float32ne pa_sconv_s16be_from_float32ne
+
+#define pa_sconv_s16le_to_float32re pa_sconv_s16be_to_float32re
+#define pa_sconv_s16le_from_float32re pa_sconv_s16be_from_float32re
 
 #ifdef WORDS_BIGENDIAN
 #define SWAP_WORDS 0

Modified: trunk/src/pulsecore/sconv-s16be.h
URL: http://0pointer.de/cgi-bin/viewcvs.cgi/trunk/src/pulsecore/sconv-s16be.h?rev=1971&root=pulseaudio&r1=1970&r2=1971&view=diff
==============================================================================
--- trunk/src/pulsecore/sconv-s16be.h (original)
+++ trunk/src/pulsecore/sconv-s16be.h Sun Oct 28 20:13:50 2007
@@ -24,7 +24,18 @@
   USA.
 ***/
 
-void pa_sconv_s16be_to_float32ne(unsigned n, const void *a, float *b);
-void pa_sconv_s16be_from_float32ne(unsigned n, const float *a, void *b);
+#include <inttypes.h>
+
+void pa_sconv_s16be_to_float32ne(unsigned n, const int16_t *a, float *b);
+void pa_sconv_s16be_from_float32ne(unsigned n, const float *a, int16_t *b);
+void pa_sconv_s16be_to_float32re(unsigned n, const int16_t *a, float *b);
+void pa_sconv_s16be_from_float32re(unsigned n, const float *a, int16_t *b);
+
+#ifdef WORDS_BIGENDIAN
+#define pa_sconv_float32be_to_s16ne pa_sconv_s16be_from_float32ne
+#define pa_sconv_float32be_from_s16ne pa_sconv_s16be_to_float32ne
+#define pa_sconv_float32le_to_s16ne pa_sconv_s16be_from_float32re
+#define pa_sconv_float32le_from_s16ne pa_sconv_s16be_to_float32re
+#endif
 
 #endif

Modified: trunk/src/pulsecore/sconv-s16le.c
URL: http://0pointer.de/cgi-bin/viewcvs.cgi/trunk/src/pulsecore/sconv-s16le.c?rev=1971&root=pulseaudio&r1=1970&r2=1971&view=diff
==============================================================================
--- trunk/src/pulsecore/sconv-s16le.c (original)
+++ trunk/src/pulsecore/sconv-s16le.c Sun Oct 28 20:13:50 2007
@@ -25,12 +25,12 @@
 #include <config.h>
 #endif
 
-#include <assert.h>
 #include <inttypes.h>
 
 #include <liboil/liboilfuncs.h>
 
 #include <pulsecore/sconv.h>
+#include <pulsecore/macro.h>
 #include <pulsecore/log.h>
 
 #include "endianmacros.h"
@@ -38,11 +38,11 @@
 #include "sconv-s16le.h"
 
 #ifndef INT16_FROM
-#define INT16_FROM INT16_FROM_LE
+#define INT16_FROM PA_INT16_FROM_LE
 #endif
 
 #ifndef INT16_TO
-#define INT16_TO INT16_TO_LE
+#define INT16_TO PA_INT16_TO_LE
 #endif
 
 #ifndef SWAP_WORDS
@@ -53,32 +53,28 @@
 #endif
 #endif
 
-void pa_sconv_s16le_to_float32ne(unsigned n, const void *a, float *b) {
-    const int16_t *ca = a;
-
-    assert(a);
-    assert(b);
+void pa_sconv_s16le_to_float32ne(unsigned n, const int16_t *a, float *b) {
+    pa_assert(a);
+    pa_assert(b);
 
 #if SWAP_WORDS == 1
 
     for (; n > 0; n--) {
-        int16_t s = *(ca++);
+        int16_t s = *(a++);
         *(b++) = ((float) INT16_FROM(s))/0x7FFF;
     }
 
 #else
 {
     static const double add = 0, factor = 1.0/0x7FFF;
-    oil_scaleconv_f32_s16(b, ca, n, &add, &factor);
+    oil_scaleconv_f32_s16(b, a, n, &add, &factor);
 }
 #endif
 }
 
-void pa_sconv_s16le_from_float32ne(unsigned n, const float *a, void *b) {
-    int16_t *cb = b;
-
-    assert(a);
-    assert(b);
+void pa_sconv_s16le_from_float32ne(unsigned n, const float *a, int16_t *b) {
+    pa_assert(a);
+    pa_assert(b);
 
 #if SWAP_WORDS == 1
 
@@ -86,20 +82,43 @@
         int16_t s;
         float v = *(a++);
 
-        if (v > 1)
-            v = 1;
-
-        if (v < -1)
-            v = -1;
-
+        v = CLAMP(v, -1, 1);
         s = (int16_t) (v * 0x7FFF);
-        *(cb++) = INT16_TO(s);
+        *(b++) = INT16_TO(s);
     }
 
 #else
 {
     static const double add = 0, factor = 0x7FFF;
-    oil_scaleconv_s16_f32(cb, a, n, &add, &factor);
+    oil_scaleconv_s16_f32(b, a, n, &add, &factor);
 }
 #endif
 }
+
+void pa_sconv_s16le_to_float32re(unsigned n, const int16_t *a, float *b) {
+    pa_assert(a);
+    pa_assert(b);
+
+    for (; n > 0; n--) {
+        int16_t s = *(a++);
+        float k = ((float) INT16_FROM(s))/0x7FFF;
+        uint32_t *j = (uint32_t*) &k;
+        *j = PA_UINT32_SWAP(*j);
+        *(b++) = k;
+    }
+}
+
+void pa_sconv_s16le_from_float32re(unsigned n, const float *a, int16_t *b) {
+    pa_assert(a);
+    pa_assert(b);
+
+    for (; n > 0; n--) {
+        int16_t s;
+        float v = *(a++);
+        uint32_t *j = (uint32_t*) &v;
+        *j = PA_UINT32_SWAP(*j);
+        v = CLAMP(v, -1, 1);
+        s = (int16_t) (v * 0x7FFF);
+        *(b++) = INT16_TO(s);
+    }
+}

Modified: trunk/src/pulsecore/sconv-s16le.h
URL: http://0pointer.de/cgi-bin/viewcvs.cgi/trunk/src/pulsecore/sconv-s16le.h?rev=1971&root=pulseaudio&r1=1970&r2=1971&view=diff
==============================================================================
--- trunk/src/pulsecore/sconv-s16le.h (original)
+++ trunk/src/pulsecore/sconv-s16le.h Sun Oct 28 20:13:50 2007
@@ -24,7 +24,18 @@
   USA.
 ***/
 
-void pa_sconv_s16le_to_float32ne(unsigned n, const void *a, float *b);
-void pa_sconv_s16le_from_float32ne(unsigned n, const float *a, void *b);
+#include <inttypes.h>
+
+void pa_sconv_s16le_to_float32ne(unsigned n, const int16_t *a, float *b);
+void pa_sconv_s16le_from_float32ne(unsigned n, const float *a, int16_t *b);
+void pa_sconv_s16le_to_float32re(unsigned n, const int16_t *a, float *b);
+void pa_sconv_s16le_from_float32re(unsigned n, const float *a, int16_t *b);
+
+#ifndef WORDS_BIGENDIAN
+#define pa_sconv_float32be_to_s16ne pa_sconv_s16le_from_float32re
+#define pa_sconv_float32be_from_s16ne pa_sconv_s16le_to_float32re
+#define pa_sconv_float32le_to_s16ne pa_sconv_s16le_from_float32ne
+#define pa_sconv_float32le_from_s16ne pa_sconv_s16le_to_float32ne
+#endif
 
 #endif

Modified: trunk/src/pulsecore/sconv.c
URL: http://0pointer.de/cgi-bin/viewcvs.cgi/trunk/src/pulsecore/sconv.c?rev=1971&root=pulseaudio&r1=1970&r2=1971&view=diff
==============================================================================
--- trunk/src/pulsecore/sconv.c (original)
+++ trunk/src/pulsecore/sconv.c Sun Oct 28 20:13:50 2007
@@ -28,12 +28,12 @@
 
 #include <stdio.h>
 #include <stdlib.h>
-#include <assert.h>
 
 #include <liboil/liboilfuncs.h>
 #include <liboil/liboil.h>
 
 #include <pulsecore/g711.h>
+#include <pulsecore/macro.h>
 
 #include "endianmacros.h"
 #include "sconv-s16le.h"
@@ -41,152 +41,223 @@
 
 #include "sconv.h"
 
-static void u8_to_float32ne(unsigned n, const void *a, float *b) {
-    const uint8_t *ca = a;
-    static const double add = -128.0/127.0, factor = 1.0/127.0;
-
-    assert(a);
-    assert(b);
-
-    oil_scaleconv_f32_u8(b, ca, n, &add, &factor);
-}
-
-static void u8_from_float32ne(unsigned n, const float *a, void *b) {
-    uint8_t *cb = b;
-    static const double add = 128.0, factor = 127.0;
-
-    assert(a);
-    assert(b);
-
-    oil_scaleconv_u8_f32(cb, a, n, &add, &factor);
-}
-
-static void float32ne_to_float32ne(unsigned n, const void *a, float *b) {
-    assert(a);
-    assert(b);
+/* u8 */
+static void u8_to_float32ne(unsigned n, const uint8_t *a, float *b) {
+    static const double add = -1, factor = 1.0/128.0;
+
+    pa_assert(a);
+    pa_assert(b);
+
+    oil_scaleconv_f32_u8(b, a, n, &add, &factor);
+}
+
+static void u8_from_float32ne(unsigned n, const float *a, uint8_t *b) {
+    static const double add = 128, factor = 127.0;
+
+    pa_assert(a);
+    pa_assert(b);
+
+    oil_scaleconv_u8_f32(b, a, n, &add, &factor);
+}
+
+static void u8_to_s16ne(unsigned n, const uint8_t *a, int16_t *b) {
+    static const int16_t add = -0x80, factor = 0x100;
+
+    pa_assert(a);
+    pa_assert(b);
+
+    oil_conv_s16_u8(b, 2, a, 1, n);
+    oil_scalaradd_s16(b, 2, b, 2, &add, n);
+    oil_scalarmult_s16(b, 2, b, 2, &factor, n);
+}
+
+static void u8_from_s16ne(unsigned n, const int16_t *a, uint8_t *b) {
+
+    pa_assert(a);
+    pa_assert(b);
+
+    for (; n > 0; n--, a++, b++)
+        *b = (uint8_t) (*a / 0x100 + 0x80);
+}
+
+/* float32 */
+
+static void float32ne_to_float32ne(unsigned n, const float *a, float *b) {
+    pa_assert(a);
+    pa_assert(b);
 
     oil_memcpy(b, a, sizeof(float) * n);
 }
 
-static void float32ne_from_float32ne(unsigned n, const float *a, void *b) {
-    assert(a);
-    assert(b);
-
-    oil_memcpy(b, a, sizeof(float) * n);
-}
-
-static void float32re_to_float32ne(unsigned n, const void *a, float *b) {
-    assert(a);
-    assert(b);
-
-    while (n-- > 0)
-        ((uint32_t *)b)[n] = UINT32_SWAP (((uint32_t *)a)[n]);
-}
-
-static void float32re_from_float32ne(unsigned n, const float *a, void *b) {
-    assert(a);
-    assert(b);
-
-    while (n-- > 0)
-        ((uint32_t *)b)[n] = UINT32_SWAP (((uint32_t *)a)[n]);
-}
-
-static void ulaw_to_float32ne(unsigned n, const void *a, float *b) {
-    const uint8_t *ca = a;
-
-    assert(a);
-    assert(b);
+static void float32re_to_float32ne(unsigned n, const float *a, float *b) {
+    pa_assert(a);
+    pa_assert(b);
+
+    for (; n > 0; n--, a++, b++)
+        *((uint32_t *) b) = PA_UINT32_SWAP(*((uint32_t *) a));
+}
+
+/* s16 */
+
+static void s16ne_to_s16ne(unsigned n, const int16_t *a, int16_t *b) {
+    pa_assert(a);
+    pa_assert(b);
+
+    oil_memcpy(b, a, sizeof(int16_t) * n);
+}
+
+static void s16re_to_s16ne(unsigned n, const int16_t *a, int16_t *b) {
+    pa_assert(a);
+    pa_assert(b);
+
+    for (; n > 0; n--, a++, b++)
+        *b = PA_UINT16_SWAP(*a);
+}
+
+/* ulaw */
+
+static void ulaw_to_float32ne(unsigned n, const uint8_t *a, float *b) {
+    pa_assert(a);
+    pa_assert(b);
 
     for (; n > 0; n--)
-        *(b++) = st_ulaw2linear16(*(ca++)) * 1.0F / 0x7FFF;
-}
-
-static void ulaw_from_float32ne(unsigned n, const float *a, void *b) {
-    uint8_t *cb = b;
-
-    assert(a);
-    assert(b);
+        *(b++) = (float) st_ulaw2linear16(*(a++)) / 0x8000;
+}
+
+static void ulaw_from_float32ne(unsigned n, const float *a, uint8_t *b) {
+    pa_assert(a);
+    pa_assert(b);
 
     for (; n > 0; n--) {
         float v = *(a++);
-
-        if (v > 1)
-            v = 1;
-
-        if (v < -1)
-            v = -1;
-
-        *(cb++) = st_14linear2ulaw((int16_t) (v * 0x1FFF));
+        v = CLAMP(v, -1, 1);
+        v *= 0x1FFF;
+        *(b++) = st_14linear2ulaw((int16_t) v);
     }
 }
 
-static void alaw_to_float32ne(unsigned n, const void *a, float *b) {
-    const uint8_t *ca = a;
-
-    assert(a);
-    assert(b);
-
-    for (; n > 0; n--)
-        *(b++) = st_alaw2linear16(*(ca++)) * 1.0F / 0x7FFF;
-}
-
-static void alaw_from_float32ne(unsigned n, const float *a, void *b) {
-    uint8_t *cb = b;
-
-    assert(a);
-    assert(b);
-
-    for (; n > 0; n--) {
-        float v = *(a++);
-
-        if (v > 1)
-            v = 1;
-
-        if (v < -1)
-            v = -1;
-
-        *(cb++) = st_13linear2alaw((int16_t) (v * 0xFFF));
+static void ulaw_to_s16ne(unsigned n, const uint8_t *a, int16_t *b) {
+    pa_assert(a);
+    pa_assert(b);
+
+    for (; n > 0; n--, a++, b++)
+        *b = st_ulaw2linear16(*a);
+}
+
+static void ulaw_from_s16ne(unsigned n, const int16_t *a, uint8_t *b) {
+    pa_assert(a);
+    pa_assert(b);
+
+    for (; n > 0; n--, a++, b++)
+        *b = st_14linear2ulaw(*a >> 2);
+}
+
+/* alaw */
+
+static void alaw_to_float32ne(unsigned n, const uint8_t *a, float *b) {
+    pa_assert(a);
+    pa_assert(b);
+
+    for (; n > 0; n--, a++, b++)
+        *b = (float) st_alaw2linear16(*a) / 0x8000;
+}
+
+static void alaw_from_float32ne(unsigned n, const float *a, uint8_t *b) {
+    pa_assert(a);
+    pa_assert(b);
+
+    for (; n > 0; n--, a++, b++) {
+        float v = *a;
+        v = CLAMP(v, -1, 1);
+        v *= 0xFFF;
+        *b = st_13linear2alaw((int16_t) v);
     }
 }
 
-pa_convert_to_float32ne_func_t pa_get_convert_to_float32ne_function(pa_sample_format_t f) {
-    switch(f) {
-        case PA_SAMPLE_U8:
-            return u8_to_float32ne;
-        case PA_SAMPLE_S16LE:
-            return pa_sconv_s16le_to_float32ne;
-        case PA_SAMPLE_S16BE:
-            return pa_sconv_s16be_to_float32ne;
-        case PA_SAMPLE_FLOAT32NE:
-            return float32ne_to_float32ne;
-        case PA_SAMPLE_FLOAT32RE:
-            return float32re_to_float32ne;
-        case PA_SAMPLE_ALAW:
-            return alaw_to_float32ne;
-        case PA_SAMPLE_ULAW:
-            return ulaw_to_float32ne;
-        default:
-            return NULL;
-    }
-}
-
-pa_convert_from_float32ne_func_t pa_get_convert_from_float32ne_function(pa_sample_format_t f) {
-    switch(f) {
-        case PA_SAMPLE_U8:
-            return u8_from_float32ne;
-        case PA_SAMPLE_S16LE:
-            return pa_sconv_s16le_from_float32ne;
-        case PA_SAMPLE_S16BE:
-            return pa_sconv_s16be_from_float32ne;
-        case PA_SAMPLE_FLOAT32NE:
-            return float32ne_from_float32ne;
-        case PA_SAMPLE_FLOAT32RE:
-            return float32re_from_float32ne;
-        case PA_SAMPLE_ALAW:
-            return alaw_from_float32ne;
-        case PA_SAMPLE_ULAW:
-            return ulaw_from_float32ne;
-        default:
-            return NULL;
-    }
-}
+static void alaw_to_s16ne(unsigned n, const int8_t *a, int16_t *b) {
+    pa_assert(a);
+    pa_assert(b);
+
+    for (; n > 0; n--, a++, b++)
+        *b = st_alaw2linear16(*a);
+}
+
+static void alaw_from_s16ne(unsigned n, const int16_t *a, uint8_t *b) {
+    pa_assert(a);
+    pa_assert(b);
+
+    for (; n > 0; n--, a++, b++)
+        *b = st_13linear2alaw(*a >> 3);
+}
+
+pa_convert_func_t pa_get_convert_to_float32ne_function(pa_sample_format_t f) {
+
+    static const pa_convert_func_t table[] = {
+        [PA_SAMPLE_U8]        = (pa_convert_func_t) u8_to_float32ne,
+        [PA_SAMPLE_ALAW]      = (pa_convert_func_t) alaw_to_float32ne,
+        [PA_SAMPLE_ULAW]      = (pa_convert_func_t) ulaw_to_float32ne,
+        [PA_SAMPLE_S16LE]     = (pa_convert_func_t) pa_sconv_s16le_to_float32ne,
+        [PA_SAMPLE_S16BE]     = (pa_convert_func_t) pa_sconv_s16be_to_float32ne,
+        [PA_SAMPLE_FLOAT32NE] = (pa_convert_func_t) float32ne_to_float32ne,
+        [PA_SAMPLE_FLOAT32RE] = (pa_convert_func_t) float32re_to_float32ne,
+    };
+
+    pa_assert(f >= 0);
+    pa_assert(f < PA_SAMPLE_MAX);
+
+    return table[f];
+}
+
+pa_convert_func_t pa_get_convert_from_float32ne_function(pa_sample_format_t f) {
+
+    static const pa_convert_func_t table[] = {
+        [PA_SAMPLE_U8]        = (pa_convert_func_t) u8_from_float32ne,
+        [PA_SAMPLE_S16LE]     = (pa_convert_func_t) pa_sconv_s16le_from_float32ne,
+        [PA_SAMPLE_S16BE]     = (pa_convert_func_t) pa_sconv_s16be_from_float32ne,
+        [PA_SAMPLE_FLOAT32NE] = (pa_convert_func_t) float32ne_to_float32ne,
+        [PA_SAMPLE_FLOAT32RE] = (pa_convert_func_t) float32re_to_float32ne,
+        [PA_SAMPLE_ALAW]      = (pa_convert_func_t) alaw_from_float32ne,
+        [PA_SAMPLE_ULAW]      = (pa_convert_func_t) ulaw_from_float32ne
+    };
+
+    pa_assert(f >= 0);
+    pa_assert(f < PA_SAMPLE_MAX);
+
+    return table[f];
+}
+
+pa_convert_func_t pa_get_convert_to_s16ne_function(pa_sample_format_t f) {
+
+    static const pa_convert_func_t table[] = {
+        [PA_SAMPLE_U8]        = (pa_convert_func_t) u8_to_s16ne,
+        [PA_SAMPLE_S16NE]     = (pa_convert_func_t) s16ne_to_s16ne,
+        [PA_SAMPLE_S16RE]     = (pa_convert_func_t) s16re_to_s16ne,
+        [PA_SAMPLE_FLOAT32BE] = (pa_convert_func_t) pa_sconv_float32be_to_s16ne,
+        [PA_SAMPLE_FLOAT32LE] = (pa_convert_func_t) pa_sconv_float32le_to_s16ne,
+        [PA_SAMPLE_ALAW]      = (pa_convert_func_t) alaw_to_s16ne,
+        [PA_SAMPLE_ULAW]      = (pa_convert_func_t) ulaw_to_s16ne
+    };
+
+    pa_assert(f >= 0);
+    pa_assert(f < PA_SAMPLE_MAX);
+
+    return table[f];
+}
+
+pa_convert_func_t pa_get_convert_from_s16ne_function(pa_sample_format_t f) {
+
+    static const pa_convert_func_t table[] = {
+        [PA_SAMPLE_U8]        = (pa_convert_func_t) u8_from_s16ne,
+        [PA_SAMPLE_S16NE]     = (pa_convert_func_t) s16ne_to_s16ne,
+        [PA_SAMPLE_S16RE]     = (pa_convert_func_t) s16re_to_s16ne,
+        [PA_SAMPLE_FLOAT32BE] = (pa_convert_func_t) pa_sconv_float32be_from_s16ne,
+        [PA_SAMPLE_FLOAT32LE] = (pa_convert_func_t) pa_sconv_float32le_from_s16ne,
+        [PA_SAMPLE_ALAW]      = (pa_convert_func_t) alaw_from_s16ne,
+        [PA_SAMPLE_ULAW]      = (pa_convert_func_t) ulaw_from_s16ne,
+    };
+
+    pa_assert(f >= 0);
+    pa_assert(f < PA_SAMPLE_MAX);
+
+    return table[f];
+}

Modified: trunk/src/pulsecore/sconv.h
URL: http://0pointer.de/cgi-bin/viewcvs.cgi/trunk/src/pulsecore/sconv.h?rev=1971&root=pulseaudio&r1=1970&r2=1971&view=diff
==============================================================================
--- trunk/src/pulsecore/sconv.h (original)
+++ trunk/src/pulsecore/sconv.h Sun Oct 28 20:13:50 2007
@@ -27,10 +27,12 @@
 
 #include <pulse/sample.h>
 
-typedef void (*pa_convert_to_float32ne_func_t)(unsigned n, const void *a, float *b);
-typedef void (*pa_convert_from_float32ne_func_t)(unsigned n, const float *a, void *b);
+typedef void (*pa_convert_func_t)(unsigned n, const void *a, void *b);
 
-pa_convert_to_float32ne_func_t pa_get_convert_to_float32ne_function(pa_sample_format_t f);
-pa_convert_from_float32ne_func_t pa_get_convert_from_float32ne_function(pa_sample_format_t f);
+pa_convert_func_t pa_get_convert_to_float32ne_function(pa_sample_format_t f) PA_GCC_PURE;
+pa_convert_func_t pa_get_convert_from_float32ne_function(pa_sample_format_t f) PA_GCC_PURE;
+
+pa_convert_func_t pa_get_convert_to_s16ne_function(pa_sample_format_t f) PA_GCC_PURE;
+pa_convert_func_t pa_get_convert_from_s16ne_function(pa_sample_format_t f) PA_GCC_PURE;
 
 #endif

Modified: trunk/src/pulsecore/shm.c
URL: http://0pointer.de/cgi-bin/viewcvs.cgi/trunk/src/pulsecore/shm.c?rev=1971&root=pulseaudio&r1=1970&r2=1971&view=diff
==============================================================================
--- trunk/src/pulsecore/shm.c (original)
+++ trunk/src/pulsecore/shm.c Sun Oct 28 20:13:50 2007
@@ -1,32 +1,31 @@
 /* $Id$ */
 
 /***
-  This file is part of PulseAudio.
-
-  Copyright 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.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.
+    This file is part of PulseAudio.
+
+    Copyright 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.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 <assert.h>
 #include <stdlib.h>
 #include <unistd.h>
 #include <fcntl.h>
@@ -34,15 +33,22 @@
 #include <errno.h>
 #include <string.h>
 #include <sys/stat.h>
+#include <sys/types.h>
+#include <dirent.h>
+#include <signal.h>
 
 #ifdef HAVE_SYS_MMAN_H
 #include <sys/mman.h>
 #endif
+
+#include <pulse/xmalloc.h>
 
 #include <pulsecore/core-error.h>
 #include <pulsecore/log.h>
 #include <pulsecore/random.h>
-#include <pulse/xmalloc.h>
+#include <pulsecore/core-util.h>
+#include <pulsecore/macro.h>
+#include <pulsecore/atomic.h>
 
 #include "shm.h"
 
@@ -50,10 +56,31 @@
 #define MADV_REMOVE 9
 #endif
 
-#define MAX_SHM_SIZE (1024*1024*20)
+#define MAX_SHM_SIZE (PA_ALIGN(1024*1024*20))
+
+#ifdef __linux__
+/* On Linux we know that the shared memory blocks are files in
+ * /dev/shm. We can use that information to list all blocks and
+ * cleanup unused ones */
+#define SHM_PATH "/dev/shm/"
+#else
+#undef SHM_PATH
+#endif
+
+#define SHM_MARKER ((int) 0xbeefcafe)
+
+/* We now put this SHM marker at the end of each segment. It's optional to not require a reboot when upgrading, though */
+struct shm_marker {
+    pa_atomic_t marker; /* 0xbeefcafe */
+    pa_atomic_t pid;
+    void *_reserverd1;
+    void *_reserverd2;
+    void *_reserverd3;
+    void *_reserverd4;
+};
 
 static char *segment_name(char *fn, size_t l, unsigned id) {
-    snprintf(fn, l, "/pulse-shm-%u", id);
+    pa_snprintf(fn, l, "/pulse-shm-%u", id);
     return fn;
 }
 
@@ -61,10 +88,17 @@
     char fn[32];
     int fd = -1;
 
-    assert(m);
-    assert(size > 0);
-    assert(size < MAX_SHM_SIZE);
-    assert(mode >= 0600);
+    pa_assert(m);
+    pa_assert(size > 0);
+    pa_assert(size < MAX_SHM_SIZE);
+    pa_assert(mode >= 0600);
+
+    /* Each time we create a new SHM area, let's first drop all stale
+     * ones */
+    pa_shm_cleanup();
+
+    /* Round up to make it aligned */
+    size = PA_ALIGN(size);
 
     if (!shared) {
         m->id = 0;
@@ -79,7 +113,7 @@
         {
             int r;
 
-            if ((r = posix_memalign(&m->ptr, sysconf(_SC_PAGESIZE), size)) < 0) {
+            if ((r = posix_memalign(&m->ptr, PA_PAGE_SIZE, size)) < 0) {
                 pa_log("posix_memalign() failed: %s", pa_cstrerror(r));
                 goto fail;
             }
@@ -92,6 +126,8 @@
 
     } else {
 #ifdef HAVE_SHM_OPEN
+        struct shm_marker *marker;
+
         pa_random(&m->id, sizeof(m->id));
         segment_name(fn, sizeof(fn), m->id);
 
@@ -100,7 +136,9 @@
             goto fail;
         }
 
-        if (ftruncate(fd, m->size = size) < 0) {
+        m->size = size + PA_ALIGN(sizeof(struct shm_marker));
+
+        if (ftruncate(fd, m->size) < 0) {
             pa_log("ftruncate() failed: %s", pa_cstrerror(errno));
             goto fail;
         }
@@ -110,10 +148,16 @@
             goto fail;
         }
 
-        close(fd);
+        /* We store our PID at the end of the shm block, so that we
+         * can check for dead shm segments later */
+        marker = (struct shm_marker*) ((uint8_t*) m->ptr + m->size - PA_ALIGN(sizeof(struct shm_marker)));
+        pa_atomic_store(&marker->pid, (int) getpid());
+        pa_atomic_store(&marker->marker, SHM_MARKER);
+
+        pa_assert_se(close(fd) == 0);
         m->do_unlink = 1;
 #else
-		return -1;
+        return -1;
 #endif
     }
 
@@ -126,7 +170,7 @@
 #ifdef HAVE_SHM_OPEN
     if (fd >= 0) {
         shm_unlink(fn);
-        close(fd);
+        pa_close(fd);
     }
 #endif
 
@@ -134,76 +178,70 @@
 }
 
 void pa_shm_free(pa_shm *m) {
-    assert(m);
-    assert(m->ptr);
-    assert(m->size > 0);
+    pa_assert(m);
+    pa_assert(m->ptr);
+    pa_assert(m->size > 0);
 
 #ifdef MAP_FAILED
-	assert(m->ptr != MAP_FAILED);
-#endif
-
-	if (!m->shared) {
+    pa_assert(m->ptr != MAP_FAILED);
+#endif
+
+    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 (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);
-#endif
-	}
+        if (munmap(m->ptr, m->size) < 0)
+            pa_log("munmap() failed: %s", pa_cstrerror(errno));
+
+        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 */
+        pa_assert_not_reached();
+#endif
+    }
 
     memset(m, 0, sizeof(*m));
 }
 
 void pa_shm_punch(pa_shm *m, size_t offset, size_t size) {
     void *ptr;
-
-    assert(m);
-    assert(m->ptr);
-    assert(m->size > 0);
-    assert(offset+size <= m->size);
+    size_t o, ps;
+
+    pa_assert(m);
+    pa_assert(m->ptr);
+    pa_assert(m->size > 0);
+    pa_assert(offset+size <= m->size);
 
 #ifdef MAP_FAILED
-	assert(m->ptr != MAP_FAILED);
+    pa_assert(m->ptr != MAP_FAILED);
 #endif
 
     /* You're welcome to implement this as NOOP on systems that don't
      * support it */
 
+    /* Align this to multiples of the page size */
     ptr = (uint8_t*) m->ptr + offset;
-
-#ifdef __linux__
-{
-    /* On Linux ptr must be page aligned */
-    long psz = sysconf(_SC_PAGESIZE);
-    unsigned o;
-
-    o = ((unsigned long) ptr) - ((((unsigned long) ptr)/psz) * psz);
+    o = (uint8_t*) ptr - (uint8_t*) PA_PAGE_ALIGN_PTR(ptr);
 
     if (o > 0) {
-        ptr = (uint8_t*) ptr + (psz - o);
-        size -= psz - o;
-    }
-}
-#endif
+        ps = PA_PAGE_SIZE;
+        ptr = (uint8_t*) ptr + (ps - o);
+        size -= ps - o;
+    }
 
 #ifdef MADV_REMOVE
     if (madvise(ptr, size, MADV_REMOVE) >= 0)
@@ -216,7 +254,9 @@
 #endif
 
 #ifdef MADV_DONTNEED
-    madvise(ptr, size, MADV_DONTNEED);
+    pa_assert_se(madvise(ptr, size, MADV_DONTNEED) == 0);
+#elif defined(POSIX_MADV_DONTNEED)
+    pa_assert_se(posix_madvise(ptr, size, POSIX_MADV_DONTNEED) == 0);
 #endif
 }
 
@@ -227,12 +267,13 @@
     int fd = -1;
     struct stat st;
 
-    assert(m);
+    pa_assert(m);
 
     segment_name(fn, sizeof(fn), m->id = id);
 
     if ((fd = shm_open(fn, O_RDONLY, 0)) < 0) {
-        pa_log("shm_open() failed: %s", pa_cstrerror(errno));
+        if (errno != EACCES)
+            pa_log("shm_open() failed: %s", pa_cstrerror(errno));
         goto fail;
     }
 
@@ -241,7 +282,7 @@
         goto fail;
     }
 
-    if (st.st_size <= 0 || st.st_size > MAX_SHM_SIZE) {
+    if (st.st_size <= 0 || st.st_size > MAX_SHM_SIZE+PA_ALIGN(sizeof(struct shm_marker)) || PA_ALIGN(st.st_size) != st.st_size) {
         pa_log("Invalid shared memory segment size");
         goto fail;
     }
@@ -256,13 +297,13 @@
     m->do_unlink = 0;
     m->shared = 1;
 
-    close(fd);
+    pa_assert_se(pa_close(fd) == 0);
 
     return 0;
 
 fail:
     if (fd >= 0)
-        close(fd);
+        pa_close(fd);
 
     return -1;
 }
@@ -270,7 +311,71 @@
 #else /* HAVE_SHM_OPEN */
 
 int pa_shm_attach_ro(pa_shm *m, unsigned id) {
-	return -1;
+    return -1;
 }
 
 #endif /* HAVE_SHM_OPEN */
+
+int pa_shm_cleanup(void) {
+
+#ifdef SHM_PATH
+    DIR *d;
+    struct dirent *de;
+
+    if (!(d = opendir(SHM_PATH))) {
+        pa_log_warn("Failed to read "SHM_PATH": %s", pa_cstrerror(errno));
+        return -1;
+    }
+
+    while ((de = readdir(d))) {
+        pa_shm seg;
+        unsigned id;
+        pid_t pid;
+        char fn[128];
+        struct shm_marker *m;
+
+        if (strncmp(de->d_name, "pulse-shm-", 10))
+            continue;
+
+        if (pa_atou(de->d_name + 10, &id) < 0)
+            continue;
+
+        if (pa_shm_attach_ro(&seg, id) < 0)
+            continue;
+
+        if (seg.size < PA_ALIGN(sizeof(struct shm_marker))) {
+            pa_shm_free(&seg);
+            continue;
+        }
+
+        m = (struct shm_marker*) ((uint8_t*) seg.ptr + seg.size - PA_ALIGN(sizeof(struct shm_marker)));
+
+        if (pa_atomic_load(&m->marker) != SHM_MARKER) {
+            pa_shm_free(&seg);
+            continue;
+        }
+
+        if (!(pid = (pid_t) pa_atomic_load(&m->pid))) {
+            pa_shm_free(&seg);
+            continue;
+        }
+
+        if (kill(pid, 0) == 0 || errno != ESRCH) {
+            pa_shm_free(&seg);
+            continue;
+        }
+
+        pa_shm_free(&seg);
+
+        /* Ok, the owner of this shms segment is dead, so, let's remove the segment */
+        segment_name(fn, sizeof(fn), id);
+
+        if (shm_unlink(fn) < 0 && errno != EACCES)
+            pa_log_warn("Failed to remove SHM segment %s: %s\n", fn, pa_cstrerror(errno));
+    }
+
+    closedir(d);
+#endif
+
+    return 0;
+}

Modified: trunk/src/pulsecore/shm.h
URL: http://0pointer.de/cgi-bin/viewcvs.cgi/trunk/src/pulsecore/shm.h?rev=1971&root=pulseaudio&r1=1970&r2=1971&view=diff
==============================================================================
--- trunk/src/pulsecore/shm.h (original)
+++ trunk/src/pulsecore/shm.h Sun Oct 28 20:13:50 2007
@@ -41,4 +41,6 @@
 
 void pa_shm_free(pa_shm *m);
 
+int pa_shm_cleanup(void);
+
 #endif

Modified: trunk/src/pulsecore/sink-input.c
URL: http://0pointer.de/cgi-bin/viewcvs.cgi/trunk/src/pulsecore/sink-input.c?rev=1971&root=pulseaudio&r1=1970&r2=1971&view=diff
==============================================================================
--- trunk/src/pulsecore/sink-input.c (original)
+++ trunk/src/pulsecore/sink-input.c Sun Oct 28 20:13:50 2007
@@ -27,7 +27,6 @@
 #endif
 
 #include <stdio.h>
-#include <assert.h>
 #include <stdlib.h>
 #include <string.h>
 
@@ -42,43 +41,49 @@
 
 #include "sink-input.h"
 
-#define CONVERT_BUFFER_LENGTH 4096
-#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)
+#define CONVERT_BUFFER_LENGTH (PA_PAGE_SIZE)
+#define SILENCE_BUFFER_LENGTH (PA_PAGE_SIZE*12)
+#define MOVE_BUFFER_LENGTH (PA_PAGE_SIZE*256)
+
+static PA_DEFINE_CHECK_TYPE(pa_sink_input, pa_msgobject);
+
+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) {
-    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, pa_bool_t mute) {
+    pa_assert(data);
+
+    data->muted_is_set = TRUE;
+    data->muted = !!mute;
 }
 
 pa_sink_input* pa_sink_input_new(
@@ -88,46 +93,52 @@
 
     pa_sink_input *i;
     pa_resampler *resampler = NULL;
-    int r;
     char st[PA_SAMPLE_SPEC_SNPRINT_MAX];
 
-    assert(core);
-    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_assert(core);
+    pa_assert(data);
+
+    if (pa_hook_fire(&core->hooks[PA_CORE_HOOK_SINK_INPUT_NEW], data) < 0)
+        return NULL;
+
+    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_UNLINKED);
+    pa_return_null_if_fail(!data->sync_base || (data->sync_base->sink == data->sink && pa_sink_input_get_state(data->sync_base) == PA_SINK_INPUT_CORKED));
 
     if (!data->sample_spec_is_set)
         data->sample_spec = data->sink->sample_spec;
 
-    CHECK_VALIDITY_RETURN_NULL(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);
-
-    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_sample_spec_valid(&data->sample_spec));
+
+    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);
+    }
+
+    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,20 +147,27 @@
 
     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,
                       &data->sample_spec, &data->channel_map,
                       &data->sink->sample_spec, &data->sink->channel_map,
-                      data->resample_method))) {
+                      data->resample_method,
+                      !!(flags & PA_SINK_INPUT_VARIABLE_RATE)))) {
             pa_log_warn("Unsupported resampling operation.");
             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;
+    i->state = PA_SINK_INPUT_INIT;
     i->flags = flags;
     i->name = pa_xstrdup(data->name);
     i->driver = pa_xstrdup(data->driver);
@@ -157,105 +175,203 @@
     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;
+
+    if (data->sync_base) {
+        i->sync_next = data->sync_base->sync_next;
+        i->sync_prev = data->sync_base;
+
+        if (data->sync_base->sync_next)
+            data->sync_base->sync_next->sync_prev = i;
+        data->sync_base->sync_next = i;
+    } else
+        i->sync_next = i->sync_prev = NULL;
 
     i->peek = NULL;
     i->drop = NULL;
     i->kill = NULL;
     i->get_latency = NULL;
-    i->underrun = NULL;
+    i->attach = NULL;
+    i->detach = NULL;
+    i->suspend = NULL;
     i->userdata = NULL;
 
-    i->move_silence = 0;
-
-    pa_memchunk_reset(&i->resampled_chunk);
-    i->resampler = resampler;
-    i->resample_method = data->resample_method;
-    i->silence_memblock = NULL;
-
-    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",
+    i->thread_info.state = i->state;
+    pa_atomic_store(&i->thread_info.drained, 1);
+    i->thread_info.sample_spec = i->sample_spec;
+    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.volume = i->volume;
+    i->thread_info.muted = i->muted;
+    i->thread_info.attached = FALSE;
+
+    pa_assert_se(pa_idxset_put(core->sink_inputs, pa_sink_input_ref(i), &i->index) == 0);
+    pa_assert_se(pa_idxset_put(i->sink->inputs, i, NULL) == 0);
+
+    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);
+static void update_n_corked(pa_sink_input *i, pa_sink_input_state_t state) {
+    pa_assert(i);
+
+    if (i->state == PA_SINK_INPUT_CORKED && state != PA_SINK_INPUT_CORKED)
+        pa_assert_se(i->sink->n_corked -- >= 1);
+    else if (i->state != PA_SINK_INPUT_CORKED && state == PA_SINK_INPUT_CORKED)
+        i->sink->n_corked++;
+
+    pa_sink_update_status(i->sink);
+}
+
+static int sink_input_set_state(pa_sink_input *i, pa_sink_input_state_t state) {
+    pa_sink_input *ssync;
+    pa_assert(i);
+
+    if (state == PA_SINK_INPUT_DRAINED)
+        state = PA_SINK_INPUT_RUNNING;
+
+    if (i->state == state)
+        return 0;
+
+    if (pa_asyncmsgq_send(i->sink->asyncmsgq, PA_MSGOBJECT(i), PA_SINK_INPUT_MESSAGE_SET_STATE, PA_UINT_TO_PTR(state), 0, NULL) < 0)
+        return -1;
+
+    update_n_corked(i, state);
+    i->state = state;
+
+    for (ssync = i->sync_prev; ssync; ssync = ssync->sync_prev) {
+        update_n_corked(ssync, state);
+        ssync->state = state;
+    }
+    for (ssync = i->sync_next; ssync; ssync = ssync->sync_next) {
+        update_n_corked(ssync, state);
+        ssync->state = state;
+    }
+
+    if (state != PA_SINK_INPUT_UNLINKED)
+        pa_hook_fire(&i->sink->core->hooks[PA_CORE_HOOK_SINK_INPUT_STATE_CHANGED], i);
+
+    return 0;
+}
+
+void pa_sink_input_unlink(pa_sink_input *i) {
+    pa_bool_t linked;
+    pa_assert(i);
+
+    /* See pa_sink_unlink() for a couple of comments how this function
+     * works */
+
+    pa_sink_input_ref(i);
+
+    linked = PA_SINK_INPUT_LINKED(i->state);
+
+    if (linked)
+        pa_hook_fire(&i->sink->core->hooks[PA_CORE_HOOK_SINK_INPUT_UNLINK], i);
+
+    if (i->sync_prev)
+        i->sync_prev->sync_next = i->sync_next;
+    if (i->sync_next)
+        i->sync_next->sync_prev = i->sync_prev;
+
+    i->sync_prev = i->sync_next = 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;
+    if (pa_idxset_remove_by_data(i->sink->inputs, i, NULL))
+        pa_sink_input_unref(i);
+
+    if (linked) {
+        pa_asyncmsgq_send(i->sink->asyncmsgq, PA_MSGOBJECT(i->sink), PA_SINK_MESSAGE_REMOVE_INPUT, i, 0, NULL);
+        sink_input_set_state(i, PA_SINK_INPUT_UNLINKED);
+        pa_sink_update_status(i->sink);
+    } else
+        i->state = PA_SINK_INPUT_UNLINKED;
 
     i->peek = NULL;
     i->drop = NULL;
     i->kill = NULL;
     i->get_latency = NULL;
-    i->underrun = NULL;
-
-    i->state = PA_SINK_INPUT_DISCONNECTED;
-}
-
-static void sink_input_free(pa_sink_input* i) {
-    assert(i);
-
-    if (i->state != PA_SINK_INPUT_DISCONNECTED)
-        pa_sink_input_disconnect(i);
-
-    pa_log_info("freed %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->silence_memblock)
-        pa_memblock_unref(i->silence_memblock);
+    i->attach = NULL;
+    i->detach = NULL;
+    i->suspend = NULL;
+
+    if (linked) {
+        pa_subscription_post(i->sink->core, PA_SUBSCRIPTION_EVENT_SINK_INPUT|PA_SUBSCRIPTION_EVENT_REMOVE, i->index);
+        pa_hook_fire(&i->sink->core->hooks[PA_CORE_HOOK_SINK_INPUT_UNLINK_POST], i);
+    }
+
+    i->sink = NULL;
+    pa_sink_input_unref(i);
+}
+
+static void sink_input_free(pa_object *o) {
+    pa_sink_input* i = PA_SINK_INPUT(o);
+
+    pa_assert(i);
+    pa_assert(pa_sink_input_refcnt(i) == 0);
+
+    if (PA_SINK_INPUT_LINKED(i->state))
+        pa_sink_input_unlink(i);
+
+    pa_log_info("Freeing output %u \"%s\"", i->index, i->name);
+
+    pa_assert(!i->thread_info.attached);
+
+    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);
+
+    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);
-
-    if (!(--i->ref))
-        sink_input_free(i);
-}
-
-pa_sink_input* pa_sink_input_ref(pa_sink_input *i) {
-    assert(i);
-    assert(i->ref >= 1);
-
-    i->ref++;
-    return i;
+void pa_sink_input_put(pa_sink_input *i) {
+    pa_sink_input_assert_ref(i);
+
+    pa_assert(i->state == PA_SINK_INPUT_INIT);
+    pa_assert(i->peek);
+    pa_assert(i->drop);
+
+    i->thread_info.state = i->state = i->flags & PA_SINK_INPUT_START_CORKED ? PA_SINK_INPUT_CORKED : PA_SINK_INPUT_RUNNING;
+    i->thread_info.volume = i->volume;
+    i->thread_info.muted = i->muted;
+
+    if (i->state == PA_SINK_INPUT_CORKED)
+        i->sink->n_corked++;
+
+    pa_asyncmsgq_send(i->sink->asyncmsgq, PA_MSGOBJECT(i->sink), PA_SINK_MESSAGE_ADD_INPUT, i, 0, NULL);
+    pa_sink_update_status(i->sink);
+
+    pa_subscription_post(i->sink->core, PA_SUBSCRIPTION_EVENT_SINK_INPUT|PA_SUBSCRIPTION_EVENT_NEW, i->index);
+    pa_hook_fire(&i->sink->core->hooks[PA_CORE_HOOK_SINK_INPUT_PUT], i);
+
+    /* Please note that if you change something here, you have to
+       change something in pa_sink_input_move() with the ghost stream
+       registration too. */
 }
 
 void pa_sink_input_kill(pa_sink_input*i) {
-    assert(i);
-    assert(i->ref >= 1);
+    pa_sink_input_assert_ref(i);
+    pa_assert(PA_SINK_INPUT_LINKED(i->state));
 
     if (i->kill)
         i->kill(i);
@@ -264,108 +380,127 @@
 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);
+    pa_assert(PA_SINK_INPUT_LINKED(i->state));
+
+    if (pa_asyncmsgq_send(i->sink->asyncmsgq, PA_MSGOBJECT(i), PA_SINK_INPUT_MESSAGE_GET_LATENCY, &r, 0, 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;
 }
 
-int pa_sink_input_peek(pa_sink_input *i, pa_memchunk *chunk, pa_cvolume *volume) {
+/* Called from thread context */
+int pa_sink_input_peek(pa_sink_input *i, size_t length, pa_memchunk *chunk, pa_cvolume *volume) {
     int ret = -1;
     int do_volume_adj_here;
     int volume_is_norm;
-
-    assert(i);
-    assert(i->ref >= 1);
-    assert(chunk);
-    assert(volume);
-
-    pa_sink_input_ref(i);
-
-    if (!i->peek || !i->drop || i->state == PA_SINK_INPUT_CORKED)
+    size_t block_size_max;
+
+    pa_sink_input_assert_ref(i);
+    pa_assert(PA_SINK_INPUT_LINKED(i->thread_info.state));
+    pa_assert(pa_frame_aligned(length, &i->sink->sample_spec));
+    pa_assert(chunk);
+    pa_assert(volume);
+
+    if (!i->peek || !i->drop || i->thread_info.state == PA_SINK_INPUT_CORKED)
         goto finish;
 
-    assert(i->state == PA_SINK_INPUT_RUNNING || i->state == PA_SINK_INPUT_DRAINED);
-
-    if (i->move_silence > 0) {
+    pa_assert(i->thread_info.state == PA_SINK_INPUT_RUNNING || i->thread_info.state == PA_SINK_INPUT_DRAINED);
+
+    /* Default buffer size */
+    if (length <= 0)
+        length = pa_frame_align(CONVERT_BUFFER_LENGTH, &i->sink->sample_spec);
+
+    /* Make sure the buffer fits in the mempool tile */
+    block_size_max = pa_mempool_block_size_max(i->sink->core->mempool);
+    if (length > block_size_max)
+        length = pa_frame_align(block_size_max, &i->sink->sample_spec);
+
+    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 */
 
-        if (!i->silence_memblock)
-            i->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);
+        if (!i->thread_info.silence_memblock)
+            i->thread_info.silence_memblock = pa_silence_memblock_new(
+                    i->sink->core->mempool,
+                    &i->sink->sample_spec,
+                    pa_frame_align(SILENCE_BUFFER_LENGTH, &i->sink->sample_spec));
+
+        chunk->memblock = pa_memblock_ref(i->thread_info.silence_memblock);
         chunk->index = 0;
-        chunk->length = i->move_silence < chunk->memblock->length ? i->move_silence : chunk->memblock->length;
+        l = pa_memblock_get_length(chunk->memblock);
+        chunk->length = i->thread_info.move_silence < l ? i->thread_info.move_silence : l;
 
         ret = 0;
         do_volume_adj_here = 1;
         goto finish;
     }
 
-    if (!i->resampler) {
-        do_volume_adj_here = 0;
-        ret = i->peek(i, chunk);
+    if (!i->thread_info.resampler) {
+        do_volume_adj_here = 0; /* FIXME??? */
+        ret = i->peek(i, length, 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->volume);
-
-    while (!i->resampled_chunk.memblock) {
+    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;
-        size_t l;
-
-        if ((ret = i->peek(i, &tchunk)) < 0)
+        size_t l, rmbs;
+
+        l = pa_resampler_request(i->thread_info.resampler, length);
+
+        if (l <= 0)
+            l = pa_frame_align(CONVERT_BUFFER_LENGTH, &i->sample_spec);
+
+        rmbs = pa_resampler_max_block_size(i->thread_info.resampler);
+        if (l > rmbs)
+            l = rmbs;
+
+        if ((ret = i->peek(i, l, &tchunk)) < 0)
             goto finish;
 
-        assert(tchunk.length);
-
-        l = pa_resampler_request(i->resampler, CONVERT_BUFFER_LENGTH);
-
-        if (l > tchunk.length)
-            l = tchunk.length;
-
-        i->drop(i, &tchunk, l);
-        tchunk.length = l;
+        pa_assert(tchunk.length > 0);
+
+        if (tchunk.length > l)
+            tchunk.length = l;
+
+        i->drop(i, tchunk.length);
 
         /* 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_resampler_run(i->resampler, &tchunk, &i->resampled_chunk);
+
+            if (i->thread_info.muted)
+                pa_silence_memchunk(&tchunk, &i->thread_info.sample_spec);
+            else
+                pa_volume_memchunk(&tchunk, &i->thread_info.sample_spec, &i->thread_info.volume);
+        }
+
+        pa_resampler_run(i->thread_info.resampler, &tchunk, &i->thread_info.resampled_chunk);
         pa_memblock_unref(tchunk.memblock);
     }
 
-    assert(i->resampled_chunk.memblock);
-    assert(i->resampled_chunk.length);
-
-    *chunk = i->resampled_chunk;
-    pa_memblock_ref(i->resampled_chunk.memblock);
+    pa_assert(i->thread_info.resampled_chunk.memblock);
+    pa_assert(i->thread_info.resampled_chunk.length > 0);
+
+    *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)
-        i->underrun(i);
-
     if (ret >= 0)
-        i->state = PA_SINK_INPUT_RUNNING;
-    else if (ret < 0 && i->state == PA_SINK_INPUT_RUNNING)
-        i->state = PA_SINK_INPUT_DRAINED;
+        pa_atomic_store(&i->thread_info.drained, 0);
+    else if (ret < 0)
+        pa_atomic_store(&i->thread_info.drained, 1);
 
     if (ret >= 0) {
         /* Let's see if we had to apply the volume adjustment
@@ -374,120 +509,179 @@
         if (do_volume_adj_here)
             /* We had different channel maps, so we already did the adjustment */
             pa_cvolume_reset(volume, i->sink->sample_spec.channels);
+        else if (i->thread_info.muted)
+            /* We've both the same channel map, so let's have the sink do the adjustment for us*/
+            pa_cvolume_mute(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;
-    }
-
-    pa_sink_input_unref(i);
+            *volume = i->thread_info.volume;
+    }
 
     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);
-
-    if (i->move_silence > 0) {
-
-        if (chunk) {
-
-            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;
-
-        }
-
-        assert(i->move_silence >= length);
-
-        i->move_silence -= length;
-
-        if (i->move_silence <= 0) {
-            assert(i->silence_memblock);
-            pa_memblock_unref(i->silence_memblock);
-            i->silence_memblock = NULL;
-        }
-
+/* Called from thread context */
+void pa_sink_input_drop(pa_sink_input *i, size_t length) {
+    pa_sink_input_assert_ref(i);
+    pa_assert(PA_SINK_INPUT_LINKED(i->thread_info.state));
+    pa_assert(pa_frame_aligned(length, &i->sink->sample_spec));
+    pa_assert(length > 0);
+
+    if (!i->peek || !i->drop || i->thread_info.state == PA_SINK_INPUT_CORKED)
         return;
-    }
-
-    if (!i->resampler) {
-        if (i->drop)
-            i->drop(i, chunk, length);
-        return;
-    }
-
-    assert(i->resampled_chunk.memblock);
-    assert(i->resampled_chunk.length >= length);
-
-    i->resampled_chunk.index += length;
-    i->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.move_silence > 0) {
+
+        if (i->thread_info.move_silence >= length) {
+            i->thread_info.move_silence -= length;
+            length = 0;
+        } else {
+            length -= i->thread_info.move_silence;
+            i->thread_info.move_silence = 0;
+        }
+
+        if (i->thread_info.move_silence <= 0) {
+            if (i->thread_info.silence_memblock) {
+                pa_memblock_unref(i->thread_info.silence_memblock);
+                i->thread_info.silence_memblock = NULL;
+            }
+        }
+
+        if (length <= 0)
+            return;
+    }
+
+    if (i->thread_info.resampled_chunk.memblock) {
+        size_t l = length;
+
+        if (l > i->thread_info.resampled_chunk.length)
+            l = i->thread_info.resampled_chunk.length;
+
+        i->thread_info.resampled_chunk.index += l;
+        i->thread_info.resampled_chunk.length -= l;
+
+        if (i->thread_info.resampled_chunk.length <= 0) {
+            pa_memblock_unref(i->thread_info.resampled_chunk.memblock);
+            pa_memchunk_reset(&i->thread_info.resampled_chunk);
+        }
+
+        length -= l;
+    }
+
+    if (length > 0) {
+
+        if (i->thread_info.resampler) {
+            /* So, we have a resampler. To avoid discontinuities we
+             * have to actually read all data that could be read and
+             * pass it through the resampler. */
+
+            while (length > 0) {
+                pa_memchunk chunk;
+                pa_cvolume volume;
+
+                if (pa_sink_input_peek(i, length, &chunk, &volume) >= 0) {
+                    size_t l;
+
+                    pa_memblock_unref(chunk.memblock);
+
+                    l = chunk.length;
+                    if (l > length)
+                        l = length;
+
+                    pa_sink_input_drop(i, l);
+                    length -= l;
+
+                } else {
+                    size_t l;
+
+                    l = pa_resampler_request(i->thread_info.resampler, length);
+
+                    /* Hmmm, peeking failed, so let's at least drop
+                     * the right amount of data */
+
+                    if (l > 0)
+                        if (i->drop)
+                            i->drop(i, l);
+
+                    break;
+                }
+            }
+
+        } else {
+
+            /* We have no resampler, hence let's just drop the data */
+
+            if (i->drop)
+                i->drop(i, length);
+        }
     }
 }
 
 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);
+    pa_assert(PA_SINK_INPUT_LINKED(i->state));
 
     if (pa_cvolume_equal(&i->volume, volume))
         return;
 
     i->volume = *volume;
+
+    pa_asyncmsgq_post(i->sink->asyncmsgq, PA_MSGOBJECT(i), PA_SINK_INPUT_MESSAGE_SET_VOLUME, pa_xnewdup(struct pa_cvolume, volume, 1), 0, NULL, 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);
+    pa_assert(PA_SINK_INPUT_LINKED(i->state));
 
     return &i->volume;
 }
 
-void pa_sink_input_cork(pa_sink_input *i, int b) {
-    int n;
-
-    assert(i);
-    assert(i->ref >= 1);
-
-    assert(i->state != PA_SINK_INPUT_DISCONNECTED);
-
-    n = i->state == PA_SINK_INPUT_CORKED && !b;
-
-    if (b)
-        i->state = PA_SINK_INPUT_CORKED;
-    else if (i->state == PA_SINK_INPUT_CORKED)
-        i->state = PA_SINK_INPUT_DRAINED;
-
-    if (n)
-        pa_sink_notify(i->sink);
-}
-
-void pa_sink_input_set_rate(pa_sink_input *i, uint32_t rate) {
-    assert(i);
-    assert(i->resampler);
-    assert(i->ref >= 1);
+void pa_sink_input_set_mute(pa_sink_input *i, pa_bool_t mute) {
+    pa_assert(i);
+    pa_sink_input_assert_ref(i);
+    pa_assert(PA_SINK_INPUT_LINKED(i->state));
+
+    if (!i->muted == !mute)
+        return;
+
+    i->muted = mute;
+
+    pa_asyncmsgq_post(i->sink->asyncmsgq, PA_MSGOBJECT(i), PA_SINK_INPUT_MESSAGE_SET_MUTE, PA_UINT_TO_PTR(mute), 0, 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);
+    pa_assert(PA_SINK_INPUT_LINKED(i->state));
+
+    return !!i->muted;
+}
+
+void pa_sink_input_cork(pa_sink_input *i, pa_bool_t b) {
+    pa_sink_input_assert_ref(i);
+    pa_assert(PA_SINK_INPUT_LINKED(i->state));
+
+    sink_input_set_state(i, b ? PA_SINK_INPUT_CORKED : PA_SINK_INPUT_RUNNING);
+}
+
+int pa_sink_input_set_rate(pa_sink_input *i, uint32_t rate) {
+    pa_sink_input_assert_ref(i);
+    pa_assert(PA_SINK_INPUT_LINKED(i->state));
+    pa_return_val_if_fail(i->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(i->sink->asyncmsgq, PA_MSGOBJECT(i), PA_SINK_INPUT_MESSAGE_SET_RATE, PA_UINT_TO_PTR(rate), 0, NULL, 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;
@@ -498,47 +692,56 @@
     pa_xfree(i->name);
     i->name = pa_xstrdup(name);
 
-    pa_subscription_post(i->sink->core, PA_SUBSCRIPTION_EVENT_SINK_INPUT|PA_SUBSCRIPTION_EVENT_CHANGE, i->index);
+    if (PA_SINK_INPUT_LINKED(i->state)) {
+        pa_hook_fire(&i->sink->core->hooks[PA_CORE_HOOK_SINK_INPUT_NAME_CHANGED], i);
+        pa_subscription_post(i->sink->core, PA_SUBSCRIPTION_EVENT_SINK_INPUT|PA_SUBSCRIPTION_EVENT_CHANGE, i->index);
+    }
 }
 
 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;
-
-    return pa_resampler_get_method(i->resampler);
+    pa_sink_input_assert_ref(i);
+
+    return i->resample_method;
 }
 
 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_resampler *new_resampler;
     pa_sink *origin;
-
-    assert(i);
-    assert(dest);
+    pa_usec_t silence_usec = 0;
+    pa_sink_input_move_info info;
+
+    pa_sink_input_assert_ref(i);
+    pa_assert(PA_SINK_INPUT_LINKED(i->state));
+    pa_sink_assert_ref(dest);
 
     origin = i->sink;
 
     if (dest == origin)
         return 0;
+
+    if (i->flags & PA_SINK_INPUT_DONT_MOVE)
+        return -1;
+
+    if (i->sync_next || i->sync_prev) {
+        pa_log_warn("Moving synchronised streams not supported.");
+        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 &&
+    if (i->thread_info.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;
+        new_resampler = i->thread_info.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)) {
+             !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 */
 
@@ -546,20 +749,26 @@
                       dest->core->mempool,
                       &i->sample_spec, &i->channel_map,
                       &dest->sample_spec, &dest->channel_map,
-                      i->resample_method))) {
+                      i->resample_method,
+                      !!(i->flags & PA_SINK_INPUT_VARIABLE_RATE)))) {
             pa_log_warn("Unsupported resampling operation.");
             return -1;
         }
-    }
+    } else
+        new_resampler = NULL;
+
+    pa_hook_fire(&i->sink->core->hooks[PA_CORE_HOOK_SINK_INPUT_MOVE], i);
+
+    memset(&info, 0, sizeof(info));
+    info.sink_input = i;
 
     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);
 
         /* Let's do a little bit of Voodoo for compensating latency
-         * differences */
+         * differences. We assume that the accuracy for our
+         * estimations is still good enough, even though we do these
+         * operations non-atomic. */
 
         old_latency = pa_sink_get_latency(origin);
         new_latency = pa_sink_get_latency(dest);
@@ -576,8 +785,6 @@
             silence_usec = old_latency - new_latency;
 
         } 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
@@ -585,87 +792,164 @@
              * sink, until we can play the first sample on the new
              * sink.*/
 
-            l = pa_usec_to_bytes(new_latency - old_latency, &origin->sample_spec);
-
-            volume_is_norm = pa_cvolume_is_norm(&i->volume);
-
-            while (l > 0) {
-                pa_memchunk chunk;
-                pa_cvolume volume;
-                size_t n;
-
-                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;
-
-                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;
-                }
-
-                pa_memblock_unref(chunk.memblock);
-                l -= n;
-            }
-        }
-
-        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 */
-
-            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);
-    }
-
-    /* Okey, let's move it */
+            info.buffer_bytes = pa_usec_to_bytes(new_latency - old_latency, &origin->sample_spec);
+        }
+
+        /* Okey, let's move it */
+
+        if (info.buffer_bytes > 0) {
+
+            info.ghost_sink_input = pa_memblockq_sink_input_new(
+                    origin,
+                    "Ghost Stream",
+                    &origin->sample_spec,
+                    &origin->channel_map,
+                    NULL,
+                    NULL);
+
+            info.ghost_sink_input->thread_info.state = info.ghost_sink_input->state = PA_SINK_INPUT_RUNNING;
+            info.ghost_sink_input->thread_info.volume = info.ghost_sink_input->volume;
+            info.ghost_sink_input->thread_info.muted = info.ghost_sink_input->muted;
+
+            info.buffer = pa_memblockq_new(0, MOVE_BUFFER_LENGTH, 0, pa_frame_size(&origin->sample_spec), 0, 0, NULL);
+        }
+    }
+
+    pa_asyncmsgq_send(i->sink->asyncmsgq, PA_MSGOBJECT(i->sink), PA_SINK_MESSAGE_REMOVE_INPUT_AND_BUFFER, &info, 0, NULL);
+
+    if (info.ghost_sink_input) {
+        /* Basically, do what pa_sink_input_put() does ...*/
+
+        pa_subscription_post(i->sink->core, PA_SUBSCRIPTION_EVENT_SINK_INPUT|PA_SUBSCRIPTION_EVENT_NEW, info.ghost_sink_input->index);
+        pa_hook_fire(&i->sink->core->hooks[PA_CORE_HOOK_SINK_INPUT_PUT], info.ghost_sink_input);
+        pa_sink_input_unref(info.ghost_sink_input);
+    }
+
     pa_idxset_remove_by_data(origin->inputs, i, NULL);
     pa_idxset_put(dest->inputs, i, NULL);
     i->sink = dest;
 
+    if (pa_sink_input_get_state(i) == PA_SINK_INPUT_CORKED) {
+        pa_assert_se(origin->n_corked-- >= 1);
+        dest->n_corked++;
+    }
+
     /* Replace resampler */
-    if (new_resampler != i->resampler) {
-        if (i->resampler)
-            pa_resampler_free(i->resampler);
-        i->resampler = new_resampler;
+    if (new_resampler != i->thread_info.resampler) {
+        if (i->thread_info.resampler)
+            pa_resampler_free(i->thread_info.resampler);
+        i->thread_info.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;
+        if (i->thread_info.silence_memblock) {
+            pa_memblock_unref(i->thread_info.silence_memblock);
+            i->thread_info.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;
-    }
+    if (i->thread_info.resampled_chunk.memblock) {
+        /* Hmm, this data has already been added to the ghost queue, presumably, hence let's sleep a little bit longer */
+        silence_usec += pa_bytes_to_usec(i->thread_info.resampled_chunk.length, &origin->sample_spec);
+        pa_memblock_unref(i->thread_info.resampled_chunk.memblock);
+        pa_memchunk_reset(&i->thread_info.resampled_chunk);
+    }
+
+    /* Calculate the new sleeping time */
+    if (immediately)
+        i->thread_info.move_silence = 0;
+    else
+        i->thread_info.move_silence = pa_usec_to_bytes(
+                pa_bytes_to_usec(i->thread_info.move_silence, &origin->sample_spec) +
+                silence_usec,
+                &dest->sample_spec);
+
+    pa_asyncmsgq_send(i->sink->asyncmsgq, PA_MSGOBJECT(i->sink), PA_SINK_MESSAGE_ADD_INPUT, i, 0, NULL);
+
+    pa_sink_update_status(origin);
+    pa_sink_update_status(dest);
+
+    pa_hook_fire(&i->sink->core->hooks[PA_CORE_HOOK_SINK_INPUT_MOVE_POST], i);
+
+    pa_log_debug("Successfully moved sink input %i from %s to %s.", i->index, origin->name, dest->name);
 
     /* 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, 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);
 
     return 0;
 }
+
+/* Called from thread context */
+int pa_sink_input_process_msg(pa_msgobject *o, int code, void *userdata, int64_t offset, pa_memchunk *chunk) {
+    pa_sink_input *i = PA_SINK_INPUT(o);
+
+    pa_sink_input_assert_ref(i);
+    pa_assert(PA_SINK_INPUT_LINKED(i->thread_info.state));
+
+    switch (code) {
+        case PA_SINK_INPUT_MESSAGE_SET_VOLUME:
+            i->thread_info.volume = *((pa_cvolume*) userdata);
+            return 0;
+
+        case PA_SINK_INPUT_MESSAGE_SET_MUTE:
+            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->thread_info.resampled_chunk.length, &i->sink->sample_spec);
+
+            if (i->thread_info.move_silence)
+                *r += pa_bytes_to_usec(i->thread_info.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->thread_info.resampler, PA_PTR_TO_UINT(userdata));
+
+            return 0;
+
+        case PA_SINK_INPUT_MESSAGE_SET_STATE: {
+            pa_sink_input *ssync;
+
+            if ((PA_PTR_TO_UINT(userdata) == PA_SINK_INPUT_DRAINED || PA_PTR_TO_UINT(userdata) == PA_SINK_INPUT_RUNNING) &&
+                (i->thread_info.state != PA_SINK_INPUT_DRAINED) && (i->thread_info.state != PA_SINK_INPUT_RUNNING))
+                pa_atomic_store(&i->thread_info.drained, 1);
+
+            i->thread_info.state = PA_PTR_TO_UINT(userdata);
+
+            for (ssync = i->thread_info.sync_prev; ssync; ssync = ssync->thread_info.sync_prev) {
+                if ((PA_PTR_TO_UINT(userdata) == PA_SINK_INPUT_DRAINED || PA_PTR_TO_UINT(userdata) == PA_SINK_INPUT_RUNNING) &&
+                    (ssync->thread_info.state != PA_SINK_INPUT_DRAINED) && (ssync->thread_info.state != PA_SINK_INPUT_RUNNING))
+                    pa_atomic_store(&ssync->thread_info.drained, 1);
+                ssync->thread_info.state = PA_PTR_TO_UINT(userdata);
+            }
+
+            for (ssync = i->thread_info.sync_next; ssync; ssync = ssync->thread_info.sync_next) {
+                if ((PA_PTR_TO_UINT(userdata) == PA_SINK_INPUT_DRAINED || PA_PTR_TO_UINT(userdata) == PA_SINK_INPUT_RUNNING) &&
+                    (ssync->thread_info.state != PA_SINK_INPUT_DRAINED) && (ssync->thread_info.state != PA_SINK_INPUT_RUNNING))
+                    pa_atomic_store(&ssync->thread_info.drained, 1);
+                ssync->thread_info.state = PA_PTR_TO_UINT(userdata);
+            }
+
+            return 0;
+        }
+    }
+
+    return -1;
+}
+
+pa_sink_input_state_t pa_sink_input_get_state(pa_sink_input *i) {
+    pa_sink_input_assert_ref(i);
+
+    if (i->state == PA_SINK_INPUT_RUNNING || i->state == PA_SINK_INPUT_DRAINED)
+        return pa_atomic_load(&i->thread_info.drained) ? PA_SINK_INPUT_DRAINED : PA_SINK_INPUT_RUNNING;
+
+    return i->state;
+}

Modified: trunk/src/pulsecore/sink-input.h
URL: http://0pointer.de/cgi-bin/viewcvs.cgi/trunk/src/pulsecore/sink-input.h?rev=1971&root=pulseaudio&r1=1970&r2=1971&view=diff
==============================================================================
--- trunk/src/pulsecore/sink-input.h (original)
+++ trunk/src/pulsecore/sink-input.h Sun Oct 28 20:13:50 2007
@@ -1,5 +1,5 @@
-#ifndef foosinkinputhfoo
-#define foosinkinputhfoo
+#ifndef foopulsesinkinputhfoo
+#define foopulsesinkinputhfoo
 
 /* $Id$ */
 
@@ -39,20 +39,32 @@
 #include <pulsecore/core.h>
 
 typedef enum pa_sink_input_state {
+    PA_SINK_INPUT_INIT,         /*< The stream is not active yet, because pa_sink_put() has not been called yet */
+    PA_SINK_INPUT_DRAINED,      /*< The stream stopped playing because there was no data to play */
     PA_SINK_INPUT_RUNNING,      /*< The stream is alive and kicking */
-    PA_SINK_INPUT_DRAINED,      /*< The stream stopped playing because there was no data to play */
     PA_SINK_INPUT_CORKED,       /*< The stream was corked on user request */
-    PA_SINK_INPUT_DISCONNECTED  /*< The stream is dead */
+    PA_SINK_INPUT_UNLINKED      /*< The stream is dead */
 } pa_sink_input_state_t;
+
+static inline pa_bool_t PA_SINK_INPUT_LINKED(pa_sink_input_state_t x) {
+    return x == PA_SINK_INPUT_DRAINED || x == PA_SINK_INPUT_RUNNING || x == PA_SINK_INPUT_CORKED;
+}
 
 typedef enum pa_sink_input_flags {
     PA_SINK_INPUT_VARIABLE_RATE = 1,
-    PA_SINK_INPUT_NO_HOOKS = 2
+    PA_SINK_INPUT_DONT_MOVE = 2,
+    PA_SINK_INPUT_START_CORKED = 4
 } pa_sink_input_flags_t;
 
 struct pa_sink_input {
-    int ref;
+    pa_msgobject parent;
+
     uint32_t index;
+    pa_core *core;
+
+    /* Please note that this state should only be read with
+     * pa_sink_input_get_state(). That function will transparently
+     * merge the thread_info.drained value in. */
     pa_sink_input_state_t state;
     pa_sink_input_flags_t flags;
 
@@ -64,27 +76,87 @@
 
     pa_sample_spec sample_spec;
     pa_channel_map channel_map;
+
+    pa_sink_input *sync_prev, *sync_next;
+
     pa_cvolume volume;
-
-    /* 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 (*peek) (pa_sink_input *i, pa_memchunk *chunk);
-    void (*drop) (pa_sink_input *i, const pa_memchunk *chunk, size_t length);
+    pa_bool_t muted;
+
+    /* Returns the chunk of audio data (but doesn't drop it
+     * yet!). Returns -1 on failure. Called from IO thread context. If
+     * data needs to be generated from scratch then please in the
+     * specified length. This is an optimization only. If less data is
+     * available, it's fine to return a smaller block. If more data is
+     * already ready, it is better to return the full block.*/
+    int (*peek) (pa_sink_input *i, size_t length, pa_memchunk *chunk);
+
+    /* Drops the specified number of bytes, usually called right after
+     * peek(), but not necessarily. Called from IO thread context. */
+    void (*drop) (pa_sink_input *i, size_t length);
+
+    /* If non-NULL this function is called when the input is first
+     * connected to a sink or when the rtpoll/asyncmsgq fields
+     * change. You usually don't need to implement this function
+     * unless you rewrite a sink that is piggy-backed onto
+     * another. Called from IO thread context */
+    void (*attach) (pa_sink_input *i);           /* may be NULL */
+
+    /* If non-NULL this function is called when the output is
+     * disconnected from its sink. Called from IO thread context */
+    void (*detach) (pa_sink_input *i);           /* may be NULL */
+
+    /* If non-NULL called whenever the the sink this input is attached
+     * to suspends or resumes. Called from main context */
+    void (*suspend) (pa_sink_input *i, int b);   /* may be NULL */
+
+    /* Supposed to unlink and destroy this stream. Called from main
+     * context. */
     void (*kill) (pa_sink_input *i);             /* may be NULL */
+
+    /* Return the current latency (i.e. length of bufferd audio) of
+    this stream. Called from main context. If NULL a
+    PA_SINK_INPUT_MESSAGE_GET_LATENCY message is sent to the IO thread
+    instead. */
     pa_usec_t (*get_latency) (pa_sink_input *i); /* may be NULL */
-    void (*underrun) (pa_sink_input *i);         /* may be NULL */
+
+    pa_resample_method_t resample_method;
+
+    struct {
+        pa_sink_input_state_t state;
+        pa_atomic_t drained;
+
+        pa_bool_t attached; /* True only between ->attach() and ->detach() calls */
+
+        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_sink_input *sync_prev, *sync_next;
+
+        pa_cvolume volume;
+        pa_bool_t muted;
+    } thread_info;
 
     void *userdata;
-
-    pa_memchunk resampled_chunk;
-    pa_resampler *resampler;                     /* may be NULL */
-
-    pa_resample_method_t resample_method;
-
-    pa_memblock *silence_memblock;               /* may be NULL */
+};
+
+PA_DECLARE_CLASS(pa_sink_input);
+#define PA_SINK_INPUT(o) pa_sink_input_cast(o)
+
+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_SET_STATE,
+    PA_SINK_INPUT_MESSAGE_MAX
 };
 
 typedef struct pa_sink_input_new_data {
@@ -95,50 +167,71 @@
     pa_sink *sink;
 
     pa_sample_spec sample_spec;
-    int sample_spec_is_set;
+    pa_bool_t sample_spec_is_set;
     pa_channel_map channel_map;
-    int channel_map_is_set;
+    pa_bool_t channel_map_is_set;
+
     pa_cvolume volume;
-    int volume_is_set;
+    pa_bool_t volume_is_set;
+    pa_bool_t muted;
+    pa_bool_t muted_is_set;
 
     pa_resample_method_t resample_method;
+
+    pa_sink_input *sync_base;
 } pa_sink_input_new_data;
 
 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, pa_bool_t 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_disconnect(pa_sink_input* i);
-
-/* External code may request disconnection with this funcion */
+void pa_sink_input_put(pa_sink_input *i);
+void pa_sink_input_unlink(pa_sink_input* i);
+
+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);
-
-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);
+const pa_cvolume *pa_sink_input_get_volume(pa_sink_input *i);
+void pa_sink_input_set_mute(pa_sink_input *i, pa_bool_t mute);
+int pa_sink_input_get_mute(pa_sink_input *i);
+
+void pa_sink_input_cork(pa_sink_input *i, pa_bool_t b);
+
+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);
 
 int pa_sink_input_move_to(pa_sink_input *i, pa_sink *dest, int immediately);
 
+pa_sink_input_state_t pa_sink_input_get_state(pa_sink_input *i);
+
+/* To be used exclusively by the sink driver thread */
+
+int pa_sink_input_peek(pa_sink_input *i, size_t length, pa_memchunk *chunk, pa_cvolume *volume);
+void pa_sink_input_drop(pa_sink_input *i, size_t length);
+int pa_sink_input_process_msg(pa_msgobject *o, int code, void *userdata, int64_t offset, pa_memchunk *chunk);
+
+typedef struct pa_sink_input_move_info {
+    pa_sink_input *sink_input;
+    pa_sink_input *ghost_sink_input;
+    pa_memblockq *buffer;
+    size_t buffer_bytes;
+} pa_sink_input_move_info;
+
 #endif

Modified: trunk/src/pulsecore/sink.c
URL: http://0pointer.de/cgi-bin/viewcvs.cgi/trunk/src/pulsecore/sink.c?rev=1971&root=pulseaudio&r1=1970&r2=1971&view=diff
==============================================================================
--- trunk/src/pulsecore/sink.c (original)
+++ trunk/src/pulsecore/sink.c Sun Oct 28 20:13:50 2007
@@ -27,7 +27,6 @@
 #endif
 
 #include <stdlib.h>
-#include <assert.h>
 #include <string.h>
 #include <stdio.h>
 
@@ -41,16 +40,18 @@
 #include <pulsecore/sample-util.h>
 #include <pulsecore/core-subscribe.h>
 #include <pulsecore/log.h>
+#include <pulsecore/macro.h>
+#include <pulsecore/play-memblockq.h>
 
 #include "sink.h"
 
 #define MAX_MIX_CHANNELS 32
-
-#define CHECK_VALIDITY_RETURN_NULL(condition) \
-do {\
-if (!(condition)) \
-    return NULL; \
-} while (0)
+#define MIX_BUFFER_LENGTH (PA_PAGE_SIZE)
+#define SILENCE_BUFFER_LENGTH (PA_PAGE_SIZE*12)
+
+static PA_DEFINE_CHECK_TYPE(pa_sink, pa_msgobject);
+
+static void sink_free(pa_object *s);
 
 pa_sink* pa_sink_new(
         pa_core *core,
@@ -63,68 +64,71 @@
     pa_sink *s;
     char *n = NULL;
     char st[256];
-    int r;
     pa_channel_map tmap;
 
-    assert(core);
-    assert(name);
-    assert(spec);
-
-    CHECK_VALIDITY_RETURN_NULL(pa_sample_spec_valid(spec));
+    pa_assert(core);
+    pa_assert(name);
+    pa_assert(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);
-
-    s = pa_xnew(pa_sink, 1);
+    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_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;
+    s->state = PA_SINK_INIT;
+    s->flags = 0;
     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;
-
-    s->is_hardware = 0;
+    s->n_corked = 0;
+
+    pa_cvolume_reset(&s->volume, spec->channels);
+    s->muted = FALSE;
+    s->refresh_volume = s->refresh_mute = FALSE;
 
     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->set_state = NULL;
     s->userdata = NULL;
 
-    r = pa_idxset_put(core->sinks, s, &s->index);
-    assert(s->index != PA_IDXSET_INVALID && r >= 0);
+    s->asyncmsgq = NULL;
+    s->rtpoll = NULL;
+    s->silence = NULL;
+
+    pa_assert_se(pa_idxset_put(core->sinks, s, &s->index) >= 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);
 
     if (!(s->monitor_source = pa_source_new(core, driver, n, 0, spec, map)))
-        pa_log_warn("failed to create monitor source.");
+        pa_log_warn("Failed to create monitor source.");
     else {
         char *d;
         s->monitor_source->monitor_of = s;
@@ -135,51 +139,124 @@
 
     pa_xfree(n);
 
-    pa_subscription_post(core, PA_SUBSCRIPTION_EVENT_SINK | PA_SUBSCRIPTION_EVENT_NEW, s->index);
+    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;
 
     return s;
 }
 
-void pa_sink_disconnect(pa_sink* s) {
+static int sink_set_state(pa_sink *s, pa_sink_state_t state) {
+    int ret;
+
+    pa_assert(s);
+
+    if (s->state == state)
+        return 0;
+
+    if ((s->state == PA_SINK_SUSPENDED && PA_SINK_OPENED(state)) ||
+        (PA_SINK_OPENED(s->state) && state == PA_SINK_SUSPENDED)) {
+        pa_sink_input *i;
+        uint32_t idx;
+
+        /* We're suspending or resuming, tell everyone about it */
+
+        for (i = PA_SINK_INPUT(pa_idxset_first(s->inputs, &idx)); i; i = PA_SINK_INPUT(pa_idxset_next(s->inputs, &idx)))
+            if (i->suspend)
+                i->suspend(i, state == PA_SINK_SUSPENDED);
+    }
+
+    if (s->set_state)
+        if ((ret = s->set_state(s, state)) < 0)
+            return -1;
+
+    if (pa_asyncmsgq_send(s->asyncmsgq, PA_MSGOBJECT(s), PA_SINK_MESSAGE_SET_STATE, PA_UINT_TO_PTR(state), 0, NULL) < 0)
+        return -1;
+
+    s->state = state;
+
+    if (state != PA_SINK_UNLINKED) /* if we enter UNLINKED state pa_sink_unlink() will fire the apropriate events */
+        pa_hook_fire(&s->core->hooks[PA_CORE_HOOK_SINK_STATE_CHANGED], s);
+    return 0;
+}
+
+void pa_sink_put(pa_sink* s) {
+    pa_sink_assert_ref(s);
+
+    pa_assert(s->state == PA_SINK_INIT);
+    pa_assert(s->asyncmsgq);
+    pa_assert(s->rtpoll);
+
+    pa_assert_se(sink_set_state(s, PA_SINK_IDLE) == 0);
+
+    pa_source_put(s->monitor_source);
+
+    pa_subscription_post(s->core, PA_SUBSCRIPTION_EVENT_SINK | PA_SUBSCRIPTION_EVENT_NEW, s->index);
+    pa_hook_fire(&s->core->hooks[PA_CORE_HOOK_SINK_NEW_POST], s);
+}
+
+void pa_sink_unlink(pa_sink* s) {
+    pa_bool_t linked;
     pa_sink_input *i, *j = NULL;
 
-    assert(s);
-    assert(s->state == PA_SINK_RUNNING);
-
-    s->state = PA_SINK_DISCONNECTED;
-    pa_namereg_unregister(s->core, s->name);
-
-    pa_hook_fire(&s->core->hook_sink_disconnect, s);
+    pa_assert(s);
+
+    /* Please note that pa_sink_unlink() does more than simply
+     * reversing pa_sink_put(). It also undoes the registrations
+     * already done in pa_sink_new()! */
+
+    /* All operations here shall be idempotent, i.e. pa_sink_unlink()
+     * may be called multiple times on the same sink without bad
+     * effects. */
+
+    linked = PA_SINK_LINKED(s->state);
+
+    if (linked)
+        pa_hook_fire(&s->core->hooks[PA_CORE_HOOK_SINK_UNLINK], s);
+
+    if (s->state != PA_SINK_UNLINKED)
+        pa_namereg_unregister(s->core, s->name);
+    pa_idxset_remove_by_data(s->core->sinks, s, NULL);
 
     while ((i = pa_idxset_first(s->inputs, NULL))) {
-        assert(i != j);
+        pa_assert(i != j);
         pa_sink_input_kill(i);
         j = i;
     }
 
+    if (linked)
+        sink_set_state(s, PA_SINK_UNLINKED);
+    else
+        s->state = PA_SINK_UNLINKED;
+
+    s->get_latency = NULL;
+    s->get_volume = NULL;
+    s->set_volume = NULL;
+    s->set_mute = NULL;
+    s->get_mute = NULL;
+    s->set_state = NULL;
+
     if (s->monitor_source)
-        pa_source_disconnect(s->monitor_source);
-
-    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;
-
-    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);
-
-    if (s->state != PA_SINK_DISCONNECTED)
-        pa_sink_disconnect(s);
-
-    pa_log_info("freed %u \"%s\"", s->index, s->name);
+        pa_source_unlink(s->monitor_source);
+
+    if (linked) {
+        pa_subscription_post(s->core, PA_SUBSCRIPTION_EVENT_SINK | PA_SUBSCRIPTION_EVENT_REMOVE, s->index);
+        pa_hook_fire(&s->core->hooks[PA_CORE_HOOK_SINK_UNLINK_POST], s);
+    }
+}
+
+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);
+
+    if (PA_SINK_LINKED(s->state))
+        pa_sink_unlink(s);
+
+    pa_log_info("Freeing sink %u \"%s\"", s->index, s->name);
 
     if (s->monitor_source) {
         pa_source_unref(s->monitor_source);
@@ -187,6 +264,14 @@
     }
 
     pa_idxset_free(s->inputs, NULL, NULL);
+
+    while ((i = pa_hashmap_steal_first(s->thread_info.inputs)))
+        pa_sink_input_unref(i);
+
+    pa_hashmap_free(s->thread_info.inputs, NULL, NULL);
+
+    if (s->silence)
+        pa_memblock_unref(s->silence);
 
     pa_xfree(s->name);
     pa_xfree(s->description);
@@ -194,102 +279,178 @@
     pa_xfree(s);
 }
 
-void pa_sink_unref(pa_sink*s) {
-    assert(s);
-    assert(s->ref >= 1);
-
-    if (!(--s->ref))
-        sink_free(s);
-}
-
-pa_sink* pa_sink_ref(pa_sink *s) {
-    assert(s);
-    assert(s->ref >= 1);
-
-    s->ref++;
-    return s;
-}
-
-void pa_sink_notify(pa_sink*s) {
-    assert(s);
-    assert(s->ref >= 1);
-
-    if (s->notify)
-        s->notify(s);
-}
-
-static unsigned fill_mix_info(pa_sink *s, pa_mix_info *info, unsigned maxinfo) {
-    uint32_t idx = PA_IDXSET_INVALID;
+void pa_sink_set_asyncmsgq(pa_sink *s, pa_asyncmsgq *q) {
+    pa_sink_assert_ref(s);
+    pa_assert(q);
+
+    s->asyncmsgq = q;
+
+    if (s->monitor_source)
+        pa_source_set_asyncmsgq(s->monitor_source, q);
+}
+
+void pa_sink_set_rtpoll(pa_sink *s, pa_rtpoll *p) {
+    pa_sink_assert_ref(s);
+    pa_assert(p);
+
+    s->rtpoll = p;
+    if (s->monitor_source)
+        pa_source_set_rtpoll(s->monitor_source, p);
+}
+
+int pa_sink_update_status(pa_sink*s) {
+    pa_sink_assert_ref(s);
+    pa_assert(PA_SINK_LINKED(s->state));
+
+    if (s->state == PA_SINK_SUSPENDED)
+        return 0;
+
+    return sink_set_state(s, pa_sink_used_by(s) ? PA_SINK_RUNNING : PA_SINK_IDLE);
+}
+
+int pa_sink_suspend(pa_sink *s, pa_bool_t suspend) {
+    pa_sink_assert_ref(s);
+    pa_assert(PA_SINK_LINKED(s->state));
+
+    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);
+}
+
+void pa_sink_ping(pa_sink *s) {
+    pa_sink_assert_ref(s);
+    pa_assert(PA_SINK_LINKED(s->state));
+
+    pa_asyncmsgq_post(s->asyncmsgq, PA_MSGOBJECT(s), PA_SINK_MESSAGE_PING, NULL, 0, NULL, NULL);
+}
+
+static unsigned fill_mix_info(pa_sink *s, size_t length, pa_mix_info *info, unsigned maxinfo) {
     pa_sink_input *i;
     unsigned n = 0;
-
-    assert(s);
-    assert(s->ref >= 1);
-    assert(info);
-
-    for (i = pa_idxset_first(s->inputs, &idx); maxinfo > 0 && i; i = pa_idxset_next(s->inputs, &idx)) {
-        /* Increase ref counter, to make sure that this input doesn't
-         * vanish while we still need it */
-        pa_sink_input_ref(i);
-
-        if (pa_sink_input_peek(i, &info->chunk, &info->volume) < 0) {
-            pa_sink_input_unref(i);
+    void *state = NULL;
+
+    pa_sink_assert_ref(s);
+    pa_assert(info);
+
+    while ((i = pa_hashmap_iterate(s->thread_info.inputs, &state, NULL)) && maxinfo > 0) {
+        pa_sink_input_assert_ref(i);
+
+        if (pa_sink_input_peek(i, length, &info->chunk, &info->volume) < 0)
             continue;
+
+        info->userdata = pa_sink_input_ref(i);
+
+        pa_assert(info->chunk.memblock);
+        pa_assert(info->chunk.length > 0);
+
+        info++;
+        n++;
+        maxinfo--;
+    }
+
+    return n;
+}
+
+static void inputs_drop(pa_sink *s, pa_mix_info *info, unsigned n, size_t length) {
+    pa_sink_input *i;
+    void *state = NULL;
+    unsigned p = 0;
+    unsigned n_unreffed = 0;
+
+    pa_sink_assert_ref(s);
+
+    /* We optimize for the case where the order of the inputs has not changed */
+
+    while ((i = pa_hashmap_iterate(s->thread_info.inputs, &state, NULL))) {
+        unsigned j;
+        pa_mix_info* m;
+
+        pa_sink_input_assert_ref(i);
+
+        m = NULL;
+
+        /* Let's try to find the matching entry info the pa_mix_info array */
+        for (j = 0; j < n; j ++) {
+
+            if (info[p].userdata == i) {
+                m = info + p;
+                break;
+            }
+
+            p++;
+            if (p >= n)
+                p = 0;
         }
 
-        info->userdata = i;
-
-        assert(info->chunk.memblock);
-        assert(info->chunk.memblock->data);
-        assert(info->chunk.length);
-
-        info++;
-        maxinfo--;
-        n++;
-    }
-
-    return n;
-}
-
-static void inputs_drop(pa_sink *s, pa_mix_info *info, unsigned maxinfo, size_t length) {
-    assert(s);
-    assert(s->ref >= 1);
-    assert(info);
-
-    for (; maxinfo > 0; maxinfo--, info++) {
-        pa_sink_input *i = info->userdata;
-
-        assert(i);
-        assert(info->chunk.memblock);
-
         /* Drop read data */
-        pa_sink_input_drop(i, &info->chunk, length);
-        pa_memblock_unref(info->chunk.memblock);
-
-        /* Decrease ref counter */
-        pa_sink_input_unref(i);
-        info->userdata = NULL;
-    }
-}
-
-int pa_sink_render(pa_sink*s, size_t length, pa_memchunk *result) {
+        pa_sink_input_drop(i, length);
+
+        if (m) {
+            pa_sink_input_unref(m->userdata);
+            m->userdata = NULL;
+            if (m->chunk.memblock)
+                pa_memblock_unref(m->chunk.memblock);
+            pa_memchunk_reset(&m->chunk);
+
+            n_unreffed += 1;
+        }
+    }
+
+    /* Now drop references to entries that are included in the
+     * pa_mix_info array but don't exist anymore */
+
+    if (n_unreffed < n) {
+        for (; n > 0; info++, n--) {
+            if (info->userdata)
+                pa_sink_input_unref(info->userdata);
+            if (info->chunk.memblock)
+                pa_memblock_unref(info->chunk.memblock);
+        }
+    }
+}
+
+void pa_sink_render(pa_sink*s, size_t length, pa_memchunk *result) {
     pa_mix_info info[MAX_MIX_CHANNELS];
     unsigned n;
-    int r = -1;
-
-    assert(s);
-    assert(s->ref >= 1);
-    assert(length);
-    assert(result);
+    size_t block_size_max;
+
+    pa_sink_assert_ref(s);
+    pa_assert(PA_SINK_OPENED(s->thread_info.state));
+    pa_assert(pa_frame_aligned(length, &s->sample_spec));
+    pa_assert(result);
 
     pa_sink_ref(s);
 
-    n = fill_mix_info(s, info, MAX_MIX_CHANNELS);
-
-    if (n <= 0)
-        goto finish;
-
-    if (n == 1) {
+    if (length <= 0)
+        length = pa_frame_align(MIX_BUFFER_LENGTH, &s->sample_spec);
+
+    block_size_max = pa_mempool_block_size_max(s->core->mempool);
+    if (length > block_size_max)
+        length = pa_frame_align(block_size_max, &s->sample_spec);
+
+    pa_assert(length > 0);
+
+    n = s->thread_info.state == PA_SINK_RUNNING ? fill_mix_info(s, length, info, MAX_MIX_CHANNELS) : 0;
+
+    if (n == 0) {
+
+        if (length > SILENCE_BUFFER_LENGTH)
+            length = pa_frame_align(SILENCE_BUFFER_LENGTH, &s->sample_spec);
+
+        pa_assert(length > 0);
+
+        if (!s->silence || pa_memblock_get_length(s->silence) < length) {
+            if (s->silence)
+                pa_memblock_unref(s->silence);
+            s->silence = pa_silence_memblock_new(s->core->mempool, &s->sample_spec, length);
+        }
+
+        result->memblock = pa_memblock_ref(s->silence);
+        result->length = length;
+        result->index = 0;
+
+    } else if (n == 1) {
         pa_cvolume volume;
 
         *result = info[0].chunk;
@@ -298,105 +459,112 @@
         if (result->length > length)
             result->length = length;
 
-        pa_sw_cvolume_multiply(&volume, &s->sw_volume, &info[0].volume);
-
-        if (s->sw_muted || !pa_cvolume_is_norm(&volume)) {
+        pa_sw_cvolume_multiply(&volume, &s->thread_info.soft_volume, &info[0].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);  */
-
-        result->length = pa_mix(info, n, result->memblock->data, length,
-            &s->sample_spec, &s->sw_volume, s->sw_muted);
+
+        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->index = 0;
     }
 
-    inputs_drop(s, info, n, result->length);
-
-    if (s->monitor_source)
+    if (s->thread_info.state == PA_SINK_RUNNING)
+        inputs_drop(s, info, n, result->length);
+
+    if (s->monitor_source && PA_SOURCE_OPENED(pa_source_get_state(s->monitor_source)))
         pa_source_post(s->monitor_source, result);
 
-    r = 0;
-
-finish:
     pa_sink_unref(s);
-
-    return r;
-}
-
-int pa_sink_render_into(pa_sink*s, pa_memchunk *target) {
+}
+
+void pa_sink_render_into(pa_sink*s, pa_memchunk *target) {
     pa_mix_info info[MAX_MIX_CHANNELS];
     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(PA_SINK_OPENED(s->thread_info.state));
+    pa_assert(target);
+    pa_assert(target->memblock);
+    pa_assert(target->length > 0);
+    pa_assert(pa_frame_aligned(target->length, &s->sample_spec));
 
     pa_sink_ref(s);
 
-    n = fill_mix_info(s, info, MAX_MIX_CHANNELS);
-
-    if (n <= 0)
-        goto finish;
-
-    if (n == 1) {
-        pa_cvolume volume;
-
+    n = s->thread_info.state == PA_SINK_RUNNING ? fill_mix_info(s, target->length, info, MAX_MIX_CHANNELS) : 0;
+
+    if (n == 0) {
+        pa_silence_memchunk(target, &s->sample_spec);
+    } else 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);
-
-    inputs_drop(s, info, n, target->length);
-
-    if (s->monitor_source)
+                                &s->thread_info.soft_volume,
+                                s->thread_info.soft_muted);
+
+        pa_memblock_release(target->memblock);
+    }
+
+    if (s->thread_info.state == PA_SINK_RUNNING)
+        inputs_drop(s, info, n, target->length);
+
+    if (s->monitor_source && PA_SOURCE_OPENED(pa_source_get_state(s->monitor_source)))
         pa_source_post(s->monitor_source, target);
 
-    r = 0;
-
-finish:
     pa_sink_unref(s);
-
-    return r;
 }
 
 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(PA_SINK_OPENED(s->thread_info.state));
+    pa_assert(target);
+    pa_assert(target->memblock);
+    pa_assert(target->length > 0);
+    pa_assert(pa_frame_aligned(target->length, &s->sample_spec));
 
     pa_sink_ref(s);
 
@@ -407,140 +575,177 @@
         chunk.index += d;
         chunk.length -= d;
 
-        if (pa_sink_render_into(s, &chunk) < 0)
-            break;
+        pa_sink_render_into(s, &chunk);
 
         d += chunk.length;
         l -= chunk.length;
     }
 
-    if (l > 0) {
-        chunk = *target;
-        chunk.index += d;
-        chunk.length -= d;
-        pa_silence_memchunk(&chunk, &s->sample_spec);
-    }
-
     pa_sink_unref(s);
 }
 
 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(PA_SINK_OPENED(s->thread_info.state));
+    pa_assert(length > 0);
+    pa_assert(pa_frame_aligned(length, &s->sample_spec));
+    pa_assert(result);
 
     /*** This needs optimization ***/
 
-    result->memblock = pa_memblock_new(s->core->mempool, result->length = length);
     result->index = 0;
+    result->length = length;
+    result->memblock = pa_memblock_new(s->core->mempool, length);
 
     pa_sink_render_into_full(s, result);
 }
 
+void pa_sink_skip(pa_sink *s, size_t length) {
+    pa_sink_input *i;
+    void *state = NULL;
+
+    pa_sink_assert_ref(s);
+    pa_assert(PA_SINK_OPENED(s->thread_info.state));
+    pa_assert(length > 0);
+    pa_assert(pa_frame_aligned(length, &s->sample_spec));
+
+    if (pa_source_used_by(s->monitor_source)) {
+        pa_memchunk chunk;
+
+        /* If something is connected to our monitor source, we have to
+         * pass valid data to it */
+
+        while (length > 0) {
+            pa_sink_render(s, length, &chunk);
+            pa_memblock_unref(chunk.memblock);
+
+            pa_assert(chunk.length <= length);
+            length -= chunk.length;
+        }
+
+    } else {
+        /* Ok, noone cares about the rendered data, so let's not even render it */
+
+        while ((i = pa_hashmap_iterate(s->thread_info.inputs, &state, NULL))) {
+            pa_sink_input_assert_ref(i);
+            pa_sink_input_drop(i, length);
+        }
+    }
+}
+
 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);
+    pa_assert(PA_SINK_LINKED(s->state));
+
+    if (!PA_SINK_OPENED(s->state))
         return 0;
 
-    return s->get_latency(s);
-}
-
-void pa_sink_set_owner(pa_sink *s, pa_module *m) {
-    assert(s);
-    assert(s->ref >= 1);
-
-    if (s->owner == m)
+    if (s->get_latency)
+        return s->get_latency(s);
+
+    if (pa_asyncmsgq_send(s->asyncmsgq, PA_MSGOBJECT(s), PA_SINK_MESSAGE_GET_LATENCY, &usec, 0, NULL) < 0)
+        return 0;
+
+    return usec;
+}
+
+void pa_sink_set_volume(pa_sink *s, const pa_cvolume *volume) {
+    int changed;
+
+    pa_sink_assert_ref(s);
+    pa_assert(PA_SINK_LINKED(s->state));
+    pa_assert(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_MSGOBJECT(s), PA_SINK_MESSAGE_SET_VOLUME, pa_xnewdup(struct pa_cvolume, volume, 1), 0, NULL, pa_xfree);
+
+    if (changed)
+        pa_subscription_post(s->core, PA_SUBSCRIPTION_EVENT_SINK|PA_SUBSCRIPTION_EVENT_CHANGE, s->index);
+}
+
+const pa_cvolume *pa_sink_get_volume(pa_sink *s) {
+    struct pa_cvolume old_volume;
+
+    pa_sink_assert_ref(s);
+    pa_assert(PA_SINK_LINKED(s->state));
+
+    old_volume = s->volume;
+
+    if (s->get_volume && s->get_volume(s) < 0)
+        s->get_volume = NULL;
+
+    if (!s->get_volume && s->refresh_volume)
+        pa_asyncmsgq_send(s->asyncmsgq, PA_MSGOBJECT(s), PA_SINK_MESSAGE_GET_VOLUME, &s->volume, 0, NULL);
+
+    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, pa_bool_t mute) {
+    int changed;
+
+    pa_sink_assert_ref(s);
+    pa_assert(PA_SINK_LINKED(s->state));
+
+    changed = s->muted != mute;
+    s->muted = mute;
+
+    if (s->set_mute && s->set_mute(s) < 0)
+        s->set_mute = NULL;
+
+    if (!s->set_mute)
+        pa_asyncmsgq_post(s->asyncmsgq, PA_MSGOBJECT(s), PA_SINK_MESSAGE_SET_MUTE, PA_UINT_TO_PTR(mute), 0, NULL, NULL);
+
+    if (changed)
+        pa_subscription_post(s->core, PA_SUBSCRIPTION_EVENT_SINK|PA_SUBSCRIPTION_EVENT_CHANGE, s->index);
+}
+
+pa_bool_t pa_sink_get_mute(pa_sink *s) {
+    pa_bool_t old_muted;
+
+    pa_sink_assert_ref(s);
+    pa_assert(PA_SINK_LINKED(s->state));
+
+    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, PA_MSGOBJECT(s), PA_SINK_MESSAGE_GET_MUTE, &s->muted, 0, NULL);
+
+    if (old_muted != s->muted)
+        pa_subscription_post(s->core, PA_SUBSCRIPTION_EVENT_SINK|PA_SUBSCRIPTION_EVENT_CHANGE, s->index);
+
+    return s->muted;
+}
+
+void pa_sink_set_module(pa_sink *s, pa_module *m) {
+    pa_sink_assert_ref(s);
+
+    if (s->module == m)
         return;
 
-    s->owner = m;
+    s->module = m;
 
     if (s->monitor_source)
-        pa_source_set_owner(s->monitor_source, m);
+        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_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;
-
-    if (pa_cvolume_equal(v, volume))
-        return;
-
-    *v = *volume;
-
-    if (v == &s->hw_volume)
-        if (s->set_hw_volume(s) < 0)
-            s->sw_volume =  *volume;
-
-    pa_subscription_post(s->core, PA_SUBSCRIPTION_EVENT_SINK|PA_SUBSCRIPTION_EVENT_CHANGE, s->index);
-}
-
-const pa_cvolume *pa_sink_get_volume(pa_sink *s, pa_mixer_t m) {
-    assert(s);
-    assert(s->ref >= 1);
-
-    if (m == PA_MIXER_HARDWARE && s->set_hw_volume) {
-
-        if (s->get_hw_volume)
-            s->get_hw_volume(s);
-
-        return &s->hw_volume;
-    } else
-        return &s->sw_volume;
-}
-
-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 (!!*t == !!mute)
-        return;
-
-    *t = !!mute;
-
-    if (t == &s->hw_muted)
-        if (s->set_hw_mute(s) < 0)
-            s->sw_muted = !!mute;
-
-    pa_subscription_post(s->core, PA_SUBSCRIPTION_EVENT_SINK|PA_SUBSCRIPTION_EVENT_CHANGE, s->index);
-}
-
-int pa_sink_get_mute(pa_sink *s, pa_mixer_t m) {
-    assert(s);
-    assert(s->ref >= 1);
-
-    if (m == PA_MIXER_HARDWARE && s->set_hw_mute) {
-
-        if (s->get_hw_mute)
-            s->get_hw_mute(s);
-
-        return s->hw_muted;
-    } else
-        return s->sw_muted;
-}
-
 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;
@@ -559,19 +764,298 @@
         pa_xfree(n);
     }
 
-    pa_subscription_post(s->core, PA_SUBSCRIPTION_EVENT_SINK|PA_SUBSCRIPTION_EVENT_CHANGE, s->index);
+    if (PA_SINK_LINKED(s->state)) {
+        pa_subscription_post(s->core, PA_SUBSCRIPTION_EVENT_SINK|PA_SUBSCRIPTION_EVENT_CHANGE, s->index);
+        pa_hook_fire(&s->core->hooks[PA_CORE_HOOK_SINK_DESCRIPTION_CHANGED], s);
+    }
+}
+
+unsigned pa_sink_linked_by(pa_sink *s) {
+    unsigned ret;
+
+    pa_sink_assert_ref(s);
+    pa_assert(PA_SINK_LINKED(s->state));
+
+    ret = pa_idxset_size(s->inputs);
+
+    /* We add in the number of streams connected to us here. Please
+     * not the asymmmetry to pa_sink_used_by()! */
+
+    if (s->monitor_source)
+        ret += pa_source_linked_by(s->monitor_source);
+
+    return ret;
 }
 
 unsigned pa_sink_used_by(pa_sink *s) {
     unsigned ret;
 
-    assert(s);
-    assert(s->ref >= 1);
+    pa_sink_assert_ref(s);
+    pa_assert(PA_SINK_LINKED(s->state));
 
     ret = pa_idxset_size(s->inputs);
+    pa_assert(ret >= s->n_corked);
+    ret -= s->n_corked;
+
+    /* Streams connected to our monitor source do not matter for
+     * pa_sink_used_by()!.*/
+
+    return ret;
+}
+
+int pa_sink_process_msg(pa_msgobject *o, int code, void *userdata, int64_t offset, pa_memchunk *chunk) {
+    pa_sink *s = PA_SINK(o);
+    pa_sink_assert_ref(s);
+    pa_assert(s->thread_info.state != PA_SINK_UNLINKED);
+
+    switch ((pa_sink_message_t) code) {
+
+        case PA_SINK_MESSAGE_ADD_INPUT: {
+            pa_sink_input *i = PA_SINK_INPUT(userdata);
+            pa_hashmap_put(s->thread_info.inputs, PA_UINT32_TO_PTR(i->index), pa_sink_input_ref(i));
+
+            /* Since the caller sleeps in pa_sink_input_put(), we can
+             * safely access data outside of thread_info even though
+             * it is mutable */
+
+            if ((i->thread_info.sync_prev = i->sync_prev)) {
+                pa_assert(i->sink == i->thread_info.sync_prev->sink);
+                pa_assert(i->sync_prev->sync_next == i);
+                i->thread_info.sync_prev->thread_info.sync_next = i;
+            }
+
+            if ((i->thread_info.sync_next = i->sync_next)) {
+                pa_assert(i->sink == i->thread_info.sync_next->sink);
+                pa_assert(i->sync_next->sync_prev == i);
+                i->thread_info.sync_next->thread_info.sync_prev = i;
+            }
+
+            pa_assert(!i->thread_info.attached);
+            i->thread_info.attached = TRUE;
+
+            if (i->attach)
+                i->attach(i);
+
+            /* If you change anything here, make sure to change the
+             * ghost sink input handling a few lines down at
+             * PA_SINK_MESSAGE_REMOVE_INPUT_AND_BUFFER, too. */
+
+            return 0;
+        }
+
+        case PA_SINK_MESSAGE_REMOVE_INPUT: {
+            pa_sink_input *i = PA_SINK_INPUT(userdata);
+
+            /* If you change anything here, make sure to change the
+             * sink input handling a few lines down at
+             * PA_SINK_MESSAGE_REMOVE_INPUT_AND_BUFFER, too. */
+
+            if (i->detach)
+                i->detach(i);
+
+            pa_assert(i->thread_info.attached);
+            i->thread_info.attached = FALSE;
+
+            /* Since the caller sleeps in pa_sink_input_unlink(),
+             * we can safely access data outside of thread_info even
+             * though it is mutable */
+
+            pa_assert(!i->thread_info.sync_prev);
+            pa_assert(!i->thread_info.sync_next);
+
+            if (i->thread_info.sync_prev) {
+                i->thread_info.sync_prev->thread_info.sync_next = i->thread_info.sync_prev->sync_next;
+                i->thread_info.sync_prev = NULL;
+            }
+
+            if (i->thread_info.sync_next) {
+                i->thread_info.sync_next->thread_info.sync_prev = i->thread_info.sync_next->sync_prev;
+                i->thread_info.sync_next = NULL;
+            }
+
+            if (pa_hashmap_remove(s->thread_info.inputs, PA_UINT32_TO_PTR(i->index)))
+                pa_sink_input_unref(i);
+
+            return 0;
+        }
+
+        case PA_SINK_MESSAGE_REMOVE_INPUT_AND_BUFFER: {
+            pa_sink_input_move_info *info = userdata;
+            int volume_is_norm;
+
+            /* We don't support moving synchronized streams. */
+            pa_assert(!info->sink_input->sync_prev);
+            pa_assert(!info->sink_input->sync_next);
+            pa_assert(!info->sink_input->thread_info.sync_next);
+            pa_assert(!info->sink_input->thread_info.sync_prev);
+
+            if (info->sink_input->detach)
+                info->sink_input->detach(info->sink_input);
+
+            pa_assert(info->sink_input->thread_info.attached);
+            info->sink_input->thread_info.attached = FALSE;
+
+            if (info->ghost_sink_input) {
+                pa_assert(info->buffer_bytes > 0);
+                pa_assert(info->buffer);
+
+                volume_is_norm = pa_cvolume_is_norm(&info->sink_input->thread_info.volume);
+
+                pa_log_debug("Buffering %lu bytes ...", (unsigned long) info->buffer_bytes);
+
+                while (info->buffer_bytes > 0) {
+                    pa_memchunk memchunk;
+                    pa_cvolume volume;
+                    size_t n;
+
+                    if (pa_sink_input_peek(info->sink_input, info->buffer_bytes, &memchunk, &volume) < 0)
+                        break;
+
+                    n = memchunk.length > info->buffer_bytes ? info->buffer_bytes : memchunk.length;
+                    pa_sink_input_drop(info->sink_input, n);
+                    memchunk.length = n;
+
+                    if (!volume_is_norm) {
+                        pa_memchunk_make_writable(&memchunk, 0);
+                        pa_volume_memchunk(&memchunk, &s->sample_spec, &volume);
+                    }
+
+                    if (pa_memblockq_push(info->buffer, &memchunk) < 0) {
+                        pa_memblock_unref(memchunk.memblock);
+                        break;
+                    }
+
+                    pa_memblock_unref(memchunk.memblock);
+                    info->buffer_bytes -= n;
+                }
+
+                /* Add the remaining already resampled chunk to the buffer */
+                if (info->sink_input->thread_info.resampled_chunk.memblock)
+                    pa_memblockq_push(info->buffer, &info->sink_input->thread_info.resampled_chunk);
+
+                pa_memblockq_sink_input_set_queue(info->ghost_sink_input, info->buffer);
+
+                pa_log_debug("Buffered %lu bytes ...", (unsigned long) pa_memblockq_get_length(info->buffer));
+            }
+
+            /* Let's remove the sink input ...*/
+            if (pa_hashmap_remove(s->thread_info.inputs, PA_UINT32_TO_PTR(info->sink_input->index)))
+                pa_sink_input_unref(info->sink_input);
+
+            /* .. and add the ghost sink input instead */
+            if (info->ghost_sink_input) {
+                pa_hashmap_put(s->thread_info.inputs, PA_UINT32_TO_PTR(info->ghost_sink_input->index), pa_sink_input_ref(info->ghost_sink_input));
+                info->ghost_sink_input->thread_info.sync_prev = info->ghost_sink_input->thread_info.sync_next = NULL;
+
+                pa_assert(!info->ghost_sink_input->thread_info.attached);
+                info->ghost_sink_input->thread_info.attached = TRUE;
+
+                if (info->ghost_sink_input->attach)
+                    info->ghost_sink_input->attach(info->ghost_sink_input);
+            }
+
+            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:
+            *((pa_bool_t*) userdata) = s->thread_info.soft_muted;
+            return 0;
+
+        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_DETACH:
+
+            /* We're detaching all our input streams so that the
+             * asyncmsgq and rtpoll fields can be changed without
+             * problems */
+            pa_sink_detach_within_thread(s);
+            break;
+
+        case PA_SINK_MESSAGE_ATTACH:
+
+            /* Reattach all streams */
+            pa_sink_attach_within_thread(s);
+            break;
+
+        case PA_SINK_MESSAGE_GET_LATENCY:
+        case PA_SINK_MESSAGE_MAX:
+            ;
+    }
+
+    return -1;
+}
+
+int pa_sink_suspend_all(pa_core *c, pa_bool_t suspend) {
+    pa_sink *sink;
+    uint32_t idx;
+    int ret = 0;
+
+    pa_core_assert_ref(c);
+
+    for (sink = PA_SINK(pa_idxset_first(c->sinks, &idx)); sink; sink = PA_SINK(pa_idxset_next(c->sinks, &idx)))
+        ret -= pa_sink_suspend(sink, suspend) < 0;
+
+    return ret;
+}
+
+void pa_sink_detach(pa_sink *s) {
+    pa_sink_assert_ref(s);
+    pa_assert(PA_SINK_LINKED(s->state));
+
+    pa_asyncmsgq_send(s->asyncmsgq, PA_MSGOBJECT(s), PA_SINK_MESSAGE_DETACH, NULL, 0, NULL);
+}
+
+void pa_sink_attach(pa_sink *s) {
+    pa_sink_assert_ref(s);
+    pa_assert(PA_SINK_LINKED(s->state));
+
+    pa_asyncmsgq_send(s->asyncmsgq, PA_MSGOBJECT(s), PA_SINK_MESSAGE_ATTACH, NULL, 0, NULL);
+}
+
+void pa_sink_detach_within_thread(pa_sink *s) {
+    pa_sink_input *i;
+    void *state = NULL;
+
+    pa_sink_assert_ref(s);
+    pa_assert(PA_SINK_LINKED(s->thread_info.state));
+
+    while ((i = pa_hashmap_iterate(s->thread_info.inputs, &state, NULL)))
+        if (i->detach)
+            i->detach(i);
 
     if (s->monitor_source)
-        ret += pa_source_used_by(s->monitor_source);
-
-    return ret;
-}
+        pa_source_detach_within_thread(s->monitor_source);
+}
+
+void pa_sink_attach_within_thread(pa_sink *s) {
+    pa_sink_input *i;
+    void *state = NULL;
+
+    pa_sink_assert_ref(s);
+    pa_assert(PA_SINK_LINKED(s->thread_info.state));
+
+    while ((i = pa_hashmap_iterate(s->thread_info.inputs, &state, NULL)))
+        if (i->attach)
+            i->attach(i);
+
+    if (s->monitor_source)
+        pa_source_attach_within_thread(s->monitor_source);
+}

Modified: trunk/src/pulsecore/sink.h
URL: http://0pointer.de/cgi-bin/viewcvs.cgi/trunk/src/pulsecore/sink.h?rev=1971&root=pulseaudio&r1=1970&r2=1971&view=diff
==============================================================================
--- trunk/src/pulsecore/sink.h (original)
+++ trunk/src/pulsecore/sink.h Sun Oct 28 20:13:50 2007
@@ -1,5 +1,5 @@
-#ifndef foosinkhfoo
-#define foosinkhfoo
+#ifndef foopulsesinkhfoo
+#define foopulsesinkhfoo
 
 /* $Id$ */
 
@@ -25,87 +25,164 @@
   USA.
 ***/
 
+typedef struct pa_sink pa_sink;
+
 #include <inttypes.h>
-
-typedef struct pa_sink pa_sink;
 
 #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>
+#include <pulsecore/rtpoll.h>
 
 #define PA_MAX_INPUTS_PER_SINK 32
 
 typedef enum pa_sink_state {
+    PA_SINK_INIT,
     PA_SINK_RUNNING,
-    PA_SINK_DISCONNECTED
+    PA_SINK_SUSPENDED,
+    PA_SINK_IDLE,
+    PA_SINK_UNLINKED
 } pa_sink_state_t;
 
+static inline pa_bool_t PA_SINK_OPENED(pa_sink_state_t x) {
+    return x == PA_SINK_RUNNING || x == PA_SINK_IDLE;
+}
+
+static inline pa_bool_t PA_SINK_LINKED(pa_sink_state_t x) {
+    return x == PA_SINK_RUNNING || x == PA_SINK_IDLE || x == PA_SINK_SUSPENDED;
+}
+
 struct pa_sink {
-    int ref;
+    pa_msgobject parent;
+
     uint32_t index;
     pa_core *core;
     pa_sink_state_t state;
+    pa_sink_flags_t flags;
 
     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;
 
     pa_idxset *inputs;
-    pa_source *monitor_source;             /* may be NULL */
+    unsigned n_corked;
+    pa_source *monitor_source;
 
-    pa_cvolume hw_volume, sw_volume;
-    int hw_muted, sw_muted;
+    pa_cvolume volume;
+    pa_bool_t muted;
+    pa_bool_t refresh_volume;
+    pa_bool_t refresh_mute;
 
-    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 */
+    int (*set_state)(pa_sink *s, pa_sink_state_t state); /* may be NULL */
+    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;
+    pa_rtpoll *rtpoll;
+
+    /* 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;
+        pa_bool_t soft_muted;
+    } thread_info;
+
+    pa_memblock *silence;
 
     void *userdata;
 };
 
+PA_DECLARE_CLASS(pa_sink);
+#define PA_SINK(s) (pa_sink_cast(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_SET_STATE,
+    PA_SINK_MESSAGE_PING,
+    PA_SINK_MESSAGE_REMOVE_INPUT_AND_BUFFER,
+    PA_SINK_MESSAGE_ATTACH,
+    PA_SINK_MESSAGE_DETACH,
+    PA_SINK_MESSAGE_MAX
+} pa_sink_message_t;
+
+/* To be called exclusively by the sink driver, from main context */
+
 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);
+void pa_sink_put(pa_sink *s);
+void pa_sink_unlink(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);
+void pa_sink_set_asyncmsgq(pa_sink *s, pa_asyncmsgq *q);
+void pa_sink_set_rtpoll(pa_sink *s, pa_rtpoll *p);
+
+void pa_sink_detach(pa_sink *s);
+void pa_sink_attach(pa_sink *s);
+
+/* May be called by everyone, from main context */
 
 pa_usec_t pa_sink_get_latency(pa_sink *s);
 
-void pa_sink_notify(pa_sink*s);
+int pa_sink_update_status(pa_sink*s);
+int pa_sink_suspend(pa_sink *s, pa_bool_t suspend);
+int pa_sink_suspend_all(pa_core *c, pa_bool_t suspend);
 
-void pa_sink_set_owner(pa_sink *sink, pa_module *m);
+/* 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, 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);
+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, pa_bool_t mute);
+pa_bool_t pa_sink_get_mute(pa_sink *sink);
 
-void pa_sink_set_description(pa_sink *s, const char *description);
+unsigned pa_sink_linked_by(pa_sink *s); /* Number of connected streams */
+unsigned pa_sink_used_by(pa_sink *s); /* Number of connected streams which are not corked */
+#define pa_sink_get_state(s) ((s)->state)
 
-unsigned pa_sink_used_by(pa_sink *s);
+/* To be called exclusively by the sink driver, from IO context */
+
+void 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);
+void 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_skip(pa_sink *s, size_t length);
+
+int pa_sink_process_msg(pa_msgobject *o, int code, void *userdata, int64_t offset, pa_memchunk *chunk);
+
+void pa_sink_attach_within_thread(pa_sink *s);
+void pa_sink_detach_within_thread(pa_sink *s);
 
 #endif

Modified: trunk/src/pulsecore/sioman.c
URL: http://0pointer.de/cgi-bin/viewcvs.cgi/trunk/src/pulsecore/sioman.c?rev=1971&root=pulseaudio&r1=1970&r2=1971&view=diff
==============================================================================
--- trunk/src/pulsecore/sioman.c (original)
+++ trunk/src/pulsecore/sioman.c Sun Oct 28 20:13:50 2007
@@ -25,21 +25,17 @@
 #include <config.h>
 #endif
 
-#include <assert.h>
+#include <pulsecore/macro.h>
+#include <pulsecore/atomic.h>
 
 #include "sioman.h"
 
-static int stdio_inuse = 0;
+static pa_atomic_t stdio_inuse = PA_ATOMIC_INIT(0);
 
 int pa_stdio_acquire(void) {
-    if (stdio_inuse)
-        return -1;
-
-    stdio_inuse = 1;
-    return 0;
+    return pa_atomic_cmpxchg(&stdio_inuse, 0, 1) ? 0 : -1;
 }
 
 void pa_stdio_release(void) {
-    assert(stdio_inuse);
-    stdio_inuse = 0;
+    pa_assert_se(pa_atomic_cmpxchg(&stdio_inuse, 1, 0));
 }

Modified: trunk/src/pulsecore/socket-client.c
URL: http://0pointer.de/cgi-bin/viewcvs.cgi/trunk/src/pulsecore/socket-client.c?rev=1971&root=pulseaudio&r1=1970&r2=1971&view=diff
==============================================================================
--- trunk/src/pulsecore/socket-client.c (original)
+++ trunk/src/pulsecore/socket-client.c Sun Oct 28 20:13:50 2007
@@ -1,25 +1,25 @@
 /* $Id$ */
 
 /***
-  This file is part of PulseAudio.
-
-  Copyright 2004-2006 Lennart Poettering
-  Copyright 2006-2007 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.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.
+    This file is part of PulseAudio.
+
+    Copyright 2004-2006 Lennart Poettering
+    Copyright 2006-2007 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.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
@@ -32,7 +32,6 @@
 #include <stdio.h>
 #include <errno.h>
 #include <string.h>
-#include <assert.h>
 #include <stdlib.h>
 
 #ifdef HAVE_SYS_SOCKET_H
@@ -55,23 +54,24 @@
 #include <asyncns.h>
 #endif
 
-#include "winsock.h"
-
 #include <pulse/timeval.h>
 #include <pulse/xmalloc.h>
 
+#include <pulsecore/winsock.h>
 #include <pulsecore/core-error.h>
 #include <pulsecore/socket-util.h>
 #include <pulsecore/core-util.h>
 #include <pulsecore/log.h>
 #include <pulsecore/parseaddr.h>
+#include <pulsecore/macro.h>
+#include <pulsecore/refcnt.h>
 
 #include "socket-client.h"
 
 #define CONNECT_TIMEOUT 5
 
 struct pa_socket_client {
-    int ref;
+    PA_REFCNT_DECLARE;
     pa_mainloop_api *mainloop;
     int fd;
     pa_io_event *io_event;
@@ -89,10 +89,10 @@
 
 static pa_socket_client*pa_socket_client_new(pa_mainloop_api *m) {
     pa_socket_client *c;
-    assert(m);
-
-    c = pa_xmalloc(sizeof(pa_socket_client));
-    c->ref = 1;
+    pa_assert(m);
+
+    c = pa_xnew(pa_socket_client, 1);
+    PA_REFCNT_INIT(c);
     c->mainloop = m;
     c->fd = -1;
     c->io_event = NULL;
@@ -112,7 +112,7 @@
 }
 
 static void free_events(pa_socket_client *c) {
-    assert(c);
+    pa_assert(c);
 
     if (c->io_event) {
         c->mainloop->io_free(c->io_event);
@@ -134,7 +134,10 @@
     pa_iochannel *io = NULL;
     int error;
     socklen_t lerror;
-    assert(c && c->callback);
+
+    pa_assert(c);
+    pa_assert(PA_REFCNT_VALUE(c) >= 1);
+    pa_assert(c->callback);
 
     pa_socket_client_ref(c);
 
@@ -153,13 +156,13 @@
     }
 
     if (error != 0) {
-        pa_log_debug("connect(): %s", pa_cstrerror(errno));
+        pa_log_debug("connect(): %s", pa_cstrerror(error));
         errno = error;
         goto finish;
     }
 
     io = pa_iochannel_new(c->mainloop, c->fd, c->fd);
-    assert(io);
+    pa_assert(io);
 
 finish:
     if (!io && c->fd >= 0)
@@ -168,7 +171,7 @@
 
     free_events(c);
 
-    assert(c->callback);
+    pa_assert(c->callback);
     c->callback(c, io, c->userdata);
 
     pa_socket_client_unref(c);
@@ -176,21 +179,36 @@
 
 static void connect_fixed_cb(pa_mainloop_api *m, pa_defer_event *e, void *userdata) {
     pa_socket_client *c = userdata;
-    assert(m && c && c->defer_event == e);
+
+    pa_assert(m);
+    pa_assert(c);
+    pa_assert(PA_REFCNT_VALUE(c) >= 1);
+    pa_assert(c->defer_event == e);
+
     do_call(c);
 }
 
 static void connect_io_cb(pa_mainloop_api*m, pa_io_event *e, int fd, PA_GCC_UNUSED pa_io_event_flags_t f, void *userdata) {
     pa_socket_client *c = userdata;
-    assert(m && c && c->io_event == e && fd >= 0);
+
+    pa_assert(m);
+    pa_assert(c);
+    pa_assert(PA_REFCNT_VALUE(c) >= 1);
+    pa_assert(c->io_event == e);
+    pa_assert(fd >= 0);
+
     do_call(c);
 }
 
 static int do_connect(pa_socket_client *c, const struct sockaddr *sa, socklen_t len) {
     int r;
-    assert(c && sa && len);
-
-    pa_make_nonblock_fd(c->fd);
+
+    pa_assert(c);
+    pa_assert(PA_REFCNT_VALUE(c) >= 1);
+    pa_assert(sa);
+    pa_assert(len > 0);
+
+    pa_make_fd_nonblock(c->fd);
 
     if ((r = connect(c->fd, sa, len)) < 0) {
 #ifdef OS_IS_WIN32
@@ -203,19 +221,18 @@
             return -1;
         }
 
-        c->io_event = c->mainloop->io_new(c->mainloop, c->fd, PA_IO_EVENT_OUTPUT, connect_io_cb, c);
-        assert(c->io_event);
-    } else {
-        c->defer_event = c->mainloop->defer_new(c->mainloop, connect_fixed_cb, c);
-        assert(c->defer_event);
-    }
+        pa_assert_se(c->io_event = c->mainloop->io_new(c->mainloop, c->fd, PA_IO_EVENT_OUTPUT, connect_io_cb, c));
+    } else
+        pa_assert_se(c->defer_event = c->mainloop->defer_new(c->mainloop, connect_fixed_cb, c));
 
     return 0;
 }
 
 pa_socket_client* pa_socket_client_new_ipv4(pa_mainloop_api *m, uint32_t address, uint16_t port) {
     struct sockaddr_in sa;
-    assert(m && port > 0);
+
+    pa_assert(m);
+    pa_assert(port > 0);
 
     memset(&sa, 0, sizeof(sa));
     sa.sin_family = AF_INET;
@@ -229,7 +246,9 @@
 
 pa_socket_client* pa_socket_client_new_unix(pa_mainloop_api *m, const char *filename) {
     struct sockaddr_un sa;
-    assert(m && filename);
+
+    pa_assert(m);
+    pa_assert(filename);
 
     memset(&sa, 0, sizeof(sa));
     sa.sun_family = AF_UNIX;
@@ -248,9 +267,9 @@
 #endif /* HAVE_SYS_UN_H */
 
 static int sockaddr_prepare(pa_socket_client *c, const struct sockaddr *sa, size_t salen) {
-    assert(c);
-    assert(sa);
-    assert(salen);
+    pa_assert(c);
+    pa_assert(sa);
+    pa_assert(salen);
 
     switch (sa->sa_family) {
         case AF_UNIX:
@@ -274,11 +293,11 @@
         return -1;
     }
 
-    pa_fd_set_cloexec(c->fd, 1);
+    pa_make_fd_cloexec(c->fd);
     if (sa->sa_family == AF_INET || sa->sa_family == AF_INET6)
-        pa_socket_tcp_low_delay(c->fd);
+        pa_make_tcp_socket_low_delay(c->fd);
     else
-        pa_socket_low_delay(c->fd);
+        pa_make_socket_low_delay(c->fd);
 
     if (do_connect(c, sa, salen) < 0)
         return -1;
@@ -288,9 +307,12 @@
 
 pa_socket_client* pa_socket_client_new_sockaddr(pa_mainloop_api *m, const struct sockaddr *sa, size_t salen) {
     pa_socket_client *c;
-    assert(m && sa);
-    c = pa_socket_client_new(m);
-    assert(c);
+
+    pa_assert(m);
+    pa_assert(sa);
+    pa_assert(salen > 0);
+
+    pa_assert_se(c = pa_socket_client_new(m));
 
     if (sockaddr_prepare(c, sa, salen) < 0)
         goto fail;
@@ -300,12 +322,11 @@
 fail:
     pa_socket_client_unref(c);
     return NULL;
-
 }
 
 static void socket_client_free(pa_socket_client *c) {
-    assert(c && c->mainloop);
-
+    pa_assert(c);
+    pa_assert(c->mainloop);
 
     free_events(c);
 
@@ -325,26 +346,35 @@
 }
 
 void pa_socket_client_unref(pa_socket_client *c) {
-    assert(c && c->ref >= 1);
-
-    if (!(--(c->ref)))
+    pa_assert(c);
+    pa_assert(PA_REFCNT_VALUE(c) >= 1);
+
+    if (PA_REFCNT_DEC(c) <= 0)
         socket_client_free(c);
 }
 
 pa_socket_client* pa_socket_client_ref(pa_socket_client *c) {
-    assert(c && c->ref >= 1);
-    c->ref++;
+    pa_assert(c);
+    pa_assert(PA_REFCNT_VALUE(c) >= 1);
+
+    PA_REFCNT_INC(c);
     return c;
 }
 
 void pa_socket_client_set_callback(pa_socket_client *c, void (*on_connection)(pa_socket_client *c, pa_iochannel*io, void *userdata), void *userdata) {
-    assert(c);
+    pa_assert(c);
+    pa_assert(PA_REFCNT_VALUE(c) >= 1);
+
     c->callback = on_connection;
     c->userdata = userdata;
 }
 
 pa_socket_client* pa_socket_client_new_ipv6(pa_mainloop_api *m, uint8_t address[16], uint16_t port) {
     struct sockaddr_in6 sa;
+
+    pa_assert(m);
+    pa_assert(address);
+    pa_assert(port > 0);
 
     memset(&sa, 0, sizeof(sa));
     sa.sin6_family = AF_INET6;
@@ -360,7 +390,12 @@
     pa_socket_client *c = userdata;
     struct addrinfo *res = NULL;
     int ret;
-    assert(m && c && c->asyncns_io_event == e && fd >= 0);
+
+    pa_assert(m);
+    pa_assert(c);
+    pa_assert(PA_REFCNT_VALUE(c) >= 1);
+    pa_assert(c->asyncns_io_event == e);
+    pa_assert(fd >= 0);
 
     if (asyncns_wait(c->asyncns, 0) < 0)
         goto fail;
@@ -397,10 +432,11 @@
 
 static void timeout_cb(pa_mainloop_api *m, pa_time_event *e, const struct timeval *tv, void *userdata) {
     pa_socket_client *c = userdata;
-    assert(m);
-    assert(e);
-    assert(tv);
-    assert(c);
+
+    pa_assert(m);
+    pa_assert(e);
+    pa_assert(tv);
+    pa_assert(c);
 
     if (c->fd >= 0) {
         pa_close(c->fd);
@@ -413,8 +449,8 @@
 
 static void start_timeout(pa_socket_client *c) {
     struct timeval tv;
-    assert(c);
-    assert(!c->timeout_event);
+    pa_assert(c);
+    pa_assert(!c->timeout_event);
 
     pa_gettimeofday(&tv);
     pa_timeval_add(&tv, CONNECT_TIMEOUT * 1000000);
@@ -424,7 +460,9 @@
 pa_socket_client* pa_socket_client_new_string(pa_mainloop_api *m, const char*name, uint16_t default_port) {
     pa_socket_client *c = NULL;
     pa_parsed_address a;
-    assert(m && name);
+
+    pa_assert(m);
+    pa_assert(name);
 
     if (pa_parse_address(name, &a) < 0)
         return NULL;
@@ -435,7 +473,7 @@
     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 */
@@ -445,7 +483,7 @@
             struct addrinfo hints;
             char port[12];
 
-            snprintf(port, sizeof(port), "%u", (unsigned) a.port);
+            pa_snprintf(port, sizeof(port), "%u", (unsigned) a.port);
 
             memset(&hints, 0, sizeof(hints));
             hints.ai_family = a.type == PA_PARSED_ADDRESS_TCP4 ? PF_INET : (a.type == PA_PARSED_ADDRESS_TCP6 ? PF_INET6 : PF_UNSPEC);
@@ -462,7 +500,7 @@
                 c->asyncns = asyncns;
                 c->asyncns_io_event = m->io_new(m, asyncns_fd(c->asyncns), PA_IO_EVENT_INPUT, asyncns_cb, c);
                 c->asyncns_query = asyncns_getaddrinfo(c->asyncns, a.path_or_host, port, &hints);
-                assert(c->asyncns_query);
+                pa_assert(c->asyncns_query);
                 start_timeout(c);
             }
 #else /* HAVE_LIBASYNCNS */
@@ -479,7 +517,7 @@
                 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 +545,7 @@
                 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 */
@@ -524,6 +562,8 @@
    local. "local" means UNIX socket or TCP socket on localhost. Other
    local IP addresses are not considered local. */
 int pa_socket_client_is_local(pa_socket_client *c) {
-    assert(c);
+    pa_assert(c);
+    pa_assert(PA_REFCNT_VALUE(c) >= 1);
+
     return c->local;
 }

Modified: trunk/src/pulsecore/socket-server.c
URL: http://0pointer.de/cgi-bin/viewcvs.cgi/trunk/src/pulsecore/socket-server.c?rev=1971&root=pulseaudio&r1=1970&r2=1971&view=diff
==============================================================================
--- trunk/src/pulsecore/socket-server.c (original)
+++ trunk/src/pulsecore/socket-server.c Sun Oct 28 20:13:50 2007
@@ -27,7 +27,6 @@
 #endif
 
 #include <stdlib.h>
-#include <assert.h>
 #include <errno.h>
 #include <string.h>
 #include <sys/types.h>
@@ -72,12 +71,14 @@
 #include <pulsecore/socket-util.h>
 #include <pulsecore/core-util.h>
 #include <pulsecore/log.h>
+#include <pulsecore/macro.h>
 #include <pulsecore/core-error.h>
+#include <pulsecore/refcnt.h>
 
 #include "socket-server.h"
 
 struct pa_socket_server {
-    int ref;
+    PA_REFCNT_DECLARE;
     int fd;
     char *filename;
     char *tcpwrap_service;
@@ -94,7 +95,14 @@
     pa_socket_server *s = userdata;
     pa_iochannel *io;
     int nfd;
-    assert(s && s->mainloop == mainloop && s->io_event == e && e && fd >= 0 && fd == s->fd);
+
+    pa_assert(s);
+    pa_assert(PA_REFCNT_VALUE(s) >= 1);
+    pa_assert(s->mainloop == mainloop);
+    pa_assert(s->io_event == e);
+    pa_assert(e);
+    pa_assert(fd >= 0);
+    pa_assert(fd == s->fd);
 
     pa_socket_server_ref(s);
 
@@ -103,7 +111,7 @@
         goto finish;
     }
 
-    pa_fd_set_cloexec(nfd, 1);
+    pa_make_fd_cloexec(nfd);
 
     if (!s->on_connection) {
         pa_close(nfd);
@@ -129,12 +137,11 @@
 
     /* There should be a check for socket type here */
     if (s->type == SOCKET_SERVER_IPV4)
-        pa_socket_tcp_low_delay(fd);
+        pa_make_tcp_socket_low_delay(fd);
     else
-        pa_socket_low_delay(fd);
-
-    io = pa_iochannel_new(s->mainloop, nfd, nfd);
-    assert(io);
+        pa_make_socket_low_delay(fd);
+
+    pa_assert_se(io = pa_iochannel_new(s->mainloop, nfd, nfd));
     s->on_connection(s, io, s->userdata);
 
 finish:
@@ -143,10 +150,12 @@
 
 pa_socket_server* pa_socket_server_new(pa_mainloop_api *m, int fd) {
     pa_socket_server *s;
-    assert(m && fd >= 0);
-
-    s = pa_xmalloc(sizeof(pa_socket_server));
-    s->ref = 1;
+
+    pa_assert(m);
+    pa_assert(fd >= 0);
+
+    s = pa_xnew(pa_socket_server, 1);
+    PA_REFCNT_INIT(s);
     s->fd = fd;
     s->filename = NULL;
     s->on_connection = NULL;
@@ -154,8 +163,7 @@
     s->tcpwrap_service = NULL;
 
     s->mainloop = m;
-    s->io_event = m->io_new(m, fd, PA_IO_EVENT_INPUT, callback, s);
-    assert(s->io_event);
+    pa_assert_se(s->io_event = m->io_new(m, fd, PA_IO_EVENT_INPUT, callback, s));
 
     s->type = SOCKET_SERVER_GENERIC;
 
@@ -163,8 +171,10 @@
 }
 
 pa_socket_server* pa_socket_server_ref(pa_socket_server *s) {
-    assert(s && s->ref >= 1);
-    s->ref++;
+    pa_assert(s);
+    pa_assert(PA_REFCNT_VALUE(s) >= 1);
+
+    PA_REFCNT_INC(s);
     return s;
 }
 
@@ -175,20 +185,21 @@
     struct sockaddr_un sa;
     pa_socket_server *s;
 
-    assert(m && filename);
+    pa_assert(m);
+    pa_assert(filename);
 
     if ((fd = socket(PF_UNIX, SOCK_STREAM, 0)) < 0) {
         pa_log("socket(): %s", pa_cstrerror(errno));
         goto fail;
     }
 
-    pa_fd_set_cloexec(fd, 1);
+    pa_make_fd_cloexec(fd);
 
     sa.sun_family = AF_UNIX;
     strncpy(sa.sun_path, filename, sizeof(sa.sun_path)-1);
     sa.sun_path[sizeof(sa.sun_path) - 1] = 0;
 
-    pa_socket_low_delay(fd);
+    pa_make_socket_low_delay(fd);
 
     if (bind(fd, (struct sockaddr*) &sa, SUN_LEN(&sa)) < 0) {
         pa_log("bind(): %s", pa_cstrerror(errno));
@@ -206,8 +217,7 @@
         goto fail;
     }
 
-    s = pa_socket_server_new(m, fd);
-    assert(s);
+    pa_assert_se(s = pa_socket_server_new(m, fd));
 
     s->filename = pa_xstrdup(filename);
     s->type = SOCKET_SERVER_UNIX;
@@ -235,21 +245,22 @@
     struct sockaddr_in sa;
     int on = 1;
 
-    assert(m && port);
+    pa_assert(m);
+    pa_assert(port);
 
     if ((fd = socket(PF_INET, SOCK_STREAM, 0)) < 0) {
         pa_log("socket(PF_INET): %s", pa_cstrerror(errno));
         goto fail;
     }
 
-    pa_fd_set_cloexec(fd, 1);
+    pa_make_fd_cloexec(fd);
 
 #ifdef SO_REUSEADDR
     if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)) < 0)
         pa_log("setsockopt(): %s", pa_cstrerror(errno));
 #endif
 
-    pa_socket_tcp_low_delay(fd);
+    pa_make_tcp_socket_low_delay(fd);
 
     memset(&sa, 0, sizeof(sa));
     sa.sin_family = AF_INET;
@@ -286,14 +297,15 @@
     struct sockaddr_in6 sa;
     int on = 1;
 
-    assert(m && port);
+    pa_assert(m);
+    pa_assert(port > 0);
 
     if ((fd = socket(PF_INET6, SOCK_STREAM, 0)) < 0) {
         pa_log("socket(PF_INET6): %s", pa_cstrerror(errno));
         goto fail;
     }
 
-    pa_fd_set_cloexec(fd, 1);
+    pa_make_fd_cloexec(fd);
 
 #ifdef IPV6_V6ONLY
     if (setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, &on, sizeof(on)) < 0)
@@ -305,7 +317,7 @@
         pa_log("setsockopt(SOL_SOCKET, SO_REUSEADDR, 1): %s", pa_cstrerror(errno));
 #endif
 
-    pa_socket_tcp_low_delay(fd);
+    pa_make_tcp_socket_low_delay(fd);
 
     memset(&sa, 0, sizeof(sa));
     sa.sin6_family = AF_INET6;
@@ -337,29 +349,29 @@
 }
 
 pa_socket_server* pa_socket_server_new_ipv4_loopback(pa_mainloop_api *m, uint16_t port, const char *tcpwrap_service) {
-    assert(m);
-    assert(port > 0);
+    pa_assert(m);
+    pa_assert(port > 0);
 
     return pa_socket_server_new_ipv4(m, INADDR_LOOPBACK, port, tcpwrap_service);
 }
 
 pa_socket_server* pa_socket_server_new_ipv6_loopback(pa_mainloop_api *m, uint16_t port, const char *tcpwrap_service) {
-    assert(m);
-    assert(port > 0);
+    pa_assert(m);
+    pa_assert(port > 0);
 
     return pa_socket_server_new_ipv6(m, in6addr_loopback.s6_addr, port, tcpwrap_service);
 }
 
 pa_socket_server* pa_socket_server_new_ipv4_any(pa_mainloop_api *m, uint16_t port, const char *tcpwrap_service) {
-    assert(m);
-    assert(port > 0);
+    pa_assert(m);
+    pa_assert(port > 0);
 
     return pa_socket_server_new_ipv4(m, INADDR_ANY, port, tcpwrap_service);
 }
 
 pa_socket_server* pa_socket_server_new_ipv6_any(pa_mainloop_api *m, uint16_t port, const char *tcpwrap_service) {
-    assert(m);
-    assert(port > 0);
+    pa_assert(m);
+    pa_assert(port > 0);
 
     return pa_socket_server_new_ipv6(m, in6addr_any.s6_addr, port, tcpwrap_service);
 }
@@ -367,9 +379,9 @@
 pa_socket_server* pa_socket_server_new_ipv4_string(pa_mainloop_api *m, const char *name, uint16_t port, const char *tcpwrap_service) {
     struct in_addr ipv4;
 
-    assert(m);
-    assert(name);
-    assert(port > 0);
+    pa_assert(m);
+    pa_assert(name);
+    pa_assert(port > 0);
 
     if (inet_pton(AF_INET, name, &ipv4) > 0)
         return pa_socket_server_new_ipv4(m, ntohl(ipv4.s_addr), port, tcpwrap_service);
@@ -380,9 +392,9 @@
 pa_socket_server* pa_socket_server_new_ipv6_string(pa_mainloop_api *m, const char *name, uint16_t port, const char *tcpwrap_service) {
     struct in6_addr ipv6;
 
-    assert(m);
-    assert(name);
-    assert(port > 0);
+    pa_assert(m);
+    pa_assert(name);
+    pa_assert(port > 0);
 
     if (inet_pton(AF_INET6, name, &ipv6) > 0)
         return pa_socket_server_new_ipv6(m, ipv6.s6_addr, port, tcpwrap_service);
@@ -391,7 +403,7 @@
 }
 
 static void socket_server_free(pa_socket_server*s) {
-    assert(s);
+    pa_assert(s);
 
     if (s->filename) {
         unlink(s->filename);
@@ -407,21 +419,26 @@
 }
 
 void pa_socket_server_unref(pa_socket_server *s) {
-    assert(s && s->ref >= 1);
-
-    if (!(--(s->ref)))
+    pa_assert(s);
+    pa_assert(PA_REFCNT_VALUE(s) >= 1);
+
+    if (PA_REFCNT_DEC(s) <= 0)
         socket_server_free(s);
 }
 
 void pa_socket_server_set_callback(pa_socket_server*s, void (*on_connection)(pa_socket_server*s, pa_iochannel *io, void *userdata), void *userdata) {
-    assert(s && s->ref >= 1);
+    pa_assert(s);
+    pa_assert(PA_REFCNT_VALUE(s) >= 1);
 
     s->on_connection = on_connection;
     s->userdata = userdata;
 }
 
 char *pa_socket_server_get_address(pa_socket_server *s, char *c, size_t l) {
-    assert(s && c && l > 0);
+    pa_assert(s);
+    pa_assert(PA_REFCNT_VALUE(s) >= 1);
+    pa_assert(c);
+    pa_assert(l > 0);
 
     switch (s->type) {
         case SOCKET_SERVER_IPV6: {
@@ -438,14 +455,14 @@
                 if (!pa_get_fqdn(fqdn, sizeof(fqdn)))
                     return NULL;
 
-                snprintf(c, l, "tcp6:%s:%u", fqdn, (unsigned) ntohs(sa.sin6_port));
+                pa_snprintf(c, l, "tcp6:%s:%u", fqdn, (unsigned) ntohs(sa.sin6_port));
 
             } else if (memcmp(&in6addr_loopback, &sa.sin6_addr, sizeof(in6addr_loopback)) == 0) {
                 char hn[256];
                 if (!pa_get_host_name(hn, sizeof(hn)))
                     return NULL;
 
-                snprintf(c, l, "{%s}tcp6:localhost:%u", hn, (unsigned) ntohs(sa.sin6_port));
+                pa_snprintf(c, l, "{%s}tcp6:localhost:%u", hn, (unsigned) ntohs(sa.sin6_port));
             } else {
                 char ip[INET6_ADDRSTRLEN];
 
@@ -454,7 +471,7 @@
                     return NULL;
                 }
 
-                snprintf(c, l, "tcp6:[%s]:%u", ip, (unsigned) ntohs(sa.sin6_port));
+                pa_snprintf(c, l, "tcp6:[%s]:%u", ip, (unsigned) ntohs(sa.sin6_port));
             }
 
             return c;
@@ -474,13 +491,13 @@
                 if (!pa_get_fqdn(fqdn, sizeof(fqdn)))
                     return NULL;
 
-                snprintf(c, l, "tcp:%s:%u", fqdn, (unsigned) ntohs(sa.sin_port));
+                pa_snprintf(c, l, "tcp:%s:%u", fqdn, (unsigned) ntohs(sa.sin_port));
             } else if (sa.sin_addr.s_addr == INADDR_LOOPBACK) {
                 char hn[256];
                 if (!pa_get_host_name(hn, sizeof(hn)))
                     return NULL;
 
-                snprintf(c, l, "{%s}tcp:localhost:%u", hn, (unsigned) ntohs(sa.sin_port));
+                pa_snprintf(c, l, "{%s}tcp:localhost:%u", hn, (unsigned) ntohs(sa.sin_port));
             } else {
                 char ip[INET_ADDRSTRLEN];
 
@@ -489,7 +506,7 @@
                     return NULL;
                 }
 
-                snprintf(c, l, "tcp:[%s]:%u", ip, (unsigned) ntohs(sa.sin_port));
+                pa_snprintf(c, l, "tcp:[%s]:%u", ip, (unsigned) ntohs(sa.sin_port));
 
             }
 
@@ -505,7 +522,7 @@
             if (!pa_get_host_name(hn, sizeof(hn)))
                 return NULL;
 
-            snprintf(c, l, "{%s}unix:%s", hn, s->filename);
+            pa_snprintf(c, l, "{%s}unix:%s", hn, s->filename);
             return c;
         }
 

Modified: trunk/src/pulsecore/socket-util.c
URL: http://0pointer.de/cgi-bin/viewcvs.cgi/trunk/src/pulsecore/socket-util.c?rev=1971&root=pulseaudio&r1=1970&r2=1971&view=diff
==============================================================================
--- trunk/src/pulsecore/socket-util.c (original)
+++ trunk/src/pulsecore/socket-util.c Sun Oct 28 20:13:50 2007
@@ -31,7 +31,6 @@
 #include <stdlib.h>
 #include <signal.h>
 #include <errno.h>
-#include <assert.h>
 #include <string.h>
 #include <stdio.h>
 #include <sys/types.h>
@@ -75,19 +74,19 @@
 #include <pulsecore/core-error.h>
 #include <pulsecore/core-util.h>
 #include <pulsecore/log.h>
+#include <pulsecore/macro.h>
 
 #include "socket-util.h"
 
 void pa_socket_peer_to_string(int fd, char *c, size_t l) {
     struct stat st;
 
-    assert(c && l && fd >= 0);
+    pa_assert(fd >= 0);
+    pa_assert(c);
+    pa_assert(l > 0);
 
 #ifndef OS_IS_WIN32
-    if (fstat(fd, &st) < 0) {
-        snprintf(c, l, "Invalid client fd");
-        return;
-    }
+    pa_assert_se(fstat(fd, &st) == 0);
 #endif
 
 #ifndef OS_IS_WIN32
@@ -108,12 +107,12 @@
             if (sa.sa.sa_family == AF_INET) {
                 uint32_t ip = ntohl(sa.in.sin_addr.s_addr);
 
-                snprintf(c, l, "TCP/IP client from %i.%i.%i.%i:%u",
-                         ip >> 24,
-                         (ip >> 16) & 0xFF,
-                         (ip >> 8) & 0xFF,
-                         ip & 0xFF,
-                         ntohs(sa.in.sin_port));
+                pa_snprintf(c, l, "TCP/IP client from %i.%i.%i.%i:%u",
+                            ip >> 24,
+                            (ip >> 16) & 0xFF,
+                            (ip >> 8) & 0xFF,
+                            ip & 0xFF,
+                            ntohs(sa.in.sin_port));
                 return;
             } else if (sa.sa.sa_family == AF_INET6) {
                 char buf[INET6_ADDRSTRLEN];
@@ -121,94 +120,107 @@
 
                 res = inet_ntop(AF_INET6, &sa.in6.sin6_addr, buf, sizeof(buf));
                 if (res) {
-                    snprintf(c, l, "TCP/IP client from [%s]:%u", buf, ntohs(sa.in6.sin6_port));
+                    pa_snprintf(c, l, "TCP/IP client from [%s]:%u", buf, ntohs(sa.in6.sin6_port));
                     return;
                 }
 #ifdef HAVE_SYS_UN_H
             } else if (sa.sa.sa_family == AF_UNIX) {
-                snprintf(c, l, "UNIX socket client");
+                pa_snprintf(c, l, "UNIX socket client");
                 return;
 #endif
             }
 
         }
 #ifndef OS_IS_WIN32
-        snprintf(c, l, "Unknown network client");
+        pa_snprintf(c, l, "Unknown network client");
         return;
     } else if (S_ISCHR(st.st_mode) && (fd == 0 || fd == 1)) {
-        snprintf(c, l, "STDIN/STDOUT client");
+        pa_snprintf(c, l, "STDIN/STDOUT client");
         return;
     }
 #endif /* OS_IS_WIN32 */
 
-    snprintf(c, l, "Unknown client");
-}
-
-int pa_socket_low_delay(int fd) {
+    pa_snprintf(c, l, "Unknown client");
+}
+
+void pa_make_socket_low_delay(int fd) {
+
 #ifdef SO_PRIORITY
     int priority;
-    assert(fd >= 0);
-
-    priority = 7;
+    pa_assert(fd >= 0);
+
+    priority = 6;
     if (setsockopt(fd, SOL_SOCKET, SO_PRIORITY, (void*)&priority, sizeof(priority)) < 0)
+        pa_log_warn("SO_PRIORITY failed: %s", pa_cstrerror(errno));
+#endif
+}
+
+void pa_make_tcp_socket_low_delay(int fd) {
+    pa_assert(fd >= 0);
+
+    pa_make_socket_low_delay(fd);
+
+#if defined(SOL_TCP) || defined(IPPROTO_TCP)
+    {
+        int on = 1;
+#if defined(SOL_TCP)
+        if (setsockopt(fd, SOL_TCP, TCP_NODELAY, (void*)&on, sizeof(on)) < 0)
+#else
+        if (setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, (void*)&on, sizeof(on)) < 0)
+#endif
+            pa_log_warn("TCP_NODELAY failed: %s", pa_cstrerror(errno));
+    }
+#endif
+
+#if defined(IPTOS_LOWDELAY) && defined(IP_TOS) && (defined(SOL_IP) || defined(IPPROTO_IP))
+    {
+        int tos = IPTOS_LOWDELAY;
+#ifdef SOL_IP
+        if (setsockopt(fd, SOL_IP, IP_TOS, (void*)&tos, sizeof(tos)) < 0)
+#else
+        if (setsockopt(fd, IPPROTO_IP, IP_TOS, (void*)&tos, sizeof(tos)) < 0)
+#endif
+            pa_log_warn("IP_TOS failed: %s", pa_cstrerror(errno));
+    }
+#endif
+}
+
+void pa_make_udp_socket_low_delay(int fd) {
+    pa_assert(fd >= 0);
+
+    pa_make_socket_low_delay(fd);
+
+#if defined(IPTOS_LOWDELAY) && defined(IP_TOS) && (defined(SOL_IP) || defined(IPPROTO_IP))
+    {
+        int tos = IPTOS_LOWDELAY;
+#ifdef SOL_IP
+        if (setsockopt(fd, SOL_IP, IP_TOS, (void*)&tos, sizeof(tos)) < 0)
+#else
+        if (setsockopt(fd, IPPROTO_IP, IP_TOS, (void*)&tos, sizeof(tos)) < 0)
+#endif
+            pa_log_warn("IP_TOS failed: %s", pa_cstrerror(errno));
+    }
+#endif
+}
+
+int pa_socket_set_rcvbuf(int fd, size_t l) {
+    pa_assert(fd >= 0);
+
+    if (setsockopt(fd, SOL_SOCKET, SO_RCVBUF, (void*)&l, sizeof(l)) < 0) {
+        pa_log_warn("SO_RCVBUF: %s", pa_cstrerror(errno));
         return -1;
-#endif
+    }
 
     return 0;
 }
 
-int pa_socket_tcp_low_delay(int fd) {
-    int ret, tos, on;
-
-    assert(fd >= 0);
-
-    ret = pa_socket_low_delay(fd);
-
-    on = 1;
-    tos = 0;
-
-#if defined(SOL_TCP) || defined(IPPROTO_TCP)
-#if defined(SOL_TCP)
-    if (setsockopt(fd, SOL_TCP, TCP_NODELAY, (void*)&on, sizeof(on)) < 0)
-#else
-    if (setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, (void*)&on, sizeof(on)) < 0)
-#endif
-        ret = -1;
-#endif
-
-#if defined(IPTOS_LOWDELAY) && defined(IP_TOS) && (defined(SOL_IP) || \
-	defined(IPPROTO_IP))
-    tos = IPTOS_LOWDELAY;
-#ifdef SOL_IP
-    if (setsockopt(fd, SOL_IP, IP_TOS, (void*)&tos, sizeof(tos)) < 0)
-#else
-    if (setsockopt(fd, IPPROTO_IP, IP_TOS, (void*)&tos, sizeof(tos)) < 0)
-#endif
-        ret = -1;
-#endif
-
-    return ret;
-
-}
-
-int pa_socket_set_rcvbuf(int fd, size_t l) {
-    assert(fd >= 0);
-
-/*     if (setsockopt(fd, SOL_SOCKET, SO_RCVBUF, (void*)&l, sizeof(l)) < 0) { */
-/*         pa_log("SO_RCVBUF: %s", strerror(errno)); */
-/*         return -1; */
-/*     } */
-
-    return 0;
-}
-
 int pa_socket_set_sndbuf(int fd, size_t l) {
-    assert(fd >= 0);
-
-/*     if (setsockopt(fd, SOL_SOCKET, SO_SNDBUF, (void*)&l, sizeof(l)) < 0) { */
-/*         pa_log("SO_SNDBUF: %s", strerror(errno)); */
-/*         return -1; */
-/*     } */
+    pa_assert(fd >= 0);
+
+    if (setsockopt(fd, SOL_SOCKET, SO_SNDBUF, (void*)&l, sizeof(l)) < 0) {
+        pa_log("SO_SNDBUF: %s", pa_cstrerror(errno));
+        return -1;
+    }
 
     return 0;
 }
@@ -218,6 +230,8 @@
 int pa_unix_socket_is_stale(const char *fn) {
     struct sockaddr_un sa;
     int fd = -1, ret = -1;
+
+    pa_assert(fn);
 
     if ((fd = socket(PF_UNIX, SOCK_STREAM, 0)) < 0) {
         pa_log("socket(): %s", pa_cstrerror(errno));
@@ -244,6 +258,8 @@
 int pa_unix_socket_remove_stale(const char *fn) {
     int r;
 
+    pa_assert(fn);
+
     if ((r = pa_unix_socket_is_stale(fn)) < 0)
         return errno != ENOENT ? -1 : 0;
 

Modified: trunk/src/pulsecore/socket-util.h
URL: http://0pointer.de/cgi-bin/viewcvs.cgi/trunk/src/pulsecore/socket-util.h?rev=1971&root=pulseaudio&r1=1970&r2=1971&view=diff
==============================================================================
--- trunk/src/pulsecore/socket-util.h (original)
+++ trunk/src/pulsecore/socket-util.h Sun Oct 28 20:13:50 2007
@@ -29,8 +29,9 @@
 
 void pa_socket_peer_to_string(int fd, char *c, size_t l);
 
-int pa_socket_low_delay(int fd);
-int pa_socket_tcp_low_delay(int fd);
+void pa_make_socket_low_delay(int fd);
+void pa_make_tcp_socket_low_delay(int fd);
+void pa_make_udp_socket_low_delay(int fd);
 
 int pa_socket_set_sndbuf(int fd, size_t l);
 int pa_socket_set_rcvbuf(int fd, size_t l);

Modified: trunk/src/pulsecore/sound-file-stream.c
URL: http://0pointer.de/cgi-bin/viewcvs.cgi/trunk/src/pulsecore/sound-file-stream.c?rev=1971&root=pulseaudio&r1=1970&r2=1971&view=diff
==============================================================================
--- trunk/src/pulsecore/sound-file-stream.c (original)
+++ trunk/src/pulsecore/sound-file-stream.c Sun Oct 28 20:13:50 2007
@@ -26,100 +26,196 @@
 #endif
 
 #include <stdlib.h>
-#include <assert.h>
 #include <stdio.h>
 #include <string.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <errno.h>
 
 #include <sndfile.h>
 
 #include <pulse/xmalloc.h>
 
+#include <pulsecore/core-error.h>
 #include <pulsecore/sink-input.h>
 #include <pulsecore/log.h>
+#include <pulsecore/thread-mq.h>
+#include <pulsecore/core-util.h>
 
 #include "sound-file-stream.h"
 
-#define BUF_SIZE (1024*10)
-
-struct userdata {
+typedef struct file_stream {
+    pa_msgobject parent;
+    pa_core *core;
     SNDFILE *sndfile;
     pa_sink_input *sink_input;
     pa_memchunk memchunk;
     sf_count_t (*readf_function)(SNDFILE *sndfile, void *ptr, sf_count_t frames);
+    size_t drop;
+} file_stream;
+
+enum {
+    FILE_STREAM_MESSAGE_UNLINK
 };
 
-static void free_userdata(struct userdata *u) {
-    assert(u);
-    if (u->sink_input) {
-        pa_sink_input_disconnect(u->sink_input);
-        pa_sink_input_unref(u->sink_input);
-    }
+PA_DECLARE_CLASS(file_stream);
+#define FILE_STREAM(o) (file_stream_cast(o))
+static PA_DEFINE_CHECK_TYPE(file_stream, pa_msgobject);
+
+static void file_stream_unlink(file_stream *u) {
+    pa_assert(u);
+
+    if (!u->sink_input)
+        return;
+
+    pa_sink_input_unlink(u->sink_input);
+
+    pa_sink_input_unref(u->sink_input);
+    u->sink_input = NULL;
+
+    /* Make sure we don't decrease the ref count twice. */
+    file_stream_unref(u);
+}
+
+static void file_stream_free(pa_object *o) {
+    file_stream *u = FILE_STREAM(o);
+    pa_assert(u);
+
+    file_stream_unlink(u);
 
     if (u->memchunk.memblock)
         pa_memblock_unref(u->memchunk.memblock);
+
     if (u->sndfile)
         sf_close(u->sndfile);
 
     pa_xfree(u);
 }
 
-static void sink_input_kill(pa_sink_input *i) {
-    assert(i && i->userdata);
-    free_userdata(i->userdata);
-}
-
-static int sink_input_peek(pa_sink_input *i, pa_memchunk *chunk) {
-    struct userdata *u;
-    assert(i && chunk && i->userdata);
-    u = i->userdata;
-
-    if (!u->memchunk.memblock) {
-        uint32_t fs = pa_frame_size(&i->sample_spec);
-        sf_count_t n;
-
-        u->memchunk.memblock = pa_memblock_new(i->sink->core->mempool, BUF_SIZE);
-        u->memchunk.index = 0;
-
-        if (u->readf_function) {
-            if ((n = u->readf_function(u->sndfile, u->memchunk.memblock->data, 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)
-                n = 0;
-
-            u->memchunk.length = n;
+static int file_stream_process_msg(pa_msgobject *o, int code, void*userdata, int64_t offset, pa_memchunk *chunk) {
+    file_stream *u = FILE_STREAM(o);
+    file_stream_assert_ref(u);
+
+    switch (code) {
+        case FILE_STREAM_MESSAGE_UNLINK:
+            file_stream_unlink(u);
+            break;
+    }
+
+    return 0;
+}
+
+static void sink_input_kill_cb(pa_sink_input *i) {
+    pa_sink_input_assert_ref(i);
+
+    file_stream_unlink(FILE_STREAM(i->userdata));
+}
+
+static int sink_input_peek_cb(pa_sink_input *i, size_t length, pa_memchunk *chunk) {
+    file_stream *u;
+
+    pa_assert(i);
+    pa_assert(chunk);
+    u = FILE_STREAM(i->userdata);
+    file_stream_assert_ref(u);
+
+    if (!u->sndfile)
+        return -1;
+
+    for (;;) {
+
+        if (!u->memchunk.memblock) {
+
+            u->memchunk.memblock = pa_memblock_new(i->sink->core->mempool, length);
+            u->memchunk.index = 0;
+
+            if (u->readf_function) {
+                sf_count_t n;
+                void *p;
+                size_t fs = pa_frame_size(&i->sample_spec);
+
+                p = pa_memblock_acquire(u->memchunk.memblock);
+                n = u->readf_function(u->sndfile, p, length/fs);
+                pa_memblock_release(u->memchunk.memblock);
+
+                if (n <= 0)
+                    n = 0;
+
+                u->memchunk.length = n * fs;
+            } else {
+                sf_count_t n;
+                void *p;
+
+                p = pa_memblock_acquire(u->memchunk.memblock);
+                n = sf_read_raw(u->sndfile, p, length);
+                pa_memblock_release(u->memchunk.memblock);
+
+                if (n <= 0)
+                    n = 0;
+
+                u->memchunk.length = n;
+            }
+
+            if (u->memchunk.length <= 0) {
+
+                pa_memblock_unref(u->memchunk.memblock);
+                pa_memchunk_reset(&u->memchunk);
+
+                pa_asyncmsgq_post(pa_thread_mq_get()->outq, PA_MSGOBJECT(u), FILE_STREAM_MESSAGE_UNLINK, NULL, 0, NULL, NULL);
+
+                sf_close(u->sndfile);
+                u->sndfile = NULL;
+
+                return -1;
+            }
         }
 
-        if (!u->memchunk.length) {
-            free_userdata(u);
-            return -1;
+        pa_assert(u->memchunk.memblock);
+        pa_assert(u->memchunk.length > 0);
+
+        if (u->drop < u->memchunk.length) {
+            u->memchunk.index += u->drop;
+            u->memchunk.length -= u->drop;
+            u->drop = 0;
+            break;
         }
+
+        u->drop -= u->memchunk.length;
+        pa_memblock_unref(u->memchunk.memblock);
+        pa_memchunk_reset(&u->memchunk);
     }
 
     *chunk = u->memchunk;
     pa_memblock_ref(chunk->memblock);
-    assert(chunk->length);
+
+    pa_assert(chunk->length > 0);
+    pa_assert(u->drop <= 0);
+
     return 0;
 }
 
-static void sink_input_drop(pa_sink_input *i, const pa_memchunk*chunk, size_t length) {
-    struct userdata *u;
-    assert(i && chunk && length && i->userdata);
-    u = i->userdata;
-
-    assert(!memcmp(chunk, &u->memchunk, sizeof(chunk)));
-    assert(length <= u->memchunk.length);
-
-    u->memchunk.index += length;
-    u->memchunk.length -= length;
-
-    if (u->memchunk.length <= 0) {
+static void sink_input_drop_cb(pa_sink_input *i, size_t length) {
+    file_stream *u;
+
+    pa_assert(i);
+    pa_assert(length > 0);
+    u = FILE_STREAM(i->userdata);
+    file_stream_assert_ref(u);
+
+    if (u->memchunk.memblock) {
+
+        if (length < u->memchunk.length) {
+            u->memchunk.index += length;
+            u->memchunk.length -= length;
+            return;
+        }
+
+        length -= u->memchunk.length;
         pa_memblock_unref(u->memchunk.memblock);
-        u->memchunk.memblock = NULL;
-        u->memchunk.index = u->memchunk.length = 0;
-    }
+        pa_memchunk_reset(&u->memchunk);
+    }
+
+    u->drop += length;
 }
 
 int pa_play_file(
@@ -127,28 +223,60 @@
         const char *fname,
         const pa_cvolume *volume) {
 
-    struct userdata *u = NULL;
+    file_stream *u = NULL;
     SF_INFO sfinfo;
     pa_sample_spec ss;
     pa_sink_input_new_data data;
-
-    assert(sink);
-    assert(fname);
-
-    u = pa_xnew(struct userdata, 1);
+    int fd;
+
+    pa_assert(sink);
+    pa_assert(fname);
+
+    u = pa_msgobject_new(file_stream);
+    u->parent.parent.free = file_stream_free;
+    u->parent.process_msg = file_stream_process_msg;
+    u->core = sink->core;
     u->sink_input = NULL;
-    u->memchunk.memblock = NULL;
-    u->memchunk.index = u->memchunk.length = 0;
+    pa_memchunk_reset(&u->memchunk);
     u->sndfile = NULL;
+    u->readf_function = NULL;
+    u->drop = 0;
 
     memset(&sfinfo, 0, sizeof(sfinfo));
 
-    if (!(u->sndfile = sf_open(fname, SFM_READ, &sfinfo))) {
+    if ((fd = open(fname, O_RDONLY
+#ifdef O_NOCTTY
+                   |O_NOCTTY
+#endif
+                   )) < 0) {
+        pa_log("Failed to open file %s: %s", fname, pa_cstrerror(errno));
+        goto fail;
+    }
+
+    /* FIXME: For now we just use posix_fadvise to avoid page faults
+     * when accessing the file data. Eventually we should move the
+     * file reader into the main event loop and pass the data over the
+     * asyncmsgq. */
+
+#ifdef HAVE_POSIX_FADVISE
+    if (posix_fadvise(fd, 0, 0, POSIX_FADV_SEQUENTIAL) < 0) {
+        pa_log_warn("POSIX_FADV_SEQUENTIAL failed: %s", pa_cstrerror(errno));
+        goto fail;
+    } else
+        pa_log_debug("POSIX_FADV_SEQUENTIAL succeeded.");
+
+    if (posix_fadvise(fd, 0, 0, POSIX_FADV_WILLNEED) < 0) {
+        pa_log_warn("POSIX_FADV_WILLNEED failed: %s", pa_cstrerror(errno));
+        goto fail;
+    } else
+        pa_log_debug("POSIX_FADV_WILLNEED succeeded.");
+#endif
+
+    if (!(u->sndfile = sf_open_fd(fd, SFM_READ, &sfinfo, 1))) {
         pa_log("Failed to open file %s", fname);
-        goto fail;
-    }
-
-    u->readf_function = NULL;
+        pa_close(fd);
+        goto fail;
+    }
 
     switch (sfinfo.format & 0xFF) {
         case SF_FORMAT_PCM_16:
@@ -191,18 +319,21 @@
     if (!(u->sink_input = pa_sink_input_new(sink->core, &data, 0)))
         goto fail;
 
-    u->sink_input->peek = sink_input_peek;
-    u->sink_input->drop = sink_input_drop;
-    u->sink_input->kill = sink_input_kill;
+    u->sink_input->peek = sink_input_peek_cb;
+    u->sink_input->drop = sink_input_drop_cb;
+    u->sink_input->kill = sink_input_kill_cb;
     u->sink_input->userdata = u;
 
-    pa_sink_notify(u->sink_input->sink);
+    pa_sink_input_put(u->sink_input);
+
+    /* The reference to u is dangling here, because we want to keep
+     * this stream around until it is fully played. */
 
     return 0;
 
 fail:
     if (u)
-        free_userdata(u);
+        file_stream_unref(u);
 
     return -1;
 }

Modified: trunk/src/pulsecore/sound-file.c
URL: http://0pointer.de/cgi-bin/viewcvs.cgi/trunk/src/pulsecore/sound-file.c?rev=1971&root=pulseaudio&r1=1970&r2=1971&view=diff
==============================================================================
--- trunk/src/pulsecore/sound-file.c (original)
+++ trunk/src/pulsecore/sound-file.c Sun Oct 28 20:13:50 2007
@@ -26,31 +26,63 @@
 #endif
 
 #include <string.h>
-#include <assert.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <errno.h>
 
 #include <sndfile.h>
 
 #include <pulse/sample.h>
 #include <pulsecore/log.h>
+#include <pulsecore/macro.h>
+#include <pulsecore/core-error.h>
+#include <pulsecore/core-util.h>
 
 #include "sound-file.h"
 #include "core-scache.h"
 
-int pa_sound_file_load(pa_mempool *pool, const char *fname, pa_sample_spec *ss, pa_channel_map *map, pa_memchunk *chunk) {
-    SNDFILE*sf = NULL;
+int pa_sound_file_load(
+        pa_mempool *pool,
+        const char *fname,
+        pa_sample_spec *ss,
+        pa_channel_map *map,
+        pa_memchunk *chunk) {
+
+    SNDFILE *sf = NULL;
     SF_INFO sfinfo;
     int ret = -1;
     size_t l;
     sf_count_t (*readf_function)(SNDFILE *sndfile, void *ptr, sf_count_t frames) = NULL;
-    assert(fname && ss && chunk);
-
-    chunk->memblock = NULL;
-    chunk->index = chunk->length = 0;
-
+    void *ptr = NULL;
+    int fd;
+
+    pa_assert(fname);
+    pa_assert(ss);
+    pa_assert(chunk);
+
+    pa_memchunk_reset(chunk);
     memset(&sfinfo, 0, sizeof(sfinfo));
 
-    if (!(sf = sf_open(fname, SFM_READ, &sfinfo))) {
+    if ((fd = open(fname, O_RDONLY
+#ifdef O_NOCTTY
+                   |O_NOCTTY
+#endif
+                   )) < 0) {
+        pa_log("Failed to open file %s: %s", fname, pa_cstrerror(errno));
+        goto finish;
+    }
+
+#ifdef HAVE_POSIX_FADVISE
+    if (posix_fadvise(fd, 0, 0, POSIX_FADV_SEQUENTIAL) < 0) {
+        pa_log_warn("POSIX_FADV_SEQUENTIAL failed: %s", pa_cstrerror(errno));
+        goto finish;
+    } else
+        pa_log_debug("POSIX_FADV_SEQUENTIAL succeeded.");
+#endif
+
+    if (!(sf = sf_open_fd(fd, SFM_READ, &sfinfo, 1))) {
         pa_log("Failed to open file %s", fname);
+        pa_close(fd);
         goto finish;
     }
 
@@ -89,18 +121,19 @@
     if (map)
         pa_channel_map_init_auto(map, ss->channels, PA_CHANNEL_MAP_DEFAULT);
 
-    if ((l = pa_frame_size(ss)*sfinfo.frames) > PA_SCACHE_ENTRY_SIZE_MAX) {
+    if ((l = pa_frame_size(ss) * sfinfo.frames) > PA_SCACHE_ENTRY_SIZE_MAX) {
         pa_log("File too large");
         goto finish;
     }
 
     chunk->memblock = pa_memblock_new(pool, l);
-    assert(chunk->memblock);
     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) != (sf_count_t) l)) {
         pa_log("Premature file end");
         goto finish;
     }
@@ -112,21 +145,26 @@
     if (sf)
         sf_close(sf);
 
+    if (ptr)
+        pa_memblock_release(chunk->memblock);
+
     if (ret != 0 && chunk->memblock)
         pa_memblock_unref(chunk->memblock);
 
     return ret;
-
 }
 
 int pa_sound_file_too_big_to_cache(const char *fname) {
+
     SNDFILE*sf = NULL;
     SF_INFO sfinfo;
     pa_sample_spec ss;
 
+    pa_assert(fname);
+
     if (!(sf = sf_open(fname, SFM_READ, &sfinfo))) {
         pa_log("Failed to open file %s", fname);
-        return 0;
+        return -1;
     }
 
     sf_close(sf);
@@ -156,8 +194,13 @@
     ss.rate = sfinfo.samplerate;
     ss.channels = sfinfo.channels;
 
+    if (!pa_sample_spec_valid(&ss)) {
+        pa_log("Unsupported sample format in file %s", fname);
+        return -1;
+    }
+
     if ((pa_frame_size(&ss) * sfinfo.frames) > PA_SCACHE_ENTRY_SIZE_MAX) {
-        pa_log("File too large %s", fname);
+        pa_log("File too large: %s", fname);
         return 1;
     }
 

Modified: trunk/src/pulsecore/source-output.c
URL: http://0pointer.de/cgi-bin/viewcvs.cgi/trunk/src/pulsecore/source-output.c?rev=1971&root=pulseaudio&r1=1970&r2=1971&view=diff
==============================================================================
--- trunk/src/pulsecore/source-output.c (original)
+++ trunk/src/pulsecore/source-output.c Sun Oct 28 20:13:50 2007
@@ -26,7 +26,6 @@
 #endif
 
 #include <stdio.h>
-#include <assert.h>
 #include <stdlib.h>
 #include <string.h>
 
@@ -39,14 +38,12 @@
 
 #include "source-output.h"
 
-#define CHECK_VALIDITY_RETURN_NULL(condition) \
-do {\
-if (!(condition)) \
-    return NULL; \
-} while (0)
+static PA_DEFINE_CHECK_TYPE(pa_source_output, pa_msgobject);
+
+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) {
-    assert(data);
+    pa_assert(data);
 
     memset(data, 0, sizeof(*data));
     data->resample_method = PA_RESAMPLER_INVALID;
@@ -54,14 +51,14 @@
 }
 
 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,183 +71,289 @@
 
     pa_source_output *o;
     pa_resampler *resampler = NULL;
-    int r;
     char st[PA_SAMPLE_SPEC_SNPRINT_MAX];
 
-    assert(core);
-    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_assert(core);
+    pa_assert(data);
+
+    if (pa_hook_fire(&core->hooks[PA_CORE_HOOK_SOURCE_OUTPUT_NEW], data) < 0)
+        return NULL;
+
+    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_UNLINKED);
 
     if (!data->sample_spec_is_set)
         data->sample_spec = data->source->sample_spec;
 
-    CHECK_VALIDITY_RETURN_NULL(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);
-
-    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_sample_spec_valid(&data->sample_spec));
+
+    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);
+    }
+
+    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,
                       &data->sample_spec, &data->channel_map,
-                      data->resample_method))) {
+                      data->resample_method,
+                      !!(flags & PA_SOURCE_OUTPUT_VARIABLE_RATE)))) {
             pa_log_warn("Unsupported resampling operation.");
             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_msgobject_new(pa_source_output);
+    o->parent.parent.free = source_output_free;
+    o->parent.process_msg = pa_source_output_process_msg;
+
+    o->core = core;
+    o->state = PA_SOURCE_OUTPUT_INIT;
+    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->push = NULL;
     o->kill = NULL;
     o->get_latency = NULL;
+    o->detach = NULL;
+    o->attach = NULL;
+    o->suspend = NULL;
     o->userdata = NULL;
 
-    o->resampler = resampler;
-    o->resample_method = data->resample_method;
-
-    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_log_info("created %u \"%s\" on %s with sample spec %s",
+    o->thread_info.state = o->state;
+    o->thread_info.attached = FALSE;
+    o->thread_info.sample_spec = o->sample_spec;
+    o->thread_info.resampler = resampler;
+
+    pa_assert_se(pa_idxset_put(core->source_outputs, o, &o->index) == 0);
+    pa_assert_se(pa_idxset_put(o->source->outputs, pa_source_output_ref(o), NULL) == 0);
+
+    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);
+static int source_output_set_state(pa_source_output *o, pa_source_output_state_t state) {
+    pa_assert(o);
+
+    if (o->state == state)
+        return 0;
+
+    if (pa_asyncmsgq_send(o->source->asyncmsgq, PA_MSGOBJECT(o), PA_SOURCE_OUTPUT_MESSAGE_SET_STATE, PA_UINT_TO_PTR(state), 0, NULL) < 0)
+        return -1;
+
+    if (o->state == PA_SOURCE_OUTPUT_CORKED && state != PA_SOURCE_OUTPUT_CORKED)
+        pa_assert_se(o->source->n_corked -- >= 1);
+    else if (o->state != PA_SOURCE_OUTPUT_CORKED && state == PA_SOURCE_OUTPUT_CORKED)
+        o->source->n_corked++;
+
+    pa_source_update_status(o->source);
+
+    o->state = state;
+
+    if (state != PA_SOURCE_OUTPUT_UNLINKED)
+        pa_hook_fire(&o->source->core->hooks[PA_CORE_HOOK_SOURCE_OUTPUT_STATE_CHANGED], o);
+
+    return 0;
+}
+
+void pa_source_output_unlink(pa_source_output*o) {
+    pa_bool_t linked;
+    pa_assert(o);
+
+    /* See pa_sink_unlink() for a couple of comments how this function
+     * works */
+
+    pa_source_output_ref(o);
+
+    linked = PA_SOURCE_OUTPUT_LINKED(o->state);
+
+    if (linked)
+        pa_hook_fire(&o->source->core->hooks[PA_CORE_HOOK_SOURCE_OUTPUT_UNLINK], o);
 
     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;
+    if (pa_idxset_remove_by_data(o->source->outputs, o, NULL))
+        pa_source_output_unref(o);
+
+    if (linked) {
+        pa_asyncmsgq_send(o->source->asyncmsgq, PA_MSGOBJECT(o->source), PA_SOURCE_MESSAGE_REMOVE_OUTPUT, o, 0, NULL);
+        source_output_set_state(o, PA_SOURCE_OUTPUT_UNLINKED);
+        pa_source_update_status(o->source);
+    } else
+        o->state = PA_SOURCE_OUTPUT_UNLINKED;
 
     o->push = NULL;
     o->kill = NULL;
     o->get_latency = NULL;
-
-    o->state = PA_SOURCE_OUTPUT_DISCONNECTED;
-}
-
-static void source_output_free(pa_source_output* o) {
-    assert(o);
-
-    if (o->state != PA_SOURCE_OUTPUT_DISCONNECTED)
-        pa_source_output_disconnect(o);
-
-    pa_log_info("freed %u \"%s\"", o->index, o->name);
-
-    if (o->resampler)
-        pa_resampler_free(o->resampler);
+    o->attach = NULL;
+    o->detach = NULL;
+    o->suspend = NULL;
+
+    if (linked) {
+        pa_subscription_post(o->source->core, PA_SUBSCRIPTION_EVENT_SOURCE_OUTPUT|PA_SUBSCRIPTION_EVENT_REMOVE, o->index);
+        pa_hook_fire(&o->source->core->hooks[PA_CORE_HOOK_SOURCE_OUTPUT_UNLINK_POST], o);
+    }
+
+    o->source = NULL;
+    pa_source_output_unref(o);
+}
+
+static void source_output_free(pa_object* mo) {
+    pa_source_output *o = PA_SOURCE_OUTPUT(mo);
+
+    pa_assert(pa_source_output_refcnt(o) == 0);
+
+    if (PA_SOURCE_OUTPUT_LINKED(o->state))
+        pa_source_output_unlink(o);
+
+    pa_log_info("Freeing output %u \"%s\"", o->index, o->name);
+
+    pa_assert(!o->thread_info.attached);
+
+    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);
-
-    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;
+void pa_source_output_put(pa_source_output *o) {
+    pa_source_output_assert_ref(o);
+
+    pa_assert(o->state == PA_SOURCE_OUTPUT_INIT);
+    pa_assert(o->push);
+
+    o->thread_info.state = o->state = o->flags & PA_SOURCE_OUTPUT_START_CORKED ? PA_SOURCE_OUTPUT_CORKED : PA_SOURCE_OUTPUT_RUNNING;
+
+    if (o->state == PA_SOURCE_OUTPUT_CORKED)
+        o->source->n_corked++;
+
+    pa_asyncmsgq_send(o->source->asyncmsgq, PA_MSGOBJECT(o->source), PA_SOURCE_MESSAGE_ADD_OUTPUT, o, 0, NULL);
+    pa_source_update_status(o->source);
+
+    pa_subscription_post(o->source->core, PA_SUBSCRIPTION_EVENT_SOURCE_OUTPUT|PA_SUBSCRIPTION_EVENT_NEW, o->index);
+
+    pa_hook_fire(&o->source->core->hooks[PA_CORE_HOOK_SOURCE_OUTPUT_PUT], o);
 }
 
 void pa_source_output_kill(pa_source_output*o) {
-    assert(o);
-    assert(o->ref >= 1);
+    pa_source_output_assert_ref(o);
+    pa_assert(PA_SOURCE_OUTPUT_LINKED(o->state));
 
     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);
+    pa_assert(PA_SOURCE_OUTPUT_LINKED(o->state));
+
+    if (pa_asyncmsgq_send(o->source->asyncmsgq, PA_MSGOBJECT(o), PA_SOURCE_OUTPUT_MESSAGE_GET_LATENCY, &r, 0, NULL) < 0)
+        r = 0;
+
+    if (o->get_latency)
+        r += o->get_latency(o);
+
+    return r;
+}
+
+/* Called from thread context */
 void pa_source_output_push(pa_source_output *o, const pa_memchunk *chunk) {
     pa_memchunk rchunk;
 
-    assert(o);
-    assert(chunk);
-    assert(chunk->length);
-    assert(o->push);
-
-    if (o->state == PA_SOURCE_OUTPUT_CORKED)
+    pa_source_output_assert_ref(o);
+    pa_assert(PA_SOURCE_OUTPUT_LINKED(o->thread_info.state));
+    pa_assert(chunk);
+    pa_assert(chunk->length);
+
+    if (!o->push || o->state == PA_SOURCE_OUTPUT_CORKED)
         return;
 
-    if (!o->resampler) {
+    pa_assert(o->state == PA_SOURCE_OUTPUT_RUNNING);
+
+    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;
 
-    assert(rchunk.memblock);
+    pa_assert(rchunk.memblock);
     o->push(o, &rchunk);
     pa_memblock_unref(rchunk.memblock);
 }
 
+void pa_source_output_cork(pa_source_output *o, pa_bool_t b) {
+    pa_source_output_assert_ref(o);
+    pa_assert(PA_SOURCE_OUTPUT_LINKED(o->state));
+
+    source_output_set_state(o, b ? PA_SOURCE_OUTPUT_CORKED : PA_SOURCE_OUTPUT_RUNNING);
+}
+
+int pa_source_output_set_rate(pa_source_output *o, uint32_t rate) {
+    pa_source_output_assert_ref(o);
+    pa_assert(PA_SOURCE_OUTPUT_LINKED(o->state));
+    pa_return_val_if_fail(o->thread_info.resampler, -1);
+
+    if (o->sample_spec.rate == rate)
+        return 0;
+
+    o->sample_spec.rate = rate;
+
+    pa_asyncmsgq_post(o->source->asyncmsgq, PA_MSGOBJECT(o), PA_SOURCE_OUTPUT_MESSAGE_SET_RATE, PA_UINT_TO_PTR(rate), 0, NULL, NULL);
+
+    pa_subscription_post(o->source->core, PA_SUBSCRIPTION_EVENT_SOURCE_OUTPUT|PA_SUBSCRIPTION_EVENT_CHANGE, o->index);
+    return 0;
+}
+
 void pa_source_output_set_name(pa_source_output *o, const char *name) {
-    assert(o);
-    assert(o->ref >= 1);
+    pa_source_output_assert_ref(o);
 
     if (!o->name && !name)
         return;
@@ -261,101 +364,122 @@
     pa_xfree(o->name);
     o->name = pa_xstrdup(name);
 
-    pa_subscription_post(o->source->core, PA_SUBSCRIPTION_EVENT_SOURCE_OUTPUT|PA_SUBSCRIPTION_EVENT_CHANGE, o->index);
-}
-
-pa_usec_t pa_source_output_get_latency(pa_source_output *o) {
-    assert(o);
-    assert(o->ref >= 1);
-
-    if (o->get_latency)
-        return o->get_latency(o);
-
-    return 0;
-}
-
-void pa_source_output_cork(pa_source_output *o, int b) {
-    int n;
-
-    assert(o);
-    assert(o->ref >= 1);
-
-    if (o->state == PA_SOURCE_OUTPUT_DISCONNECTED)
-        return;
-
-    n = o->state == PA_SOURCE_OUTPUT_CORKED && !b;
-
-    o->state = b ? PA_SOURCE_OUTPUT_CORKED : PA_SOURCE_OUTPUT_RUNNING;
-
-    if (n)
-        pa_source_notify(o->source);
+    if (PA_SOURCE_OUTPUT_LINKED(o->state)) {
+        pa_hook_fire(&o->source->core->hooks[PA_CORE_HOOK_SOURCE_OUTPUT_NAME_CHANGED], o);
+        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);
-
-    if (!o->resampler)
-        return o->resample_method;
-
-    return pa_resampler_get_method(o->resampler);
+    pa_source_output_assert_ref(o);
+
+    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_assert(PA_SOURCE_OUTPUT_LINKED(o->state));
+    pa_source_assert_ref(dest);
 
     origin = o->source;
 
     if (dest == origin)
         return 0;
+
+    if (o->flags & PA_SOURCE_OUTPUT_DONT_MOVE)
+        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 &&
+    if (o->thread_info.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;
-
-    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 */
+        new_resampler = o->thread_info.resampler;
+
+    else if ((o->flags & PA_SOURCE_OUTPUT_VARIABLE_RATE) ||
+             !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 source */
 
         if (!(new_resampler = pa_resampler_new(
                       dest->core->mempool,
                       &dest->sample_spec, &dest->channel_map,
                       &o->sample_spec, &o->channel_map,
-                      o->resample_method))) {
+                      o->resample_method,
+                      !!(o->flags & PA_SOURCE_OUTPUT_VARIABLE_RATE)))) {
             pa_log_warn("Unsupported resampling operation.");
             return -1;
         }
     }
 
+    pa_hook_fire(&o->source->core->hooks[PA_CORE_HOOK_SOURCE_OUTPUT_MOVE], o);
+
     /* Okey, let's move it */
+    pa_asyncmsgq_send(o->source->asyncmsgq, PA_MSGOBJECT(o->source), PA_SOURCE_MESSAGE_REMOVE_OUTPUT, o, 0, NULL);
+
     pa_idxset_remove_by_data(origin->outputs, o, NULL);
     pa_idxset_put(dest->outputs, o, NULL);
     o->source = dest;
 
+    if (pa_source_output_get_state(o) == PA_SOURCE_OUTPUT_CORKED) {
+        pa_assert_se(origin->n_corked-- >= 1);
+        dest->n_corked++;
+    }
+
     /* Replace resampler */
-    if (new_resampler != o->resampler) {
-        if (o->resampler)
-            pa_resampler_free(o->resampler);
-        o->resampler = new_resampler;
-    }
+    if (new_resampler != o->thread_info.resampler) {
+        if (o->thread_info.resampler)
+            pa_resampler_free(o->thread_info.resampler);
+        o->thread_info.resampler = new_resampler;
+    }
+
+    pa_asyncmsgq_send(o->source->asyncmsgq, PA_MSGOBJECT(o->source), PA_SOURCE_MESSAGE_ADD_OUTPUT, o, 0, NULL);
+
+    pa_source_update_status(origin);
+    pa_source_update_status(dest);
+
+    pa_hook_fire(&o->source->core->hooks[PA_CORE_HOOK_SOURCE_OUTPUT_MOVE_POST], o);
+
+    pa_log_debug("Successfully moved source output %i from %s to %s.", o->index, origin->name, dest->name);
 
     /* 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;
 }
+
+/* Called from thread context */
+int pa_source_output_process_msg(pa_msgobject *mo, int code, void *userdata, int64_t offset, pa_memchunk* chunk) {
+    pa_source_output *o = PA_SOURCE_OUTPUT(mo);
+
+    pa_source_output_assert_ref(o);
+    pa_assert(PA_SOURCE_OUTPUT_LINKED(o->thread_info.state));
+
+    switch (code) {
+
+        case PA_SOURCE_OUTPUT_MESSAGE_SET_RATE: {
+
+            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;
+        }
+
+        case PA_SOURCE_OUTPUT_MESSAGE_SET_STATE: {
+            o->thread_info.state = PA_PTR_TO_UINT(userdata);
+
+            return 0;
+        }
+    }
+
+    return -1;
+}

Modified: trunk/src/pulsecore/source-output.h
URL: http://0pointer.de/cgi-bin/viewcvs.cgi/trunk/src/pulsecore/source-output.h?rev=1971&root=pulseaudio&r1=1970&r2=1971&view=diff
==============================================================================
--- trunk/src/pulsecore/source-output.h (original)
+++ trunk/src/pulsecore/source-output.h Sun Oct 28 20:13:50 2007
@@ -1,5 +1,5 @@
-#ifndef foosourceoutputhfoo
-#define foosourceoutputhfoo
+#ifndef foopulsesourceoutputhfoo
+#define foopulsesourceoutputhfoo
 
 /* $Id$ */
 
@@ -35,38 +35,89 @@
 #include <pulsecore/module.h>
 #include <pulsecore/client.h>
 
-typedef enum {
+typedef enum pa_source_output_state {
+    PA_SOURCE_OUTPUT_INIT,
     PA_SOURCE_OUTPUT_RUNNING,
     PA_SOURCE_OUTPUT_CORKED,
-    PA_SOURCE_OUTPUT_DISCONNECTED
+    PA_SOURCE_OUTPUT_UNLINKED
 } pa_source_output_state_t;
 
+static inline pa_bool_t PA_SOURCE_OUTPUT_LINKED(pa_source_output_state_t x) {
+    return x == PA_SOURCE_OUTPUT_RUNNING || x == PA_SOURCE_OUTPUT_CORKED;
+}
+
 typedef enum pa_source_output_flags {
-    PA_SOURCE_OUTPUT_NO_HOOKS = 1
+    PA_SOURCE_OUTPUT_VARIABLE_RATE = 1,
+    PA_SOURCE_OUTPUT_DONT_MOVE = 2,
+    PA_SOURCE_OUTPUT_START_CORKED = 4
 } pa_source_output_flags_t;
 
 struct pa_source_output {
-    int ref;
+    pa_msgobject parent;
+
     uint32_t index;
+    pa_core *core;
     pa_source_output_state_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;
 
+    /* Pushes a new memchunk into the output. Called from IO thread
+     * context. */
     void (*push)(pa_source_output *o, const pa_memchunk *chunk);
+
+    /* If non-NULL this function is called when the output is first
+     * connected to a source. Called from IO thread context */
+    void (*attach) (pa_source_output *o);           /* may be NULL */
+
+    /* If non-NULL this function is called when the output is
+     * disconnected from its source. Called from IO thread context */
+    void (*detach) (pa_source_output *o);           /* may be NULL */
+
+    /* If non-NULL called whenever the the source this output is attached
+     * to suspends or resumes. Called from main context */
+    void (*suspend) (pa_source_output *o, int b);   /* may be NULL */
+
+    /* Supposed to unlink and destroy this stream. Called from main
+     * context. */
     void (*kill)(pa_source_output* o);              /* may be NULL */
+
+    /* Return the current latency (i.e. length of bufferd audio) of
+    this stream. Called from main context. If NULL a
+    PA_SOURCE_OUTPUT_MESSAGE_GET_LATENCY message is sent to the IO
+    thread instead. */
     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_source_output_state_t state;
+
+        pa_bool_t attached; /* True only between ->attach() and ->detach() calls */
+
+        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_cast(o)
+
+enum {
+    PA_SOURCE_OUTPUT_MESSAGE_GET_LATENCY,
+    PA_SOURCE_OUTPUT_MESSAGE_SET_RATE,
+    PA_SOURCE_OUTPUT_MESSAGE_SET_STATE,
+    PA_SOURCE_OUTPUT_MESSAGE_MAX
 };
 
 typedef struct pa_source_output_new_data {
@@ -77,9 +128,9 @@
     pa_source *source;
 
     pa_sample_spec sample_spec;
-    int sample_spec_is_set;
+    pa_bool_t sample_spec_is_set;
     pa_channel_map channel_map;
-    int channel_map_is_set;
+    pa_bool_t channel_map_is_set;
 
     pa_resample_method_t resample_method;
 } pa_source_output_new_data;
@@ -89,30 +140,38 @@
 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);
+void pa_source_output_put(pa_source_output *o);
+void pa_source_output_unlink(pa_source_output*o);
 
-/* To be called by the implementing module only */
-void pa_source_output_disconnect(pa_source_output*o);
+void pa_source_output_set_name(pa_source_output *i, const char *name);
+
+/* Callable by everyone */
 
 /* External code may request disconnection with this funcion */
 void pa_source_output_kill(pa_source_output*o);
 
-void pa_source_output_push(pa_source_output *o, const pa_memchunk *chunk);
-
-void pa_source_output_set_name(pa_source_output *i, const char *name);
-
 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_cork(pa_source_output *i, pa_bool_t b);
+
+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);
 
 int pa_source_output_move_to(pa_source_output *o, pa_source *dest);
 
+#define pa_source_output_get_state(o) ((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, int64_t offset, pa_memchunk *chunk);
+
 #endif

Modified: trunk/src/pulsecore/source.c
URL: http://0pointer.de/cgi-bin/viewcvs.cgi/trunk/src/pulsecore/source.c?rev=1971&root=pulseaudio&r1=1970&r2=1971&view=diff
==============================================================================
--- trunk/src/pulsecore/source.c (original)
+++ trunk/src/pulsecore/source.c Sun Oct 28 20:13:50 2007
@@ -27,7 +27,6 @@
 #endif
 
 #include <stdio.h>
-#include <assert.h>
 #include <stdlib.h>
 #include <string.h>
 
@@ -42,11 +41,9 @@
 
 #include "source.h"
 
-#define CHECK_VALIDITY_RETURN_NULL(condition) \
-do {\
-if (!(condition)) \
-    return NULL; \
-} while (0)
+static PA_DEFINE_CHECK_TYPE(pa_source, pa_msgobject);
+
+static void source_free(pa_object *o);
 
 pa_source* pa_source_new(
         pa_core *core,
@@ -58,109 +55,182 @@
 
     pa_source *s;
     char st[256];
-    int r;
     pa_channel_map tmap;
 
-    assert(core);
-    assert(name);
-    assert(spec);
-
-    CHECK_VALIDITY_RETURN_NULL(pa_sample_spec_valid(spec));
+    pa_assert(core);
+    pa_assert(name);
+    pa_assert(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);
-
-    s = pa_xnew(pa_source, 1);
+    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_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;
+    s->state = PA_SOURCE_INIT;
+    s->flags = 0;
     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->outputs = pa_idxset_new(NULL, NULL);
+    s->n_corked = 0;
     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;
-
-    s->is_hardware = 0;
+    pa_cvolume_reset(&s->volume, spec->channels);
+    s->muted = FALSE;
+    s->refresh_volume = s->refresh_muted = FALSE;
 
     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->set_state = NULL;
     s->userdata = NULL;
 
-    r = pa_idxset_put(core->sources, s, &s->index);
-    assert(s->index != PA_IDXSET_INVALID && r >= 0);
+    s->asyncmsgq = NULL;
+    s->rtpoll = NULL;
+
+    pa_assert_se(pa_idxset_put(core->sources, s, &s->index) >= 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_subscription_post(core, PA_SUBSCRIPTION_EVENT_SOURCE | PA_SUBSCRIPTION_EVENT_NEW, s->index);
+    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;
+    s->thread_info.state = s->state;
 
     return s;
 }
 
-void pa_source_disconnect(pa_source *s) {
+static int source_set_state(pa_source *s, pa_source_state_t state) {
+    int ret;
+
+    pa_assert(s);
+
+    if (s->state == state)
+        return 0;
+
+    if ((s->state == PA_SOURCE_SUSPENDED && PA_SOURCE_OPENED(state)) ||
+        (PA_SOURCE_OPENED(s->state) && state == PA_SOURCE_SUSPENDED)) {
+        pa_source_output *o;
+        uint32_t idx;
+
+        /* We're suspending or resuming, tell everyone about it */
+
+        for (o = PA_SOURCE_OUTPUT(pa_idxset_first(s->outputs, &idx)); o; o = PA_SOURCE_OUTPUT(pa_idxset_next(s->outputs, &idx)))
+            if (o->suspend)
+                o->suspend(o, state == PA_SINK_SUSPENDED);
+    }
+
+    if (s->set_state)
+        if ((ret = s->set_state(s, state)) < 0)
+            return -1;
+
+    if (pa_asyncmsgq_send(s->asyncmsgq, PA_MSGOBJECT(s), PA_SOURCE_MESSAGE_SET_STATE, PA_UINT_TO_PTR(state), 0, NULL) < 0)
+        return -1;
+
+    s->state = state;
+
+    if (state != PA_SOURCE_UNLINKED) /* if we enter UNLINKED state pa_source_unlink() will fire the apropriate events */
+        pa_hook_fire(&s->core->hooks[PA_CORE_HOOK_SOURCE_STATE_CHANGED], s);
+    return 0;
+}
+
+void pa_source_put(pa_source *s) {
+    pa_source_assert_ref(s);
+
+    pa_assert(s->state == PA_SINK_INIT);
+    pa_assert(s->rtpoll);
+    pa_assert(s->asyncmsgq);
+
+    pa_assert_se(source_set_state(s, PA_SOURCE_IDLE) == 0);
+
+    pa_subscription_post(s->core, PA_SUBSCRIPTION_EVENT_SOURCE | PA_SUBSCRIPTION_EVENT_NEW, s->index);
+    pa_hook_fire(&s->core->hooks[PA_CORE_HOOK_SOURCE_NEW_POST], s);
+}
+
+void pa_source_unlink(pa_source *s) {
+    pa_bool_t linked;
     pa_source_output *o, *j = NULL;
 
-    assert(s);
-    assert(s->state == PA_SOURCE_RUNNING);
-
-    s->state = PA_SOURCE_DISCONNECTED;
-    pa_namereg_unregister(s->core, s->name);
-
-    pa_hook_fire(&s->core->hook_source_disconnect, s);
+    pa_assert(s);
+
+    /* See pa_sink_unlink() for a couple of comments how this function
+     * works. */
+
+    linked = PA_SOURCE_LINKED(s->state);
+
+    if (linked)
+        pa_hook_fire(&s->core->hooks[PA_CORE_HOOK_SOURCE_UNLINK], s);
+
+    if (s->state != PA_SOURCE_UNLINKED)
+        pa_namereg_unregister(s->core, s->name);
+    pa_idxset_remove_by_data(s->core->sources, s, NULL);
 
     while ((o = pa_idxset_first(s->outputs, NULL))) {
-        assert(o != j);
+        pa_assert(o != j);
         pa_source_output_kill(o);
         j = o;
     }
 
-    pa_idxset_remove_by_data(s->core->sources, s, NULL);
+    if (linked)
+        source_set_state(s, PA_SOURCE_UNLINKED);
+    else
+        s->state = PA_SOURCE_UNLINKED;
 
     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;
-
-    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);
-
-    if (s->state != PA_SOURCE_DISCONNECTED)
-        pa_source_disconnect(s);
-
-    pa_log_info("freed %u \"%s\"", s->index, s->name);
+    s->get_volume = NULL;
+    s->set_volume = NULL;
+    s->set_mute = NULL;
+    s->get_mute = NULL;
+    s->set_state = NULL;
+
+    if (linked) {
+        pa_subscription_post(s->core, PA_SUBSCRIPTION_EVENT_SOURCE | PA_SUBSCRIPTION_EVENT_REMOVE, s->index);
+        pa_hook_fire(&s->core->hooks[PA_CORE_HOOK_SOURCE_UNLINK_POST], s);
+    }
+}
+
+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);
+
+    if (PA_SOURCE_LINKED(s->state))
+        pa_source_unlink(s);
+
+    pa_log_info("Freeing source %u \"%s\"", s->index, s->name);
 
     pa_idxset_free(s->outputs, NULL, NULL);
+
+    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);
@@ -168,164 +238,176 @@
     pa_xfree(s);
 }
 
-void pa_source_unref(pa_source *s) {
-    assert(s);
-    assert(s->ref >= 1);
-
-    if (!(--s->ref))
-        source_free(s);
-}
-
-pa_source* pa_source_ref(pa_source *s) {
-    assert(s);
-    assert(s->ref >= 1);
-
-    s->ref++;
-    return s;
-}
-
-void pa_source_notify(pa_source*s) {
-    assert(s);
-    assert(s->ref >= 1);
-
-    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;
-
-    assert(o);
-    assert(chunk);
-
-    pa_source_output_push(o, chunk);
-    return 0;
+int pa_source_update_status(pa_source*s) {
+    pa_source_assert_ref(s);
+    pa_assert(PA_SOURCE_LINKED(s->state));
+
+    if (s->state == PA_SOURCE_SUSPENDED)
+        return 0;
+
+    return source_set_state(s, pa_source_used_by(s) ? PA_SOURCE_RUNNING : PA_SOURCE_IDLE);
+}
+
+int pa_source_suspend(pa_source *s, pa_bool_t suspend) {
+    pa_source_assert_ref(s);
+    pa_assert(PA_SOURCE_LINKED(s->state));
+
+    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);
+}
+
+void pa_source_ping(pa_source *s) {
+    pa_source_assert_ref(s);
+    pa_assert(PA_SOURCE_LINKED(s->state));
+
+    pa_asyncmsgq_post(s->asyncmsgq, PA_MSGOBJECT(s), PA_SOURCE_MESSAGE_PING, NULL, 0, NULL, NULL);
 }
 
 void pa_source_post(pa_source*s, const pa_memchunk *chunk) {
-    assert(s);
-    assert(s->ref >= 1);
-    assert(chunk);
-
-    pa_source_ref(s);
-
-    if (s->sw_muted || !pa_cvolume_is_norm(&s->sw_volume)) {
+    pa_source_output *o;
+    void *state = NULL;
+
+    pa_source_assert_ref(s);
+    pa_assert(PA_SOURCE_OPENED(s->thread_info.state));
+    pa_assert(chunk);
+
+    if (s->thread_info.state != PA_SOURCE_RUNNING)
+        return;
+
+    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->sw_muted)
+
+        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->sw_volume);
-        pa_idxset_foreach(s->outputs, do_post, &vchunk);
+            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);
+
         pa_memblock_unref(vchunk.memblock);
-    } else
-        pa_idxset_foreach(s->outputs, do_post, (void*) 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)
+    } else {
+
+        while ((o = pa_hashmap_iterate(s->thread_info.outputs, &state, NULL)))
+            pa_source_output_push(o, chunk);
+    }
+}
+
+pa_usec_t pa_source_get_latency(pa_source *s) {
+    pa_usec_t usec;
+
+    pa_source_assert_ref(s);
+    pa_assert(PA_SOURCE_LINKED(s->state));
+
+    if (!PA_SOURCE_OPENED(s->state))
+        return 0;
+
+    if (s->get_latency)
+        return s->get_latency(s);
+
+    if (pa_asyncmsgq_send(s->asyncmsgq, PA_MSGOBJECT(s), PA_SOURCE_MESSAGE_GET_LATENCY, &usec, 0, NULL) < 0)
+        return 0;
+
+    return usec;
+}
+
+void pa_source_set_volume(pa_source *s, const pa_cvolume *volume) {
+    int changed;
+
+    pa_source_assert_ref(s);
+    pa_assert(PA_SOURCE_LINKED(s->state));
+    pa_assert(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_MSGOBJECT(s), PA_SOURCE_MESSAGE_SET_VOLUME, pa_xnewdup(struct pa_cvolume, volume, 1), 0, 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);
+    pa_assert(PA_SOURCE_LINKED(s->state));
+
+    old_volume = s->volume;
+
+    if (s->get_volume && s->get_volume(s) < 0)
+        s->get_volume = NULL;
+
+    if (!s->get_volume && s->refresh_volume)
+        pa_asyncmsgq_send(s->asyncmsgq, PA_MSGOBJECT(s), PA_SOURCE_MESSAGE_GET_VOLUME, &s->volume, 0, NULL);
+
+    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_bool_t mute) {
+    int changed;
+
+    pa_source_assert_ref(s);
+    pa_assert(PA_SOURCE_LINKED(s->state));
+
+    changed = s->muted != mute;
+    s->muted = mute;
+
+    if (s->set_mute && s->set_mute(s) < 0)
+        s->set_mute = NULL;
+
+    if (!s->set_mute)
+        pa_asyncmsgq_post(s->asyncmsgq, PA_MSGOBJECT(s), PA_SOURCE_MESSAGE_SET_MUTE, PA_UINT_TO_PTR(mute), 0, NULL, NULL);
+
+    if (changed)
+        pa_subscription_post(s->core, PA_SUBSCRIPTION_EVENT_SOURCE|PA_SUBSCRIPTION_EVENT_CHANGE, s->index);
+}
+
+pa_bool_t pa_source_get_mute(pa_source *s) {
+    pa_bool_t old_muted;
+
+    pa_source_assert_ref(s);
+    pa_assert(PA_SOURCE_LINKED(s->state));
+
+    old_muted = s->muted;
+
+    if (s->get_mute && s->get_mute(s) < 0)
+        s->get_mute = NULL;
+
+    if (!s->get_mute && s->refresh_muted)
+        pa_asyncmsgq_send(s->asyncmsgq, PA_MSGOBJECT(s), PA_SOURCE_MESSAGE_GET_MUTE, &s->muted, 0, NULL);
+
+    if (old_muted != s->muted)
+        pa_subscription_post(s->core, PA_SUBSCRIPTION_EVENT_SOURCE|PA_SUBSCRIPTION_EVENT_CHANGE, s->index);
+
+    return s->muted;
+}
+
+void pa_source_set_module(pa_source *s, pa_module *m) {
+    pa_source_assert_ref(s);
+
+    if (m == s->module)
         return;
 
-    s->owner = m;
+    s->module = m;
+
     pa_subscription_post(s->core, PA_SUBSCRIPTION_EVENT_SOURCE|PA_SUBSCRIPTION_EVENT_CHANGE, s->index);
 }
 
-pa_usec_t pa_source_get_latency(pa_source *s) {
-    assert(s);
-    assert(s->ref >= 1);
-
-    if (!s->get_latency)
-        return 0;
-
-    return s->get_latency(s);
-}
-
-void pa_source_set_volume(pa_source *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;
-
-    if (pa_cvolume_equal(v, volume))
-        return;
-
-    *v = *volume;
-
-    if (v == &s->hw_volume)
-        if (s->set_hw_volume(s) < 0)
-            s->sw_volume =  *volume;
-
-    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);
-
-    if (m == PA_MIXER_HARDWARE && s->set_hw_volume) {
-
-        if (s->get_hw_volume)
-            s->get_hw_volume(s);
-
-        return &s->hw_volume;
-    } else
-        return &s->sw_volume;
-}
-
-void pa_source_set_mute(pa_source *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 (!!*t == !!mute)
-        return;
-
-    *t = !!mute;
-
-    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);
-}
-
-int pa_source_get_mute(pa_source *s, pa_mixer_t m) {
-    assert(s);
-    assert(s->ref >= 1);
-
-    if (m == PA_MIXER_HARDWARE && s->set_hw_mute) {
-
-        if (s->get_hw_mute)
-            s->get_hw_mute(s);
-
-        return s->hw_muted;
-    } else
-        return s->sw_muted;
-}
-
 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;
@@ -336,12 +418,172 @@
     pa_xfree(s->description);
     s->description = pa_xstrdup(description);
 
-    pa_subscription_post(s->core, PA_SUBSCRIPTION_EVENT_SOURCE|PA_SUBSCRIPTION_EVENT_CHANGE, s->index);
+    if (PA_SOURCE_LINKED(s->state)) {
+        pa_hook_fire(&s->core->hooks[PA_CORE_HOOK_SOURCE_DESCRIPTION_CHANGED], s);
+        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;
+}
+
+void pa_source_set_rtpoll(pa_source *s, pa_rtpoll *p) {
+    pa_source_assert_ref(s);
+    pa_assert(p);
+
+    s->rtpoll = p;
+}
+
+unsigned pa_source_linked_by(pa_source *s) {
+    pa_source_assert_ref(s);
+    pa_assert(PA_SOURCE_LINKED(s->state));
+
+    return pa_idxset_size(s->outputs);
 }
 
 unsigned pa_source_used_by(pa_source *s) {
-    assert(s);
-    assert(s->ref >= 1);
-
-    return pa_idxset_size(s->outputs);
-}
+    unsigned ret;
+
+    pa_source_assert_ref(s);
+    pa_assert(PA_SOURCE_LINKED(s->state));
+
+    ret = pa_idxset_size(s->outputs);
+    pa_assert(ret >= s->n_corked);
+
+    return ret - s->n_corked;
+}
+
+int pa_source_process_msg(pa_msgobject *object, int code, void *userdata, int64_t offset, pa_memchunk *chunk) {
+    pa_source *s = PA_SOURCE(object);
+    pa_source_assert_ref(s);
+    pa_assert(s->thread_info.state != PA_SOURCE_UNLINKED);
+
+    switch ((pa_source_message_t) code) {
+        case PA_SOURCE_MESSAGE_ADD_OUTPUT: {
+            pa_source_output *o = PA_SOURCE_OUTPUT(userdata);
+            pa_hashmap_put(s->thread_info.outputs, PA_UINT32_TO_PTR(o->index), pa_source_output_ref(o));
+
+            pa_assert(!o->thread_info.attached);
+            o->thread_info.attached = TRUE;
+
+            if (o->attach)
+                o->attach(o);
+
+            return 0;
+        }
+
+        case PA_SOURCE_MESSAGE_REMOVE_OUTPUT: {
+            pa_source_output *o = PA_SOURCE_OUTPUT(userdata);
+
+            if (o->detach)
+                o->detach(o);
+
+            pa_assert(o->thread_info.attached);
+            o->thread_info.attached = FALSE;
+
+            if (pa_hashmap_remove(s->thread_info.outputs, PA_UINT32_TO_PTR(o->index)))
+                pa_source_output_unref(o);
+
+            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:
+            *((pa_bool_t*) userdata) = s->thread_info.soft_muted;
+            return 0;
+
+        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_DETACH:
+
+            /* We're detaching all our output streams so that the
+             * asyncmsgq and rtpoll fields can be changed without
+             * problems */
+            pa_source_detach_within_thread(s);
+            break;
+
+        case PA_SOURCE_MESSAGE_ATTACH:
+
+            /* Reattach all streams */
+            pa_source_attach_within_thread(s);
+            break;
+
+        case PA_SOURCE_MESSAGE_GET_LATENCY:
+        case PA_SOURCE_MESSAGE_MAX:
+            ;
+    }
+
+    return -1;
+}
+
+int pa_source_suspend_all(pa_core *c, pa_bool_t suspend) {
+    uint32_t idx;
+    pa_source *source;
+    int ret = 0;
+
+    pa_core_assert_ref(c);
+
+    for (source = PA_SOURCE(pa_idxset_first(c->sources, &idx)); source; source = PA_SOURCE(pa_idxset_next(c->sources, &idx)))
+        ret -= pa_source_suspend(source, suspend) < 0;
+
+    return ret;
+}
+
+void pa_source_detach(pa_source *s) {
+    pa_source_assert_ref(s);
+    pa_assert(PA_SOURCE_LINKED(s->state));
+
+    pa_asyncmsgq_send(s->asyncmsgq, PA_MSGOBJECT(s), PA_SOURCE_MESSAGE_DETACH, NULL, 0, NULL);
+}
+
+void pa_source_attach(pa_source *s) {
+    pa_source_assert_ref(s);
+    pa_assert(PA_SOURCE_LINKED(s->state));
+
+    pa_asyncmsgq_send(s->asyncmsgq, PA_MSGOBJECT(s), PA_SOURCE_MESSAGE_ATTACH, NULL, 0, NULL);
+}
+
+void pa_source_detach_within_thread(pa_source *s) {
+    pa_source_output *o;
+    void *state = NULL;
+
+    pa_source_assert_ref(s);
+    pa_assert(PA_SOURCE_LINKED(s->thread_info.state));
+
+    while ((o = pa_hashmap_iterate(s->thread_info.outputs, &state, NULL)))
+        if (o->detach)
+            o->detach(o);
+}
+
+void pa_source_attach_within_thread(pa_source *s) {
+    pa_source_output *o;
+    void *state = NULL;
+
+    pa_source_assert_ref(s);
+    pa_assert(PA_SOURCE_LINKED(s->thread_info.state));
+
+    while ((o = pa_hashmap_iterate(s->thread_info.outputs, &state, NULL)))
+        if (o->attach)
+            o->attach(o);
+
+}

Modified: trunk/src/pulsecore/source.h
URL: http://0pointer.de/cgi-bin/viewcvs.cgi/trunk/src/pulsecore/source.h?rev=1971&root=pulseaudio&r1=1970&r2=1971&view=diff
==============================================================================
--- trunk/src/pulsecore/source.h (original)
+++ trunk/src/pulsecore/source.h Sun Oct 28 20:13:50 2007
@@ -1,5 +1,5 @@
-#ifndef foosourcehfoo
-#define foosourcehfoo
+#ifndef foopulsesourcehfoo
+#define foopulsesourcehfoo
 
 /* $Id$ */
 
@@ -32,6 +32,7 @@
 #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,73 +40,140 @@
 #include <pulsecore/memchunk.h>
 #include <pulsecore/sink.h>
 #include <pulsecore/module.h>
+#include <pulsecore/asyncmsgq.h>
+#include <pulsecore/msgobject.h>
+#include <pulsecore/rtpoll.h>
 
-#define PA_MAX_OUTPUTS_PER_SOURCE 16
+#define PA_MAX_OUTPUTS_PER_SOURCE 32
 
 typedef enum pa_source_state {
+    PA_SOURCE_INIT,
     PA_SOURCE_RUNNING,
-    PA_SOURCE_DISCONNECTED
+    PA_SOURCE_SUSPENDED,
+    PA_SOURCE_IDLE,
+    PA_SOURCE_UNLINKED
 } pa_source_state_t;
 
+static inline pa_bool_t PA_SOURCE_OPENED(pa_source_state_t x) {
+    return x == PA_SOURCE_RUNNING || x == PA_SOURCE_IDLE;
+}
+
+static inline pa_bool_t PA_SOURCE_LINKED(pa_source_state_t x) {
+    return x == PA_SOURCE_RUNNING || x == PA_SOURCE_IDLE || x == PA_SOURCE_SUSPENDED;
+}
+
 struct pa_source {
-    int ref;
+    pa_msgobject parent;
+
     uint32_t index;
     pa_core *core;
     pa_source_state_t state;
+    pa_source_flags_t flags;
 
     char *name;
     char *description, *driver;              /* may be NULL */
 
-    pa_module *owner;                        /* may be NULL */
+    pa_module *module;                        /* may be NULL */
 
     pa_sample_spec sample_spec;
     pa_channel_map channel_map;
 
     pa_idxset *outputs;
+    unsigned n_corked;
     pa_sink *monitor_of;                     /* may be NULL */
 
-    pa_cvolume hw_volume, sw_volume;
-    int hw_muted, sw_muted;
+    pa_cvolume volume;
+    pa_bool_t muted;
+    pa_bool_t refresh_volume;
+    pa_bool_t refresh_muted;
 
-    int is_hardware;
+    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 */
+    int (*get_mute)(pa_source *s);           /* dito */
+    pa_usec_t (*get_latency)(pa_source *s);  /* dito */
 
-    void (*notify)(pa_source*source);        /* may be NULL */
-    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;
+    pa_rtpoll *rtpoll;
+
+    /* Contains copies of the above data so that the real-time worker
+     * thread can work without access locking */
+    struct {
+        pa_source_state_t state;
+        pa_hashmap *outputs;
+        pa_cvolume soft_volume;
+        pa_bool_t soft_muted;
+    } thread_info;
 
     void *userdata;
 };
 
+PA_DECLARE_CLASS(pa_source);
+#define PA_SOURCE(s) pa_source_cast(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_SET_STATE,
+    PA_SOURCE_MESSAGE_PING,
+    PA_SOURCE_MESSAGE_ATTACH,
+    PA_SOURCE_MESSAGE_DETACH,
+    PA_SOURCE_MESSAGE_MAX
+} pa_source_message_t;
+
+/* To be called exclusively by the source driver, from main context */
+
 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);
+void pa_source_put(pa_source *s);
+void pa_source_unlink(pa_source *s);
 
-/* Pass a new memory block to all output streams */
-void pa_source_post(pa_source*s, const pa_memchunk *b);
+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);
+void pa_source_set_rtpoll(pa_source *s, pa_rtpoll *p);
 
-void pa_source_notify(pa_source *s);
+void pa_source_detach(pa_source *s);
+void pa_source_attach(pa_source *s);
 
-void pa_source_set_owner(pa_source *s, pa_module *m);
+/* May be called by everyone, from main context */
 
 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);
+int pa_source_update_status(pa_source*s);
+int pa_source_suspend(pa_source *s, pa_bool_t suspend);
+int pa_source_suspend_all(pa_core *c, pa_bool_t suspend);
 
-void pa_source_set_description(pa_source *s, const char *description);
+void pa_source_ping(pa_source *s);
 
-unsigned pa_source_used_by(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);
+void pa_source_set_mute(pa_source *source, pa_bool_t mute);
+pa_bool_t pa_source_get_mute(pa_source *source);
+
+unsigned pa_source_linked_by(pa_source *s); /* Number of connected streams */
+unsigned pa_source_used_by(pa_source *s); /* Number of connected streams that are not corked */
+#define pa_source_get_state(s) ((pa_source_state_t) (s)->state)
+
+/* To be called exclusively by the source driver, from IO context */
+
+void pa_source_post(pa_source*s, const pa_memchunk *b);
+
+int pa_source_process_msg(pa_msgobject *o, int code, void *userdata, int64_t, pa_memchunk *chunk);
+
+void pa_source_attach_within_thread(pa_source *s);
+void pa_source_detach_within_thread(pa_source *s);
+
 #endif

Modified: trunk/src/pulsecore/speex/arch.h
URL: http://0pointer.de/cgi-bin/viewcvs.cgi/trunk/src/pulsecore/speex/arch.h?rev=1971&root=pulseaudio&r1=1970&r2=1971&view=diff
==============================================================================
--- trunk/src/pulsecore/speex/arch.h (original)
+++ trunk/src/pulsecore/speex/arch.h Sun Oct 28 20:13:50 2007
@@ -7,18 +7,18 @@
    Redistribution and use in source and binary forms, with or without
    modification, are permitted provided that the following conditions
    are met:
-   
+
    - Redistributions of source code must retain the above copyright
    notice, this list of conditions and the following disclaimer.
-   
+
    - Redistributions in binary form must reproduce the above copyright
    notice, this list of conditions and the following disclaimer in the
    documentation and/or other materials provided with the distribution.
-   
+
    - Neither the name of the Xiph.org Foundation nor the names of its
    contributors may be used to endorse or promote products derived from
    this software without specific prior written permission.
-   
+
    THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
    ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
    LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
@@ -182,11 +182,11 @@
 #if defined (CONFIG_TI_C54X) || defined (CONFIG_TI_C55X)
 
 /* 2 on TI C5x DSP */
-#define BYTES_PER_CHAR 2 
+#define BYTES_PER_CHAR 2
 #define BITS_PER_CHAR 16
 #define LOG2_BITS_PER_CHAR 4
 
-#else 
+#else
 
 #define BYTES_PER_CHAR 1
 #define BITS_PER_CHAR 8

Modified: trunk/src/pulsecore/speex/fixed_generic.h
URL: http://0pointer.de/cgi-bin/viewcvs.cgi/trunk/src/pulsecore/speex/fixed_generic.h?rev=1971&root=pulseaudio&r1=1970&r2=1971&view=diff
==============================================================================
--- trunk/src/pulsecore/speex/fixed_generic.h (original)
+++ trunk/src/pulsecore/speex/fixed_generic.h Sun Oct 28 20:13:50 2007
@@ -7,18 +7,18 @@
    Redistribution and use in source and binary forms, with or without
    modification, are permitted provided that the following conditions
    are met:
-   
+
    - Redistributions of source code must retain the above copyright
    notice, this list of conditions and the following disclaimer.
-   
+
    - Redistributions in binary form must reproduce the above copyright
    notice, this list of conditions and the following disclaimer in the
    documentation and/or other materials provided with the distribution.
-   
+
    - Neither the name of the Xiph.org Foundation nor the names of its
    contributors may be used to endorse or promote products derived from
    this software without specific prior written permission.
-   
+
    THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
    ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
    LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR

Modified: trunk/src/pulsecore/speex/resample.c
URL: http://0pointer.de/cgi-bin/viewcvs.cgi/trunk/src/pulsecore/speex/resample.c?rev=1971&root=pulseaudio&r1=1970&r2=1971&view=diff
==============================================================================
--- trunk/src/pulsecore/speex/resample.c (original)
+++ trunk/src/pulsecore/speex/resample.c Sun Oct 28 20:13:50 2007
@@ -1,5 +1,5 @@
 /* Copyright (C) 2007 Jean-Marc Valin
-      
+
    File: resample.c
    Arbitrary resampling code
 
@@ -38,7 +38,7 @@
       - Good *perceptual* quality (and not best SNR)
 
    The code is working, but it's in a very early stage, so it may have
-   artifacts, noise or subliminal messages from satan. Also, the API 
+   artifacts, noise or subliminal messages from satan. Also, the API
    isn't stable and I can actually promise that I *will* change the API
    some time in the future.
 
@@ -46,7 +46,7 @@
       - Variable calculation resolution depending on quality setting
          - Single vs double in float mode
          - 16-bit vs 32-bit (sinc only) in fixed-point mode
-      - Make sure the filter update works even when changing params 
+      - Make sure the filter update works even when changing params
              after only a few samples procesed
 */
 
@@ -62,7 +62,7 @@
 #include "speex_resampler.h"
 #include "arch.h"
 #else /* OUTSIDE_SPEEX */
-               
+
 #include "speex/speex_resampler.h"
 #include "misc.h"
 #endif /* OUTSIDE_SPEEX */
@@ -74,11 +74,11 @@
 #endif
 
 #ifdef FIXED_POINT
-#define WORD2INT(x) ((x) < -32767 ? -32768 : ((x) > 32766 ? 32767 : (x)))  
+#define WORD2INT(x) ((x) < -32767 ? -32768 : ((x) > 32766 ? 32767 : (x)))
 #else
-#define WORD2INT(x) ((x) < -32767.5f ? -32768 : ((x) > 32766.5f ? 32767 : floor(.5+(x))))  
-#endif
-               
+#define WORD2INT(x) ((x) < -32767.5f ? -32768 : ((x) > 32766.5f ? 32767 : floor(.5+(x))))
+#endif
+
 /*#define float double*/
 #define FILTER_SIZE 64
 #define OVERSAMPLE 8
@@ -97,7 +97,7 @@
    spx_uint32_t out_rate;
    spx_uint32_t num_rate;
    spx_uint32_t den_rate;
-   
+
    int    quality;
    spx_uint32_t nb_channels;
    spx_uint32_t filt_len;
@@ -108,17 +108,17 @@
    spx_uint32_t oversample;
    int          initialised;
    int          started;
-   
+
    /* These are per-channel */
    spx_int32_t  *last_sample;
    spx_uint32_t *samp_frac_num;
    spx_uint32_t *magic_samples;
-   
+
    spx_word16_t *mem;
    spx_word16_t *sinc_table;
    spx_uint32_t sinc_table_length;
    resampler_basic_func resampler_ptr;
-         
+
    int    in_stride;
    int    out_stride;
 } ;
@@ -160,7 +160,7 @@
    0.32108304, 0.27619388, 0.23465776, 0.19672670, 0.16255380, 0.13219758,
    0.10562887, 0.08273982, 0.06335451, 0.04724088, 0.03412321, 0.02369490,
    0.01563093, 0.00959968, 0.00527363, 0.00233883, 0.00050000, 0.00000000};
-   
+
 static double kaiser6_table[36] = {
    0.99733006, 1.00000000, 0.99733006, 0.98935595, 0.97618418, 0.95799003,
    0.93501423, 0.90755855, 0.87598009, 0.84068475, 0.80211977, 0.76076565,
@@ -173,7 +173,7 @@
    double *table;
    int oversample;
 };
-      
+
 static struct FuncDef _KAISER12 = {kaiser12_table, 64};
 #define KAISER12 (&_KAISER12)
 /*static struct FuncDef _KAISER12 = {kaiser12_table, 32};
@@ -195,7 +195,7 @@
 
 
 /* This table maps conversion quality to internal parameters. There are two
-   reasons that explain why the up-sampling bandwidth is larger than the 
+   reasons that explain why the up-sampling bandwidth is larger than the
    down-sampling bandwidth:
    1) When up-sampling, we can assume that the spectrum is already attenuated
       close to the Nyquist rate (from an A/D or a previous resampling filter)
@@ -221,7 +221,7 @@
 {
    float y, frac;
    double interp[4];
-   int ind; 
+   int ind;
    y = x*func->oversample;
    ind = (int)floor(y);
    frac = (y-ind);
@@ -232,7 +232,7 @@
    interp[0] = -0.3333333333*frac + 0.5*(frac*frac) - 0.1666666667*(frac*frac*frac);
    /* Just to make sure we don't have rounding problems */
    interp[1] = 1.f-interp[3]-interp[2]-interp[0];
-   
+
    /*sum = frac*accum[1] + (1-frac)*accum[2];*/
    return interp[0]*func->table[ind] + interp[1]*func->table[ind+1] + interp[2]*func->table[ind+2] + interp[3]*func->table[ind+3];
 }
@@ -320,7 +320,7 @@
    {
       int j;
       spx_word32_t sum=0;
-      
+
       /* We already have all the filter coefficients pre-computed in the table */
       const spx_word16_t *ptr;
       /* Do the memory part */
@@ -328,7 +328,7 @@
       {
          sum += MULT16_16(mem[last_sample+j],st->sinc_table[samp_frac_num*st->filt_len+j]);
       }
-      
+
       /* Do the new part */
       ptr = in+st->in_stride*(last_sample-N+1+j);
       for (;j<N;j++)
@@ -336,7 +336,7 @@
          sum += MULT16_16(*ptr,st->sinc_table[samp_frac_num*st->filt_len+j]);
          ptr += st->in_stride;
       }
-   
+
       *out = PSHR32(sum,15);
       out += st->out_stride;
       out_sample++;
@@ -368,7 +368,7 @@
    {
       int j;
       double sum=0;
-      
+
       /* We already have all the filter coefficients pre-computed in the table */
       const spx_word16_t *ptr;
       /* Do the memory part */
@@ -376,7 +376,7 @@
       {
          sum += MULT16_16(mem[last_sample+j],(double)st->sinc_table[samp_frac_num*st->filt_len+j]);
       }
-      
+
       /* Do the new part */
       ptr = in+st->in_stride*(last_sample-N+1+j);
       for (;j<N;j++)
@@ -384,7 +384,7 @@
          sum += MULT16_16(*ptr,(double)st->sinc_table[samp_frac_num*st->filt_len+j]);
          ptr += st->in_stride;
       }
-   
+
       *out = sum;
       out += st->out_stride;
       out_sample++;
@@ -414,7 +414,7 @@
    {
       int j;
       spx_word32_t sum=0;
-      
+
       /* We need to interpolate the sinc filter */
       spx_word32_t accum[4] = {0.f,0.f, 0.f, 0.f};
       spx_word16_t interp[4];
@@ -428,7 +428,7 @@
       frac = ((float)((samp_frac_num*st->oversample) % st->den_rate))/st->den_rate;
 #endif
          /* This code is written like this to make it easy to optimise with SIMD.
-      For most DSPs, it would be best to split the loops in two because most DSPs 
+      For most DSPs, it would be best to split the loops in two because most DSPs
       have only two accumulators */
       for (j=0;last_sample-N+1+j < 0;j++)
       {
@@ -451,7 +451,7 @@
       }
       cubic_coef(frac, interp);
       sum = MULT16_32_Q15(interp[0],accum[0]) + MULT16_32_Q15(interp[1],accum[1]) + MULT16_32_Q15(interp[2],accum[2]) + MULT16_32_Q15(interp[3],accum[3]);
-   
+
       *out = PSHR32(sum,15);
       out += st->out_stride;
       out_sample++;
@@ -483,7 +483,7 @@
    {
       int j;
       spx_word32_t sum=0;
-      
+
       /* We need to interpolate the sinc filter */
       double accum[4] = {0.f,0.f, 0.f, 0.f};
       float interp[4];
@@ -492,7 +492,7 @@
       int offset = samp_frac_num*st->oversample/st->den_rate;
       float frac = alpha*st->oversample - offset;
          /* This code is written like this to make it easy to optimise with SIMD.
-      For most DSPs, it would be best to split the loops in two because most DSPs 
+      For most DSPs, it would be best to split the loops in two because most DSPs
       have only two accumulators */
       for (j=0;last_sample-N+1+j < 0;j++)
       {
@@ -515,7 +515,7 @@
       }
       cubic_coef(frac, interp);
       sum = interp[0]*accum[0] + interp[1]*accum[1] + interp[2]*accum[2] + interp[3]*accum[3];
-   
+
       *out = PSHR32(sum,15);
       out += st->out_stride;
       out_sample++;
@@ -536,11 +536,11 @@
 static void update_filter(SpeexResamplerState *st)
 {
    spx_uint32_t old_length;
-   
+
    old_length = st->filt_len;
    st->oversample = quality_map[st->quality].oversample;
    st->filt_len = quality_map[st->quality].base_length;
-   
+
    if (st->num_rate > st->den_rate)
    {
       /* down-sampling */
@@ -616,7 +616,7 @@
    st->int_advance = st->num_rate/st->den_rate;
    st->frac_advance = st->num_rate%st->den_rate;
 
-   
+
    /* Here's the place where we update the filter memory to take into account
       the change in filter length. It's probably the messiest part of the code
       due to handling of lots of corner cases. */
@@ -654,7 +654,7 @@
          /*if (st->magic_samples[i])*/
          {
             /* Try and remove the magic samples as if nothing had happened */
-            
+
             /* FIXME: This is wrong but for now we need it to avoid going over the array bounds */
             olen = old_length + 2*st->magic_samples[i];
             for (j=old_length-2+st->magic_samples[i];j>=0;j--)
@@ -729,12 +729,12 @@
    st->filt_len = 0;
    st->mem = 0;
    st->resampler_ptr = 0;
-         
+
    st->cutoff = 1.f;
    st->nb_channels = nb_channels;
    st->in_stride = 1;
    st->out_stride = 1;
-   
+
    /* Per channel data */
    st->last_sample = (spx_int32_t*)speex_alloc(nb_channels*sizeof(int));
    st->magic_samples = (spx_uint32_t*)speex_alloc(nb_channels*sizeof(int));
@@ -749,9 +749,9 @@
    speex_resampler_set_quality(st, quality);
    speex_resampler_set_rate_frac(st, ratio_num, ratio_den, in_rate, out_rate);
 
-   
+
    update_filter(st);
-   
+
    st->initialised = 1;
    if (err)
       *err = RESAMPLER_ERR_SUCCESS;
@@ -780,14 +780,14 @@
    spx_uint32_t tmp_out_len = 0;
    mem = st->mem + channel_index * st->mem_alloc_size;
    st->started = 1;
-   
+
    /* Handle the case where we have samples left from a reduction in filter length */
    if (st->magic_samples[channel_index])
    {
       int istride_save;
       spx_uint32_t tmp_in_len;
       spx_uint32_t tmp_magic;
-      
+
       istride_save = st->in_stride;
       tmp_in_len = st->magic_samples[channel_index];
       tmp_out_len = *out_len;
@@ -809,20 +809,20 @@
       out += tmp_out_len*st->out_stride;
       *out_len -= tmp_out_len;
    }
-   
+
    /* Call the right resampler through the function ptr */
    out_sample = st->resampler_ptr(st, channel_index, in, in_len, out, out_len);
-   
+
    if (st->last_sample[channel_index] < (spx_int32_t)*in_len)
       *in_len = st->last_sample[channel_index];
    *out_len = out_sample+tmp_out_len;
    st->last_sample[channel_index] -= *in_len;
-   
+
    for (j=0;j<N-1-(spx_int32_t)*in_len;j++)
       mem[j] = mem[j+*in_len];
    for (;j<N-1;j++)
       mem[j] = in[st->in_stride*(j+*in_len-N+1)];
-   
+
    return RESAMPLER_ERR_SUCCESS;
 }
 
@@ -879,7 +879,7 @@
       olen -= ochunk;
    }
    *in_len -= ilen;
-   *out_len -= olen;   
+   *out_len -= olen;
 #endif
    return RESAMPLER_ERR_SUCCESS;
 }
@@ -942,7 +942,7 @@
       olen -= ochunk;
    }
    *in_len -= ilen;
-   *out_len -= olen;   
+   *out_len -= olen;
 #endif
    return RESAMPLER_ERR_SUCCESS;
 }
@@ -966,7 +966,7 @@
    return RESAMPLER_ERR_SUCCESS;
 }
 
-               
+
 int speex_resampler_process_interleaved_int(SpeexResamplerState *st, const spx_int16_t *in, spx_uint32_t *in_len, spx_int16_t *out, spx_uint32_t *out_len)
 {
    spx_uint32_t i;
@@ -1003,7 +1003,7 @@
    spx_uint32_t i;
    if (st->in_rate == in_rate && st->out_rate == out_rate && st->num_rate == ratio_num && st->den_rate == ratio_den)
       return RESAMPLER_ERR_SUCCESS;
-   
+
    old_den = st->den_rate;
    st->in_rate = in_rate;
    st->out_rate = out_rate;
@@ -1018,7 +1018,7 @@
          st->den_rate /= fact;
       }
    }
-      
+
    if (old_den > 0)
    {
       for (i=0;i<st->nb_channels;i++)
@@ -1029,7 +1029,7 @@
             st->samp_frac_num[i] = st->den_rate-1;
       }
    }
-   
+
    if (st->initialised)
       update_filter(st);
    return RESAMPLER_ERR_SUCCESS;

Modified: trunk/src/pulsecore/speex/speex_resampler.h
URL: http://0pointer.de/cgi-bin/viewcvs.cgi/trunk/src/pulsecore/speex/speex_resampler.h?rev=1971&root=pulseaudio&r1=1970&r2=1971&view=diff
==============================================================================
--- trunk/src/pulsecore/speex/speex_resampler.h (original)
+++ trunk/src/pulsecore/speex/speex_resampler.h Sun Oct 28 20:13:50 2007
@@ -1,8 +1,8 @@
 /* Copyright (C) 2007 Jean-Marc Valin
-      
+
    File: speex_resampler.h
    Resampling code
-      
+
    The design goals of this code are:
       - Very fast algorithm
       - Low memory requirement
@@ -43,7 +43,7 @@
 
 /********* WARNING: MENTAL SANITY ENDS HERE *************/
 
-/* If the resampler is defined outside of Speex, we change the symbol names so that 
+/* If the resampler is defined outside of Speex, we change the symbol names so that
    there won't be any clash if linking with Speex later on. */
 
 /* #define RANDOM_PREFIX your software name here */
@@ -53,7 +53,7 @@
 
 #define CAT_PREFIX2(a,b) a ## b
 #define CAT_PREFIX(a,b) CAT_PREFIX2(a, b)
-      
+
 #define speex_resampler_init CAT_PREFIX(RANDOM_PREFIX,_resampler_init)
 #define speex_resampler_init_frac CAT_PREFIX(RANDOM_PREFIX,_resampler_init_frac)
 #define speex_resampler_destroy CAT_PREFIX(RANDOM_PREFIX,_resampler_destroy)
@@ -79,7 +79,7 @@
 #define spx_int32_t int
 #define spx_uint16_t unsigned short
 #define spx_uint32_t unsigned int
-      
+
 #else /* OUTSIDE_SPEEX */
 
 #include "speex/speex_types.h"
@@ -102,7 +102,7 @@
    RESAMPLER_ERR_BAD_STATE       = 2,
    RESAMPLER_ERR_INVALID_ARG     = 3,
    RESAMPLER_ERR_PTR_OVERLAP     = 4,
-   
+
    RESAMPLER_ERR_MAX_ERROR
 };
 
@@ -118,14 +118,14 @@
  * @return Newly created resampler state
  * @retval NULL Error: not enough memory
  */
-SpeexResamplerState *speex_resampler_init(spx_uint32_t nb_channels, 
-                                          spx_uint32_t in_rate, 
-                                          spx_uint32_t out_rate, 
+SpeexResamplerState *speex_resampler_init(spx_uint32_t nb_channels,
+                                          spx_uint32_t in_rate,
+                                          spx_uint32_t out_rate,
                                           int quality,
                                           int *err);
 
-/** Create a new resampler with fractional input/output rates. The sampling 
- * rate ratio is an arbitrary rational number with both the numerator and 
+/** Create a new resampler with fractional input/output rates. The sampling
+ * rate ratio is an arbitrary rational number with both the numerator and
  * denominator being 32-bit integers.
  * @param nb_channels Number of channels to be processed
  * @param ratio_num Numerator of the sampling rate ratio
@@ -137,11 +137,11 @@
  * @return Newly created resampler state
  * @retval NULL Error: not enough memory
  */
-SpeexResamplerState *speex_resampler_init_frac(spx_uint32_t nb_channels, 
-                                               spx_uint32_t ratio_num, 
-                                               spx_uint32_t ratio_den, 
-                                               spx_uint32_t in_rate, 
-                                               spx_uint32_t out_rate, 
+SpeexResamplerState *speex_resampler_init_frac(spx_uint32_t nb_channels,
+                                               spx_uint32_t ratio_num,
+                                               spx_uint32_t ratio_den,
+                                               spx_uint32_t in_rate,
+                                               spx_uint32_t out_rate,
                                                int quality,
                                                int *err);
 
@@ -152,24 +152,24 @@
 
 /** Resample a float array. The input and output buffers must *not* overlap.
  * @param st Resampler state
- * @param channel_index Index of the channel to process for the multi-channel 
+ * @param channel_index Index of the channel to process for the multi-channel
  * base (0 otherwise)
  * @param in Input buffer
- * @param in_len Number of input samples in the input buffer. Returns the 
+ * @param in_len Number of input samples in the input buffer. Returns the
  * number of samples processed
  * @param out Output buffer
  * @param out_len Size of the output buffer. Returns the number of samples written
  */
-int speex_resampler_process_float(SpeexResamplerState *st, 
-                                   spx_uint32_t channel_index, 
-                                   const float *in, 
-                                   spx_uint32_t *in_len, 
-                                   float *out, 
+int speex_resampler_process_float(SpeexResamplerState *st,
+                                   spx_uint32_t channel_index,
+                                   const float *in,
+                                   spx_uint32_t *in_len,
+                                   float *out,
                                    spx_uint32_t *out_len);
 
 /** Resample an int array. The input and output buffers must *not* overlap.
  * @param st Resampler state
- * @param channel_index Index of the channel to process for the multi-channel 
+ * @param channel_index Index of the channel to process for the multi-channel
  * base (0 otherwise)
  * @param in Input buffer
  * @param in_len Number of input samples in the input buffer. Returns the number
@@ -177,11 +177,11 @@
  * @param out Output buffer
  * @param out_len Size of the output buffer. Returns the number of samples written
  */
-int speex_resampler_process_int(SpeexResamplerState *st, 
-                                 spx_uint32_t channel_index, 
-                                 const spx_int16_t *in, 
-                                 spx_uint32_t *in_len, 
-                                 spx_int16_t *out, 
+int speex_resampler_process_int(SpeexResamplerState *st,
+                                 spx_uint32_t channel_index,
+                                 const spx_int16_t *in,
+                                 spx_uint32_t *in_len,
+                                 spx_int16_t *out,
                                  spx_uint32_t *out_len);
 
 /** Resample an interleaved float array. The input and output buffers must *not* overlap.
@@ -193,10 +193,10 @@
  * @param out_len Size of the output buffer. Returns the number of samples written.
  * This is all per-channel.
  */
-int speex_resampler_process_interleaved_float(SpeexResamplerState *st, 
-                                               const float *in, 
-                                               spx_uint32_t *in_len, 
-                                               float *out, 
+int speex_resampler_process_interleaved_float(SpeexResamplerState *st,
+                                               const float *in,
+                                               spx_uint32_t *in_len,
+                                               float *out,
                                                spx_uint32_t *out_len);
 
 /** Resample an interleaved int array. The input and output buffers must *not* overlap.
@@ -208,10 +208,10 @@
  * @param out_len Size of the output buffer. Returns the number of samples written.
  * This is all per-channel.
  */
-int speex_resampler_process_interleaved_int(SpeexResamplerState *st, 
-                                             const spx_int16_t *in, 
-                                             spx_uint32_t *in_len, 
-                                             spx_int16_t *out, 
+int speex_resampler_process_interleaved_int(SpeexResamplerState *st,
+                                             const spx_int16_t *in,
+                                             spx_uint32_t *in_len,
+                                             spx_int16_t *out,
                                              spx_uint32_t *out_len);
 
 /** Set (change) the input/output sampling rates (integer value).
@@ -219,8 +219,8 @@
  * @param in_rate Input sampling rate (integer number of Hz).
  * @param out_rate Output sampling rate (integer number of Hz).
  */
-int speex_resampler_set_rate(SpeexResamplerState *st, 
-                              spx_uint32_t in_rate, 
+int speex_resampler_set_rate(SpeexResamplerState *st,
+                              spx_uint32_t in_rate,
                               spx_uint32_t out_rate);
 
 /** Get the current input/output sampling rates (integer value).
@@ -228,11 +228,11 @@
  * @param in_rate Input sampling rate (integer number of Hz) copied.
  * @param out_rate Output sampling rate (integer number of Hz) copied.
  */
-void speex_resampler_get_rate(SpeexResamplerState *st, 
-                              spx_uint32_t *in_rate, 
+void speex_resampler_get_rate(SpeexResamplerState *st,
+                              spx_uint32_t *in_rate,
                               spx_uint32_t *out_rate);
 
-/** Set (change) the input/output sampling rates and resampling ratio 
+/** Set (change) the input/output sampling rates and resampling ratio
  * (fractional values in Hz supported).
  * @param st Resampler state
  * @param ratio_num Numerator of the sampling rate ratio
@@ -240,10 +240,10 @@
  * @param in_rate Input sampling rate rounded to the nearest integer (in Hz).
  * @param out_rate Output sampling rate rounded to the nearest integer (in Hz).
  */
-int speex_resampler_set_rate_frac(SpeexResamplerState *st, 
-                                   spx_uint32_t ratio_num, 
-                                   spx_uint32_t ratio_den, 
-                                   spx_uint32_t in_rate, 
+int speex_resampler_set_rate_frac(SpeexResamplerState *st,
+                                   spx_uint32_t ratio_num,
+                                   spx_uint32_t ratio_den,
+                                   spx_uint32_t in_rate,
                                    spx_uint32_t out_rate);
 
 /** Get the current resampling ratio. This will be reduced to the least
@@ -252,56 +252,56 @@
  * @param ratio_num Numerator of the sampling rate ratio copied
  * @param ratio_den Denominator of the sampling rate ratio copied
  */
-void speex_resampler_get_ratio(SpeexResamplerState *st, 
-                               spx_uint32_t *ratio_num, 
+void speex_resampler_get_ratio(SpeexResamplerState *st,
+                               spx_uint32_t *ratio_num,
                                spx_uint32_t *ratio_den);
 
 /** Set (change) the conversion quality.
  * @param st Resampler state
- * @param quality Resampling quality between 0 and 10, where 0 has poor 
+ * @param quality Resampling quality between 0 and 10, where 0 has poor
  * quality and 10 has very high quality.
  */
-int speex_resampler_set_quality(SpeexResamplerState *st, 
+int speex_resampler_set_quality(SpeexResamplerState *st,
                                  int quality);
 
 /** Get the conversion quality.
  * @param st Resampler state
- * @param quality Resampling quality between 0 and 10, where 0 has poor 
+ * @param quality Resampling quality between 0 and 10, where 0 has poor
  * quality and 10 has very high quality.
  */
-void speex_resampler_get_quality(SpeexResamplerState *st, 
+void speex_resampler_get_quality(SpeexResamplerState *st,
                                  int *quality);
 
 /** Set (change) the input stride.
  * @param st Resampler state
  * @param stride Input stride
  */
-void speex_resampler_set_input_stride(SpeexResamplerState *st, 
+void speex_resampler_set_input_stride(SpeexResamplerState *st,
                                       spx_uint32_t stride);
 
 /** Get the input stride.
  * @param st Resampler state
  * @param stride Input stride copied
  */
-void speex_resampler_get_input_stride(SpeexResamplerState *st, 
+void speex_resampler_get_input_stride(SpeexResamplerState *st,
                                       spx_uint32_t *stride);
 
 /** Set (change) the output stride.
  * @param st Resampler state
  * @param stride Output stride
  */
-void speex_resampler_set_output_stride(SpeexResamplerState *st, 
+void speex_resampler_set_output_stride(SpeexResamplerState *st,
                                       spx_uint32_t stride);
 
 /** Get the output stride.
  * @param st Resampler state copied
  * @param stride Output stride
  */
-void speex_resampler_get_output_stride(SpeexResamplerState *st, 
+void speex_resampler_get_output_stride(SpeexResamplerState *st,
                                       spx_uint32_t *stride);
 
-/** Make sure that the first samples to go out of the resamplers don't have 
- * leading zeros. This is only useful before starting to use a newly created 
+/** Make sure that the first samples to go out of the resamplers don't have
+ * leading zeros. This is only useful before starting to use a newly created
  * resampler. It is recommended to use that when resampling an audio file, as
  * it will generate a file with the same length. For real-time processing,
  * it is probably easier not to use this call (so that the output duration

Modified: trunk/src/pulsecore/strbuf.c
URL: http://0pointer.de/cgi-bin/viewcvs.cgi/trunk/src/pulsecore/strbuf.c?rev=1971&root=pulseaudio&r1=1970&r2=1971&view=diff
==============================================================================
--- trunk/src/pulsecore/strbuf.c (original)
+++ trunk/src/pulsecore/strbuf.c Sun Oct 28 20:13:50 2007
@@ -27,12 +27,12 @@
 
 #include <sys/types.h>
 #include <stdlib.h>
-#include <assert.h>
 #include <string.h>
 #include <stdarg.h>
 #include <stdio.h>
 
 #include <pulse/xmalloc.h>
+#include <pulsecore/macro.h>
 
 #include "strbuf.h"
 
@@ -42,7 +42,7 @@
     size_t length;
 };
 
-#define CHUNK_TO_TEXT(c) ((char*) (c) + sizeof(struct chunk))
+#define CHUNK_TO_TEXT(c) ((char*) (c) + PA_ALIGN(sizeof(struct chunk)))
 
 struct pa_strbuf {
     size_t length;
@@ -50,14 +50,18 @@
 };
 
 pa_strbuf *pa_strbuf_new(void) {
-    pa_strbuf *sb = pa_xmalloc(sizeof(pa_strbuf));
+    pa_strbuf *sb;
+
+    sb = pa_xnew(pa_strbuf, 1);
     sb->length = 0;
     sb->head = sb->tail = NULL;
+
     return sb;
 }
 
 void pa_strbuf_free(pa_strbuf *sb) {
-    assert(sb);
+    pa_assert(sb);
+
     while (sb->head) {
         struct chunk *c = sb->head;
         sb->head = sb->head->next;
@@ -72,12 +76,13 @@
 char *pa_strbuf_tostring(pa_strbuf *sb) {
     char *t, *e;
     struct chunk *c;
-    assert(sb);
 
-    e = t = pa_xmalloc(sb->length+1);
+    pa_assert(sb);
+
+    e = t = pa_xnew(char, sb->length+1);
 
     for (c = sb->head; c; c = c->next) {
-        assert((size_t) (e-t) <= sb->length);
+        pa_assert((size_t) (e-t) <= sb->length);
         memcpy(e, CHUNK_TO_TEXT(c), c->length);
         e += c->length;
     }
@@ -85,7 +90,7 @@
     /* Trailing NUL */
     *e = 0;
 
-    assert(e == t+sb->length);
+    pa_assert(e == t+sb->length);
 
     return t;
 }
@@ -93,27 +98,33 @@
 /* Combination of pa_strbuf_free() and pa_strbuf_tostring() */
 char *pa_strbuf_tostring_free(pa_strbuf *sb) {
     char *t;
-    assert(sb);
+
+    pa_assert(sb);
     t = pa_strbuf_tostring(sb);
     pa_strbuf_free(sb);
+
     return t;
 }
 
 /* Append a string to the string buffer */
 void pa_strbuf_puts(pa_strbuf *sb, const char *t) {
-    assert(sb && t);
+
+    pa_assert(sb);
+    pa_assert(t);
+
     pa_strbuf_putsn(sb, t, strlen(t));
 }
 
 /* Append a new chunk to the linked list */
 static void append(pa_strbuf *sb, struct chunk *c) {
-    assert(sb && c);
+    pa_assert(sb);
+    pa_assert(c);
 
     if (sb->tail) {
-        assert(sb->head);
+        pa_assert(sb->head);
         sb->tail->next = c;
     } else {
-        assert(!sb->head);
+        pa_assert(!sb->head);
         sb->head = c;
     }
 
@@ -125,12 +136,14 @@
 /* Append up to l bytes of a string to the string buffer */
 void pa_strbuf_putsn(pa_strbuf *sb, const char *t, size_t l) {
     struct chunk *c;
-    assert(sb && t);
+
+    pa_assert(sb);
+    pa_assert(t);
 
     if (!l)
        return;
 
-    c = pa_xmalloc(sizeof(struct chunk)+l);
+    c = pa_xmalloc(PA_ALIGN(sizeof(struct chunk)) + l);
     c->length = l;
     memcpy(CHUNK_TO_TEXT(c), t, l);
 
@@ -143,16 +156,18 @@
     int size = 100;
     struct chunk *c = NULL;
 
-    assert(sb);
+    pa_assert(sb);
+    pa_assert(format);
 
     for(;;) {
         va_list ap;
         int r;
 
-        c = pa_xrealloc(c, sizeof(struct chunk)+size);
+        c = pa_xrealloc(c, PA_ALIGN(sizeof(struct chunk)) + size);
 
         va_start(ap, format);
         r = vsnprintf(CHUNK_TO_TEXT(c), size, format, ap);
+        CHUNK_TO_TEXT(c)[size-1] = 0;
         va_end(ap);
 
         if (r > -1 && r < size) {

Modified: trunk/src/pulsecore/strlist.c
URL: http://0pointer.de/cgi-bin/viewcvs.cgi/trunk/src/pulsecore/strlist.c?rev=1971&root=pulseaudio&r1=1970&r2=1971&view=diff
==============================================================================
--- trunk/src/pulsecore/strlist.c (original)
+++ trunk/src/pulsecore/strlist.c Sun Oct 28 20:13:50 2007
@@ -26,26 +26,31 @@
 #endif
 
 #include <string.h>
-#include <assert.h>
 
 #include <pulse/xmalloc.h>
 
 #include <pulsecore/strbuf.h>
+#include <pulsecore/macro.h>
 #include <pulsecore/core-util.h>
 
 #include "strlist.h"
 
 struct pa_strlist {
     pa_strlist *next;
-    char *str;
 };
+
+#define ITEM_TO_TEXT(c) ((char*) (c) + PA_ALIGN(sizeof(pa_strlist)))
 
 pa_strlist* pa_strlist_prepend(pa_strlist *l, const char *s) {
     pa_strlist *n;
-    assert(s);
-    n = pa_xmalloc(sizeof(pa_strlist));
-    n->str = pa_xstrdup(s);
+    size_t size;
+
+    pa_assert(s);
+    size = strlen(s);
+    n = pa_xmalloc(PA_ALIGN(sizeof(pa_strlist)) + size + 1);
+    memcpy(ITEM_TO_TEXT(n), s, size + 1);
     n->next = l;
+
     return  n;
 }
 
@@ -58,7 +63,7 @@
         if (!first)
             pa_strbuf_puts(b, " ");
         first = 0;
-        pa_strbuf_puts(b, l->str);
+        pa_strbuf_puts(b, ITEM_TO_TEXT(l));
     }
 
     return pa_strbuf_tostring_free(b);
@@ -66,19 +71,20 @@
 
 pa_strlist* pa_strlist_remove(pa_strlist *l, const char *s) {
     pa_strlist *ret = l, *prev = NULL;
-    assert(l && s);
+
+    pa_assert(l);
+    pa_assert(s);
 
     while (l) {
-        if (!strcmp(l->str, s)) {
+        if (!strcmp(ITEM_TO_TEXT(l), s)) {
             pa_strlist *n = l->next;
 
             if (!prev) {
-                assert(ret == l);
+                pa_assert(ret == l);
                 ret = n;
             } else
                 prev->next = n;
 
-            pa_xfree(l->str);
             pa_xfree(l);
 
             l = n;
@@ -96,22 +102,21 @@
     while (l) {
         pa_strlist *c = l;
         l = l->next;
-
-        pa_xfree(c->str);
         pa_xfree(c);
     }
 }
 
 pa_strlist* pa_strlist_pop(pa_strlist *l, char **s) {
     pa_strlist *r;
-    assert(s);
+
+    pa_assert(s);
 
     if (!l) {
         *s = NULL;
         return NULL;
     }
 
-    *s = l->str;
+    *s = pa_xstrdup(ITEM_TO_TEXT(l));
     r = l->next;
     pa_xfree(l);
     return r;
@@ -124,10 +129,12 @@
 
     while ((r = pa_split_spaces(s, &state))) {
         pa_strlist *n;
+        size_t size = strlen(r);
 
-        n = pa_xmalloc(sizeof(pa_strlist));
-        n->str = r;
+        n = pa_xmalloc(PA_ALIGN(sizeof(pa_strlist)) + size + 1);
         n->next = NULL;
+        memcpy(ITEM_TO_TEXT(n), r, size+1);
+        pa_xfree(r);
 
         if (p)
             p->next = n;

Modified: trunk/src/pulsecore/tagstruct.c
URL: http://0pointer.de/cgi-bin/viewcvs.cgi/trunk/src/pulsecore/tagstruct.c?rev=1971&root=pulseaudio&r1=1970&r2=1971&view=diff
==============================================================================
--- trunk/src/pulsecore/tagstruct.c (original)
+++ trunk/src/pulsecore/tagstruct.c Sun Oct 28 20:13:50 2007
@@ -29,19 +29,18 @@
 #include <string.h>
 #include <unistd.h>
 #include <sys/time.h>
-#include <assert.h>
 #include <stdarg.h>
 
 #ifdef HAVE_NETINET_IN_H
 #include <netinet/in.h>
 #endif
 
-#include "winsock.h"
-
 #include <pulse/xmalloc.h>
 
+#include <pulsecore/winsock.h>
+#include <pulsecore/macro.h>
+
 #include "tagstruct.h"
-
 
 struct pa_tagstruct {
     uint8_t *data;
@@ -54,18 +53,20 @@
 pa_tagstruct *pa_tagstruct_new(const uint8_t* data, size_t length) {
     pa_tagstruct*t;
 
-    assert(!data || (data && length));
-
-    t = pa_xmalloc(sizeof(pa_tagstruct));
+    pa_assert(!data || (data && length));
+
+    t = pa_xnew(pa_tagstruct, 1);
     t->data = (uint8_t*) data;
     t->allocated = t->length = data ? length : 0;
     t->rindex = 0;
     t->dynamic = !data;
+
     return t;
 }
 
 void pa_tagstruct_free(pa_tagstruct*t) {
-    assert(t);
+    pa_assert(t);
+
     if (t->dynamic)
         pa_xfree(t->data);
     pa_xfree(t);
@@ -73,7 +74,11 @@
 
 uint8_t* pa_tagstruct_free_data(pa_tagstruct*t, size_t *l) {
     uint8_t *p;
-    assert(t && t->dynamic && l);
+
+    pa_assert(t);
+    pa_assert(t->dynamic);
+    pa_assert(l);
+
     p = t->data;
     *l = t->length;
     pa_xfree(t);
@@ -81,8 +86,8 @@
 }
 
 static void extend(pa_tagstruct*t, size_t l) {
-    assert(t);
-    assert(t->dynamic);
+    pa_assert(t);
+    pa_assert(t->dynamic);
 
     if (t->length+l <= t->allocated)
         return;
@@ -92,7 +97,8 @@
 
 void pa_tagstruct_puts(pa_tagstruct*t, const char *s) {
     size_t l;
-    assert(t);
+    pa_assert(t);
+
     if (s) {
         l = strlen(s)+2;
         extend(t, l);
@@ -107,7 +113,8 @@
 }
 
 void pa_tagstruct_putu32(pa_tagstruct*t, uint32_t i) {
-    assert(t);
+    pa_assert(t);
+
     extend(t, 5);
     t->data[t->length] = PA_TAG_U32;
     i = htonl(i);
@@ -116,7 +123,8 @@
 }
 
 void pa_tagstruct_putu8(pa_tagstruct*t, uint8_t c) {
-    assert(t);
+    pa_assert(t);
+
     extend(t, 2);
     t->data[t->length] = PA_TAG_U8;
     *(t->data+t->length+1) = c;
@@ -125,7 +133,10 @@
 
 void pa_tagstruct_put_sample_spec(pa_tagstruct *t, const pa_sample_spec *ss) {
     uint32_t rate;
-    assert(t && ss);
+
+    pa_assert(t);
+    pa_assert(ss);
+
     extend(t, 7);
     t->data[t->length] = PA_TAG_SAMPLE_SPEC;
     t->data[t->length+1] = (uint8_t) ss->format;
@@ -137,7 +148,9 @@
 
 void pa_tagstruct_put_arbitrary(pa_tagstruct *t, const void *p, size_t length) {
     uint32_t tmp;
-    assert(t && p);
+
+    pa_assert(t);
+    pa_assert(p);
 
     extend(t, 5+length);
     t->data[t->length] = PA_TAG_ARBITRARY;
@@ -149,7 +162,8 @@
 }
 
 void pa_tagstruct_put_boolean(pa_tagstruct*t, int b) {
-    assert(t);
+    pa_assert(t);
+
     extend(t, 1);
     t->data[t->length] = b ? PA_TAG_BOOLEAN_TRUE : PA_TAG_BOOLEAN_FALSE;
     t->length += 1;
@@ -157,7 +171,8 @@
 
 void pa_tagstruct_put_timeval(pa_tagstruct*t, const struct timeval *tv) {
     uint32_t tmp;
-    assert(t);
+    pa_assert(t);
+
     extend(t, 9);
     t->data[t->length] = PA_TAG_TIMEVAL;
     tmp = htonl(tv->tv_sec);
@@ -169,7 +184,9 @@
 
 void pa_tagstruct_put_usec(pa_tagstruct*t, pa_usec_t u) {
     uint32_t tmp;
-    assert(t);
+
+    pa_assert(t);
+
     extend(t, 9);
     t->data[t->length] = PA_TAG_USEC;
     tmp = htonl((uint32_t) (u >> 32));
@@ -181,7 +198,9 @@
 
 void pa_tagstruct_putu64(pa_tagstruct*t, uint64_t u) {
     uint32_t tmp;
-    assert(t);
+
+    pa_assert(t);
+
     extend(t, 9);
     t->data[t->length] = PA_TAG_U64;
     tmp = htonl((uint32_t) (u >> 32));
@@ -193,7 +212,9 @@
 
 void pa_tagstruct_puts64(pa_tagstruct*t, int64_t u) {
     uint32_t tmp;
-    assert(t);
+
+    pa_assert(t);
+
     extend(t, 9);
     t->data[t->length] = PA_TAG_S64;
     tmp = htonl((uint32_t) ((uint64_t) u >> 32));
@@ -206,7 +227,7 @@
 void pa_tagstruct_put_channel_map(pa_tagstruct *t, const pa_channel_map *map) {
     unsigned i;
 
-    assert(t);
+    pa_assert(t);
     extend(t, 2 + map->channels);
 
     t->data[t->length++] = PA_TAG_CHANNEL_MAP;
@@ -220,7 +241,7 @@
     unsigned i;
     pa_volume_t vol;
 
-    assert(t);
+    pa_assert(t);
     extend(t, 2 + cvolume->channels * sizeof(pa_volume_t));
 
     t->data[t->length++] = PA_TAG_CVOLUME;
@@ -237,7 +258,9 @@
     int error = 0;
     size_t n;
     char *c;
-    assert(t && s);
+
+    pa_assert(t);
+    pa_assert(s);
 
     if (t->rindex+1 > t->length)
         return -1;
@@ -271,7 +294,8 @@
 }
 
 int pa_tagstruct_getu32(pa_tagstruct*t, uint32_t *i) {
-    assert(t && i);
+    pa_assert(t);
+    pa_assert(i);
 
     if (t->rindex+5 > t->length)
         return -1;
@@ -286,7 +310,8 @@
 }
 
 int pa_tagstruct_getu8(pa_tagstruct*t, uint8_t *c) {
-    assert(t && c);
+    pa_assert(t);
+    pa_assert(c);
 
     if (t->rindex+2 > t->length)
         return -1;
@@ -300,7 +325,8 @@
 }
 
 int pa_tagstruct_get_sample_spec(pa_tagstruct *t, pa_sample_spec *ss) {
-    assert(t && ss);
+    pa_assert(t);
+    pa_assert(ss);
 
     if (t->rindex+7 > t->length)
         return -1;
@@ -319,7 +345,9 @@
 
 int pa_tagstruct_get_arbitrary(pa_tagstruct *t, const void **p, size_t length) {
     uint32_t len;
-    assert(t && p);
+
+    pa_assert(t);
+    pa_assert(p);
 
     if (t->rindex+5+length > t->length)
         return -1;
@@ -337,18 +365,23 @@
 }
 
 int pa_tagstruct_eof(pa_tagstruct*t) {
-    assert(t);
+    pa_assert(t);
+
     return t->rindex >= t->length;
 }
 
 const uint8_t* pa_tagstruct_data(pa_tagstruct*t, size_t *l) {
-    assert(t && t->dynamic && l);
+    pa_assert(t);
+    pa_assert(t->dynamic);
+    pa_assert(l);
+
     *l = t->length;
     return t->data;
 }
 
 int pa_tagstruct_get_boolean(pa_tagstruct*t, int *b) {
-    assert(t && b);
+    pa_assert(t);
+    pa_assert(b);
 
     if (t->rindex+1 > t->length)
         return -1;
@@ -366,6 +399,9 @@
 
 int pa_tagstruct_get_timeval(pa_tagstruct*t, struct timeval *tv) {
 
+    pa_assert(t);
+    pa_assert(tv);
+
     if (t->rindex+9 > t->length)
         return -1;
 
@@ -382,7 +418,9 @@
 
 int pa_tagstruct_get_usec(pa_tagstruct*t, pa_usec_t *u) {
     uint32_t tmp;
-    assert(t && u);
+
+    pa_assert(t);
+    pa_assert(u);
 
     if (t->rindex+9 > t->length)
         return -1;
@@ -400,7 +438,9 @@
 
 int pa_tagstruct_getu64(pa_tagstruct*t, uint64_t *u) {
     uint32_t tmp;
-    assert(t && u);
+
+    pa_assert(t);
+    pa_assert(u);
 
     if (t->rindex+9 > t->length)
         return -1;
@@ -418,7 +458,9 @@
 
 int pa_tagstruct_gets64(pa_tagstruct*t, int64_t *u) {
     uint32_t tmp;
-    assert(t && u);
+
+    pa_assert(t);
+    pa_assert(u);
 
     if (t->rindex+9 > t->length)
         return -1;
@@ -437,8 +479,8 @@
 int pa_tagstruct_get_channel_map(pa_tagstruct *t, pa_channel_map *map) {
     unsigned i;
 
-    assert(t);
-    assert(map);
+    pa_assert(t);
+    pa_assert(map);
 
     if (t->rindex+2 > t->length)
         return -1;
@@ -463,8 +505,8 @@
     unsigned i;
     pa_volume_t vol;
 
-    assert(t);
-    assert(cvolume);
+    pa_assert(t);
+    pa_assert(cvolume);
 
     if (t->rindex+2 > t->length)
         return -1;
@@ -489,7 +531,7 @@
 
 void pa_tagstruct_put(pa_tagstruct *t, ...) {
     va_list va;
-    assert(t);
+    pa_assert(t);
 
     va_start(va, t);
 
@@ -550,7 +592,7 @@
                 break;
 
             default:
-                abort();
+                pa_assert_not_reached();
         }
     }
 
@@ -561,7 +603,7 @@
     va_list va;
     int ret = 0;
 
-    assert(t);
+    pa_assert(t);
 
     va_start(va, t);
     while (ret == 0) {
@@ -620,9 +662,8 @@
                 ret = pa_tagstruct_get_cvolume(t, va_arg(va, pa_cvolume *));
                 break;
 
-
             default:
-                abort();
+                pa_assert_not_reached();
         }
 
     }

Copied: trunk/src/pulsecore/thread-mq.c (from r1970, branches/lennart/src/pulsecore/thread-mq.c)
URL: http://0pointer.de/cgi-bin/viewcvs.cgi/trunk/src/pulsecore/thread-mq.c?p2=trunk/src/pulsecore/thread-mq.c&p1=branches/lennart/src/pulsecore/thread-mq.c&r1=1970&r2=1971&rev=1971&root=pulseaudio&view=diff
==============================================================================
--- branches/lennart/src/pulsecore/thread-mq.c (original)
+++ trunk/src/pulsecore/thread-mq.c Sun Oct 28 20:13:50 2007
@@ -82,7 +82,7 @@
     q->mainloop = mainloop;
     pa_assert_se(q->inq = pa_asyncmsgq_new(0));
     pa_assert_se(q->outq = pa_asyncmsgq_new(0));
-    
+
     pa_assert_se(pa_asyncmsgq_before_poll(q->outq) == 0);
     pa_assert_se(q->io_event = mainloop->io_new(mainloop, pa_asyncmsgq_get_fd(q->outq), PA_IO_EVENT_INPUT, asyncmsgq_cb, q));
 }
@@ -96,7 +96,7 @@
     pa_asyncmsgq_unref(q->inq);
     pa_asyncmsgq_unref(q->outq);
     q->inq = q->outq = NULL;
-    
+
     q->mainloop = NULL;
 }
 

Modified: trunk/src/pulsecore/thread-posix.c
URL: http://0pointer.de/cgi-bin/viewcvs.cgi/trunk/src/pulsecore/thread-posix.c?rev=1971&root=pulseaudio&r1=1970&r2=1971&view=diff
==============================================================================
--- trunk/src/pulsecore/thread-posix.c (original)
+++ trunk/src/pulsecore/thread-posix.c Sun Oct 28 20:13:50 2007
@@ -26,7 +26,6 @@
 #include <config.h>
 #endif
 
-#include <assert.h>
 #include <pthread.h>
 #include <sched.h>
 #include <errno.h>
@@ -35,56 +34,44 @@
 #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 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);
-}
+PA_STATIC_TLS_DECLARE(current_thread, thread_free_cb);
 
 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);
+    PA_STATIC_TLS_SET(current_thread, 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 +79,7 @@
 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 +97,26 @@
 }
 
 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 +124,7 @@
 pa_thread* pa_thread_self(void) {
     pa_thread *t;
 
-    pa_once(&thread_tls_once, thread_tls_once_func);
-
-    if ((t = pa_tls_get(thread_tls)))
+    if ((t = PA_STATIC_TLS_GET(current_thread)))
         return t;
 
     /* This is a foreign thread, let's create a pthread structure to
@@ -151,19 +136,19 @@
     t->userdata = NULL;
     pa_atomic_store(&t->running, 2);
 
-    pa_tls_set(thread_tls, t);
+    PA_STATIC_TLS_SET(current_thread, 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 +157,7 @@
 #ifdef HAVE_PTHREAD_YIELD
     pthread_yield();
 #else
-    ASSERT_SUCCESS(sched_yield());
+    pa_assert_se(sched_yield() == 0);
 #endif
 }
 
@@ -190,14 +175,14 @@
 }
 
 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 +191,7 @@
     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;
 }
 

Modified: trunk/src/pulsecore/thread-win32.c
URL: http://0pointer.de/cgi-bin/viewcvs.cgi/trunk/src/pulsecore/thread-win32.c?rev=1971&root=pulseaudio&r1=1970&r2=1971&view=diff
==============================================================================
--- trunk/src/pulsecore/thread-win32.c (original)
+++ trunk/src/pulsecore/thread-win32.c Sun Oct 28 20:13:50 2007
@@ -53,9 +53,8 @@
 };
 
 static pa_tls *thread_tls;
-static pa_once_t thread_tls_once = PA_ONCE_INIT;
+static pa_once thread_tls_once = PA_ONCE_INIT;
 static pa_tls *monitor_tls;
-static pa_once_t monitor_tls_once = PA_ONCE_INIT;
 
 static void thread_tls_once_func(void) {
     thread_tls = pa_tls_new(NULL);
@@ -66,7 +65,7 @@
     pa_thread *t = param;
     assert(t);
 
-    pa_once(&thread_tls_once, thread_tls_once_func);
+    pa_run_once(&thread_tls_once, thread_tls_once_func);
     pa_tls_set(thread_tls, t);
 
     t->thread_func(t->userdata);
@@ -122,18 +121,12 @@
 }
 
 pa_thread* pa_thread_self(void) {
-    pa_once(&thread_tls_once, thread_tls_once_func);
+    pa_run_once(&thread_tls_once, thread_tls_once_func);
     return pa_tls_get(thread_tls);
 }
 
 void pa_thread_yield(void) {
     Sleep(0);
-}
-
-static void monitor_tls_once_func(void) {
-    monitor_tls = pa_tls_new(NULL);
-    assert(monitor_tls);
-    pa_tls_set(monitor_tls, NULL);
 }
 
 static DWORD WINAPI monitor_thread_func(LPVOID param) {
@@ -191,7 +184,11 @@
     if (t->free_func) {
         struct pa_tls_monitor *m;
 
-        pa_once(&monitor_tls_once, monitor_tls_once_func);
+        PA_ONCE_BEGIN {
+            monitor_tls = pa_tls_new(NULL);
+            assert(monitor_tls);
+            pa_tls_set(monitor_tls, NULL);
+        } PA_ONCE_END;
 
         m = pa_tls_get(monitor_tls);
         if (!m) {

Modified: trunk/src/pulsecore/thread.h
URL: http://0pointer.de/cgi-bin/viewcvs.cgi/trunk/src/pulsecore/thread.h?rev=1971&root=pulseaudio&r1=1970&r2=1971&view=diff
==============================================================================
--- trunk/src/pulsecore/thread.h (original)
+++ trunk/src/pulsecore/thread.h Sun Oct 28 20:13:50 2007
@@ -26,6 +26,11 @@
 ***/
 
 #include <pulse/def.h>
+#include <pulsecore/once.h>
+
+#ifndef PACKAGE
+#error "Please include config.h before including this file!"
+#endif
 
 typedef struct pa_thread pa_thread;
 
@@ -48,4 +53,60 @@
 void * pa_tls_get(pa_tls *t);
 void *pa_tls_set(pa_tls *t, void *userdata);
 
+#define PA_STATIC_TLS_DECLARE(name, free_cb)                            \
+    static struct {                                                     \
+        pa_once once;                                                   \
+        pa_tls *tls;                                                    \
+    } name##_tls = {                                                    \
+        .once = PA_ONCE_INIT,                                           \
+        .tls = NULL                                                     \
+    };                                                                  \
+    static void name##_tls_init(void) {                                 \
+        name##_tls.tls = pa_tls_new(free_cb);                           \
+    }                                                                   \
+    static inline pa_tls* name##_tls_obj(void) {                        \
+        pa_run_once(&name##_tls.once, name##_tls_init);                 \
+        return name##_tls.tls;                                          \
+    }                                                                   \
+    static void name##_tls_destructor(void) PA_GCC_DESTRUCTOR;          \
+    static void name##_tls_destructor(void) {                           \
+        static void (*_free_cb)(void*) = free_cb;                       \
+        if (!name##_tls.tls)                                            \
+            return;                                                     \
+        if (_free_cb) {                                                 \
+            void *p;                                                    \
+            if ((p = pa_tls_get(name##_tls.tls)))                       \
+                _free_cb(p);                                            \
+        }                                                               \
+        pa_tls_free(name##_tls.tls);                                    \
+    }                                                                   \
+    static inline void* name##_tls_get(void) {                          \
+        return pa_tls_get(name##_tls_obj());                            \
+    }                                                                   \
+    static inline void* name##_tls_set(void *p) {                       \
+        return pa_tls_set(name##_tls_obj(), p);                         \
+    }                                                                   \
+    struct __stupid_useless_struct_to_allow_trailing_semicolon
+
+#ifdef HAVE_TLS_BUILTIN
+/* An optimized version of the above that requires no dynamic
+ * allocation if the compiler supports __thread */
+#define PA_STATIC_TLS_DECLARE_NO_FREE(name)                             \
+    static __thread void *name##_tls = NULL;                            \
+    static inline void* name##_tls_get(void) {                          \
+        return name##_tls;                                              \
+    }                                                                   \
+    static inline void* name##_tls_set(void *p) {                       \
+        void *r = name##_tls;                                           \
+        name##_tls = p;                                                 \
+        return r;                                                       \
+    }                                                                   \
+    struct __stupid_useless_struct_to_allow_trailing_semicolon
+#else
+#define PA_STATIC_TLS_DECLARE_NO_FREE(name) PA_STATIC_TLS_DECLARE(name, NULL)
 #endif
+
+#define PA_STATIC_TLS_GET(name) (name##_tls_get())
+#define PA_STATIC_TLS_SET(name, p) (name##_tls_set(p))
+
+#endif

Modified: trunk/src/pulsecore/tokenizer.c
URL: http://0pointer.de/cgi-bin/viewcvs.cgi/trunk/src/pulsecore/tokenizer.c?rev=1971&root=pulseaudio&r1=1970&r2=1971&view=diff
==============================================================================
--- trunk/src/pulsecore/tokenizer.c (original)
+++ trunk/src/pulsecore/tokenizer.c Sun Oct 28 20:13:50 2007
@@ -26,19 +26,15 @@
 #endif
 
 #include <string.h>
-#include <assert.h>
 #include <stdlib.h>
 
 #include <pulse/xmalloc.h>
 
 #include <pulsecore/dynarray.h>
 #include <pulsecore/gccmacro.h>
+#include <pulsecore/macro.h>
 
 #include "tokenizer.h"
-
-struct pa_tokenizer {
-    pa_dynarray *dynarray;
-};
 
 static void token_free(void *p, PA_GCC_UNUSED void *userdata) {
     pa_xfree(p);
@@ -48,7 +44,9 @@
     int infty = 0;
     const char delimiter[] = " \t\n\r";
     const char *p;
-    assert(a && s);
+
+    pa_assert(a);
+    pa_assert(s);
 
     if (args == 0)
         infty = 1;
@@ -70,23 +68,23 @@
 }
 
 pa_tokenizer* pa_tokenizer_new(const char *s, unsigned args) {
-    pa_tokenizer *t;
+    pa_dynarray *a;
 
-    t = pa_xmalloc(sizeof(pa_tokenizer));
-    t->dynarray = pa_dynarray_new();
-    assert(t->dynarray);
-
-    parse(t->dynarray, s, args);
-    return t;
+    a = pa_dynarray_new();
+    parse(a, s, args);
+    return (pa_tokenizer*) a;
 }
 
 void pa_tokenizer_free(pa_tokenizer *t) {
-    assert(t);
-    pa_dynarray_free(t->dynarray, token_free, NULL);
-    pa_xfree(t);
+    pa_dynarray *a = (pa_dynarray*) t;
+
+    pa_assert(a);
+    pa_dynarray_free(a, token_free, NULL);
 }
 
 const char *pa_tokenizer_get(pa_tokenizer *t, unsigned i) {
-    assert(t);
-    return pa_dynarray_get(t->dynarray, i);
+    pa_dynarray *a = (pa_dynarray*) t;
+
+    pa_assert(a);
+    return pa_dynarray_get(a, i);
 }

Modified: trunk/src/pulsecore/winsock.h
URL: http://0pointer.de/cgi-bin/viewcvs.cgi/trunk/src/pulsecore/winsock.h?rev=1971&root=pulseaudio&r1=1970&r2=1971&view=diff
==============================================================================
--- trunk/src/pulsecore/winsock.h (original)
+++ trunk/src/pulsecore/winsock.h Sun Oct 28 20:13:50 2007
@@ -15,6 +15,8 @@
 #define EHOSTUNREACH    WSAEHOSTUNREACH
 #define EWOULDBLOCK     WSAEWOULDBLOCK
 
+typedef long suseconds_t;
+
 #endif
 
 #ifdef HAVE_WS2TCPIP_H

Modified: trunk/src/pulsecore/x11prop.c
URL: http://0pointer.de/cgi-bin/viewcvs.cgi/trunk/src/pulsecore/x11prop.c?rev=1971&root=pulseaudio&r1=1970&r2=1971&view=diff
==============================================================================
--- trunk/src/pulsecore/x11prop.c (original)
+++ trunk/src/pulsecore/x11prop.c Sun Oct 28 20:13:50 2007
@@ -31,7 +31,6 @@
 #include <X11/Xatom.h>
 
 #include "x11prop.h"
-
 
 void pa_x11_set_prop(Display *d, const char *name, const char *data) {
     Atom a = XInternAtom(d, name, False);

Modified: trunk/src/pulsecore/x11wrap.c
URL: http://0pointer.de/cgi-bin/viewcvs.cgi/trunk/src/pulsecore/x11wrap.c?rev=1971&root=pulseaudio&r1=1970&r2=1971&view=diff
==============================================================================
--- trunk/src/pulsecore/x11wrap.c (original)
+++ trunk/src/pulsecore/x11wrap.c Sun Oct 28 20:13:50 2007
@@ -21,7 +21,10 @@
   USA.
 ***/
 
-#include <assert.h>
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
 #include <stdio.h>
 
 #include <pulse/xmalloc.h>
@@ -29,6 +32,8 @@
 #include <pulsecore/llist.h>
 #include <pulsecore/log.h>
 #include <pulsecore/props.h>
+#include <pulsecore/core-util.h>
+#include <pulsecore/macro.h>
 
 #include "x11wrap.h"
 
@@ -42,8 +47,8 @@
 };
 
 struct pa_x11_wrapper {
+    PA_REFCNT_DECLARE;
     pa_core *core;
-    int ref;
 
     char *property_name;
     Display *display;
@@ -64,7 +69,8 @@
 
 /* Dispatch all pending X11 events */
 static void work(pa_x11_wrapper *w) {
-    assert(w && w->ref >= 1);
+    pa_assert(w);
+    pa_assert(PA_REFCNT_VALUE(w) >= 1);
 
     while (XPending(w->display)) {
         pa_x11_client *c;
@@ -72,7 +78,7 @@
         XNextEvent(w->display, &e);
 
         for (c = w->clients; c; c = c->next) {
-            assert(c->callback);
+            pa_assert(c->callback);
             if (c->callback(w, &e, c->userdata) != 0)
                 break;
         }
@@ -82,14 +88,24 @@
 /* IO notification event for the X11 display connection */
 static void display_io_event(pa_mainloop_api *m, pa_io_event *e, int fd, PA_GCC_UNUSED pa_io_event_flags_t f, void *userdata) {
     pa_x11_wrapper *w = userdata;
-    assert(m && e && fd >= 0 && w && w->ref >= 1);
+
+    pa_assert(m);
+    pa_assert(e);
+    pa_assert(fd >= 0);
+    pa_assert(w);
+    pa_assert(PA_REFCNT_VALUE(w) >= 1);
+
     work(w);
 }
 
 /* Deferred notification event. Called once each main loop iteration */
 static void defer_event(pa_mainloop_api *m, pa_defer_event *e, void *userdata) {
     pa_x11_wrapper *w = userdata;
-    assert(m && e && w && w->ref >= 1);
+
+    pa_assert(m);
+    pa_assert(e);
+    pa_assert(w);
+    pa_assert(PA_REFCNT_VALUE(w) >= 1);
 
     m->defer_enable(e, 0);
 
@@ -99,7 +115,12 @@
 /* IO notification event for X11 internal connections */
 static void internal_io_event(pa_mainloop_api *m, pa_io_event *e, int fd, PA_GCC_UNUSED pa_io_event_flags_t f, void *userdata) {
     pa_x11_wrapper *w = userdata;
-    assert(m && e && fd >= 0 && w && w->ref >= 1);
+
+    pa_assert(m);
+    pa_assert(e);
+    pa_assert(fd >= 0);
+    pa_assert(w);
+    pa_assert(PA_REFCNT_VALUE(w) >= 1);
 
     XProcessInternalConnection(w->display, fd);
 
@@ -109,10 +130,9 @@
 /* Add a new IO source for the specified X11 internal connection */
 static pa_x11_internal* x11_internal_add(pa_x11_wrapper *w, int fd) {
     pa_x11_internal *i;
-    assert(fd >= 0);
-
-    i = pa_xmalloc(sizeof(pa_x11_internal));
-    assert(i);
+    pa_assert(fd >= 0);
+
+    i = pa_xnew(pa_x11_internal, 1);
     i->wrapper = w;
     i->io_event = w->core->mainloop->io_new(w->core->mainloop, fd, PA_IO_EVENT_INPUT, internal_io_event, w);
     i->fd = fd;
@@ -123,7 +143,7 @@
 
 /* Remove an IO source for an X11 internal connection */
 static void x11_internal_remove(pa_x11_wrapper *w, pa_x11_internal *i) {
-    assert(i);
+    pa_assert(i);
 
     PA_LLIST_REMOVE(pa_x11_internal, w->internals, i);
     w->core->mainloop->io_free(i->io_event);
@@ -133,7 +153,10 @@
 /* Implementation of XConnectionWatchProc */
 static void x11_watch(Display *display, XPointer userdata, int fd, Bool opening, XPointer *watch_data) {
     pa_x11_wrapper *w = (pa_x11_wrapper*) userdata;
-    assert(display && w && fd >= 0);
+
+    pa_assert(display);
+    pa_assert(w);
+    pa_assert(fd >= 0);
 
     if (opening)
         *watch_data = (XPointer) x11_internal_add(w, fd);
@@ -144,16 +167,15 @@
 static pa_x11_wrapper* x11_wrapper_new(pa_core *c, const char *name, const char *t) {
     pa_x11_wrapper*w;
     Display *d;
-    int r;
 
     if (!(d = XOpenDisplay(name))) {
         pa_log("XOpenDisplay() failed");
         return NULL;
     }
 
-    w = pa_xmalloc(sizeof(pa_x11_wrapper));
+    w = pa_xnew(pa_x11_wrapper, 1);
+    PA_REFCNT_INIT(w);
     w->core = c;
-    w->ref = 1;
     w->property_name = pa_xstrdup(t);
     w->display = d;
 
@@ -165,20 +187,17 @@
 
     XAddConnectionWatch(d, x11_watch, (XPointer) w);
 
-    r = pa_property_set(c, w->property_name, w);
-    assert(r >= 0);
+    pa_assert_se(pa_property_set(c, w->property_name, w) >= 0);
 
     return w;
 }
 
 static void x11_wrapper_free(pa_x11_wrapper*w) {
-    int r;
-    assert(w);
-
-    r = pa_property_remove(w->core, w->property_name);
-    assert(r >= 0);
-
-    assert(!w->clients);
+    pa_assert(w);
+
+    pa_assert_se(pa_property_remove(w->core, w->property_name) >= 0);
+
+    pa_assert(!w->clients);
 
     XRemoveConnectionWatch(w->display, x11_watch, (XPointer) w);
     XCloseDisplay(w->display);
@@ -196,9 +215,10 @@
 pa_x11_wrapper* pa_x11_wrapper_get(pa_core *c, const char *name) {
     char t[256];
     pa_x11_wrapper *w;
-    assert(c);
-
-    snprintf(t, sizeof(t), "x11-wrapper%s%s", name ? "-" : "", name ? name : "");
+
+    pa_core_assert_ref(c);
+
+    pa_snprintf(t, sizeof(t), "x11-wrapper%s%s", name ? "-" : "", name ? name : "");
     if ((w = pa_property_get(c, t)))
         return pa_x11_wrapper_ref(w);
 
@@ -206,20 +226,24 @@
 }
 
 pa_x11_wrapper* pa_x11_wrapper_ref(pa_x11_wrapper *w) {
-    assert(w && w->ref >= 1);
-    w->ref++;
+    pa_assert(w);
+    pa_assert(PA_REFCNT_VALUE(w) >= 1);
+
+    PA_REFCNT_INC(w);
     return w;
 }
 
 void pa_x11_wrapper_unref(pa_x11_wrapper* w) {
-    assert(w && w->ref >= 1);
-
-    if (!(--w->ref))
+    pa_assert(w);
+    pa_assert(PA_REFCNT_VALUE(w) >= 1);
+
+    if (PA_REFCNT_DEC(w) <= 0)
         x11_wrapper_free(w);
 }
 
 Display *pa_x11_wrapper_get_display(pa_x11_wrapper *w) {
-    assert(w && w->ref >= 1);
+    pa_assert(w);
+    pa_assert(PA_REFCNT_VALUE(w) >= 1);
 
     /* Somebody is using us, schedule a output buffer flush */
     w->core->mainloop->defer_enable(w->defer_event, 1);
@@ -229,9 +253,11 @@
 
 pa_x11_client* pa_x11_client_new(pa_x11_wrapper *w, int (*cb)(pa_x11_wrapper *w, XEvent *e, void *userdata), void *userdata) {
     pa_x11_client *c;
-    assert(w && w->ref >= 1);
-
-    c = pa_xmalloc(sizeof(pa_x11_client));
+
+    pa_assert(w);
+    pa_assert(PA_REFCNT_VALUE(w) >= 1);
+
+    c = pa_xnew(pa_x11_client, 1);
     c->wrapper = w;
     c->callback = cb;
     c->userdata = userdata;
@@ -242,7 +268,9 @@
 }
 
 void pa_x11_client_free(pa_x11_client *c) {
-    assert(c && c->wrapper && c->wrapper->ref >= 1);
+    pa_assert(c);
+    pa_assert(c->wrapper);
+    pa_assert(PA_REFCNT_VALUE(c->wrapper) >= 1);
 
     PA_LLIST_REMOVE(pa_x11_client, c->wrapper->clients, c);
     pa_xfree(c);

Copied: trunk/src/tests/asyncmsgq-test.c (from r1970, branches/lennart/src/tests/asyncmsgq-test.c)
URL: http://0pointer.de/cgi-bin/viewcvs.cgi/trunk/src/tests/asyncmsgq-test.c?p2=trunk/src/tests/asyncmsgq-test.c&p1=branches/lennart/src/tests/asyncmsgq-test.c&r1=1970&r2=1971&rev=1971&root=pulseaudio&view=diff
==============================================================================
--- branches/lennart/src/tests/asyncmsgq-test.c (original)
+++ trunk/src/tests/asyncmsgq-test.c Sun Oct 28 20:13:50 2007
@@ -91,7 +91,7 @@
 
     printf("Operation B post\n");
     pa_asyncmsgq_post(q, NULL, OPERATION_B, NULL, 0, NULL, NULL);
-    
+
     pa_thread_yield();
 
     printf("Operation C send\n");

Modified: trunk/src/tests/hook-list-test.c
URL: http://0pointer.de/cgi-bin/viewcvs.cgi/trunk/src/tests/hook-list-test.c?rev=1971&root=pulseaudio&r1=1970&r2=1971&view=diff
==============================================================================
--- trunk/src/tests/hook-list-test.c (original)
+++ trunk/src/tests/hook-list-test.c Sun Oct 28 20:13:50 2007
@@ -1,4 +1,8 @@
 /* $Id$ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
 
 #include <pulsecore/hook-list.h>
 #include <pulsecore/log.h>

Modified: trunk/src/tests/interpol-test.c
URL: http://0pointer.de/cgi-bin/viewcvs.cgi/trunk/src/tests/interpol-test.c?rev=1971&root=pulseaudio&r1=1970&r2=1971&view=diff
==============================================================================
--- trunk/src/tests/interpol-test.c (original)
+++ trunk/src/tests/interpol-test.c Sun Oct 28 20:13:50 2007
@@ -137,7 +137,7 @@
             pa_gettimeofday(&now);
 
             rtc = pa_timeval_diff(&now, &start);
-            printf("%i\t%llu\t%llu\t%llu\t%llu\t%u\n", k, rtc, t, rtc-old_rtc, t-old_t, changed);
+            printf("%i\t%llu\t%llu\t%llu\t%llu\t%u\n", k, (unsigned long long) rtc, (unsigned long long) t, (unsigned long long) (rtc-old_rtc), (unsigned long long) (t-old_t), changed);
             old_t = t;
             old_rtc = rtc;
         }

Modified: trunk/src/tests/mcalign-test.c
URL: http://0pointer.de/cgi-bin/viewcvs.cgi/trunk/src/tests/mcalign-test.c?rev=1971&root=pulseaudio&r1=1970&r2=1971&view=diff
==============================================================================
--- trunk/src/tests/mcalign-test.c (original)
+++ trunk/src/tests/mcalign-test.c Sun Oct 28 20:13:50 2007
@@ -59,16 +59,21 @@
             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);
@@ -76,7 +81,7 @@
 
         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 @@
             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);

Modified: trunk/src/tests/memblock-test.c
URL: http://0pointer.de/cgi-bin/viewcvs.cgi/trunk/src/tests/memblock-test.c?rev=1971&root=pulseaudio&r1=1970&r2=1971&view=diff
==============================================================================
--- trunk/src/tests/memblock-test.c (original)
+++ trunk/src/tests/memblock-test.c Sun Oct 28 20:13:50 2007
@@ -23,11 +23,11 @@
 #include <config.h>
 #endif
 
-#include <assert.h>
 #include <stdio.h>
 #include <unistd.h>
 
 #include <pulsecore/memblock.h>
+#include <pulsecore/macro.h>
 #include <pulse/xmalloc.h>
 
 static void release_cb(pa_memimport *i, uint32_t block_id, void *userdata) {
@@ -76,6 +76,7 @@
     pa_memblock* blocks[5];
     uint32_t id, shm_id;
     size_t offset, size;
+    char *x;
 
     const char txt[] = "This is a test!";
 
@@ -87,13 +88,20 @@
     pa_mempool_get_shm_id(pool_b, &id_b);
     pa_mempool_get_shm_id(pool_c, &id_c);
 
-    assert(pool_a && pool_b && pool_c);
+    pa_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[2]);
+
     blocks[3] = pa_memblock_new_malloced(pool_a, pa_xstrdup(txt), sizeof(txt));
     blocks[4] = NULL;
 
@@ -101,43 +109,47 @@
         printf("Memory block %u\n", i);
 
         mb_a = blocks[i];
-        assert(mb_a);
+        pa_assert(mb_a);
 
         export_a = pa_memexport_new(pool_a, revoke_cb, (void*) "A");
         export_b = pa_memexport_new(pool_b, revoke_cb, (void*) "B");
 
-        assert(export_a && export_b);
+        pa_assert(export_a && export_b);
 
         import_b = pa_memimport_new(pool_b, release_cb, (void*) "B");
         import_c = pa_memimport_new(pool_c, release_cb, (void*) "C");
 
-        assert(import_b && import_c);
+        pa_assert(import_b && import_c);
 
         r = pa_memexport_put(export_a, mb_a, &id, &shm_id, &offset, &size);
-        assert(r >= 0);
-        assert(shm_id == id_a);
+        pa_assert(r >= 0);
+        pa_assert(shm_id == id_a);
 
         printf("A: Memory block exported as %u\n", id);
 
         mb_b = pa_memimport_get(import_b, id, shm_id, offset, size);
-        assert(mb_b);
+        pa_assert(mb_b);
         r = pa_memexport_put(export_b, mb_b, &id, &shm_id, &offset, &size);
-        assert(r >= 0);
-        assert(shm_id == id_a || shm_id == id_b);
+        pa_assert(r >= 0);
+        pa_assert(shm_id == id_a || shm_id == id_b);
         pa_memblock_unref(mb_b);
 
         printf("B: Memory block exported as %u\n", id);
 
         mb_c = pa_memimport_get(import_c, id, shm_id, offset, size);
-        assert(mb_c);
-        printf("1 data=%s\n", (char*) mb_c->data);
+        pa_assert(mb_c);
+        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);

Modified: trunk/src/tests/memblockq-test.c
URL: http://0pointer.de/cgi-bin/viewcvs.cgi/trunk/src/tests/memblockq-test.c?rev=1971&root=pulseaudio&r1=1970&r2=1971&view=diff
==============================================================================
--- trunk/src/tests/memblockq-test.c (original)
+++ trunk/src/tests/memblockq-test.c Sun Oct 28 20:13:50 2007
@@ -26,6 +26,7 @@
 #include <stdlib.h>
 #include <assert.h>
 #include <stdio.h>
+#include <signal.h>
 
 #include <pulsecore/memblockq.h>
 #include <pulsecore/log.h>
@@ -48,22 +49,22 @@
     bq = pa_memblockq_new(0, 40, 10, 2, 4, 4, silence);
     assert(bq);
 
-    chunk1.memblock = pa_memblock_new_fixed(p, (char*) "AA", 2, 1);
+    chunk1.memblock = pa_memblock_new_fixed(p, (char*) "11", 2, 1);
     chunk1.index = 0;
     chunk1.length = 2;
     assert(chunk1.memblock);
 
-    chunk2.memblock = pa_memblock_new_fixed(p, (char*) "TTBB", 4, 1);
+    chunk2.memblock = pa_memblock_new_fixed(p, (char*) "XX22", 4, 1);
     chunk2.index = 2;
     chunk2.length = 2;
     assert(chunk2.memblock);
 
-    chunk3.memblock = pa_memblock_new_fixed(p, (char*) "ZZZZ", 4, 1);
+    chunk3.memblock = pa_memblock_new_fixed(p, (char*) "3333", 4, 1);
     chunk3.index = 0;
     chunk3.length = 4;
     assert(chunk3.memblock);
 
-    chunk4.memblock = pa_memblock_new_fixed(p, (char*) "KKKKKKKK", 8, 1);
+    chunk4.memblock = pa_memblock_new_fixed(p, (char*) "44444444", 8, 1);
     chunk4.index = 0;
     chunk4.length = 8;
     assert(chunk4.memblock);
@@ -115,13 +116,12 @@
 
     chunk3.index += 2;
     chunk3.length -= 2;
-
     ret = pa_memblockq_push(bq, &chunk3);
     assert(ret == 0);
 
+    pa_memblockq_shorten(bq, pa_memblockq_get_length(bq)-2);
+
     printf(">");
-
-    pa_memblockq_shorten(bq, 6);
 
     for (;;) {
         pa_memchunk out;
@@ -131,11 +131,13 @@
         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);
+        pa_memblockq_drop(bq, out.length);
     }
 
     printf("<\n");

Copied: trunk/src/tests/queue-test.c (from r1970, branches/lennart/src/tests/queue-test.c)
URL: http://0pointer.de/cgi-bin/viewcvs.cgi/trunk/src/tests/queue-test.c?p2=trunk/src/tests/queue-test.c&p1=branches/lennart/src/tests/queue-test.c&r1=1970&r2=1971&rev=1971&root=pulseaudio&view=diff
==============================================================================
--- branches/lennart/src/tests/queue-test.c (original)
+++ trunk/src/tests/queue-test.c Sun Oct 28 20:13:50 2007
@@ -40,12 +40,12 @@
     pa_assert_se(q = pa_queue_new());
 
     pa_assert(pa_queue_is_empty(q));
-    
+
     pa_queue_push(q, (void*) "eins");
     pa_log("%s\n", (char*) pa_queue_pop(q));
 
     pa_assert(pa_queue_is_empty(q));
-    
+
     pa_queue_push(q, (void*) "zwei");
     pa_queue_push(q, (void*) "drei");
     pa_queue_push(q, (void*) "vier");
@@ -62,7 +62,7 @@
 
     pa_queue_push(q, (void*) "sechs");
     pa_queue_push(q, (void*) "sieben");
-    
+
     pa_queue_free(q, NULL, NULL);
 
     return 0;

Copied: trunk/src/tests/sig2str-test.c (from r1970, branches/lennart/src/tests/sig2str-test.c)
URL: http://0pointer.de/cgi-bin/viewcvs.cgi/trunk/src/tests/sig2str-test.c?p2=trunk/src/tests/sig2str-test.c&p1=branches/lennart/src/tests/sig2str-test.c&r1=1970&r2=1971&rev=1971&root=pulseaudio&view=diff
==============================================================================
--- branches/lennart/src/tests/sig2str-test.c (original)
+++ trunk/src/tests/sig2str-test.c Sun Oct 28 20:13:50 2007
@@ -31,7 +31,7 @@
 
 int main(int argc, char *argv[]) {
     int sig;
-    
+
     for (sig = -1; sig <= NSIG; sig++)
         printf("%i = %s\n", sig, pa_sig2str(sig));
 

Modified: trunk/src/tests/thread-mainloop-test.c
URL: http://0pointer.de/cgi-bin/viewcvs.cgi/trunk/src/tests/thread-mainloop-test.c?rev=1971&root=pulseaudio&r1=1970&r2=1971&view=diff
==============================================================================
--- trunk/src/tests/thread-mainloop-test.c (original)
+++ trunk/src/tests/thread-mainloop-test.c Sun Oct 28 20:13:50 2007
@@ -23,18 +23,19 @@
 #include <config.h>
 #endif
 
-#include <assert.h>
 #include <stdlib.h>
 #include <unistd.h>
 #include <stdio.h>
 
 #include <pulse/timeval.h>
 #include <pulse/util.h>
+#include <pulse/thread-mainloop.h>
 
 #include <pulsecore/gccmacro.h>
-#include <pulse/thread-mainloop.h>
+#include <pulsecore/macro.h>
 
 static void tcb(pa_mainloop_api*a, pa_time_event *e, const struct timeval *tv, void *userdata) {
+    pa_assert_se(pa_threaded_mainloop_in_thread(userdata));
     fprintf(stderr, "TIME EVENT START\n");
     pa_threaded_mainloop_signal(userdata, 1);
     fprintf(stderr, "TIME EVENT END\n");
@@ -45,14 +46,14 @@
     pa_threaded_mainloop *m;
     struct timeval tv;
 
-    m = pa_threaded_mainloop_new();
-    assert(m);
-    a = pa_threaded_mainloop_get_api(m);
-    assert(a);
+    pa_assert_se(m = pa_threaded_mainloop_new());
+    pa_assert_se(a = pa_threaded_mainloop_get_api(m));
 
     pa_threaded_mainloop_start(m);
 
     pa_threaded_mainloop_lock(m);
+
+    pa_assert_se(!pa_threaded_mainloop_in_thread(m));
 
     pa_gettimeofday(&tv);
     tv.tv_sec += 5;

Modified: trunk/src/tests/thread-test.c
URL: http://0pointer.de/cgi-bin/viewcvs.cgi/trunk/src/tests/thread-test.c?rev=1971&root=pulseaudio&r1=1970&r2=1971&view=diff
==============================================================================
--- trunk/src/tests/thread-test.c (original)
+++ trunk/src/tests/thread-test.c Sun Oct 28 20:13:50 2007
@@ -42,7 +42,7 @@
     pa_log("once!");
 }
 
-static pa_once_t once = PA_ONCE_INIT;
+static pa_once once = PA_ONCE_INIT;
 
 static void thread_func(void *data) {
     pa_tls_set(tls, data);
@@ -72,7 +72,7 @@
 
         pa_mutex_unlock(mutex);
 
-        pa_once(&once, once_func);
+        pa_run_once(&once, once_func);
 
         pa_cond_signal(cond2, 0);
 
@@ -98,7 +98,7 @@
 
     assert(pa_thread_is_running(pa_thread_self()));
 
-    mutex = pa_mutex_new(0);
+    mutex = pa_mutex_new(FALSE, FALSE);
     cond1 = pa_cond_new();
     cond2 = pa_cond_new();
     tls = pa_tls_new(pa_xfree);

Modified: trunk/src/utils/pactl.c
URL: http://0pointer.de/cgi-bin/viewcvs.cgi/trunk/src/utils/pactl.c?rev=1971&root=pulseaudio&r1=1970&r2=1971&view=diff
==============================================================================
--- trunk/src/utils/pactl.c (original)
+++ trunk/src/utils/pactl.c Sun Oct 28 20:13:50 2007
@@ -48,8 +48,10 @@
 static pa_context *context = NULL;
 static pa_mainloop_api *mainloop_api = NULL;
 
-static char *device = NULL, *sample_name = NULL, *sink_name = NULL, *source_name = NULL;
+static char *device = NULL, *sample_name = NULL, *sink_name = NULL, *source_name = NULL, *module_name = NULL, *module_args = NULL;
 static uint32_t sink_input_idx = PA_INVALID_INDEX, source_output_idx = PA_INVALID_INDEX;
+static uint32_t module_index;
+static int suspend;
 
 static SNDFILE *sndfile = NULL;
 static pa_stream *sample_stream = NULL;
@@ -69,7 +71,11 @@
     REMOVE_SAMPLE,
     LIST,
     MOVE_SINK_INPUT,
-    MOVE_SOURCE_OUTPUT
+    MOVE_SOURCE_OUTPUT,
+    LOAD_MODULE,
+    UNLOAD_MODULE,
+    SUSPEND_SINK,
+    SUSPEND_SOURCE,
 } action = NONE;
 
 static void quit(int ret) {
@@ -354,7 +360,7 @@
            i->sink,
            pa_sample_spec_snprint(s, sizeof(s), &i->sample_spec),
            pa_channel_map_snprint(cm, sizeof(cm), &i->channel_map),
-           pa_cvolume_snprint(cv, sizeof(cv), &i->volume),
+           i->mute ? "muted" : pa_cvolume_snprint(cv, sizeof(cv), &i->volume),
            (double) i->buffer_usec,
            (double) i->sink_usec,
            i->resample_method ? i->resample_method : "n/a");
@@ -492,6 +498,18 @@
     complete_action();
 }
 
+static void index_callback(pa_context *c, uint32_t idx, void *userdata) {
+    if (idx == PA_INVALID_INDEX) {
+        fprintf(stderr, "Failure: %s\n", pa_strerror(pa_context_errno(c)));
+        quit(1);
+        return;
+    }
+
+    printf("%u\n", idx);
+
+    complete_action();
+}
+
 static void stream_state_callback(pa_stream *s, void *userdata) {
     assert(s);
 
@@ -594,6 +612,28 @@
                     pa_operation_unref(pa_context_move_source_output_by_name(c, source_output_idx, source_name, simple_callback, NULL));
                     break;
 
+                case LOAD_MODULE:
+                    pa_operation_unref(pa_context_load_module(c, module_name, module_args, index_callback, NULL));
+                    break;
+
+                case UNLOAD_MODULE:
+                    pa_operation_unref(pa_context_unload_module(c, module_index, simple_callback, NULL));
+                    break;
+
+                case SUSPEND_SINK:
+                    if (sink_name)
+                        pa_operation_unref(pa_context_suspend_sink_by_name(c, sink_name, suspend, simple_callback, NULL));
+                    else
+                        pa_operation_unref(pa_context_suspend_sink_by_index(c, PA_INVALID_INDEX, suspend, simple_callback, NULL));
+                    break;
+
+                case SUSPEND_SOURCE:
+                    if (source_name)
+                        pa_operation_unref(pa_context_suspend_source_by_name(c, source_name, suspend, simple_callback, NULL));
+                    else
+                        pa_operation_unref(pa_context_suspend_source_by_index(c, PA_INVALID_INDEX, suspend, simple_callback, NULL));
+                    break;
+
                 default:
                     assert(0);
             }
@@ -624,12 +664,16 @@
            "%s [options] play-sample NAME [SINK]\n"
            "%s [options] move-sink-input ID SINK\n"
            "%s [options] move-source-output ID SOURCE\n"
-           "%s [options] remove-sample NAME\n\n"
+           "%s [options] remove-sample NAME\n"
+           "%s [options] load-module NAME [ARGS ...]\n"
+           "%s [options] unload-module ID\n"
+           "%s [options] suspend-sink [SINK] 1|0\n"
+           "%s [options] suspend-source [SOURCE] 1|0\n\n"
            "  -h, --help                            Show this help\n"
            "      --version                         Show version\n\n"
            "  -s, --server=SERVER                   The name of the server to connect to\n"
            "  -n, --client-name=NAME                How to call this client on the server\n",
-           argv0, argv0, argv0, argv0, argv0, argv0, argv0, argv0);
+           argv0, argv0, argv0, argv0, argv0, argv0, argv0, argv0, argv0, argv0, argv0, argv0);
 }
 
 enum { ARG_VERSION = 256 };
@@ -728,7 +772,7 @@
             sample_length = sfinfo.frames*pa_frame_size(&sample_spec);
         } else if (!strcmp(argv[optind], "play-sample")) {
             action = PLAY_SAMPLE;
-            if (optind+1 >= argc) {
+            if (argc != optind+2 && argc != optind+3) {
                 fprintf(stderr, "You have to specify a sample name to play\n");
                 goto quit;
             }
@@ -740,7 +784,7 @@
 
         } else if (!strcmp(argv[optind], "remove-sample")) {
             action = REMOVE_SAMPLE;
-            if (optind+1 >= argc) {
+            if (argc != optind+2) {
                 fprintf(stderr, "You have to specify a sample name to remove\n");
                 goto quit;
             }
@@ -748,7 +792,7 @@
             sample_name = pa_xstrdup(argv[optind+1]);
         } else if (!strcmp(argv[optind], "move-sink-input")) {
             action = MOVE_SINK_INPUT;
-            if (optind+2 >= argc) {
+            if (argc != optind+3) {
                 fprintf(stderr, "You have to specify a sink input index and a sink\n");
                 goto quit;
             }
@@ -757,13 +801,72 @@
             sink_name = pa_xstrdup(argv[optind+2]);
         } else if (!strcmp(argv[optind], "move-source-output")) {
             action = MOVE_SOURCE_OUTPUT;
-            if (optind+2 >= argc) {
+            if (argc != optind+3) {
                 fprintf(stderr, "You have to specify a source output index and a source\n");
                 goto quit;
             }
 
             source_output_idx = atoi(argv[optind+1]);
             source_name = pa_xstrdup(argv[optind+2]);
+        } else if (!strcmp(argv[optind], "load-module")) {
+            int i;
+            size_t n = 0;
+            char *p;
+
+            action = LOAD_MODULE;
+
+            if (argc <= optind+1) {
+                fprintf(stderr, "You have to specify a module name and arguments.\n");
+                goto quit;
+            }
+
+            module_name = argv[optind+1];
+
+            for (i = optind+2; i < argc; i++)
+                n += strlen(argv[i])+1;
+
+            if (n > 0) {
+                p = module_args = pa_xnew0(char, n);
+
+                for (i = optind+2; i < argc; i++)
+                    p += sprintf(p, "%s%s", p == module_args ? "" : " ", argv[i]);
+            }
+
+        } else if (!strcmp(argv[optind], "unload-module")) {
+            action = UNLOAD_MODULE;
+
+            if (argc != optind+2) {
+                fprintf(stderr, "You have to specify a module index\n");
+                goto quit;
+            }
+
+            module_index = atoi(argv[optind+1]);
+
+        } else if (!strcmp(argv[optind], "suspend-sink")) {
+            action = SUSPEND_SINK;
+
+            if (argc > optind+3 || optind+1 >= argc) {
+                fprintf(stderr, "You may not specify more than one sink. You have to specify at least one boolean value.\n");
+                goto quit;
+            }
+
+            suspend = !!atoi(argv[argc-1]);
+
+            if (argc > optind+2)
+                sink_name = pa_xstrdup(argv[optind+1]);
+
+        } else if (!strcmp(argv[optind], "suspend-source")) {
+            action = SUSPEND_SOURCE;
+
+            if (argc > optind+3 || optind+1 >= argc) {
+                fprintf(stderr, "You may not specify more than one source. You have to specify at least one boolean value.\n");
+                goto quit;
+            }
+
+            suspend = !!atoi(argv[argc-1]);
+
+            if (argc > optind+2)
+                source_name = pa_xstrdup(argv[optind+1]);
         }
     }
 
@@ -819,6 +922,8 @@
     pa_xfree(sample_name);
     pa_xfree(sink_name);
     pa_xfree(source_name);
+    pa_xfree(module_args);
+    pa_xfree(client_name);
 
     return ret;
 }

Modified: trunk/src/utils/padsp.c
URL: http://0pointer.de/cgi-bin/viewcvs.cgi/trunk/src/utils/padsp.c?rev=1971&root=pulseaudio&r1=1970&r2=1971&view=diff
==============================================================================
--- trunk/src/utils/padsp.c (original)
+++ trunk/src/utils/padsp.c Sun Oct 28 20:13:50 2007
@@ -60,6 +60,10 @@
 #if !defined(SIOCINQ) && defined(FIONREAD)
 # define SIOCINQ FIONREAD
 #endif
+
+/* make sure gcc doesn't redefine open and friends as macros */
+#undef open
+#undef open64
 
 typedef enum {
     FD_INFO_MIXER,
@@ -259,9 +263,9 @@
 
 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 +425,7 @@
     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 +1399,7 @@
 
     if (flags != O_RDONLY
 #ifdef O_LARGEFILE
-	&& flags != (O_RDONLY|O_LARGEFILE)
+        && flags != (O_RDONLY|O_LARGEFILE)
 #endif
        ) {
         *_errno = EACCES;
@@ -1436,45 +1440,50 @@
     return -1;
 }
 
+static int real_open(const char *filename, int flags, mode_t mode) {
+    int r, _errno = 0;
+
+    debug(DEBUG_LEVEL_VERBOSE, __FILE__": open(%s)\n", filename);
+
+    if (!function_enter()) {
+        LOAD_OPEN_FUNC();
+        return _open(filename, flags, mode);
+    }
+
+    if (dsp_cloak_enable() && (strcmp(filename, "/dev/dsp") == 0 || strcmp(filename, "/dev/adsp") == 0))
+        r = dsp_open(flags, &_errno);
+    else if (mixer_cloak_enable() && strcmp(filename, "/dev/mixer") == 0)
+        r = mixer_open(flags, &_errno);
+    else if (sndstat_cloak_enable() && strcmp(filename, "/dev/sndstat") == 0)
+        r = sndstat_open(flags, &_errno);
+    else {
+        function_exit();
+        LOAD_OPEN_FUNC();
+        return _open(filename, flags, mode);
+    }
+
+    function_exit();
+
+    if (_errno)
+        errno = _errno;
+
+    return r;
+}
+
 int open(const char *filename, int flags, ...) {
     va_list args;
     mode_t mode = 0;
-    int r, _errno = 0;
-
-    debug(DEBUG_LEVEL_VERBOSE, __FILE__": open(%s)\n", filename);
-
-    va_start(args, flags);
+
     if (flags & O_CREAT) {
-      if (sizeof(mode_t) < sizeof(int))
-	mode = va_arg(args, int);
-      else
-        mode = va_arg(args, mode_t);
-    }
-    va_end(args);
-
-    if (!function_enter()) {
-        LOAD_OPEN_FUNC();
-        return _open(filename, flags, mode);
-    }
-
-    if (dsp_cloak_enable() && (strcmp(filename, "/dev/dsp") == 0 || strcmp(filename, "/dev/adsp") == 0)) {
-        r = dsp_open(flags, &_errno);
-    } else if (mixer_cloak_enable() && strcmp(filename, "/dev/mixer") == 0) {
-        r = mixer_open(flags, &_errno);
-    } else if (sndstat_cloak_enable() && strcmp(filename, "/dev/sndstat") == 0) {
-        r = sndstat_open(flags, &_errno);
-    } else {
-        function_exit();
-        LOAD_OPEN_FUNC();
-        return _open(filename, flags, mode);
-    }
-
-    function_exit();
-
-    if (_errno)
-        errno = _errno;
-
-    return r;
+        va_start(args, flags);
+        if (sizeof(mode_t) < sizeof(int))
+            mode = va_arg(args, int);
+        else
+            mode = va_arg(args, mode_t);
+        va_end(args);
+    }
+
+    return real_open(filename, flags, mode);
 }
 
 static int mixer_ioctl(fd_info *i, unsigned long request, void*argp, int *_errno) {
@@ -2023,9 +2032,9 @@
 
             *(int*)  argp = DSP_CAP_DUPLEX | DSP_CAP_TRIGGER
 #ifdef DSP_CAP_MULTI
-	      | DSP_CAP_MULTI
+              | DSP_CAP_MULTI
 #endif
-	      ;
+              ;
             break;
 
         case SNDCTL_DSP_GETODELAY: {
@@ -2497,10 +2506,14 @@
 
     debug(DEBUG_LEVEL_VERBOSE, __FILE__": open64(%s)\n", filename);
 
-    va_start(args, flags);
-    if (flags & O_CREAT)
-        mode = va_arg(args, mode_t);
-    va_end(args);
+    if (flags & O_CREAT) {
+        va_start(args, flags);
+        if (sizeof(mode_t) < sizeof(int))
+            mode = va_arg(args, int);
+        else
+            mode = va_arg(args, mode_t);
+        va_end(args);
+    }
 
     if (strcmp(filename, "/dev/dsp") != 0 &&
         strcmp(filename, "/dev/adsp") != 0 &&
@@ -2510,7 +2523,7 @@
         return _open64(filename, flags, mode);
     }
 
-    return open(filename, flags, mode);
+    return real_open(filename, flags, mode);
 }
 
 #endif
@@ -2602,7 +2615,7 @@
     if ((((mode[1] == 'b') || (mode[1] == 't')) && (mode[2] == '+')) || (mode[1] == '+'))
         m = O_RDWR;
 
-    if ((fd = open(filename, m)) < 0)
+    if ((fd = real_open(filename, m, 0)) < 0)
         return NULL;
 
     if (!(f = fdopen(fd, mode))) {

Modified: trunk/src/utils/paplay.c
URL: http://0pointer.de/cgi-bin/viewcvs.cgi/trunk/src/utils/paplay.c?rev=1971&root=pulseaudio&r1=1970&r2=1971&view=diff
==============================================================================
--- trunk/src/utils/paplay.c (original)
+++ trunk/src/utils/paplay.c Sun Oct 28 20:13:50 2007
@@ -123,7 +123,7 @@
     else
         pa_xfree(data);
 
-    if (bytes < length) {
+    if (bytes < (sf_count_t) length) {
         sf_close(sndfile);
         sndfile = NULL;
         pa_operation_unref(pa_stream_drain(s, stream_drain_complete, NULL));

Copied: trunk/src/utils/pasuspender.c (from r1970, branches/lennart/src/utils/pasuspender.c)
URL: http://0pointer.de/cgi-bin/viewcvs.cgi/trunk/src/utils/pasuspender.c?p2=trunk/src/utils/pasuspender.c&p1=branches/lennart/src/utils/pasuspender.c&r1=1970&r2=1971&rev=1971&root=pulseaudio&view=diff
==============================================================================
--- branches/lennart/src/utils/pasuspender.c (original)
+++ trunk/src/utils/pasuspender.c Sun Oct 28 20:13:50 2007
@@ -81,26 +81,26 @@
 }
 
 static void start_child(void) {
-    
+
     if ((child_pid = fork()) < 0) {
-        
+
         fprintf(stderr, "fork(): %s\n", strerror(errno));
         quit(1);
-        
+
     } else if (child_pid == 0) {
         /* Child */
-        
+
 #ifdef __linux__
         prctl(PR_SET_PDEATHSIG, SIGTERM, 0, 0, 0);
 #endif
-        
+
         if (execvp(child_argv[0], child_argv) < 0)
             fprintf(stderr, "execvp(): %s\n", strerror(errno));
-        
+
         _exit(1);
-        
+
     } else {
-        
+
         /* parent */
         dead = 0;
     }
@@ -110,7 +110,7 @@
     static int n = 0;
 
     n++;
-    
+
     if (!success) {
         fprintf(stderr, "Failure to suspend: %s\n", pa_strerror(pa_context_errno(c)));
         quit(1);
@@ -138,7 +138,7 @@
 
 static void context_state_callback(pa_context *c, void *userdata) {
     pa_assert(c);
-    
+
     switch (pa_context_get_state(c)) {
         case PA_CONTEXT_CONNECTING:
         case PA_CONTEXT_AUTHORIZING:
@@ -151,9 +151,9 @@
                 pa_operation_unref(pa_context_suspend_source_by_index(c, PA_INVALID_INDEX, 1, suspend_complete, NULL));
             } else
                 start_child();
-            
+
             break;
-                    
+
         case PA_CONTEXT_TERMINATED:
             quit(0);
             break;
@@ -184,14 +184,14 @@
 static void sigchld_callback(pa_mainloop_api *m, pa_signal_event *e, int sig, void *userdata) {
     int status = 0;
     pid_t p;
-    
+
     p = waitpid(-1, &status, WNOHANG);
 
     if (p != child_pid)
         return;
 
     dead = 1;
-    
+
     if (WIFEXITED(status))
         child_ret = WEXITSTATUS(status);
     else if (WIFSIGNALED(status)) {

Modified: trunk/todo
URL: http://0pointer.de/cgi-bin/viewcvs.cgi/trunk/todo?rev=1971&root=pulseaudio&r1=1970&r2=1971&view=diff
==============================================================================
--- trunk/todo (original)
+++ trunk/todo Sun Oct 28 20:13:50 2007
@@ -4,7 +4,6 @@
 - Remove symdef files and use macros (like most other projects)
 - Use own name mangling scheme instead of ltdl's, which will eliminate the
   need for .la files or extra trickery.
-- build pulsecore only statically by default, it's not a public API yet
 
 Porting:
 - rtp module ported to Win32 (sendmsg/recvmsg emulation)
@@ -13,16 +12,12 @@
 - iconv stuff sent from utils to server (UTF-8)
 - iconv sample loading in server
 - Document utf8.h, timeval.h and util.h
-- gettextify polypaudio
+- gettextify pulseaudio
 
 Cleanups:
 - drop dependency of libpolyp on libX11, instead use an external mini binary
-- merge module-oss-mmap into module-oss
 - module-tunnel: improve latency calculation
 - use software volume when hardware doesn't support all channels (alsa done)
-- silence generation should be moved into the core to avoid races and code
-  duplication in the backends
-- don't read/write audio data from/to ALSA devices if noone is listening
 - using POSIX monotonous clocks wherever possible instead of gettimeofday()
 
 Test:
@@ -35,7 +30,6 @@
 - sasl auth 
 
 Features:
-- alsa mmap driver
 - alsa driver with hw mixing
 - "window manager for sound"
 - chroot()
@@ -52,7 +46,8 @@
 - Support for device selection in waveout driver
 - add an API to libpulse for allocating memory from the pa_context memory pool
 - allow buffer metric changes during runtime
-- "include" command in configuration files. should have glob support.
+- better ".include" command in configuration files. should have glob support.
+- recursive .if
 
 Long term:
 - pass meta info for hearing impaired




More information about the pulseaudio-commits mailing list