[pulseaudio-commits] r1469 - in /branches/lennart/src: ./ modules/ modules/rtp/ pulse/ pulsecore/ tests/

svnmailer-noreply at 0pointer.de svnmailer-noreply at 0pointer.de
Mon Jun 11 05:08:38 PDT 2007


Author: lennart
Date: Mon Jun 11 14:08:37 2007
New Revision: 1469

URL: http://0pointer.de/cgi-bin/viewcvs.cgi?rev=3D1469&root=3Dpulseaudio&vi=
ew=3Drev
Log:
Merge HUGE set of changes temporarily into a branch, to allow me to move th=
em from one machine to another (lock-free and stuff)

Added:
    branches/lennart/src/pulsecore/asyncmsgq.c   (with props)
    branches/lennart/src/pulsecore/asyncmsgq.h   (with props)
    branches/lennart/src/pulsecore/asyncq.c   (with props)
    branches/lennart/src/pulsecore/asyncq.h   (with props)
    branches/lennart/src/pulsecore/macro.h   (with props)
    branches/lennart/src/pulsecore/msgobject.c   (with props)
    branches/lennart/src/pulsecore/msgobject.h   (with props)
    branches/lennart/src/pulsecore/object.c   (with props)
    branches/lennart/src/pulsecore/object.h   (with props)
    branches/lennart/src/pulsecore/semaphore-posix.c   (with props)
    branches/lennart/src/pulsecore/semaphore.h   (with props)
    branches/lennart/src/tests/asyncmsgq-test.c   (with props)
    branches/lennart/src/tests/asyncq-test.c   (with props)
Modified:
    branches/lennart/src/Makefile.am
    branches/lennart/src/modules/module-alsa-sink.c
    branches/lennart/src/modules/module-alsa-source.c
    branches/lennart/src/modules/module-esound-sink.c
    branches/lennart/src/modules/module-jack-sink.c
    branches/lennart/src/modules/module-jack-source.c
    branches/lennart/src/modules/module-null-sink.c
    branches/lennart/src/modules/module-oss-mmap.c
    branches/lennart/src/modules/module-oss.c
    branches/lennart/src/modules/module-pipe-sink.c
    branches/lennart/src/modules/module-pipe-source.c
    branches/lennart/src/modules/module-sine.c
    branches/lennart/src/modules/rtp/rtp.c
    branches/lennart/src/pulse/internal.h
    branches/lennart/src/pulse/stream.c
    branches/lennart/src/pulse/xmalloc.h
    branches/lennart/src/pulsecore/atomic.h
    branches/lennart/src/pulsecore/cli-command.c
    branches/lennart/src/pulsecore/cli-text.c
    branches/lennart/src/pulsecore/core-def.h
    branches/lennart/src/pulsecore/core.c
    branches/lennart/src/pulsecore/core.h
    branches/lennart/src/pulsecore/flist.c
    branches/lennart/src/pulsecore/flist.h
    branches/lennart/src/pulsecore/hashmap.h
    branches/lennart/src/pulsecore/idxset.c
    branches/lennart/src/pulsecore/idxset.h
    branches/lennart/src/pulsecore/mcalign.c
    branches/lennart/src/pulsecore/memblock.c
    branches/lennart/src/pulsecore/memblock.h
    branches/lennart/src/pulsecore/memblockq.c
    branches/lennart/src/pulsecore/memchunk.c
    branches/lennart/src/pulsecore/mutex-posix.c
    branches/lennart/src/pulsecore/once-posix.c
    branches/lennart/src/pulsecore/once.h
    branches/lennart/src/pulsecore/play-memblockq.c
    branches/lennart/src/pulsecore/play-memchunk.c
    branches/lennart/src/pulsecore/protocol-esound.c
    branches/lennart/src/pulsecore/protocol-native.c
    branches/lennart/src/pulsecore/protocol-simple.c
    branches/lennart/src/pulsecore/pstream.c
    branches/lennart/src/pulsecore/refcnt.h
    branches/lennart/src/pulsecore/resampler.c
    branches/lennart/src/pulsecore/sample-util.c
    branches/lennart/src/pulsecore/sample-util.h
    branches/lennart/src/pulsecore/sink-input.c
    branches/lennart/src/pulsecore/sink-input.h
    branches/lennart/src/pulsecore/sink.c
    branches/lennart/src/pulsecore/sink.h
    branches/lennart/src/pulsecore/sound-file-stream.c
    branches/lennart/src/pulsecore/sound-file.c
    branches/lennart/src/pulsecore/source-output.c
    branches/lennart/src/pulsecore/source-output.h
    branches/lennart/src/pulsecore/source.c
    branches/lennart/src/pulsecore/source.h
    branches/lennart/src/pulsecore/thread-posix.c
    branches/lennart/src/tests/mcalign-test.c
    branches/lennart/src/tests/memblock-test.c
    branches/lennart/src/tests/memblockq-test.c

Modified: branches/lennart/src/Makefile.am
URL: http://0pointer.de/cgi-bin/viewcvs.cgi/branches/lennart/src/Makefile.a=
m?rev=3D1469&root=3Dpulseaudio&r1=3D1468&r2=3D1469&view=3Ddiff
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D
--- branches/lennart/src/Makefile.am (original)
+++ branches/lennart/src/Makefile.am Mon Jun 11 14:08:37 2007
@@ -78,13 +78,15 @@
 PA_THREAD_OBJS =3D \
 		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 =3D \
 		pulsecore/atomic.h \
 		pulsecore/once-posix.c pulsecore/once.h \
 		pulsecore/mutex-posix.c pulsecore/mutex.h \
-		pulsecore/thread-posix.c pulsecore/thread.h
+		pulsecore/thread-posix.c pulsecore/thread.h \
+		pulsecore/semaphore-posix.c pulsecore/semaphore.h
 endif
 =

 ###################################
@@ -219,7 +221,9 @@
 		hook-list-test \
 		memblock-test \
 		thread-test \
-		flist-test
+		flist-test \
+		asyncq-test \
+		asyncmsgq-test
 =

 if HAVE_SIGXCPU
 noinst_PROGRAMS +=3D \
@@ -274,12 +278,20 @@
 thread_test_LDADD =3D $(AM_LDADD) libpulsecore.la
 thread_test_LDFLAGS =3D $(AM_LDFLAGS) $(BINLDFLAGS)
 =

-flist_test_SOURCES =3D tests/flist-test.c \
-		pulsecore/atomic.h \
-		pulsecore/flist.c pulsecore/flist.h
+flist_test_SOURCES =3D tests/flist-test.c
 flist_test_CFLAGS =3D $(AM_CFLAGS)
 flist_test_LDADD =3D $(AM_LDADD) libpulsecore.la
 flist_test_LDFLAGS =3D $(AM_LDFLAGS) $(BINLDFLAGS)
+
+asyncq_test_SOURCES =3D tests/asyncq-test.c pulsecore/thread-posix.c pulse=
core/thread.h pulsecore/asyncq.c pulsecore/asyncq.h pulsecore/core-util.c p=
ulsecore/core-util.h pulse/xmalloc.c pulse/xmalloc.h pulsecore/log.h pulsec=
ore/log.c pulsecore/core-error.h pulsecore/core-error.c pulsecore/once-posi=
x.c pulsecore/once.h pulsecore/mutex-posix.c pulsecore/mutex.h pulse/utf8.c=
 pulse/utf8.h pulse/util.h pulse/util.c
+asyncq_test_CFLAGS =3D $(AM_CFLAGS)
+asyncq_test_LDADD =3D $(AM_LDADD) #libpulsecore.la
+asyncq_test_LDFLAGS =3D $(AM_LDFLAGS) $(BINLDFLAGS)
+
+asyncmsgq_test_SOURCES =3D tests/asyncmsgq-test.c pulsecore/thread-posix.c=
 pulsecore/thread.h pulsecore/asyncq.c pulsecore/asyncq.h pulsecore/asyncms=
gq.c pulsecore/asyncmsgq.h pulsecore/core-util.c pulsecore/core-util.h puls=
e/xmalloc.c pulse/xmalloc.h pulsecore/log.h pulsecore/log.c pulsecore/core-=
error.h pulsecore/core-error.c pulsecore/once-posix.c pulsecore/once.h puls=
ecore/mutex-posix.c pulsecore/mutex.h pulse/utf8.c pulse/utf8.h pulse/util.=
h pulse/util.c pulsecore/semaphore.h pulsecore/semaphore-posix.c pulsecore/=
flist.h pulsecore/flist.c
+asyncmsgq_test_CFLAGS =3D $(AM_CFLAGS)
+asyncmsgq_test_LDADD =3D $(AM_LDADD) #libpulsecore.la
+asyncmsgq_test_LDFLAGS =3D $(AM_LDFLAGS) $(BINLDFLAGS)
 =

 mcalign_test_SOURCES =3D tests/mcalign-test.c
 mcalign_test_CFLAGS =3D $(AM_CFLAGS)
@@ -455,6 +467,9 @@
 		pulsecore/core-error.c pulsecore/core-error.h \
 		pulsecore/winsock.h pulsecore/creds.h \
 		pulsecore/shm.c pulsecore/shm.h \
+		pulsecore/flist.c pulsecore/flist.h \
+		pulsecore/object.c pulsecore/object.h \
+		pulsecore/msgobject.c pulsecore/msgobject.h \
 		$(PA_THREAD_OBJS)
 =

 if OS_IS_WIN32
@@ -567,6 +582,7 @@
 		pulsecore/refcnt.h \
 		pulsecore/mutex.h \
 		pulsecore/thread.h \
+		pulsecore/semaphore.h \
 		pulsecore/once.h
 =

 lib_LTLIBRARIES +=3D libpulsecore.la
@@ -636,6 +652,8 @@
 		pulsecore/core-error.c pulsecore/core-error.h \
 		pulsecore/hook-list.c pulsecore/hook-list.h \
 		pulsecore/shm.c pulsecore/shm.h \
+		pulsecore/flist.c pulsecore/flist.h \
+		pulsecore/anotify.c pulsecore/anotify.h \
 		$(PA_THREAD_OBJS)
 =

 if OS_IS_WIN32
@@ -851,34 +869,34 @@
 		module-cli.la \
 		module-cli-protocol-tcp.la \
 		module-simple-protocol-tcp.la \
-		module-esound-protocol-tcp.la \
-		module-native-protocol-tcp.la \
-		module-native-protocol-fd.la \
-		module-sine.la \
-		module-combine.la \
-		module-tunnel-sink.la \
-		module-tunnel-source.la \
-		module-null-sink.la \
-		module-esound-sink.la \
-		module-http-protocol-tcp.la \
-		module-detect.la \
-		module-volume-restore.la \
-		module-rescue-streams.la
+		module-null-sink.la
+#		module-esound-protocol-tcp.la \
+#		module-native-protocol-tcp.la \
+#		module-native-protocol-fd.la \
+#		module-sine.la \
+#		module-combine.la \
+#		module-tunnel-sink.la \
+#		module-tunnel-source.la \
+#		module-esound-sink.la \
+#		module-http-protocol-tcp.la \
+#		module-detect.la \
+#		module-volume-restore.la \
+#		module-rescue-streams.la
 =

 # See comment at librtp.la above
-if !OS_IS_WIN32
-modlibexec_LTLIBRARIES +=3D \
-		module-rtp-send.la \
-		module-rtp-recv.la
-endif
+#if !OS_IS_WIN32
+#modlibexec_LTLIBRARIES +=3D \
+#		module-rtp-send.la \
+#		module-rtp-recv.la
+#endif
 =

 if HAVE_AF_UNIX
 modlibexec_LTLIBRARIES +=3D \
 		module-cli-protocol-unix.la \
-		module-simple-protocol-unix.la \
-		module-esound-protocol-unix.la \
-		module-native-protocol-unix.la \
-		module-http-protocol-unix.la
+		module-simple-protocol-unix.la
+#		module-esound-protocol-unix.la \
+#		module-native-protocol-unix.la \
+#		module-http-protocol-unix.la
 endif
 =

 if HAVE_MKFIFO
@@ -887,11 +905,11 @@
 		module-pipe-source.la
 endif
 =

-if !OS_IS_WIN32
-modlibexec_LTLIBRARIES +=3D \
-		module-esound-compat-spawnfd.la \
-		module-esound-compat-spawnpid.la
-endif
+#if !OS_IS_WIN32
+#modlibexec_LTLIBRARIES +=3D \
+#		module-esound-compat-spawnfd.la \
+#		module-esound-compat-spawnpid.la
+#endif
 =

 if HAVE_REGEX
 modlibexec_LTLIBRARIES +=3D \
@@ -904,19 +922,19 @@
 		module-x11-publish.la
 endif
 =

-if HAVE_OSS
-modlibexec_LTLIBRARIES +=3D \
-		liboss-util.la \
-		module-oss.la \
-		module-oss-mmap.la
-endif
-
-if HAVE_ALSA
-modlibexec_LTLIBRARIES +=3D \
-		libalsa-util.la \
-		module-alsa-sink.la \
-		module-alsa-source.la
-endif
+#if HAVE_OSS
+#modlibexec_LTLIBRARIES +=3D \
+#		liboss-util.la \
+#		module-oss.la \
+#		module-oss-mmap.la
+#endif
+
+#if HAVE_ALSA
+#modlibexec_LTLIBRARIES +=3D \
+#		libalsa-util.la \
+#		module-alsa-sink.la \
+#		module-alsa-source.la
+#endif
 =

 if HAVE_SOLARIS
 modlibexec_LTLIBRARIES +=3D \
@@ -938,11 +956,11 @@
 		module-mmkbd-evdev.la
 endif
 =

-if HAVE_JACK
-modlibexec_LTLIBRARIES +=3D \
-		module-jack-sink.la \
-		module-jack-source.la
-endif
+#if HAVE_JACK
+#modlibexec_LTLIBRARIES +=3D \
+#		module-jack-sink.la \
+#		module-jack-source.la
+#endif
 =

 if HAVE_GCONF
 modlibexec_LTLIBRARIES +=3D \

Modified: branches/lennart/src/modules/module-alsa-sink.c
URL: http://0pointer.de/cgi-bin/viewcvs.cgi/branches/lennart/src/modules/mo=
dule-alsa-sink.c?rev=3D1469&root=3Dpulseaudio&r1=3D1468&r2=3D1469&view=3Ddi=
ff
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D
--- branches/lennart/src/modules/module-alsa-sink.c (original)
+++ branches/lennart/src/modules/module-alsa-sink.c Mon Jun 11 14:08:37 2007
@@ -174,6 +174,7 @@
     update_usage(u);
 =

     for (;;) {
+        void *p;
         pa_memchunk *memchunk =3D NULL;
         snd_pcm_sframes_t frames;
 =

@@ -185,14 +186,15 @@
             else
                 memchunk =3D &u->memchunk;
         }
-
         assert(memchunk->memblock);
-        assert(memchunk->memblock->data);
         assert(memchunk->length);
-        assert(memchunk->memblock->length);
         assert((memchunk->length % u->frame_size) =3D=3D 0);
 =

-        if ((frames =3D snd_pcm_writei(u->pcm_handle, (uint8_t*) memchunk-=
>memblock->data + memchunk->index, memchunk->length / u->frame_size)) < 0) {
+        p =3D pa_memblock_acquire(memchunk->memblock);
+
+        if ((frames =3D snd_pcm_writei(u->pcm_handle, (uint8_t*) p + memch=
unk->index, memchunk->length / u->frame_size)) < 0) {
+            pa_memblock_release(memchunk->memblock);
+
             if (frames =3D=3D -EAGAIN)
                 return;
 =

@@ -216,6 +218,8 @@
             pa_module_unload_request(u->module);
             return;
         }
+
+        pa_memblock_release(memchunk->memblock);
 =

         if (memchunk =3D=3D &u->memchunk) {
             size_t l =3D frames * u->frame_size;

Modified: branches/lennart/src/modules/module-alsa-source.c
URL: http://0pointer.de/cgi-bin/viewcvs.cgi/branches/lennart/src/modules/mo=
dule-alsa-source.c?rev=3D1469&root=3Dpulseaudio&r1=3D1468&r2=3D1469&view=3D=
diff
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D
--- branches/lennart/src/modules/module-alsa-source.c (original)
+++ branches/lennart/src/modules/module-alsa-source.c Mon Jun 11 14:08:37 2=
007
@@ -180,6 +180,7 @@
         pa_memchunk post_memchunk;
         snd_pcm_sframes_t frames;
         size_t l;
+        void *p;
 =

         if (!u->memchunk.memblock) {
             u->memchunk.memblock =3D pa_memblock_new(u->source->core->memp=
ool, u->memchunk.length =3D u->fragment_size);
@@ -188,11 +189,13 @@
 =

         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 =3D=3D 0);
 =

-        if ((frames =3D snd_pcm_readi(u->pcm_handle, (uint8_t*) u->memchun=
k.memblock->data + u->memchunk.index, u->memchunk.length / u->frame_size)) =
< 0) {
+        p =3D pa_memblock_acquire(u->memchunk.memblock);
+
+        if ((frames =3D snd_pcm_readi(u->pcm_handle, (uint8_t*) p + u->mem=
chunk.index, u->memchunk.length / u->frame_size)) < 0) {
+            pa_memblock_release(u->memchunk.memblock);
+
             if (frames =3D=3D -EAGAIN)
                 return;
 =

@@ -216,6 +219,7 @@
             pa_module_unload_request(u->module);
             return;
         }
+        pa_memblock_release(u->memchunk.memblock);
 =

         l =3D frames * u->frame_size;
 =


Modified: branches/lennart/src/modules/module-esound-sink.c
URL: http://0pointer.de/cgi-bin/viewcvs.cgi/branches/lennart/src/modules/mo=
dule-esound-sink.c?rev=3D1469&root=3Dpulseaudio&r1=3D1468&r2=3D1469&view=3D=
diff
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D
--- branches/lennart/src/modules/module-esound-sink.c (original)
+++ branches/lennart/src/modules/module-esound-sink.c Mon Jun 11 14:08:37 2=
007
@@ -144,18 +144,25 @@
             u->write_index =3D u->write_length =3D 0;
         }
     } else if (u->state =3D=3D STATE_RUNNING) {
+        void *p;
+
         pa_module_set_used(u->module, pa_sink_used_by(u->sink));
 =

         if (!u->memchunk.length)
             if (pa_sink_render(u->sink, 8192, &u->memchunk) < 0)
                 return 0;
 =

-        assert(u->memchunk.memblock && u->memchunk.length);
-
-        if ((r =3D pa_iochannel_write(u->io, (uint8_t*) u->memchunk.memblo=
ck->data + u->memchunk.index, u->memchunk.length)) < 0) {
+        assert(u->memchunk.memblock);
+        assert(u->memchunk.length);
+
+        p =3D pa_memblock_acquire(u->memchunk.memblock);
+
+        if ((r =3D pa_iochannel_write(u->io, (uint8_t*) p + u->memchunk.in=
dex, u->memchunk.length)) < 0) {
+            pa_memblock_release(u->memchunk.memblock);
             pa_log("write() failed: %s", pa_cstrerror(errno));
             return -1;
         }
+        pa_memblock_release(u->memchunk.memblock);
 =

         u->memchunk.index +=3D r;
         u->memchunk.length -=3D r;

Modified: branches/lennart/src/modules/module-jack-sink.c
URL: http://0pointer.de/cgi-bin/viewcvs.cgi/branches/lennart/src/modules/mo=
dule-jack-sink.c?rev=3D1469&root=3Dpulseaudio&r1=3D1468&r2=3D1469&view=3Ddi=
ff
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D
--- branches/lennart/src/modules/module-jack-sink.c (original)
+++ branches/lennart/src/modules/module-jack-sink.c Mon Jun 11 14:08:37 2007
@@ -137,22 +137,25 @@
         unsigned fs;
         jack_nframes_t frame_idx;
         pa_memchunk chunk;
+        void *p;
 =

         fs =3D pa_frame_size(&u->sink->sample_spec);
 =

         pa_sink_render_full(u->sink, u->frames_requested * fs, &chunk);
+        p =3D pa_memblock_acquire(chunk.memblock);
 =

         for (frame_idx =3D 0; frame_idx < u->frames_requested; frame_idx +=
+) {
             unsigned c;
 =

             for (c =3D 0; c < u->channels; c++) {
-                float *s =3D ((float*) ((uint8_t*) chunk.memblock->data + =
chunk.index)) + (frame_idx * u->channels) + c;
+                float *s =3D ((float*) ((uint8_t*) p + chunk.index)) + (fr=
ame_idx * u->channels) + c;
                 float *d =3D ((float*) u->buffer[c]) + frame_idx;
 =

                 *d =3D *s;
             }
         }
 =

+        pa_memblock_release(chunk.memblock);
         pa_memblock_unref(chunk.memblock);
 =

         u->frames_requested =3D 0;

Modified: branches/lennart/src/modules/module-jack-source.c
URL: http://0pointer.de/cgi-bin/viewcvs.cgi/branches/lennart/src/modules/mo=
dule-jack-source.c?rev=3D1469&root=3Dpulseaudio&r1=3D1468&r2=3D1469&view=3D=
diff
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D
--- branches/lennart/src/modules/module-jack-source.c (original)
+++ branches/lennart/src/modules/module-jack-source.c Mon Jun 11 14:08:37 2=
007
@@ -136,22 +136,27 @@
         unsigned fs;
         jack_nframes_t frame_idx;
         pa_memchunk chunk;
+        void *p;
 =

         fs =3D pa_frame_size(&u->source->sample_spec);
 =

         chunk.memblock =3D pa_memblock_new(u->core->mempool, chunk.length =
=3D u->frames_posted * fs);
         chunk.index =3D 0;
 =

+        p =3D pa_memblock_acquire(chunk.memblock);
+
         for (frame_idx =3D 0; frame_idx < u->frames_posted; frame_idx ++) {
             unsigned c;
 =

             for (c =3D 0; c < u->channels; c++) {
                 float *s =3D ((float*) u->buffer[c]) + frame_idx;
-                float *d =3D ((float*) ((uint8_t*) chunk.memblock->data + =
chunk.index)) + (frame_idx * u->channels) + c;
+                float *d =3D ((float*) ((uint8_t*) p + chunk.index)) + (fr=
ame_idx * u->channels) + c;
 =

                 *d =3D *s;
             }
         }
+
+        pa_memblock_release(chunk.memblock);
 =

         pa_source_post(u->source, &chunk);
         pa_memblock_unref(chunk.memblock);

Modified: branches/lennart/src/modules/module-null-sink.c
URL: http://0pointer.de/cgi-bin/viewcvs.cgi/branches/lennart/src/modules/mo=
dule-null-sink.c?rev=3D1469&root=3Dpulseaudio&r1=3D1468&r2=3D1469&view=3Ddi=
ff
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D
--- branches/lennart/src/modules/module-null-sink.c (original)
+++ branches/lennart/src/modules/module-null-sink.c Mon Jun 11 14:08:37 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,6 +37,7 @@
 #include <pulse/timeval.h>
 #include <pulse/xmalloc.h>
 =

+#include <pulsecore/macro.h>
 #include <pulsecore/iochannel.h>
 #include <pulsecore/sink.h>
 #include <pulsecore/module.h>
@@ -64,11 +64,9 @@
     pa_core *core;
     pa_module *module;
     pa_sink *sink;
-    pa_time_event *time_event;
+    pa_thread *thread;
     size_t block_size;
-
-    uint64_t n_bytes;
-    struct timeval start_time;
+    struct timeval timestamp;
 };
 =

 static const char* const valid_modargs[] =3D {
@@ -81,35 +79,131 @@
     NULL
 };
 =

-static void time_callback(pa_mainloop_api *m, pa_time_event*e, const struc=
t timeval *tv, void *userdata) {
+static void thread_func(void *userdata) {
     struct userdata *u =3D userdata;
-    pa_memchunk chunk;
-    struct timeval ntv =3D *tv;
-    size_t l;
-
-    assert(u);
-
-    if (pa_sink_render(u->sink, u->block_size, &chunk) >=3D 0) {
-        l =3D chunk.length;
-        pa_memblock_unref(chunk.memblock);
-    } else
-        l =3D u->block_size;
-
-    pa_timeval_add(&ntv, pa_bytes_to_usec(l, &u->sink->sample_spec));
-    m->time_restart(e, &ntv);
-
-    u->n_bytes +=3D l;
-}
-
-static pa_usec_t get_latency(pa_sink *s) {
-    struct userdata *u =3D s->userdata;
-    pa_usec_t a, b;
-    struct timeval now;
-
-    a =3D pa_timeval_diff(pa_gettimeofday(&now), &u->start_time);
-    b =3D pa_bytes_to_usec(u->n_bytes, &s->sample_spec);
-
-    return b > a ? b - a : 0;
+    int quit =3D 0;
+    struct pollfd pollfd;
+    int running =3D 1;
+
+    pa_assert(u);
+
+    pa_log_debug("Thread starting up");
+
+    memset(&pollfd, 0, sizeof(pollfd));
+    pollfd.fd =3D pa_asyncmsgq_get_fd(u->sink->asyncmsgq, PA_ASYNCQ_POP);
+    pollfd.events =3D POLLIN;
+
+    pa_gettimeofday(u->timestamp);
+    =

+    for (;;) {
+        int code;
+        void *data, *object;
+        int r, timeout;
+        struct timeval now;
+
+        /* Check whether there is a message for us to process */
+        if (pa_asyncmsgq_get(u->sink->asyncmsgq, &object, &code, &data) =
=3D=3D 0) {
+
+
+            /* Now process these messages our own way */
+            if (!object) {
+
+                switch (code) {
+                    case PA_MESSAGE_SHUTDOWN:
+                        goto finish;
+
+                    default:
+                        pa_sink_process_msg(u->sink->asyncmsgq, object, co=
de, data);
+
+                }
+                =

+            } else if (object =3D=3D u->sink) {
+
+                switch (code) {
+                    case PA_SINK_MESSAGE_STOP:
+                        pa_assert(running);
+                        running =3D 0;
+                        break;
+                        =

+                    case PA_SINK_MESSAGE_START:
+                        pa_assert(!running);
+                        running =3D 1;
+                        =

+                        pa_gettimeofday(u->timestamp);
+                        break;
+                        =

+                    case PA_SINK_MESSAGE_GET_LATENCY:
+                        =

+                        if (pa_timeval_cmp(&u->timestamp, &now) > 0)
+                            *((pa_usec_t*) data) =3D 0;
+                        else
+                            *((pa_usec_t*) data) =3D pa_timeval_diff(&u->t=
imestamp, &now);
+                        break;
+                        =

+                        /* ... */
+
+                    default:
+                        pa_sink_process_msg(u->sink->asyncmsgq, object, co=
de, data);
+                }
+            }
+            =

+            pa_asyncmsgq_done(u->sink->asyncmsgq);
+            continue;
+        }
+
+        /* Render some data and drop it immediately */
+
+        if (running) {
+            pa_gettimeofday(&now);
+            =

+            if (pa_timeval_cmp(u->timestamp, &now) <=3D 0) {
+                pa_memchunk chunk;
+                size_t l;
+                =

+                if (pa_sink_render(u->sink, u->block_size, &chunk) >=3D 0)=
 {
+                    l =3D chunk.length;
+                    pa_memblock_unref(chunk.memblock);
+                } else
+                    l =3D u->block_size;
+                =

+                pa_timeval_add(&u->timestamp, pa_bytes_to_usec(l, &u->sink=
->sample_spec));
+                continue;
+            }
+
+            timeout =3D pa_timeval_diff(&u->timestamp, &now)/1000;
+            =

+            if (timeout < 1)
+                timeout =3D 1;
+        } else
+            timeout =3D -1;
+
+        /* Hmm, nothing to do. Let's sleep */
+        =

+        if (pa_asyncmsgq_before_poll(u->sink->asyncmsgq) < 0)
+            continue;
+
+        r =3D poll(&pollfd, 1, timeout);
+        pa_asyncmsgq_after_poll(u->sink->asyncmsgq);
+
+        if (r < 0) {
+            if (errno =3D=3D EINTR)
+                continue;
+
+            pa_log("poll() failed: %s", pa_cstrerror(errno));
+            goto fail;
+        }
+        =

+        pa_assert(r =3D=3D 0 || pollfd.revents =3D=3D POLLIN);
+    }
+
+fail:
+    /* We have to continue processing messages until we receive the
+     * SHUTDOWN message */
+    pa_asyncmsgq_post(u->core->asyncmsgq, u->core, PA_CORE_MESSAGE_UNLOAD_=
MODULE, pa_module_ref(u->module), NULL, pa_module_unref);
+    pa_asyncmsgq_wait_for(PA_MESSAGE_SHUTDOWN);
+
+finish:
+    pa_log_debug("Thread shutting down");
 }
 =

 int pa__init(pa_core *c, pa_module*m) {
@@ -118,17 +212,17 @@
     pa_channel_map map;
     pa_modargs *ma =3D NULL;
 =

-    assert(c);
-    assert(m);
+    pa_assert(c);
+    pa_assert(m);
 =

     if (!(ma =3D pa_modargs_new(m->argument, valid_modargs))) {
-        pa_log("failed to parse module arguments.");
+        pa_log("Failed to parse module arguments.");
         goto fail;
     }
 =

     ss =3D c->default_sample_spec;
     if (pa_modargs_get_sample_spec_and_channel_map(ma, &ss, &map, PA_CHANN=
EL_MAP_DEFAULT) < 0) {
-        pa_log("invalid sample format specification or channel map.");
+        pa_log("Invalid sample format specification or channel map");
         goto fail;
     }
 =

@@ -138,22 +232,24 @@
     m->userdata =3D u;
 =

     if (!(u->sink =3D pa_sink_new(c, __FILE__, pa_modargs_get_value(ma, "s=
ink_name", DEFAULT_SINK_NAME), 0, &ss, &map))) {
-        pa_log("failed to create sink.");
-        goto fail;
-    }
-
-    u->sink->get_latency =3D get_latency;
+        pa_log("Failed to create sink.");
+        goto fail;
+    }
+
     u->sink->userdata =3D u;
     pa_sink_set_owner(u->sink, m);
     pa_sink_set_description(u->sink, pa_modargs_get_value(ma, "description=
", "NULL sink"));
 =

-    u->n_bytes =3D 0;
-    pa_gettimeofday(&u->start_time);
-
-    u->time_event =3D c->mainloop->time_new(c->mainloop, &u->start_time, t=
ime_callback, u);
-
-    u->block_size =3D pa_bytes_per_second(&ss) / 10;
-
+    u->block_size =3D pa_bytes_per_second(&ss) / 20; /* 50 ms */
+    =

+    if (u->block_size <=3D 0)
+        u->block_size =3D pa_frame_size(&ss);
+
+    if (!(u->thread =3D pa_thread_new(thread_func, u))) {
+        pa_log("Failed to create thread.");
+        goto fail;
+    }
+    =

     pa_modargs_free(ma);
 =

     return 0;
@@ -169,15 +265,21 @@
 =

 void pa__done(pa_core *c, pa_module*m) {
     struct userdata *u;
-    assert(c && m);
+    =

+    pa_assert(c);
+    pa_assert(m);
 =

     if (!(u =3D m->userdata))
         return;
 =

     pa_sink_disconnect(u->sink);
+
+    if (u->thread) {
+        pa_asyncmsgq_send(u->sink->asyncmsgq, PA_SINK_MESSAGE_SHUTDOWN, NU=
LL);
+        pa_thread_free(u->thread);
+    }
+    =

     pa_sink_unref(u->sink);
-
-    u->core->mainloop->time_free(u->time_event);
 =

     pa_xfree(u);
 }

Modified: branches/lennart/src/modules/module-oss-mmap.c
URL: http://0pointer.de/cgi-bin/viewcvs.cgi/branches/lennart/src/modules/mo=
dule-oss-mmap.c?rev=3D1469&root=3Dpulseaudio&r1=3D1468&r2=3D1469&view=3Ddiff
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D
--- branches/lennart/src/modules/module-oss-mmap.c (original)
+++ branches/lennart/src/modules/module-oss-mmap.c Mon Jun 11 14:08:37 2007
@@ -173,7 +173,7 @@
                     u->out_fragment_size,
                     1);
         assert(chunk.memblock);
-        chunk.length =3D chunk.memblock->length;
+        chunk.length =3D pa_memblock_get_length(chunk.memblock);
         chunk.index =3D 0;
 =

         pa_sink_render_into_full(u->sink, &chunk);
@@ -217,7 +217,7 @@
 =

         if (!u->in_memblocks[u->in_current]) {
             chunk.memblock =3D u->in_memblocks[u->in_current] =3D pa_membl=
ock_new_fixed(u->core->mempool, (uint8_t*) u->in_mmap+u->in_fragment_size*u=
->in_current, u->in_fragment_size, 1);
-            chunk.length =3D chunk.memblock->length;
+            chunk.length =3D pa_memblock_get_length(chunk.memblock);
             chunk.index =3D 0;
 =

             pa_source_post(u->source, &chunk);

Modified: branches/lennart/src/modules/module-oss.c
URL: http://0pointer.de/cgi-bin/viewcvs.cgi/branches/lennart/src/modules/mo=
dule-oss.c?rev=3D1469&root=3Dpulseaudio&r1=3D1468&r2=3D1469&view=3Ddiff
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D
--- branches/lennart/src/modules/module-oss.c (original)
+++ branches/lennart/src/modules/module-oss.c Mon Jun 11 14:08:37 2007
@@ -158,6 +158,7 @@
     }
 =

     do {
+        void *p;
         memchunk =3D &u->memchunk;
 =

         if (!memchunk->length)
@@ -165,10 +166,11 @@
                 memchunk =3D &u->silence;
 =

         assert(memchunk->memblock);
-        assert(memchunk->memblock->data);
         assert(memchunk->length);
 =

-        if ((r =3D pa_iochannel_write(u->io, (uint8_t*) memchunk->memblock=
->data + memchunk->index, memchunk->length)) < 0) {
+        p =3D pa_memblock_acquire(memchunk->memblock);
+        if ((r =3D pa_iochannel_write(u->io, (uint8_t*) p + memchunk->inde=
x, memchunk->length)) < 0) {
+            pa_memblock_release(memchunk->memblock);
 =

             if (errno !=3D EAGAIN) {
                 pa_log("write() failed: %s", pa_cstrerror(errno));
@@ -179,6 +181,8 @@
 =

             break;
         }
+
+        pa_memblock_release(memchunk->memblock);
 =

         if (memchunk =3D=3D &u->silence)
             assert(r % u->sample_size =3D=3D 0);
@@ -224,9 +228,13 @@
     }
 =

     do {
+        void *p;
         memchunk.memblock =3D pa_memblock_new(u->core->mempool, l);
-        assert(memchunk.memblock);
-        if ((r =3D pa_iochannel_read(u->io, memchunk.memblock->data, memch=
unk.memblock->length)) < 0) {
+
+        p =3D pa_memblock_acquire(memchunk.memblock);
+
+        if ((r =3D pa_iochannel_read(u->io, p, pa_memblock_get_length(memc=
hunk.memblock))) < 0) {
+            pa_memblock_release(memchunk.memblock);
             pa_memblock_unref(memchunk.memblock);
 =

             if (errno !=3D EAGAIN) {
@@ -239,8 +247,10 @@
             break;
         }
 =

-        assert(r <=3D (ssize_t) memchunk.memblock->length);
-        memchunk.length =3D memchunk.memblock->length =3D r;
+        pa_memblock_release(memchunk.memblock);
+
+        assert(r <=3D (ssize_t) pa_memblock_get_length(memchunk.memblock));
+        memchunk.length =3D r;
         memchunk.index =3D 0;
 =

         pa_source_post(u->source, &memchunk);

Modified: branches/lennart/src/modules/module-pipe-sink.c
URL: http://0pointer.de/cgi-bin/viewcvs.cgi/branches/lennart/src/modules/mo=
dule-pipe-sink.c?rev=3D1469&root=3Dpulseaudio&r1=3D1468&r2=3D1469&view=3Ddi=
ff
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D
--- branches/lennart/src/modules/module-pipe-sink.c (original)
+++ branches/lennart/src/modules/module-pipe-sink.c Mon Jun 11 14:08:37 2007
@@ -58,20 +58,16 @@
         "rate=3D<sample rate>"
         "channel_map=3D<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;
     char *filename;
-
-    pa_sink *sink;
-    pa_iochannel *io;
-    pa_defer_event *defer_event;
-
-    pa_memchunk memchunk;
-    pa_module *module;
+    int fd;
+    pa_thread *thread;
 };
 =

 static const char* const valid_modargs[] =3D {
@@ -84,97 +80,203 @@
     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 =3D 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 +=3D r;
-    u->memchunk.length -=3D r;
-
-    if (u->memchunk.length <=3D 0) {
-        pa_memblock_unref(u->memchunk.memblock);
-        u->memchunk.memblock =3D NULL;
-    }
-}
-
-static void notify_cb(pa_sink*s) {
-    struct userdata *u =3D 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 =3D 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) {
+enum {
+    POLLFD_ASYNCQ,
+    POLLFD_FIFO,
+    POLLFD_MAX,
+};
+
+static void thread_func(void *userdata) {
     struct userdata *u =3D userdata;
-    assert(u);
-    do_write(u);
-}
-
-static void io_callback(PA_GCC_UNUSED pa_iochannel *io, void*userdata) {
-    struct userdata *u =3D userdata;
-    assert(u);
-    do_write(u);
+    int quit =3D 0;
+    struct pollfd pollfd[POLLFD_MAX];
+    int running =3D 1, underrun =3D 0;
+    pa_memchunk memchunk;
+
+    pa_assert(u);
+
+    pa_log_debug("Thread starting up");
+
+    memset(&pollfd, 0, sizeof(pollfd));
+    pollfd[POLLFD_ASYNCQ].fd =3D pa_asyncmsgq_get_fd(u->sink->asyncmsgq, P=
A_ASYNCQ_POP);
+    pollfd[POLLFD_ASYNCQ].events =3D POLLIN;
+
+    pollfd[POLLFD_FIFO].fd =3D u->fd;
+
+    memset(&memchunk, 0, sizeof(memchunk));
+
+    for (;;) {
+        int code;
+        void *object, *data;
+        int r;
+        struct timeval now;
+
+        /* Check whether there is a message for us to process */
+        if (pa_asyncmsgq_get(u->sink->asyncmsgq, &object, &code, &data) =
=3D=3D 0) {
+
+
+            /* Now process these messages our own way */
+            if (!object) {
+                switch (code) {
+                    case PA_SINK_MESSAGE_SHUTDOWN:
+                        goto finish;
+
+                    default:
+                        pa_sink_process_msg(u->sink->asyncmsgq, object, co=
de, data);
+                }
+                =

+            } else if (object =3D=3D u->sink) {
+                        =

+                case PA_SINK_MESSAGE_STOP:
+                    pa_assert(running);
+                    running =3D 0;
+                    break;
+
+                case PA_SINK_MESSAGE_START:
+                    pa_assert(!running);
+                    running =3D 1;
+                    break;
+
+                case PA_SINK_MESSAGE_GET_LATENCY: {
+                    size_t n =3D 0;
+                    int l;
+
+                    if (ioctl(u->fd, TIOCINQ, &l) >=3D 0 && l > 0)
+                        n =3D (size_t) l;
+
+                    n +=3D memchunk.length;
+
+                    *((pa_usec_t*) data) pa_bytes_to_usec(n, &u->sink->sam=
ple_spec);
+                    break;
+                }
+
+                /* ... */
+
+                default:
+                    pa_sink_process_msg(u->sink->asyncmsgq, object, code, =
data);
+            }
+            =

+            pa_asyncmsgq_done(u->sink->asyncmsgq);
+            continue;
+        }
+
+        /* Render some data and write it to the fifo */
+
+        if (running && (pollfd[POLLFD_FIFO].revents || underrun)) {
+
+            if (chunk.length <=3D 0)
+                pa_sink_render(u->fd, PIPE_BUF, &chunk);
+
+            underrun =3D chunk.length <=3D 0;
+
+            if (!underrun) {
+                ssize_t l;
+                =

+                p =3D pa_memblock_acquire(u->memchunk.memblock);
+                l =3D pa_write(u->fd, (uint8_t*) p + u->memchunk.index, u-=
>memchunk.length);
+                pa_memblock_release(p);
+                    =

+                if (l < 0) {
+
+                    if (errno !=3D EINTR && errno !=3D EAGAIN) {
+                        pa_log("Failed to write data to FIFO: %s", pa_cstr=
error(errno));
+                        goto fail;
+                    }
+                    =

+                } else {
+                        =

+                    u->memchunk.index +=3D l;
+                    u->memchunk.length -=3D l;
+
+                    if (u->memchunk.length <=3D 0) {
+                        pa_memblock_unref(u->memchunk.memblock);
+                        u->memchunk.memblock =3D NULL;
+                    }
+                }
+
+                pollfd[POLLFD_FIFO].revents =3D 0;
+                continue;
+            }
+        }
+
+        pollfd[POLLFD_FIFO].events =3D running && !underrun ? POLLOUT : 0;
+
+        /* Hmm, nothing to do. Let's sleep */
+        =

+        if (pa_asyncmsgq_before_poll(u->sink->asyncmsgq) < 0)
+            continue;
+
+        r =3D poll(&pollfd, 1, 0);
+        pa_asyncmsgq_after_poll(u->sink->asyncmsgq);
+
+        if (r < 0) {
+            if (errno =3D=3D EINTR)
+                continue;
+
+            pa_log("poll() failed: %s", pa_cstrerror(errno));
+            goto fail;
+        }
+
+        if (pollfd[POLLFD_FIFO].revents & ~POLLIN) {
+            pa_log("FIFO shutdown.");
+            goto fail;
+        }
+        =

+        pa_assert(pollfd[POLLFD_ASYNCQ].revents & ~POLLIN =3D=3D 0);
+    }
+    =

+fail:
+    /* We have to continue processing messages until we receive the
+     * SHUTDOWN message */
+    pa_asyncmsgq_post(u->core->asyncmsgq, u->core, PA_CORE_MESSAGE_UNLOAD_=
MODULE, pa_module_ref(u->module), pa_module_unref);
+    pa_asyncmsgq_wait_for(PA_SINK_MESSAGE_SHUTDOWN);
+
+finish:
+    pa_log_debug("Thread shutting down");
 }
 =

 int pa__init(pa_core *c, pa_module*m) {
     struct userdata *u =3D NULL;
     struct stat st;
-    const char *p;
-    int fd =3D -1;
     pa_sample_spec ss;
     pa_channel_map map;
     pa_modargs *ma =3D NULL;
     char *t;
 =

-    assert(c && m);
+    pa_assert(c);
+    pa_assert(m);
 =

     if (!(ma =3D pa_modargs_new(m->argument, valid_modargs))) {
-        pa_log("failed to parse module arguments");
+        pa_log("Failed to parse module arguments.");
         goto fail;
     }
 =

     ss =3D c->default_sample_spec;
     if (pa_modargs_get_sample_spec_and_channel_map(ma, &ss, &map, PA_CHANN=
EL_MAP_DEFAULT) < 0) {
-        pa_log("invalid sample format specification");
-        goto fail;
-    }
-
-    mkfifo(p =3D pa_modargs_get_value(ma, "file", DEFAULT_FIFO_NAME), 0777=
);
-
-    if ((fd =3D open(p, O_RDWR)) < 0) {
+        pa_log("Invalid sample format specification");
+        goto fail;
+    }
+
+    u =3D pa_xnew0(struct userdata, 1);
+    u->core =3D c;
+    u->module =3D m;
+    u->filename =3D pa_xstrdup(pa_modargs_get_value(ma, "file", DEFAULT_FI=
FO_NAME));
+    u->fd =3D fd;
+    u->memchunk.memblock =3D NULL;
+    u->memchunk.length =3D 0;
+    m->userdata =3D u;
+    =

+    mkfifo(u->filename, 0666);
+    =

+    if ((u->fd =3D open(u->filename, 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_fd_set_cloexec(u->fd, 1);
+    pa_make_nonblock_fd(u->fd);
+
+    if (fstat(u->fd, &st) < 0) {
         pa_log("fstat('%s'): %s", p, pa_cstrerror(errno));
         goto fail;
     }
@@ -184,34 +286,21 @@
         goto fail;
     }
 =

-    u =3D pa_xmalloc0(sizeof(struct userdata));
-    u->filename =3D pa_xstrdup(p);
-    u->core =3D c;
-    u->module =3D m;
-    m->userdata =3D u;
-
     if (!(u->sink =3D pa_sink_new(c, __FILE__, pa_modargs_get_value(ma, "s=
ink_name", DEFAULT_SINK_NAME), 0, &ss, &map))) {
-        pa_log("failed to create sink.");
-        goto fail;
-    }
-    u->sink->notify =3D notify_cb;
-    u->sink->get_latency =3D get_latency_cb;
+        pa_log("Failed to create sink.");
+        goto fail;
+    }
+    =

     u->sink->userdata =3D u;
     pa_sink_set_owner(u->sink, m);
     pa_sink_set_description(u->sink, t =3D pa_sprintf_malloc("Unix FIFO si=
nk '%s'", p));
     pa_xfree(t);
 =

-    u->io =3D pa_iochannel_new(c->mainloop, -1, fd);
-    assert(u->io);
-    pa_iochannel_set_callback(u->io, io_callback, u);
-
-    u->memchunk.memblock =3D NULL;
-    u->memchunk.length =3D 0;
-
-    u->defer_event =3D c->mainloop->defer_new(c->mainloop, defer_callback,=
 u);
-    assert(u->defer_event);
-    c->mainloop->defer_enable(u->defer_event, 0);
-
+    if (!(u->thread =3D pa_thread_new(thread_func, u))) {
+        pa_log("Failed to create thread.");
+        goto fail;
+    }
+    =

     pa_modargs_free(ma);
 =

     return 0;
@@ -220,9 +309,6 @@
     if (ma)
         pa_modargs_free(ma);
 =

-    if (fd >=3D 0)
-        close(fd);
-
     pa__done(c, m);
 =

     return -1;
@@ -230,22 +316,31 @@
 =

 void pa__done(pa_core *c, pa_module*m) {
     struct userdata *u;
-    assert(c && m);
+    pa_assert(c);
+    pa_assert(m);
 =

     if (!(u =3D m->userdata))
         return;
 =

+    pa_sink_disconnect(u->sink);
+
+    if (u->thread) {
+        pa_asyncmsgq_send(u->sink->asyncmsgq, PA_SINK_MESSAGE_SHUTDOWN, NU=
LL);
+        pa_thread_free(u->thread);
+    }
+    =

+    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->filename) {
+        unlink(u->filename);
+        pa_xfree(u->filename);
+    }
+
+    if (u->fd >=3D 0)
+        close(u->fd);
 =

     pa_xfree(u);
 }

Modified: branches/lennart/src/modules/module-pipe-source.c
URL: http://0pointer.de/cgi-bin/viewcvs.cgi/branches/lennart/src/modules/mo=
dule-pipe-source.c?rev=3D1469&root=3Dpulseaudio&r1=3D1468&r2=3D1469&view=3D=
diff
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D
--- branches/lennart/src/modules/module-pipe-source.c (original)
+++ branches/lennart/src/modules/module-pipe-source.c Mon Jun 11 14:08:37 2=
007
@@ -84,7 +84,9 @@
 =

 static void do_read(struct userdata *u) {
     ssize_t r;
+    void *p;
     pa_memchunk chunk;
+
     assert(u);
 =

     if (!pa_iochannel_is_readable(u->io))
@@ -97,17 +99,22 @@
         u->chunk.index =3D chunk.length =3D 0;
     }
 =

-    assert(u->chunk.memblock && u->chunk.memblock->length > u->chunk.index=
);
-    if ((r =3D pa_iochannel_read(u->io, (uint8_t*) u->chunk.memblock->data=
 + u->chunk.index, u->chunk.memblock->length - u->chunk.index)) <=3D 0) {
+    assert(u->chunk.memblock);
+    assert(pa_memblock_get_length(u->chunk.memblock) > u->chunk.index);
+
+    p =3D pa_memblock_acquire(u->chunk.memblock);
+    if ((r =3D pa_iochannel_read(u->io, (uint8_t*) p + u->chunk.index, pa_=
memblock_get_length(u->chunk.memblock) - u->chunk.index)) <=3D 0) {
+        pa_memblock_release(u->chunk.memblock);
         pa_log("read(): %s", pa_cstrerror(errno));
         return;
     }
+    pa_memblock_release(u->chunk.memblock);
 =

     u->chunk.length =3D r;
     pa_source_post(u->source, &u->chunk);
     u->chunk.index +=3D r;
 =

-    if (u->chunk.index >=3D u->chunk.memblock->length) {
+    if (u->chunk.index >=3D pa_memblock_get_length(u->chunk.memblock)) {
         u->chunk.index =3D u->chunk.length =3D 0;
         pa_memblock_unref(u->chunk.memblock);
         u->chunk.memblock =3D NULL;

Modified: branches/lennart/src/modules/module-sine.c
URL: http://0pointer.de/cgi-bin/viewcvs.cgi/branches/lennart/src/modules/mo=
dule-sine.c?rev=3D1469&root=3Dpulseaudio&r1=3D1468&r2=3D1469&view=3Ddiff
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D
--- branches/lennart/src/modules/module-sine.c (original)
+++ branches/lennart/src/modules/module-sine.c Mon Jun 11 14:08:37 2007
@@ -65,7 +65,7 @@
 =

     chunk->memblock =3D pa_memblock_ref(u->memblock);
     chunk->index =3D u->peek_index;
-    chunk->length =3D u->memblock->length - u->peek_index;
+    chunk->length =3D pa_memblock_get_length(u->memblock) - u->peek_index;
     return 0;
 }
 =

@@ -74,11 +74,12 @@
     assert(i && chunk && length && i->userdata);
     u =3D i->userdata;
 =

-    assert(chunk->memblock =3D=3D u->memblock && length <=3D u->memblock->=
length-u->peek_index);
+    assert(chunk->memblock =3D=3D u->memblock);
+    assert(length <=3D pa_memblock_get_length(u->memblock)-u->peek_index);
 =

     u->peek_index +=3D length;
 =

-    if (u->peek_index >=3D u->memblock->length)
+    if (u->peek_index >=3D pa_memblock_get_length(u->memblock))
         u->peek_index =3D 0;
 }
 =

@@ -111,6 +112,7 @@
     pa_sample_spec ss;
     uint32_t frequency;
     char t[256];
+    void *p;
     pa_sink_input_new_data data;
 =

     if (!(ma =3D pa_modargs_new(m->argument, valid_modargs))) {
@@ -142,7 +144,9 @@
     }
 =

     u->memblock =3D pa_memblock_new(c->mempool, pa_bytes_per_second(&ss));
-    calc_sine(u->memblock->data, u->memblock->length, frequency);
+    p =3D pa_memblock_acquire(u->memblock);
+    calc_sine(p, pa_memblock_get_length(u->memblock), frequency);
+    pa_memblock_release(u->memblock);
 =

     snprintf(t, sizeof(t), "Sine Generator at %u Hz", frequency);
 =


Modified: branches/lennart/src/modules/rtp/rtp.c
URL: http://0pointer.de/cgi-bin/viewcvs.cgi/branches/lennart/src/modules/rt=
p/rtp.c?rev=3D1469&root=3Dpulseaudio&r1=3D1468&r2=3D1469&view=3Ddiff
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D
--- branches/lennart/src/modules/rtp/rtp.c (original)
+++ branches/lennart/src/modules/rtp/rtp.c Mon Jun 11 14:08:37 2007
@@ -81,7 +81,7 @@
             size_t k =3D n + chunk.length > size ? size - n : chunk.length;
 =

             if (chunk.memblock) {
-                iov[iov_idx].iov_base =3D (void*)((uint8_t*) chunk.membloc=
k->data + chunk.index);
+                iov[iov_idx].iov_base =3D (void*)((uint8_t*) pa_memblock_a=
cquire(chunk.memblock) + chunk.index);
                 iov[iov_idx].iov_len =3D k;
                 mb[iov_idx] =3D chunk.memblock;
                 iov_idx ++;
@@ -116,8 +116,10 @@
 =

                 k =3D sendmsg(c->fd, &m, MSG_DONTWAIT);
 =

-                for (i =3D 1; i < iov_idx; i++)
+                for (i =3D 1; i < iov_idx; i++) {
+                    pa_memblock_release(mb[i]);
                     pa_memblock_unref(mb[i]);
+                }
 =

                 c->sequence++;
             } else
@@ -174,7 +176,7 @@
 =

     chunk->memblock =3D pa_memblock_new(pool, size);
 =

-    iov.iov_base =3D chunk->memblock->data;
+    iov.iov_base =3D pa_memblock_acquire(chunk->memblock);
     iov.iov_len =3D size;
 =

     m.msg_name =3D NULL;
@@ -195,9 +197,9 @@
         goto fail;
     }
 =

-    memcpy(&header, chunk->memblock->data, sizeof(uint32_t));
-    memcpy(&c->timestamp, (uint8_t*) chunk->memblock->data + 4, sizeof(uin=
t32_t));
-    memcpy(&c->ssrc, (uint8_t*) chunk->memblock->data + 8, sizeof(uint32_t=
));
+    memcpy(&header, iov.iov_base, sizeof(uint32_t));
+    memcpy(&c->timestamp, (uint8_t*) iov.iov_base + 4, sizeof(uint32_t));
+    memcpy(&c->ssrc, (uint8_t*) iov.iov_base + 8, sizeof(uint32_t));
 =

     header =3D ntohl(header);
     c->timestamp =3D ntohl(c->timestamp);
@@ -238,8 +240,10 @@
     return 0;
 =

 fail:
-    if (chunk->memblock)
+    if (chunk->memblock) {
+        pa_memblock_release(chunk->memblock);
         pa_memblock_unref(chunk->memblock);
+    }
 =

     return -1;
 }

Modified: branches/lennart/src/pulse/internal.h
URL: http://0pointer.de/cgi-bin/viewcvs.cgi/branches/lennart/src/pulse/inte=
rnal.h?rev=3D1469&root=3Dpulseaudio&r1=3D1468&r2=3D1469&view=3Ddiff
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D
--- branches/lennart/src/pulse/internal.h (original)
+++ branches/lennart/src/pulse/internal.h Mon Jun 11 14:08:37 2007
@@ -116,6 +116,7 @@
     uint32_t requested_bytes;
 =

     pa_memchunk peek_memchunk;
+    void *peek_data;
     pa_memblockq *record_memblockq;
 =

     int corked;

Modified: branches/lennart/src/pulse/stream.c
URL: http://0pointer.de/cgi-bin/viewcvs.cgi/branches/lennart/src/pulse/stre=
am.c?rev=3D1469&root=3Dpulseaudio&r1=3D1468&r2=3D1469&view=3Ddiff
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D
--- branches/lennart/src/pulse/stream.c (original)
+++ branches/lennart/src/pulse/stream.c Mon Jun 11 14:08:37 2007
@@ -91,6 +91,7 @@
     s->peek_memchunk.index =3D 0;
     s->peek_memchunk.length =3D 0;
     s->peek_memchunk.memblock =3D NULL;
+    s->peek_data =3D NULL;
 =

     s->record_memblockq =3D NULL;
 =

@@ -125,8 +126,11 @@
         s->mainloop->time_free(s->auto_timing_update_event);
     }
 =

-    if (s->peek_memchunk.memblock)
+    if (s->peek_memchunk.memblock) {
+        if (s->peek_data)
+            pa_memblock_release(s->peek_memchunk.memblock);
         pa_memblock_unref(s->peek_memchunk.memblock);
+    }
 =

     if (s->record_memblockq)
         pa_memblockq_free(s->record_memblockq);
@@ -608,8 +612,11 @@
     if (free_cb)
         chunk.memblock =3D pa_memblock_new_user(s->context->mempool, (void=
*) data, length, free_cb, 1);
     else {
+        void *tdata;
         chunk.memblock =3D pa_memblock_new(s->context->mempool, length);
-        memcpy(chunk.memblock->data, data, length);
+        tdata =3D pa_memblock_acquire(chunk.memblock);
+        memcpy(tdata, data, length);
+        pa_memblock_release(chunk.memblock);
     }
 =

     chunk.index =3D 0;
@@ -675,9 +682,12 @@
             *length =3D 0;
             return 0;
         }
-    }
-
-    *data =3D (const char*) s->peek_memchunk.memblock->data + s->peek_memc=
hunk.index;
+
+        s->peek_data =3D pa_memblock_acquire(s->peek_memchunk.memblock);
+    }
+
+    assert(s->peek_data);
+    *data =3D (uint8_t*) s->peek_data + s->peek_memchunk.index;
     *length =3D s->peek_memchunk.length;
     return 0;
 }
@@ -696,6 +706,8 @@
     if (s->timing_info_valid && !s->timing_info.read_index_corrupt)
         s->timing_info.read_index +=3D s->peek_memchunk.length;
 =

+    assert(s->peek_data);
+    pa_memblock_release(s->peek_memchunk.memblock);
     pa_memblock_unref(s->peek_memchunk.memblock);
     s->peek_memchunk.length =3D 0;
     s->peek_memchunk.index =3D 0;

Modified: branches/lennart/src/pulse/xmalloc.h
URL: http://0pointer.de/cgi-bin/viewcvs.cgi/branches/lennart/src/pulse/xmal=
loc.h?rev=3D1469&root=3Dpulseaudio&r1=3D1468&r2=3D1469&view=3Ddiff
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D
--- branches/lennart/src/pulse/xmalloc.h (original)
+++ branches/lennart/src/pulse/xmalloc.h Mon Jun 11 14:08:37 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), size=
of(type)))
+
 PA_C_DECL_END
 =

 #endif

Added: branches/lennart/src/pulsecore/asyncmsgq.c
URL: http://0pointer.de/cgi-bin/viewcvs.cgi/branches/lennart/src/pulsecore/=
asyncmsgq.c?rev=3D1469&root=3Dpulseaudio&view=3Dauto
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D
--- branches/lennart/src/pulsecore/asyncmsgq.c (added)
+++ branches/lennart/src/pulsecore/asyncmsgq.c Mon Jun 11 14:08:37 2007
@@ -1,0 +1,235 @@
+/* $Id$ */
+
+/***
+  This file is part of PulseAudio.
+
+  Copyright 2006 Lennart Poettering
+
+  PulseAudio is free software; you can redistribute it and/or modify
+  it under the terms of the GNU Lesser General Public License as
+  published by the Free Software Foundation; either version 2.1 of the
+  License, or (at your option) any later version.
+
+  PulseAudio is distributed in the hope that it will be useful, but
+  WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+  Lesser General Public License for more details.
+
+  You should have received a copy of the GNU Lesser General Public
+  License along with PulseAudio; if not, write to the Free Software
+  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+  USA.
+***/
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <unistd.h>
+#include <errno.h>
+
+#include <pulsecore/atomic.h>
+#include <pulsecore/log.h>
+#include <pulsecore/thread.h>
+#include <pulsecore/semaphore.h>
+#include <pulsecore/macro.h>
+#include <pulsecore/core-util.h>
+#include <pulsecore/flist.h>
+#include <pulse/xmalloc.h>
+
+#include "asyncmsgq.h"
+
+PA_STATIC_FLIST_DECLARE(asyncmsgq, 0);
+
+struct asyncmsgq_item {
+    int code;
+    pa_msgobject *object;
+    void *userdata;
+    pa_free_cb_t free_cb;
+    pa_memchunk memchunk;
+    pa_semaphore *semaphore;
+};
+
+struct pa_asyncmsgq {
+    pa_asyncq *asyncq;
+    pa_mutex *mutex; /* only for the writer side */
+
+    struct asyncmsgq_item *current;
+};
+
+pa_asyncmsgq *pa_asyncmsgq_new(unsigned size) {
+    pa_asyncmsgq *a;
+
+    a =3D pa_xnew(pa_asyncmsgq, 1);
+
+    pa_assert_se(a->asyncq =3D pa_asyncq_new(size));
+    pa_assert_se(a->mutex =3D pa_mutex_new(0));
+    a->current =3D NULL;
+    =

+    return a;
+}
+
+void pa_asyncmsgq_free(pa_asyncmsgq *a) {
+    struct asyncmsgq_item *i;
+    pa_assert(a);
+
+    while ((i =3D pa_asyncq_pop(a->asyncq, 0))) {
+
+        pa_assert(!i->semaphore);
+
+        if (i->object)
+            pa_msgobject_unref(i->object);
+
+        if (i->memchunk.memblock)
+            pa_memblock_unref(i->object);
+        =

+        if (i->userdata_free_cb)
+            i->userdata_free_cb(i->userdata);
+        =

+        if (pa_flist_push(PA_STATIC_FLIST_GET(asyncmsgq), i) < 0)
+            pa_xfree(i);
+    }
+
+    pa_asyncq_free(a->asyncq, NULL);
+    pa_mutex_free(a->mutex);
+    pa_xfree(a);
+}
+
+void pa_asyncmsgq_post(pa_asyncmsgq *a, pa_msgobject *object, int code, co=
nst void *userdata, const pa_memchunk *chunk, pa_free_cb_t free_cb) {
+    struct asyncmsgq_item *i;
+    pa_assert(a);
+
+    if (!(i =3D pa_flist_pop(PA_STATIC_FLIST_GET(asyncmsgq))))
+        i =3D pa_xnew(struct asyncmsgq_item, 1);
+
+    i->code =3D code;
+    i->object =3D pa_msgobject_ref(object);
+    i->userdata =3D (void*) userdata;
+    i->free_cb =3D free_cb;
+    if (chunk) {
+        pa_assert(chunk->memblock);
+        i->memchunk =3D *chunk;
+        pa_memblock_ref(i->memchunk.memblock);
+    } else
+        pa_memchunk_reset(&i->memchunk);
+    i->semaphore =3D NULL;
+
+    /* Thus mutex makes the queue multiple-writer safe. This lock is only =
used on the writing side */
+    pa_mutex_lock(a->mutex);
+    pa_assert_se(pa_asyncq_push(a->asyncq, i, 1) =3D=3D 0);
+    pa_mutex_unlock(a->mutex);
+}
+
+int pa_asyncmsgq_send(pa_asyncmsgq *a, pa_msgobject *object, int code, con=
st void *userdata, const pa_memchunk *chunk) {
+    struct asyncmsgq_item i;
+    pa_assert(a);
+
+    i.code =3D code;
+    i.object =3D object;
+    i.userdata =3D (void*) userdata;
+    i.free_cb =3D NULL;
+    i.ret =3D -1;
+    if (chunk) {
+        pa_assert(chunk->memblock);
+        i->memchunk =3D *chunk;
+    } else
+        pa_memchunk_reset(&i->memchunk);
+    pa_assert_se(i.semaphore =3D pa_semaphore_new(0));
+
+    /* Thus mutex makes the queue multiple-writer safe. This lock is only =
used on the writing side */
+    pa_mutex_lock(a->mutex);
+    pa_assert_se(pa_asyncq_push(a->asyncq, &i, 1) =3D=3D 0);
+    pa_mutex_unlock(a->mutex);
+
+    pa_semaphore_wait(i.semaphore);
+    pa_semaphore_free(i.semaphore);
+
+    return i.ret;
+}
+
+int pa_asyncmsgq_get(pa_asyncmsgq *a, pa_msgobject **object, int *code, vo=
id **userdata, pa_memchunk *chunk, int wait) {
+    pa_assert(a);
+    pa_assert(code);
+    pa_assert(!a->current);
+
+    if (!(a->current =3D pa_asyncq_pop(a->asyncq, wait)))
+        return -1;
+
+    *code =3D a->current->code;
+    if (userdata)
+        *userdata =3D a->current->userdata;
+    if (object)
+        *object =3D a->current->object;
+    if (chunk)
+        *chunk =3D a->chunk;
+    =

+    return 0;
+}
+
+void pa_asyncmsgq_done(pa_asyncmsgq *a, int ret) {
+    pa_assert(a);
+    pa_assert(a->current);
+
+    if (a->current->semaphore) {
+        a->current->ret =3D ret;
+        pa_semaphore_post(a->current->semaphore);
+    } else {
+
+        if (a->current->free_cb)
+            a->current->free_cb(a->current->userdata);
+
+        if (a->current->object)
+            pa_msgobject_unref(a->current->object);
+
+        if (a->current->memchunk.memblock)
+            pa_memblock_unref(a->current->memchunk.memblock);
+        =

+        if (pa_flist_push(PA_STATIC_FLIST_GET(asyncmsgq), a->current) < 0)
+            pa_xfree(a->current);
+    }
+
+    a->current =3D NULL;
+}
+
+int pa_asyncmsgq_wait_for(pa_asyncmsgq *a, int code) {
+    int c;
+    pa_assert(a);
+    =

+    do {
+        =

+        if (pa_asyncmsgq_get(a, NULL, &c, NULL, 1) < 0)
+            return -1;
+
+        pa_asyncmsgq_done(a);
+        =

+    } while (c !=3D code);
+
+    return 0;
+}
+
+int pa_asyncmsgq_get_fd(pa_asyncmsgq *a) {
+    pa_assert(a);
+
+    return pa_asyncq_get_fd(a->asyncq);
+}
+
+int pa_asyncmsgq_before_poll(pa_asyncmsgq *a) {
+    pa_assert(a);
+
+    return pa_asyncq_before_poll(a->asyncq);
+}
+
+void pa_asyncmsgq_after_poll(pa_asyncmsgq *a) {
+    pa_assert(a);
+
+    pa_asyncq_after_poll(a->asyncq);
+}
+
+int pa_asyncmsgq_dispatch(pa_msgobject *object, int code, void *userdata, =
pa_memchunk *memchunk) {
+    pa_assert(q);
+
+    if (object)
+        return object->msg_process(object, code, userdata, memchunk);
+
+    return 0;
+}

Propchange: branches/lennart/src/pulsecore/asyncmsgq.c
---------------------------------------------------------------------------=
---
    svn:keywords =3D Id

Added: branches/lennart/src/pulsecore/asyncmsgq.h
URL: http://0pointer.de/cgi-bin/viewcvs.cgi/branches/lennart/src/pulsecore/=
asyncmsgq.h?rev=3D1469&root=3Dpulseaudio&view=3Dauto
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D
--- branches/lennart/src/pulsecore/asyncmsgq.h (added)
+++ branches/lennart/src/pulsecore/asyncmsgq.h Mon Jun 11 14:08:37 2007
@@ -1,0 +1,73 @@
+#ifndef foopulseasyncmsgqhfoo
+#define foopulseasyncmsgqhfoo
+
+/* $Id$ */
+
+/***
+  This file is part of PulseAudio.
+
+  Copyright 2004-2006 Lennart Poettering
+
+  PulseAudio is free software; you can redistribute it and/or modify
+  it under the terms of the GNU Lesser General Public License as
+  published by the Free Software Foundation; either version 2.1 of the
+  License, or (at your option) any later version.
+
+  PulseAudio is distributed in the hope that it will be useful, but
+  WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+  Lesser General Public License for more details.
+
+  You should have received a copy of the GNU Lesser General Public
+  License along with PulseAudio; if not, write to the Free Software
+  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+  USA.
+***/
+
+#include <sys/types.h>
+
+#include <pulsecore/asyncq.h>
+#include <pulsecore/memchunk.h>
+#include <pulsecore/msgobject.h>
+
+/* A simple asynchronous message queue, based on pa_asyncq. In
+ * contrast to pa_asyncq this one is multiple-writer safe, though
+ * still not multiple-reader safe. This queue is intended to be used
+ * for controlling real-time threads from normal-priority
+ * threads. Multiple-writer-safety is accomplished by using a mutex on
+ * the writer side. This queue is thus not useful for communication
+ * between several real-time threads.
+ *
+ * The queue takes messages consisting of:
+ *    "Object" for which this messages is intended (may be NULL)
+ *    A numeric message code
+ *    Arbitrary userdata pointer (may be NULL)
+ *    A memchunk (may be NULL)
+ *
+ * There are two functions for submitting messages: _post and
+ * _send. The fromer just enqueues the message asynchronously, the
+ * latter waits for completion, synchronously. */
+
+enum {
+    PA_MESSAGE_SHUTDOWN /* A generic message to inform the handler of this=
 queue to quit */
+};
+
+typedef struct pa_asyncmsgq pa_asyncmsgq;
+
+pa_asyncmsgq* pa_asyncmsgq_new(size_t size);
+void pa_asyncmsgq_free(pa_asyncmsgq* q);
+
+void pa_asyncmsgq_post(pa_asyncmsgq *q, pa_msgobject *object, int code, co=
nst void *userdata, const pa_memchunk *memchunk, pa_free_cb_t userdata_free=
_cb);
+int pa_asyncmsgq_send(pa_asyncmsgq *q, pa_msgobject *object, int code, con=
st void *userdata, const pa_memchunk *memchunk);
+
+int pa_asyncmsgq_get(pa_asyncmsgq *q, pa_msgobject **object, int *code, vo=
id **userdata, pa_memchunk *memchunk, int wait);
+int pa_asyncmsgq_dispatch(pa_msgobject *object, int code, void *userdata, =
pa_memchunk *memchunk);
+void pa_asyncmsgq_done(pa_asyncmsgq *q, int ret);
+int pa_asyncmsgq_wait_for(pa_asyncmsgq *a, int code);
+
+/* Just for the reading side */
+int pa_asyncmsgq_get_fd(pa_asyncmsgq *q);
+int pa_asyncmsgq_before_poll(pa_asyncmsgq *a);
+void pa_asyncmsgq_after_poll(pa_asyncmsgq *a);
+
+#endif

Propchange: branches/lennart/src/pulsecore/asyncmsgq.h
---------------------------------------------------------------------------=
---
    svn:keywords =3D Id

Added: branches/lennart/src/pulsecore/asyncq.c
URL: http://0pointer.de/cgi-bin/viewcvs.cgi/branches/lennart/src/pulsecore/=
asyncq.c?rev=3D1469&root=3Dpulseaudio&view=3Dauto
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D
--- branches/lennart/src/pulsecore/asyncq.c (added)
+++ branches/lennart/src/pulsecore/asyncq.c Mon Jun 11 14:08:37 2007
@@ -1,0 +1,271 @@
+/* $Id$ */
+
+/***
+  This file is part of PulseAudio.
+
+  Copyright 2006 Lennart Poettering
+
+  PulseAudio is free software; you can redistribute it and/or modify
+  it under the terms of the GNU Lesser General Public License as
+  published by the Free Software Foundation; either version 2.1 of the
+  License, or (at your option) any later version.
+
+  PulseAudio is distributed in the hope that it will be useful, but
+  WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+  Lesser General Public License for more details.
+
+  You should have received a copy of the GNU Lesser General Public
+  License along with PulseAudio; if not, write to the Free Software
+  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+  USA.
+***/
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <unistd.h>
+#include <errno.h>
+
+#include <pulsecore/atomic.h>
+#include <pulsecore/log.h>
+#include <pulsecore/thread.h>
+#include <pulsecore/macro.h>
+#include <pulsecore/core-util.h>
+#include <pulse/xmalloc.h>
+
+#include "asyncq.h"
+
+#define ASYNCQ_SIZE 128
+
+/* For debugging purposes we can define _Y to put and extra thread
+ * yield between each operation. */
+
+#ifdef PROFILE
+#define _Y pa_thread_yield()
+#else
+#define _Y do { } while(0)
+#endif
+
+struct pa_asyncq {
+    unsigned size;
+    unsigned read_idx;
+    unsigned write_idx;
+    pa_atomic_int_t read_waiting;
+    pa_atomic_int_t write_waiting;
+    int read_fds[2], write_fds[2];
+};
+
+#define PA_ASYNCQ_CELLS(x) ((pa_atomic_ptr_t*) ((uint8_t*) (x) + PA_ALIGN(=
sizeof(struct pa_asyncq))))
+
+static int is_power_of_two(unsigned size) {
+    return !(size & (size - 1));
+}
+
+static int reduce(pa_asyncq *l, int value) {
+    return value & (unsigned) (l->size - 1);
+}
+
+pa_asyncq *pa_asyncq_new(unsigned size) {
+    pa_asyncq *l;
+
+    if (!size)
+        size =3D ASYNCQ_SIZE;
+
+    pa_assert(is_power_of_two(size));
+
+    l =3D pa_xmalloc0(PA_ALIGN(sizeof(pa_asyncq)) + (sizeof(pa_atomic_ptr_=
t) * size));
+
+    l->size =3D size;
+    pa_atomic_store(&l->read_waiting, 0);
+    pa_atomic_store(&l->write_waiting, 0);
+
+    if (pipe(l->read_fds) < 0) {
+        pa_xfree(l);
+        return NULL;
+    }
+    =

+    if (pipe(l->write_fds) < 0) {
+        pa_close(l->read_fds[0]);
+        pa_close(l->read_fds[1]);
+        pa_xfree(l);
+        return NULL;
+    }
+
+    pa_make_nonblock_fd(l->read_fds[1]);
+    pa_make_nonblock_fd(l->write_fds[1]);
+
+    return l;
+}
+
+void pa_asyncq_free(pa_asyncq *l, pa_free_cb_t free_cb) {
+    pa_assert(l);
+
+    if (free_cb) {
+        void *p;
+        =

+        while ((p =3D pa_asyncq_pop(l, 0)))
+            free_cb(p);
+    }
+
+    pa_close(l->read_fds[0]);
+    pa_close(l->read_fds[1]);
+    pa_close(l->write_fds[0]);
+    pa_close(l->write_fds[1]);
+    =

+    pa_xfree(l);
+}
+
+int pa_asyncq_push(pa_asyncq*l, void *p, int wait) {
+    int idx;
+    pa_atomic_ptr_t *cells;
+
+    pa_assert(l);
+    pa_assert(p);
+
+    cells =3D PA_ASYNCQ_CELLS(l);
+    =

+    _Y;
+    idx =3D reduce(l, l->write_idx);
+
+    if (!pa_atomic_ptr_cmpxchg(&cells[idx], NULL, p)) {
+        =

+        /* First try failed. Let's wait for changes. */
+
+        if (!wait)
+            return -1;
+
+        _Y;
+
+        pa_atomic_inc(&l->write_waiting);
+
+        for (;;) {
+            char x[20];
+            =

+            _Y;
+
+            if (pa_atomic_ptr_cmpxchg(&cells[idx], NULL, p))
+                break;
+
+            _Y;
+
+            if (read(l->write_fds[0], x, sizeof(x)) < 0 && errno !=3D EINT=
R) {
+                pa_atomic_dec(&l->write_waiting);
+                return -1;
+            }
+        }
+        =

+        _Y;
+
+        pa_atomic_dec(&l->write_waiting);
+    }
+    =

+    _Y;
+    l->write_idx++;
+    =

+    if (pa_atomic_load(&l->read_waiting)) {
+        char x =3D 'x';
+        _Y;
+        write(l->read_fds[1], &x, sizeof(x));
+    }
+    =

+    return 0;
+}
+
+void* pa_asyncq_pop(pa_asyncq*l, int wait) {
+    int idx;
+    void *ret;
+    pa_atomic_ptr_t *cells;
+
+    pa_assert(l);
+
+    cells =3D PA_ASYNCQ_CELLS(l);
+
+    _Y;
+    idx =3D reduce(l, l->read_idx);
+
+    if (!(ret =3D pa_atomic_ptr_load(&cells[idx]))) {
+
+        /* First try failed. Let's wait for changes. */
+    =

+        if (!wait)
+            return NULL;
+
+        _Y;
+
+        pa_atomic_inc(&l->read_waiting);
+
+        for (;;) {
+            char x[20];
+
+            _Y;
+
+            if ((ret =3D pa_atomic_ptr_load(&cells[idx])))
+                break;
+
+            _Y;
+
+            if (read(l->read_fds[0], x, sizeof(x)) < 0 && errno !=3D EINTR=
) {
+                pa_atomic_dec(&l->read_waiting);
+                return NULL;
+            }
+        }
+
+        _Y;
+
+        pa_atomic_dec(&l->read_waiting);
+    }
+
+    /* Guaranteed if we only have a single reader */
+    pa_assert_se(pa_atomic_ptr_cmpxchg(&cells[idx], ret, NULL));
+
+    _Y;
+    l->read_idx++;
+
+    if (pa_atomic_load(&l->write_waiting)) {
+        char x =3D 'x';
+        _Y;
+        write(l->write_fds[1], &x, sizeof(x));
+    }
+            =

+    return ret;
+}
+
+int pa_asyncq_get_fd(pa_asyncq *q) {
+    pa_assert(q);
+
+    return q->read_fds[0];
+}
+
+int pa_asyncq_before_poll(pa_asyncq *l) {
+    int idx;
+    pa_atomic_ptr_t *cells;
+
+    pa_assert(l);
+
+    cells =3D PA_ASYNCQ_CELLS(l);
+
+    _Y;
+    idx =3D reduce(l, l->read_idx);
+
+    if (pa_atomic_ptr_load(&cells[idx]))
+        return -1;
+
+    pa_atomic_inc(&l->read_waiting);
+    =

+    if (pa_atomic_ptr_load(&cells[idx])) {
+        pa_atomic_dec(&l->read_waiting);
+        return -1;
+    }
+
+    return 0;
+}
+
+int pa_asyncq_after_poll(pa_asyncq *l) {
+    pa_assert(l);
+
+    pa_assert(pa_atomic_load(&l->read_waiting) > 0);
+
+    pa_atomic_dec(&l->read_waiting);
+}

Propchange: branches/lennart/src/pulsecore/asyncq.c
---------------------------------------------------------------------------=
---
    svn:keywords =3D Id

Added: branches/lennart/src/pulsecore/asyncq.h
URL: http://0pointer.de/cgi-bin/viewcvs.cgi/branches/lennart/src/pulsecore/=
asyncq.h?rev=3D1469&root=3Dpulseaudio&view=3Dauto
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D
--- branches/lennart/src/pulsecore/asyncq.h (added)
+++ branches/lennart/src/pulsecore/asyncq.h Mon Jun 11 14:08:37 2007
@@ -1,0 +1,56 @@
+#ifndef foopulseasyncqhfoo
+#define foopulseasyncqhfoo
+
+/* $Id$ */
+
+/***
+  This file is part of PulseAudio.
+
+  Copyright 2004-2006 Lennart Poettering
+
+  PulseAudio is free software; you can redistribute it and/or modify
+  it under the terms of the GNU Lesser General Public License as
+  published by the Free Software Foundation; either version 2.1 of the
+  License, or (at your option) any later version.
+
+  PulseAudio is distributed in the hope that it will be useful, but
+  WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+  Lesser General Public License for more details.
+
+  You should have received a copy of the GNU Lesser General Public
+  License along with PulseAudio; if not, write to the Free Software
+  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+  USA.
+***/
+
+#include <sys/types.h>
+#include <pulse/def.h>
+
+/* A simple, asynchronous, lock-free (if requested also wait-free)
+ * queue. Not multiple-reader/multiple-writer safe. If that is
+ * required both sides can be protected by a mutex each. --- Which is
+ * not a bad thing in most cases, since this queue is intended for
+ * communication between a normal thread and a single real-time
+ * thread. Only the real-time side needs to be lock-free/wait-free.
+ *
+ * If the queue is full and another entry shall be pushed, or when the
+ * queue is empty and another entry shall be popped and the "wait"
+ * argument is non-zero, the queue will block on a UNIX FIFO object --
+ * that will probably require locking on the kernel side -- which
+ * however is probably not problematic, because we do it only on
+ * starvation or overload in which case we have to block anyway.  */
+
+typedef struct pa_asyncq pa_asyncq;
+
+pa_asyncq* pa_asyncq_new(size_t size);
+void pa_asyncq_free(pa_asyncq* q, pa_free_cb_t free_cb);
+
+void* pa_asyncq_pop(pa_asyncq *q, int wait);
+int pa_asyncq_push(pa_asyncq *q, void *p, int wait);
+
+int pa_asyncq_get_fd(pa_asyncq *q);
+int pa_asyncq_before_poll(pa_asyncq *a);
+int pa_asyncq_after_poll(pa_asyncq *a);
+
+#endif

Propchange: branches/lennart/src/pulsecore/asyncq.h
---------------------------------------------------------------------------=
---
    svn:keywords =3D Id

Modified: branches/lennart/src/pulsecore/atomic.h
URL: http://0pointer.de/cgi-bin/viewcvs.cgi/branches/lennart/src/pulsecore/=
atomic.h?rev=3D1469&root=3Dpulseaudio&r1=3D1468&r2=3D1469&view=3Ddiff
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D
--- branches/lennart/src/pulsecore/atomic.h (original)
+++ branches/lennart/src/pulsecore/atomic.h Mon Jun 11 14:08:37 2007
@@ -31,9 +31,9 @@
  * It is not guaranteed however, that sizeof(AO_t) =3D=3D 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 =3D (v) }
 =

@@ -41,37 +41,39 @@
  * 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);
 }
 =

 typedef struct pa_atomic_ptr {
     volatile AO_t value;
 } pa_atomic_ptr_t;
+
+#define PA_ATOMIC_PTR_INIT(v) { .value =3D (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);

Modified: branches/lennart/src/pulsecore/cli-command.c
URL: http://0pointer.de/cgi-bin/viewcvs.cgi/branches/lennart/src/pulsecore/=
cli-command.c?rev=3D1469&root=3Dpulseaudio&r1=3D1468&r2=3D1469&view=3Ddiff
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D
--- branches/lennart/src/pulsecore/cli-command.c (original)
+++ branches/lennart/src/pulsecore/cli-command.c Mon Jun 11 14:08:37 2007
@@ -95,6 +95,7 @@
 static int pa_cli_command_source_volume(pa_core *c, pa_tokenizer *t, pa_st=
rbuf *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_strb=
uf *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_str=
buf *buf, int *fail);
 static int pa_cli_command_source_default(pa_core *c, pa_tokenizer *t, pa_s=
trbuf *buf, int *fail);
 static int pa_cli_command_kill_client(pa_core *c, pa_tokenizer *t, pa_strb=
uf *buf, int *fail);
@@ -130,12 +131,13 @@
     { "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,             "Unloa=
d a module (args: index)",                             2},
-    { "set-sink-volume",         pa_cli_command_sink_volume,        "Set t=
he volume of a sink (args: index|name, volume)",             3},
+    { "load-module",             pa_cli_command_load,               "Load =
a module (args: name, arguments)", 3},
+    { "unload-module",           pa_cli_command_unload,             "Unloa=
d a module (args: index)", 2},
+    { "set-sink-volume",         pa_cli_command_sink_volume,        "Set t=
he volume of a sink (args: index|name, volume)", 3},
     { "set-sink-input-volume",   pa_cli_command_sink_input_volume,  "Set t=
he volume of a sink input (args: index|name, volume)", 3},
     { "set-source-volume",       pa_cli_command_source_volume,      "Set t=
he volume of a source (args: index|name, volume)", 3},
     { "set-sink-mute",           pa_cli_command_sink_mute,          "Set t=
he mute switch of a sink (args: index|name, mute)", 3},
+    { "set-sink-input-mute",     pa_cli_command_sink_input_mute,    "Set t=
he mute switch of a sink input (args: index|name, mute)", 3},
     { "set-source-mute",         pa_cli_command_source_mute,        "Set t=
he mute switch of a source (args: index|name, mute)", 3},
     { "set-default-sink",        pa_cli_command_sink_default,       "Set t=
he default sink (args: index|name)", 2},
     { "set-default-source",      pa_cli_command_source_default,     "Set t=
he default source (args: index|name)", 2},
@@ -392,7 +394,7 @@
     }
 =

     pa_cvolume_set(&cvolume, sink->sample_spec.channels, volume);
-    pa_sink_set_volume(sink, PA_MIXER_HARDWARE, &cvolume);
+    pa_sink_set_volume(sink, &cvolume);
     return 0;
 }
 =

@@ -460,7 +462,7 @@
     }
 =

     pa_cvolume_set(&cvolume, source->sample_spec.channels, volume);
-    pa_source_set_volume(source, PA_MIXER_HARDWARE, &cvolume);
+    pa_source_set_volume(source, &cvolume);
     return 0;
 }
 =

@@ -489,7 +491,7 @@
         return -1;
     }
 =

-    pa_sink_set_mute(sink, PA_MIXER_HARDWARE, mute);
+    pa_sink_set_mute(sink, mute);
     return 0;
 }
 =

@@ -518,7 +520,42 @@
         return -1;
     }
 =

-    pa_source_set_mute(source, PA_MIXER_HARDWARE, mute);
+    pa_source_set_mute(source, mute);
+    return 0;
+}
+
+static int pa_cli_command_sink_input_mute(pa_core *c, pa_tokenizer *t, pa_=
strbuf *buf, PA_GCC_UNUSED int *fail) {
+    const char *n, *v;
+    pa_sink_input *si;
+    uint32_t idx;
+    int mute;
+
+    if (!(n =3D pa_tokenizer_get(t, 1))) {
+        pa_strbuf_puts(buf, "You need to specify a sink input by its index=
.\n");
+        return -1;
+    }
+
+    if ((idx =3D parse_index(n)) =3D=3D PA_IDXSET_INVALID) {
+        pa_strbuf_puts(buf, "Failed to parse index.\n");
+        return -1;
+    }
+
+    if (!(v =3D pa_tokenizer_get(t, 2))) {
+        pa_strbuf_puts(buf, "You need to specify a volume >=3D 0. (0 is mu=
ted, 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 =3D pa_idxset_get_by_index(c->sink_inputs, (uint32_t) idx))) {
+        pa_strbuf_puts(buf, "No sink input found with this index.\n");
+        return -1;
+    }
+
+    pa_sink_input_set_mute(si, mute);
     return 0;
 }
 =

@@ -900,7 +937,7 @@
     nl =3D 0;
 =

     for (sink =3D pa_idxset_first(c->sinks, &idx); sink; sink =3D pa_idxse=
t_next(c->sinks, &idx)) {
-        if (sink->owner && sink->owner->auto_unload)
+        if (sink->module && sink->module->auto_unload)
             continue;
 =

         if (!nl) {
@@ -908,12 +945,12 @@
             nl =3D 1;
         }
 =

-        pa_strbuf_printf(buf, "set-sink-volume %s 0x%03x\n", sink->name, p=
a_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, p=
a_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 =3D pa_idxset_first(c->sources, &idx); source; source =3D =
pa_idxset_next(c->sources, &idx)) {
-        if (source->owner && source->owner->auto_unload)
+        if (source->module && source->module->auto_unload)
             continue;
 =

         if (!nl) {
@@ -921,8 +958,8 @@
             nl =3D 1;
         }
 =

-        pa_strbuf_printf(buf, "set-source-volume %s 0x%03x\n", source->nam=
e, 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->nam=
e, 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));
     }
 =

 =


Modified: branches/lennart/src/pulsecore/cli-text.c
URL: http://0pointer.de/cgi-bin/viewcvs.cgi/branches/lennart/src/pulsecore/=
cli-text.c?rev=3D1469&root=3Dpulseaudio&r1=3D1468&r2=3D1469&view=3Ddiff
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D
--- branches/lennart/src/pulsecore/cli-text.c (original)
+++ branches/lennart/src/pulsecore/cli-text.c Mon Jun 11 14:08:37 2007
@@ -93,6 +93,12 @@
     pa_strbuf *s;
     pa_sink *sink;
     uint32_t idx =3D PA_IDXSET_INVALID;
+    static const char* const state_table[] =3D {
+        [PA_SINK_RUNNING] =3D "RUNNING",
+        [PA_SINK_SUSPENDED] =3D "SUSPENDED",
+        [PA_SINK_IDLE] =3D "IDLE",
+        [PA_SINK_DISCONNECTED] =3D "DISCONNECTED"
+    };
     assert(c);
 =

     s =3D pa_strbuf_new();
@@ -108,22 +114,29 @@
             "  %c index: %u\n"
             "\tname: <%s>\n"
             "\tdriver: <%s>\n"
+            "\tis_hardware: <%i>\n"
+            "\tstate: %s\n"
             "\tvolume: <%s>\n"
+            "\tmute: <%i>\n"
             "\tlatency: <%0.0f usec>\n"
             "\tmonitor_source: <%u>\n"
             "\tsample spec: <%s>\n"
             "\tchannel map: <%s>\n",
             c->default_sink_name && !strcmp(sink->name, c->default_sink_na=
me) ? '*' : ' ',
-            sink->index, sink->name,
+            sink->index,
+            sink->name,
             sink->driver,
-            pa_cvolume_snprint(cv, sizeof(cv), pa_sink_get_volume(sink, PA=
_MIXER_HARDWARE)),
+            !!sink->is_hardware,
+            state_table[pa_sink_get_state(sink)],
+            pa_cvolume_snprint(cv, sizeof(cv), pa_sink_get_volume(sink)),
+            !!pa_sink_get_mute(sink),
             (double) pa_sink_get_latency(sink),
             sink->monitor_source ? sink->monitor_source->index : PA_INVALI=
D_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->ind=
ex);
+        if (sink->module)
+            pa_strbuf_printf(s, "\tmodule: <%u>\n", sink->module->index);
         if (sink->description)
             pa_strbuf_printf(s, "\tdescription: <%s>\n", sink->description=
);
     }
@@ -135,6 +148,12 @@
     pa_strbuf *s;
     pa_source *source;
     uint32_t idx =3D PA_IDXSET_INVALID;
+    static const char* const state_table[] =3D {
+        [PA_SOURCE_RUNNING] =3D "RUNNING",
+        [PA_SOURCE_SUSPENDED] =3D "SUSPENDED",
+        [PA_SOURCE_IDLE] =3D "IDLE",
+        [PA_SOURCE_DISCONNECTED] =3D "DISCONNECTED"
+    };
     assert(c);
 =

     s =3D pa_strbuf_new();
@@ -143,7 +162,7 @@
     pa_strbuf_printf(s, "%u source(s) available.\n", pa_idxset_size(c->sou=
rces));
 =

     for (source =3D pa_idxset_first(c->sources, &idx); source; source =3D =
pa_idxset_next(c->sources, &idx)) {
-        char ss[PA_SAMPLE_SPEC_SNPRINT_MAX], cm[PA_CHANNEL_MAP_SNPRINT_MAX=
];
+        char ss[PA_SAMPLE_SPEC_SNPRINT_MAX], cm[PA_CHANNEL_MAP_SNPRINT_MAX=
], cv[PA_CVOLUME_SNPRINT_MAX];
 =

 =

         pa_strbuf_printf(
@@ -151,6 +170,10 @@
             "  %c index: %u\n"
             "\tname: <%s>\n"
             "\tdriver: <%s>\n"
+            "\tis_hardware: <%i>\n"
+            "\tstate: %s\n"
+            "\tvolume: <%s>\n"
+            "\tmute: <%u>\n"
             "\tlatency: <%0.0f usec>\n"
             "\tsample spec: <%s>\n"
             "\tchannel map: <%s>\n",
@@ -158,14 +181,18 @@
             source->index,
             source->name,
             source->driver,
+            !!source->is_hardware,
+            state_table[pa_source_get_state(source)],
+            pa_cvolume_snprint(cv, sizeof(cv), pa_source_get_volume(source=
)),
+            !!pa_source_get_mute(source),
             (double) pa_source_get_latency(source),
             pa_sample_spec_snprint(ss, sizeof(ss), &source->sample_spec),
             pa_channel_map_snprint(cm, sizeof(cm), &source->channel_map));
 =

         if (source->monitor_of)
             pa_strbuf_printf(s, "\tmonitor_of: <%u>\n", source->monitor_of=
->index);
-        if (source->owner)
-            pa_strbuf_printf(s, "\towner module: <%u>\n", source->owner->i=
ndex);
+        if (source->module)
+            pa_strbuf_printf(s, "\tmodule: <%u>\n", source->module->index);
         if (source->description)
             pa_strbuf_printf(s, "\tdescription: <%s>\n", source->descripti=
on);
     }
@@ -179,9 +206,9 @@
     pa_source_output *o;
     uint32_t idx =3D PA_IDXSET_INVALID;
     static const char* const state_table[] =3D {
-        "RUNNING",
-        "CORKED",
-        "DISCONNECTED"
+        [PA_SOURCE_OUTPUT_RUNNING] =3D "RUNNING",
+        [PA_SOURCE_OUTPUT_CORKED] =3D "CORKED",
+        [PA_SOURCE_OUTPUT_DISCONNECTED] =3D "DISCONNECTED"
     };
     assert(c);
 =

@@ -202,14 +229,16 @@
             "\tdriver: <%s>\n"
             "\tstate: %s\n"
             "\tsource: <%u> '%s'\n"
+            "\tlatency: <%0.0f usec>\n"
             "\tsample spec: <%s>\n"
             "\tchannel map: <%s>\n"
             "\tresample method: %s\n",
             o->index,
             o->name,
             o->driver,
-            state_table[o->state],
+            state_table[pa_source_output_get_state(o)],
             o->source->index, o->source->name,
+            (double) pa_source_output_get_latency(o),
             pa_sample_spec_snprint(ss, sizeof(ss), &o->sample_spec),
             pa_channel_map_snprint(cm, sizeof(cm), &o->channel_map),
             pa_resample_method_to_string(pa_source_output_get_resample_met=
hod(o)));
@@ -227,9 +256,10 @@
     pa_sink_input *i;
     uint32_t idx =3D PA_IDXSET_INVALID;
     static const char* const state_table[] =3D {
-        "RUNNING",
-        "CORKED",
-        "DISCONNECTED"
+        [PA_SINK_INPUT_RUNNING] =3D "RUNNING",
+        [PA_SINK_INPUT_DRAINED] =3D "DRAINED",
+        [PA_SINK_INPUT_CORKED] =3D "CORKED",
+        [PA_SINK_INPUT_DISCONNECTED] =3D "DISCONNECTED"
     };
 =

     assert(c);
@@ -251,6 +281,7 @@
             "\tstate: %s\n"
             "\tsink: <%u> '%s'\n"
             "\tvolume: <%s>\n"
+            "\tmute: <%i>\n"
             "\tlatency: <%0.0f usec>\n"
             "\tsample spec: <%s>\n"
             "\tchannel map: <%s>\n"
@@ -258,16 +289,17 @@
             i->index,
             i->name,
             i->driver,
-            state_table[i->state],
+            state_table[pa_sink_input_get_state(i)],
             i->sink->index, i->sink->name,
             pa_cvolume_snprint(cv, sizeof(cv), pa_sink_input_get_volume(i)=
),
+            !!pa_sink_input_get_mute(i),
             (double) pa_sink_input_get_latency(i),
             pa_sample_spec_snprint(ss, sizeof(ss), &i->sample_spec),
             pa_channel_map_snprint(cm, sizeof(cm), &i->channel_map),
             pa_resample_method_to_string(pa_sink_input_get_resample_method=
(i)));
 =

         if (i->module)
-            pa_strbuf_printf(s, "\towner module: <%u>\n", i->module->index=
);
+            pa_strbuf_printf(s, "\tmodule: <%u>\n", i->module->index);
         if (i->client)
             pa_strbuf_printf(s, "\tclient: <%u> '%s'\n", i->client->index,=
 i->client->name);
     }

Modified: branches/lennart/src/pulsecore/core-def.h
URL: http://0pointer.de/cgi-bin/viewcvs.cgi/branches/lennart/src/pulsecore/=
core-def.h?rev=3D1469&root=3Dpulseaudio&r1=3D1468&r2=3D1469&view=3Ddiff
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D
--- branches/lennart/src/pulsecore/core-def.h (original)
+++ branches/lennart/src/pulsecore/core-def.h Mon Jun 11 14:08:37 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: branches/lennart/src/pulsecore/core.c
URL: http://0pointer.de/cgi-bin/viewcvs.cgi/branches/lennart/src/pulsecore/=
core.c?rev=3D1469&root=3Dpulseaudio&r1=3D1468&r2=3D1469&view=3Ddiff
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D
--- branches/lennart/src/pulsecore/core.c (original)
+++ branches/lennart/src/pulsecore/core.c Mon Jun 11 14:08:37 2007
@@ -45,13 +45,59 @@
 #include <pulsecore/props.h>
 #include <pulsecore/random.h>
 #include <pulsecore/log.h>
+#include <pulsecore/macro.h>
 =

 #include "core.h"
+
+static int core_process_msg(pa_msgobject *o, int code, void *userdata, pa_=
memchunk *chunk) {
+    pa_core *c =3D PA_CORE(o);
+
+    pa_core_assert_ref(c);
+    =

+    switch (code) {
+        =

+        case PA_CORE_MESSAGE_UNLOAD_MODULE:
+            pa_module_unload(c, userdata);
+            return 0;
+
+        default:
+            return -1;
+    }
+}
+
+static void asyncmsgq_cb(pa_mainloop_api*api, pa_io_event* e, int fd, pa_i=
o_event_flags_t events, void *userdata) {
+    pa_core *c =3D userdata;
+    =

+    pa_assert(pa_asyncmsgq_get_fd(c->asyncmsgq) =3D=3D fd);
+    pa_assert(events =3D=3D PA_IO_EVENT_INPUT);
+
+    pa_asyncmsgq_after_poll(c->asyncmsgq);
+
+    for (;;) {
+        pa_msgobject *object;
+        int code;
+        void *data;
+        pa_memchunk chunk;
+
+        /* Check whether there is a message for us to process */
+        while (pa_asyncmsgq_get(c->asyncmsgq, &object, &code, &data, &chun=
k, 0) =3D=3D 0) {
+            pa_asyncmsgq_dispatch(object, code, data, &chunk);
+            pa_asyncmsgq_done(c->asyncmsgq, 0);
+        }
+        =

+        if (pa_asyncmsgq_before_poll(c->asyncmsgq) =3D=3D 0)
+            break;
+    }
+}
+
+static void core_free(pa_object *o);
 =

 pa_core* pa_core_new(pa_mainloop_api *m, int shared) {
     pa_core* c;
     pa_mempool *pool;
 =

+    pa_assert(m);
+    =

     if (shared) {
         if (!(pool =3D pa_mempool_new(shared))) {
             pa_log_warn("failed to allocate shared memory pool. Falling ba=
ck to a normal memory pool.");
@@ -66,7 +112,9 @@
         }
     }
 =

-    c =3D pa_xnew(pa_core, 1);
+    c =3D pa_msgobject_new(pa_core);
+    c->parent.parent.free =3D core_free;
+    c->parent.process_msg =3D core_process_msg;
 =

     c->mainloop =3D m;
     c->clients =3D pa_idxset_new(NULL, NULL);
@@ -123,11 +171,17 @@
 #ifdef SIGPIPE
     pa_check_signal_is_blocked(SIGPIPE);
 #endif
+
+    pa_assert_se(c->asyncmsgq =3D pa_asyncmsgq_new(0));
+    pa_assert_se(pa_asyncmsgq_before_poll(c->asyncmsgq) =3D=3D 0);
+    pa_assert_se(c->asyncmsgq_event =3D c->mainloop->io_new(c->mainloop, p=
a_asyncmsgq_get_fd(c->asyncmsgq), PA_IO_EVENT_INPUT, asyncmsgq_cb, c));
+            =

     return c;
 }
 =

-void pa_core_free(pa_core *c) {
-    assert(c);
+static void core_free(pa_object *o) {
+    pa_core *c =3D PA_CORE(o);
+    pa_core_assert_ref(c);
 =

     pa_module_unload_all(c);
     assert(!c->modules);
@@ -161,6 +215,10 @@
     pa_mempool_free(c->mempool);
 =

     pa_property_cleanup(c);
+
+    c->mainloop->io_free(c->asyncmsgq_event);
+    pa_asyncmsgq_after_poll(c->asyncmsgq);
+    pa_asyncmsgq_free(c->asyncmsgq);
 =

     pa_hook_free(&c->hook_sink_input_new);
     pa_hook_free(&c->hook_sink_disconnect);

Modified: branches/lennart/src/pulsecore/core.h
URL: http://0pointer.de/cgi-bin/viewcvs.cgi/branches/lennart/src/pulsecore/=
core.h?rev=3D1469&root=3Dpulseaudio&r1=3D1468&r2=3D1469&view=3Ddiff
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D
--- branches/lennart/src/pulsecore/core.h (original)
+++ branches/lennart/src/pulsecore/core.h Mon Jun 11 14:08:37 2007
@@ -34,17 +34,21 @@
 #include <pulsecore/queue.h>
 #include <pulsecore/llist.h>
 #include <pulsecore/hook-list.h>
+#include <pulsecore/asyncmsgq.h>
 =

 typedef struct pa_core pa_core;
 =

 #include <pulsecore/core-subscribe.h>
 #include <pulsecore/sink-input.h>
+#include <pulsecore/msgobject.h>
 =

 /* The core structure of PulseAudio. Every PulseAudio daemon contains
  * exactly one of these. It is used for storing kind of global
  * variables for the daemon. */
 =

 struct pa_core {
+    pa_msgobject parent;
+    =

     /* A random value which may be used to identify this instance of
      * PulseAudio. Not cryptographically secure in any way. */
     uint32_t cookie;
@@ -88,10 +92,20 @@
         hook_sink_disconnect,
         hook_source_output_new,
         hook_source_disconnect;
+
+    pa_asyncmsgq *asyncmsgq;
+    pa_io_event *asyncmsgq_event;
+};
+
+PA_DECLARE_CLASS(pa_core);
+#define PA_CORE(o) ((pa_core*) o)
+
+enum {
+    PA_CORE_MESSAGE_UNLOAD_MODULE,
+    PA_CORE_MESSAGE_MAX
 };
 =

 pa_core* pa_core_new(pa_mainloop_api *m, int shared);
-void pa_core_free(pa_core*c);
 =

 /* Check whether noone is connected to this core */
 void pa_core_check_quit(pa_core *c);

Modified: branches/lennart/src/pulsecore/flist.c
URL: http://0pointer.de/cgi-bin/viewcvs.cgi/branches/lennart/src/pulsecore/=
flist.c?rev=3D1469&root=3Dpulseaudio&r1=3D1468&r2=3D1469&view=3Ddiff
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D
--- branches/lennart/src/pulsecore/flist.c (original)
+++ branches/lennart/src/pulsecore/flist.c Mon Jun 11 14:08:37 2007
@@ -30,6 +30,7 @@
 #include <pulsecore/atomic.h>
 #include <pulsecore/log.h>
 #include <pulsecore/thread.h>
+#include <pulsecore/macro.h>
 #include <pulse/xmalloc.h>
 =

 #include "flist.h"
@@ -90,17 +91,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;
 };
+
+#define PA_FLIST_CELLS(x) ((struct cell*) ((uint8_t*) (x) + PA_ALIGN(sizeo=
f(struct pa_flist))))
 =

 static int is_power_of_two(unsigned size) {
     return !(size & (size - 1));
@@ -114,10 +116,9 @@
 =

     assert(is_power_of_two(size));
 =

-    l =3D pa_xnew(pa_flist, 1);
+    l =3D pa_xmalloc0(PA_ALIGN(sizeof(pa_flist)) + (sizeof(struct cell) * =
size));
 =

     l->size =3D size;
-    l->cells =3D pa_xnew0(struct cell, size);
 =

     pa_atomic_store(&l->read_idx, 0);
     pa_atomic_store(&l->write_idx, 0);
@@ -134,30 +135,35 @@
     assert(l);
 =

     if (free_cb) {
+        struct cell *cells;
         int len, idx;
+
+        cells =3D PA_FLIST_CELLS(l);
 =

         idx =3D reduce(l, pa_atomic_load(&l->read_idx));
         len =3D pa_atomic_load(&l->length);
 =

         for (; len > 0; len--) {
 =

-            if (pa_atomic_load(&l->cells[idx].state) =3D=3D STATE_USED)
-                free_cb(l->cells[idx].data);
+            if (pa_atomic_load(&cells[idx].state) =3D=3D STATE_USED)
+                free_cb(cells[idx].data);
 =

             idx =3D reduce(l, idx + 1);
         }
     }
 =

-    pa_xfree(l->cells);
     pa_xfree(l);
 }
 =

 int pa_flist_push(pa_flist*l, void *p) {
     int idx, len, n;
+    struct cell *cells;
 =

     assert(l);
     assert(p);
 =

+    cells =3D PA_FLIST_CELLS(l);
+    =

     n =3D len =3D (int) l->size - pa_atomic_load(&l->length) + N_EXTRA_SCA=
N;
     _Y;
     idx =3D reduce(l, pa_atomic_load(&l->write_idx));
@@ -165,13 +171,13 @@
     for (; n > 0 ; n--) {
         _Y;
 =

-        if (pa_atomic_cmpxchg(&l->cells[idx].state, STATE_UNUSED, STATE_BU=
SY)) {
+        if (pa_atomic_cmpxchg(&cells[idx].state, STATE_UNUSED, STATE_BUSY)=
) {
             _Y;
             pa_atomic_inc(&l->write_idx);
             _Y;
-            l->cells[idx].data =3D p;
-            _Y;
-            pa_atomic_store(&l->cells[idx].state, STATE_USED);
+            cells[idx].data =3D p;
+            _Y;
+            pa_atomic_store(&cells[idx].state, STATE_USED);
             _Y;
             pa_atomic_inc(&l->length);
             return 0;
@@ -191,8 +197,11 @@
 =

 void* pa_flist_pop(pa_flist*l) {
     int idx, len, n;
+    struct cell *cells;
 =

     assert(l);
+
+    cells =3D PA_FLIST_CELLS(l);
 =

     n =3D len =3D pa_atomic_load(&l->length) + N_EXTRA_SCAN;
     _Y;
@@ -201,14 +210,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 =3D l->cells[idx].data;
-            _Y;
-            pa_atomic_store(&l->cells[idx].state, STATE_UNUSED);
+            p =3D cells[idx].data;
+            _Y;
+            pa_atomic_store(&cells[idx].state, STATE_UNUSED);
             _Y;
 =

             pa_atomic_dec(&l->length);

Modified: branches/lennart/src/pulsecore/flist.h
URL: http://0pointer.de/cgi-bin/viewcvs.cgi/branches/lennart/src/pulsecore/=
flist.h?rev=3D1469&root=3Dpulseaudio&r1=3D1468&r2=3D1469&view=3Ddiff
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D
--- branches/lennart/src/pulsecore/flist.h (original)
+++ branches/lennart/src/pulsecore/flist.h Mon Jun 11 14:08:37 2007
@@ -26,6 +26,8 @@
 =

 #include <pulse/def.h>
 =

+#include <pulsecore/once.h>
+
 /* A multiple-reader multipler-write lock-free free list implementation */
 =

 typedef struct pa_flist pa_flist;
@@ -38,4 +40,22 @@
 int pa_flist_push(pa_flist*l, void *p);
 void* pa_flist_pop(pa_flist*l);
 =

+#define PA_STATIC_FLIST_DECLARE(name, size)                     \
+    struct {                                                    \
+        pa_flist *flist;                                        \
+        pa_once_t once;                                         \
+    } name##_static_flist =3D { NULL, PA_ONCE_INIT };             \
+                                                                \
+    static void name##_init(void) {                             \
+        name##_static_flist.flist =3D pa_flist_new(size);         \
+    }                                                           \
+                                                                \
+    static inline pa_flist* name##_get(void) {                  \
+        pa_once(&name##_static_flist.once, name##_init);        \
+        return name##_static_flist.flist;                       \
+    } \
+    struct __stupid_useless_struct_to_allow_trailing_semicolon
+
+#define PA_STATIC_FLIST_GET(name) (name##_get())
+
 #endif

Modified: branches/lennart/src/pulsecore/hashmap.h
URL: http://0pointer.de/cgi-bin/viewcvs.cgi/branches/lennart/src/pulsecore/=
hashmap.h?rev=3D1469&root=3Dpulseaudio&r1=3D1468&r2=3D1469&view=3Ddiff
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D
--- branches/lennart/src/pulsecore/hashmap.h (original)
+++ branches/lennart/src/pulsecore/hashmap.h Mon Jun 11 14:08:37 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 compa=
ring objects in the map */
 pa_hashmap *pa_hashmap_new(pa_hash_func_t hash_func, pa_compare_func_t com=
pare_func);
 =

 /* Free the hash table. Calls the specified function for every value in th=
e table. The function may be NULL */
-void pa_hashmap_free(pa_hashmap*, void (*free_func)(void *p, void *userdat=
a), 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: branches/lennart/src/pulsecore/idxset.c
URL: http://0pointer.de/cgi-bin/viewcvs.cgi/branches/lennart/src/pulsecore/=
idxset.c?rev=3D1469&root=3Dpulseaudio&r1=3D1468&r2=3D1469&view=3Ddiff
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D
--- branches/lennart/src/pulsecore/idxset.c (original)
+++ branches/lennart/src/pulsecore/idxset.c Mon Jun 11 14:08:37 2007
@@ -32,6 +32,7 @@
 #include <string.h>
 =

 #include <pulse/xmalloc.h>
+#include <pulsecore/macro.h>
 =

 #include "idxset.h"
 =


Modified: branches/lennart/src/pulsecore/idxset.h
URL: http://0pointer.de/cgi-bin/viewcvs.cgi/branches/lennart/src/pulsecore/=
idxset.h?rev=3D1469&root=3Dpulseaudio&r1=3D1468&r2=3D1469&view=3Ddiff
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D
--- branches/lennart/src/pulsecore/idxset.h (original)
+++ branches/lennart/src/pulsecore/idxset.h Mon Jun 11 14:08:37 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);

Added: branches/lennart/src/pulsecore/macro.h
URL: http://0pointer.de/cgi-bin/viewcvs.cgi/branches/lennart/src/pulsecore/=
macro.h?rev=3D1469&root=3Dpulseaudio&view=3Dauto
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D
--- branches/lennart/src/pulsecore/macro.h (added)
+++ branches/lennart/src/pulsecore/macro.h Mon Jun 11 14:08:37 2007
@@ -1,0 +1,80 @@
+#ifndef foopulsemacrohfoo
+#define foopulsemacrohfoo
+
+/* $Id$ */
+
+/***
+  This file is part of PulseAudio.
+
+  Copyright 2004-2006 Lennart Poettering
+
+  PulseAudio is free software; you can redistribute it and/or modify
+  it under the terms of the GNU Lesser General Public License as published
+  by the Free Software Foundation; either version 2 of the License,
+  or (at your option) any later version.
+
+  PulseAudio is distributed in the hope that it will be useful, but
+  WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+  General Public License for more details.
+
+  You should have received a copy of the GNU Lesser General Public License
+  along with PulseAudio; if not, write to the Free Software
+  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+  USA.
+***/
+
+#include <sys/types.h>
+#include <pulsecore/log.h>
+
+static inline size_t pa_align(size_t l) {
+    return (((l + sizeof(void*) - 1) / sizeof(void*)) * sizeof(void*));
+}
+
+#define PA_ALIGN(x) (pa_align(x))
+
+#define PA_ELEMENTSOF(x) (sizeof(x)/sizeof((x)[0]))
+
+#define SA_MAX(a, b) ((a) > (b) ? (a) : (b))
+#define SA_MIN(a, b) ((a) < (b) ? (a) : (b))
+
+#ifdef __GNUC__
+#define PA_PRETTY_FUNCTION __PRETTY_FUNCTION__
+#else
+#define PA_PRETTY_FUNCTION ""
+#endif
+
+#define pa_return_if_fail(expr) \
+    do { \
+        if (!(expr)) { \
+            pa_log_debug("%s: Assertion <%s> failed.\n", PA_PRETTY_FUNCTIO=
N, #expr ); \
+            return; \
+        } \
+    } while(0)
+
+#define pa_return_val_if_fail(expr, val) \
+    do { \
+        if (!(expr)) { \
+            pa_log_debug("%s: Assertion <%s> failed.\n", PA_PRETTY_FUNCTIO=
N, #expr ); \
+            return (val); \
+        } \
+    } while(0)
+
+#define pa_return_null_if_fail(expr) pa_return_val_if_fail(expr, NULL)
+
+#define pa_assert assert
+
+#define pa_assert_not_reached() pa_assert(!"Should not be reached.")
+
+/* An assert which guarantees side effects of x */
+#define pa_assert_se(x) do {                  \
+        int _r =3D !!(x);                       \
+        pa_assert(_r);                        \
+    } while(0)
+
+#define PA_PTR_TO_UINT(p) ((unsigned int) (unsigned long) (p))
+#define PA_UINT_TO_PTR(u) ((void*) (unsigned long) (u))
+#define PA_PTR_TO_UINT32(p) ((uint32_t) PA_PTR_TO_UINT(p))
+#define PA_UINT32_TO_PTR(u) PA_UINT_TO_PTR(u)
+
+#endif

Propchange: branches/lennart/src/pulsecore/macro.h
---------------------------------------------------------------------------=
---
    svn:keywords =3D Id

Modified: branches/lennart/src/pulsecore/mcalign.c
URL: http://0pointer.de/cgi-bin/viewcvs.cgi/branches/lennart/src/pulsecore/=
mcalign.c?rev=3D1469&root=3Dpulseaudio&r1=3D1468&r2=3D1469&view=3Ddiff
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D
--- branches/lennart/src/pulsecore/mcalign.c (original)
+++ branches/lennart/src/pulsecore/mcalign.c Mon Jun 11 14:08:37 2007
@@ -91,6 +91,7 @@
 =

         } else {
             size_t l;
+            void *lo_data, *m_data;
 =

             /* We have to copy */
             assert(m->leftover.length < m->base);
@@ -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.ind=
ex + m->leftover.length, (uint8_t*) c->memblock->data + c->index, l);
+            lo_data =3D pa_memblock_acquire(m->leftover.memblock);
+            m_data =3D pa_memblock_acquire(c->memblock);
+            memcpy((uint8_t*) lo_data + m->leftover.index + m->leftover.le=
ngth, (uint8_t*) m_data + c->index, l);
+            pa_memblock_release(m->leftover.memblock);
+            pa_memblock_release(c->memblock);
             m->leftover.length +=3D l;
 =

-            assert(m->leftover.length <=3D m->base && m->leftover.length <=
=3D m->leftover.memblock->length);
+            assert(m->leftover.length <=3D m->base);
+            assert(m->leftover.length <=3D pa_memblock_get_length(m->lefto=
ver.memblock));
 =

             if (c->length > l) {
                 /* Save the remainder of the memory block */

Modified: branches/lennart/src/pulsecore/memblock.c
URL: http://0pointer.de/cgi-bin/viewcvs.cgi/branches/lennart/src/pulsecore/=
memblock.c?rev=3D1469&root=3Dpulseaudio&r1=3D1468&r2=3D1469&view=3Ddiff
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D
--- branches/lennart/src/pulsecore/memblock.c (original)
+++ branches/lennart/src/pulsecore/memblock.c Mon Jun 11 14:08:37 2007
@@ -33,10 +33,14 @@
 #include <unistd.h>
 =

 #include <pulse/xmalloc.h>
+#include <pulse/def.h>
 =

 #include <pulsecore/shm.h>
 #include <pulsecore/log.h>
 #include <pulsecore/hashmap.h>
+#include <pulsecore/semaphore.h>
+#include <pulsecore/macro.h>
+#include <pulsecore/flist.h>
 =

 #include "memblock.h"
 =

@@ -47,6 +51,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 =3D=3D PA_MEMBLOCK_USER this points to a function f=
or 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 +85,8 @@
 };
 =

 struct pa_memimport {
+    pa_mutex *mutex;
+
     pa_mempool *pool;
     pa_hashmap *segments;
     pa_hashmap *blocks;
@@ -73,9 +105,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,21 +129,27 @@
 };
 =

 struct pa_mempool {
+    pa_semaphore *semaphore;
+    pa_mutex *mutex;
+
     pa_shm memory;
     size_t block_size;
-    unsigned n_blocks, n_init;
+    unsigned n_blocks;
+
+    pa_atomic_t n_init;
 =

     PA_LLIST_HEAD(pa_memimport, imports);
     PA_LLIST_HEAD(pa_memexport, exports);
 =

     /* A list of free slots that may be reused */
-    PA_LLIST_HEAD(struct mempool_slot, free_slots);
+    pa_flist *free_slots;
 =

     pa_mempool_stat stat;
 };
 =

 static void segment_detach(pa_memimport_segment *seg);
 =

+/* No lock necessary */
 static void stat_add(pa_memblock*b) {
     assert(b);
     assert(b->pool);
@@ -129,6 +169,7 @@
     pa_atomic_inc(&b->pool->stat.n_accumulated_by_type[b->type]);
 }
 =

+/* No lock necessary */
 static void stat_remove(pa_memblock *b) {
     assert(b);
     assert(b->pool);
@@ -152,6 +193,7 @@
 =

 static pa_memblock *memblock_new_appended(pa_mempool *p, size_t length);
 =

+/* No lock necessary */
 pa_memblock *pa_memblock_new(pa_mempool *p, size_t length) {
     pa_memblock *b;
 =

@@ -164,56 +206,70 @@
     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 =3D pa_xmalloc(sizeof(pa_memblock) + length);
+    b =3D pa_xmalloc(PA_ALIGN(sizeof(pa_memblock)) + length);
+    PA_REFCNT_INIT(b);
+    b->pool =3D p;
     b->type =3D PA_MEMBLOCK_APPENDED;
     b->read_only =3D 0;
-    PA_REFCNT_INIT(b);
+    pa_atomic_ptr_store(&b->data, (uint8_t*) b + PA_ALIGN(sizeof(pa_memblo=
ck)));
     b->length =3D length;
-    b->data =3D (uint8_t*) b + sizeof(pa_memblock);
-    b->pool =3D 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 =3D p->free_slots;
-        PA_LLIST_REMOVE(struct mempool_slot, p->free_slots, slot);
-    } else if (p->n_init < p->n_blocks)
-        slot =3D (struct mempool_slot*) ((uint8_t*) p->memory.ptr + (p->bl=
ock_size * p->n_init++));
-    else {
-        pa_log_debug("Pool full");
-        pa_atomic_inc(&p->stat.n_pool_full);
-        return NULL;
+    if (!(slot =3D pa_flist_pop(p->free_slots))) {
+        int idx;
+
+        /* The free list was empty, we have to allocate a new entry */
+
+        if ((unsigned) (idx =3D pa_atomic_inc(&p->n_init)) >=3D p->n_block=
s)
+            pa_atomic_dec(&p->n_init);
+        else
+            slot =3D (struct mempool_slot*) ((uint8_t*) p->memory.ptr + (p=
->block_size * idx));
+
+        if (!slot) {
+            pa_log_debug("Pool full");
+            pa_atomic_inc(&p->stat.n_pool_full);
+            return NULL;
+        }
     }
 =

     return slot;
 }
 =

+/* No lock necessary */
 static void* mempool_slot_data(struct mempool_slot *slot) {
     assert(slot);
 =

     return (uint8_t*) slot + sizeof(struct mempool_slot);
 }
 =

+/* No lock necessary */
 static unsigned mempool_slot_idx(pa_mempool *p, void *ptr) {
     assert(p);
+
     assert((uint8_t*) ptr >=3D (uint8_t*) p->memory.ptr);
     assert((uint8_t*) ptr < (uint8_t*) p->memory.ptr + p->memory.size);
 =

     return ((uint8_t*) ptr - (uint8_t*) p->memory.ptr) / p->block_size;
 }
 =

+/* No lock necessary */
 static struct mempool_slot* mempool_slot_by_ptr(pa_mempool *p, void *ptr) {
     unsigned idx;
 =

@@ -223,6 +279,7 @@
     return (struct mempool_slot*) ((uint8_t*) p->memory.ptr + (idx * p->bl=
ock_size));
 }
 =

+/* No lock necessary */
 pa_memblock *pa_memblock_new_pool(pa_mempool *p, size_t length) {
     pa_memblock *b =3D NULL;
     struct mempool_slot *slot;
@@ -237,7 +294,7 @@
 =

         b =3D mempool_slot_data(slot);
         b->type =3D PA_MEMBLOCK_POOL;
-        b->data =3D (uint8_t*) b + sizeof(pa_memblock);
+        pa_atomic_ptr_store(&b->data, (uint8_t*) b + sizeof(pa_memblock));
 =

     } else if (p->block_size - sizeof(struct mempool_slot) >=3D length) {
 =

@@ -246,22 +303,26 @@
 =

         b =3D pa_xnew(pa_memblock, 1);
         b->type =3D PA_MEMBLOCK_POOL_EXTERNAL;
-        b->data =3D mempool_slot_data(slot);
+        pa_atomic_ptr_store(&b->data, mempool_slot_data(slot));
+
     } else {
         pa_log_debug("Memory block too large for pool: %u > %u", length, p=
->block_size - sizeof(struct mempool_slot));
         pa_atomic_inc(&p->stat.n_too_large_for_pool);
         return NULL;
     }
 =

-    b->length =3D length;
-    b->read_only =3D 0;
     PA_REFCNT_INIT(b);
     b->pool =3D p;
+    b->read_only =3D 0;
+    b->length =3D length;
+    pa_atomic_store(&b->n_acquired, 0);
+    pa_atomic_store(&b->please_signal, 0);
 =

     stat_add(b);
     return b;
 }
 =

+/* No lock necessary */
 pa_memblock *pa_memblock_new_fixed(pa_mempool *p, void *d, size_t length, =
int read_only) {
     pa_memblock *b;
 =

@@ -270,17 +331,20 @@
     assert(length > 0);
 =

     b =3D pa_xnew(pa_memblock, 1);
+    PA_REFCNT_INIT(b);
+    b->pool =3D p;
     b->type =3D PA_MEMBLOCK_FIXED;
     b->read_only =3D read_only;
-    PA_REFCNT_INIT(b);
+    pa_atomic_ptr_store(&b->data, d);
     b->length =3D length;
-    b->data =3D d;
-    b->pool =3D 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, v=
oid (*free_cb)(void *p), int read_only) {
     pa_memblock *b;
 =

@@ -290,18 +354,68 @@
     assert(free_cb);
 =

     b =3D pa_xnew(pa_memblock, 1);
+    PA_REFCNT_INIT(b);
+    b->pool =3D p;
     b->type =3D PA_MEMBLOCK_USER;
     b->read_only =3D read_only;
-    PA_REFCNT_INIT(b);
+    pa_atomic_ptr_store(&b->data, d);
     b->length =3D length;
-    b->data =3D d;
+    pa_atomic_store(&b->n_acquired, 0);
+    pa_atomic_store(&b->please_signal, 0);
+
     b->per_type.user.free_cb =3D free_cb;
-    b->pool =3D p;
 =

     stat_add(b);
     return b;
 }
 =

+/* No lock necessary */
+int pa_memblock_is_read_only(pa_memblock *b) {
+    assert(b);
+    assert(PA_REFCNT_VALUE(b) > 0);
+
+    return b->read_only && PA_REFCNT_VALUE(b) =3D=3D 1;
+}
+
+/* No lock necessary */
+void* pa_memblock_acquire(pa_memblock *b) {
+    assert(b);
+    assert(PA_REFCNT_VALUE(b) > 0);
+
+    pa_atomic_inc(&b->n_acquired);
+
+    return pa_atomic_ptr_load(&b->data);
+}
+
+/* No lock necessary, in corner cases locks by its own */
+void pa_memblock_release(pa_memblock *b) {
+    int r;
+    assert(b);
+    assert(PA_REFCNT_VALUE(b) > 0);
+
+    r =3D pa_atomic_dec(&b->n_acquired);
+    assert(r >=3D 1);
+
+    /* Signal a waiting thread that this memblock is no longer used */
+    if (r =3D=3D 1 && pa_atomic_load(&b->please_signal))
+        pa_semaphore_post(b->pool->semaphore);
+}
+
+size_t pa_memblock_get_length(pa_memblock *b) {
+    assert(b);
+    assert(PA_REFCNT_VALUE(b) > 0);
+
+    return b->length;
+}
+
+pa_mempool* pa_memblock_get_pool(pa_memblock *b) {
+    assert(b);
+    assert(PA_REFCNT_VALUE(b) > 0);
+
+    return b->pool;
+}
+
+/* No lock necessary */
 pa_memblock* pa_memblock_ref(pa_memblock*b) {
     assert(b);
     assert(PA_REFCNT_VALUE(b) > 0);
@@ -310,19 +424,17 @@
     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) {
+    assert(b);
+
+    assert(pa_atomic_load(&b->n_acquired) =3D=3D 0);
 =

     stat_remove(b);
 =

     switch (b->type) {
         case PA_MEMBLOCK_USER :
             assert(b->per_type.user.free_cb);
-            b->per_type.user.free_cb(b->data);
+            b->per_type.user.free_cb(pa_atomic_ptr_load(&b->data));
 =

             /* Fall through */
 =

@@ -333,16 +445,23 @@
 =

         case PA_MEMBLOCK_IMPORTED : {
             pa_memimport_segment *segment;
+            pa_memimport *import;
+
+            /* FIXME! This should be implemented lock-free */
 =

             segment =3D 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.impor=
ted.id, segment->import->userdata);
-
+            import =3D segment->import;
+            assert(import);
+
+            pa_mutex_lock(import->mutex);
+            pa_hashmap_remove(import->blocks, PA_UINT32_TO_PTR(b->per_type=
.imported.id));
             if (-- segment->n_blocks <=3D 0)
                 segment_detach(segment);
+
+            pa_mutex_unlock(import->mutex);
+
+            import->release_cb(import, b->per_type.imported.id, import->us=
erdata);
 =

             pa_xfree(b);
             break;
@@ -351,13 +470,20 @@
         case PA_MEMBLOCK_POOL_EXTERNAL:
         case PA_MEMBLOCK_POOL: {
             struct mempool_slot *slot;
-
-            slot =3D mempool_slot_by_ptr(b->pool, b->data);
+            int call_free;
+
+            slot =3D mempool_slot_by_ptr(b->pool, pa_atomic_ptr_load(&b->d=
ata));
             assert(slot);
 =

-            PA_LLIST_PREPEND(struct mempool_slot, b->pool->free_slots, slo=
t);
-
-            if (b->type =3D=3D PA_MEMBLOCK_POOL_EXTERNAL)
+            call_free =3D b->type =3D=3D PA_MEMBLOCK_POOL_EXTERNAL;
+
+            /* The free list dimensions should easily allow all slots
+             * to fit in, hence try harder if pushing this slot into
+             * the free list fails */
+            while (pa_flist_push(b->pool->free_slots, slot) < 0)
+                ;
+
+            if (call_free)
                 pa_xfree(b);
 =

             break;
@@ -369,6 +495,36 @@
     }
 }
 =

+/* No lock necessary */
+void pa_memblock_unref(pa_memblock*b) {
+    assert(b);
+    assert(PA_REFCNT_VALUE(b) > 0);
+
+    if (PA_REFCNT_DEC(b) > 0)
+        return;
+
+    memblock_free(b);
+}
+
+/* Self locked */
+static void memblock_wait(pa_memblock *b) {
+    assert(b);
+
+    if (pa_atomic_load(&b->n_acquired) > 0) {
+        /* We need to wait until all threads gave up access to the
+         * memory block before we can go on. Unfortunately this means
+         * that we have to lock and wait here. Sniff! */
+
+        pa_atomic_inc(&b->please_signal);
+
+        while (pa_atomic_load(&b->n_acquired) > 0)
+            pa_semaphore_wait(b->pool->semaphore);
+
+        pa_atomic_dec(&b->please_signal);
+    }
+}
+
+/* No lock necessary. This function is not multiple caller safe! */
 static void memblock_make_local(pa_memblock *b) {
     assert(b);
 =

@@ -381,38 +537,43 @@
             void *new_data;
             /* We can move it into a local pool, perfect! */
 =

+            new_data =3D 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 =3D PA_MEMBLOCK_POOL_EXTERNAL;
             b->read_only =3D 0;
 =

-            new_data =3D mempool_slot_data(slot);
-            memcpy(new_data, b->data, b->length);
-            b->data =3D new_data;
             goto finish;
         }
     }
 =

     /* Humm, not enough space in the pool, so lets allocate the memory wit=
h malloc() */
+    b->per_type.user.free_cb =3D pa_xfree;
+    pa_atomic_ptr_store(&b->data, pa_xmemdup(pa_atomic_ptr_load(&b->data),=
 b->length));
+
     b->type =3D PA_MEMBLOCK_USER;
-    b->per_type.user.free_cb =3D pa_xfree;
     b->read_only =3D 0;
-    b->data =3D 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 =3D=3D PA_MEMBLOCK_FIXED);
 =

-    if (PA_REFCNT_VALUE(b) > 1)
+    if (PA_REFCNT_DEC(b) > 0)
         memblock_make_local(b);
-
-    pa_memblock_unref(b);
-}
-
+    else
+        memblock_free(b);
+}
+
+/* Self-locked. This function is not multiple-caller safe */
 static void memblock_replace_import(pa_memblock *b) {
     pa_memimport_segment *seg;
 =

@@ -428,6 +589,8 @@
     assert(seg);
     assert(seg->import);
 =

+    pa_mutex_lock(seg->import->mutex);
+
     pa_hashmap_remove(
             seg->import->blocks,
             PA_UINT32_TO_PTR(b->per_type.imported.id));
@@ -436,6 +599,8 @@
 =

     if (-- seg->n_blocks <=3D 0)
         segment_detach(seg);
+
+    pa_mutex_unlock(seg->import->mutex);
 }
 =

 pa_mempool* pa_mempool_new(int shared) {
@@ -444,12 +609,15 @@
 =

     p =3D pa_xnew(pa_mempool, 1);
 =

+    p->mutex =3D pa_mutex_new(1);
+    p->semaphore =3D pa_semaphore_new(0);
+
 #ifdef HAVE_SYSCONF
     ps =3D (size_t) sysconf(_SC_PAGESIZE);
 #elif defined(PAGE_SIZE)
-	ps =3D (size_t) PAGE_SIZE;
+    ps =3D (size_t) PAGE_SIZE;
 #else
-	ps =3D 4096; /* Let's hope it's like x86. */
+    ps =3D 4096; /* Let's hope it's like x86. */
 #endif
 =

     p->block_size =3D (PA_MEMPOOL_SLOT_SIZE/ps)*ps;
@@ -466,19 +634,21 @@
         return NULL;
     }
 =

-    p->n_init =3D 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 =3D pa_flist_new(p->n_blocks*2);
 =

     return p;
 }
 =

 void pa_mempool_free(pa_mempool *p) {
     assert(p);
+
+    pa_mutex_lock(p->mutex);
 =

     while (p->imports)
         pa_memimport_free(p->imports);
@@ -486,28 +656,53 @@
     while (p->exports)
         pa_memexport_free(p->exports);
 =

+    pa_mutex_unlock(p->mutex);
+
     if (pa_atomic_load(&p->stat.n_allocated) > 0)
         pa_log_warn("WARNING! Memory pool destroyed but not all memory blo=
cks freed!");
 =

+    pa_flist_free(p->free_slots, NULL);
     pa_shm_free(&p->memory);
+
+    pa_mutex_free(p->mutex);
+    pa_semaphore_free(p->semaphore);
+
     pa_xfree(p);
 }
 =

+/* No lock necessary */
 const pa_mempool_stat* pa_mempool_get_stat(pa_mempool *p) {
     assert(p);
 =

     return &p->stat;
 }
 =

+/* No lock necessary */
 void pa_mempool_vacuum(pa_mempool *p) {
     struct mempool_slot *slot;
-
-    assert(p);
-
-    for (slot =3D p->free_slots; slot; slot =3D slot->next)
-        pa_shm_punch(&p->memory, (uint8_t*) slot + sizeof(struct mempool_s=
lot) - (uint8_t*) p->memory.ptr, p->block_size - sizeof(struct mempool_slot=
));
-}
-
+    pa_flist *list;
+
+    assert(p);
+
+    list =3D pa_flist_new(p->n_blocks*2);
+
+    while ((slot =3D pa_flist_pop(p->free_slots)))
+        while (pa_flist_push(list, slot) < 0)
+            ;
+
+    while ((slot =3D pa_flist_pop(list))) {
+        pa_shm_punch(&p->memory,
+                     (uint8_t*) slot - (uint8_t*) p->memory.ptr + sizeof(s=
truct mempool_slot),
+                     p->block_size - sizeof(struct mempool_slot));
+
+        while (pa_flist_push(p->free_slots, slot))
+            ;
+    }
+
+    pa_flist_free(list, NULL);
+}
+
+/* No lock necessary */
 int pa_mempool_get_shm_id(pa_mempool *p, uint32_t *id) {
     assert(p);
 =

@@ -519,6 +714,7 @@
     return 0;
 }
 =

+/* No lock necessary */
 int pa_mempool_is_shared(pa_mempool *p) {
     assert(p);
 =

@@ -533,18 +729,23 @@
     assert(cb);
 =

     i =3D pa_xnew(pa_memimport, 1);
+    i->mutex =3D pa_mutex_new(0);
     i->pool =3D p;
     i->segments =3D pa_hashmap_new(NULL, NULL);
     i->blocks =3D pa_hashmap_new(NULL, NULL);
     i->release_cb =3D cb;
     i->userdata =3D userdata;
 =

+    pa_mutex_lock(p->mutex);
     PA_LLIST_PREPEND(pa_memimport, p->imports, i);
+    pa_mutex_unlock(p->mutex);
+
     return i;
 }
 =

 static void memexport_revoke_blocks(pa_memexport *e, pa_memimport *i);
 =

+/* Should be called locked */
 static pa_memimport_segment* segment_attach(pa_memimport *i, uint32_t shm_=
id) {
     pa_memimport_segment* seg;
 =

@@ -565,6 +766,7 @@
     return seg;
 }
 =

+/* Should be called locked */
 static void segment_detach(pa_memimport_segment *seg) {
     assert(seg);
 =

@@ -573,51 +775,68 @@
     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_mutex_lock(i->mutex);
+
+    while ((b =3D pa_hashmap_get_first(i->blocks)))
+        memblock_replace_import(b);
+
+    assert(pa_hashmap_size(i->segments) =3D=3D 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 =3D i->pool->exports; e; e =3D e->next)
         memexport_revoke_blocks(e, i);
 =

-    while ((b =3D pa_hashmap_get_first(i->blocks)))
-        memblock_replace_import(b);
-
-    assert(pa_hashmap_size(i->segments) =3D=3D 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 =3D NULL;
     pa_memimport_segment *seg;
 =

     assert(i);
 =

+    pa_mutex_lock(i->mutex);
+
     if (pa_hashmap_size(i->blocks) >=3D PA_MEMIMPORT_SLOTS_MAX)
-        return NULL;
+        goto finish;
 =

     if (!(seg =3D pa_hashmap_get(i->segments, PA_UINT32_TO_PTR(shm_id))))
         if (!(seg =3D segment_attach(i, shm_id)))
-            return NULL;
+            goto finish;
 =

     if (offset+size > seg->memory.size)
-        return NULL;
+        goto finish;
 =

     b =3D pa_xnew(pa_memblock, 1);
+    PA_REFCNT_INIT(b);
+    b->pool =3D i->pool;
     b->type =3D PA_MEMBLOCK_IMPORTED;
     b->read_only =3D 1;
-    PA_REFCNT_INIT(b);
+    pa_atomic_ptr_store(&b->data, (uint8_t*) seg->memory.ptr + offset);
     b->length =3D size;
-    b->data =3D (uint8_t*) seg->memory.ptr + offset;
-    b->pool =3D i->pool;
+    pa_atomic_store(&b->n_acquired, 0);
+    pa_atomic_store(&b->please_signal, 0);
     b->per_type.imported.id =3D block_id;
     b->per_type.imported.segment =3D seg;
 =

@@ -625,6 +844,10 @@
 =

     seg->n_blocks++;
 =

+finish:
+    pa_mutex_unlock(i->mutex);
+
+    if (b)
     stat_add(b);
 =

     return b;
@@ -634,10 +857,15 @@
     pa_memblock *b;
     assert(i);
 =

+    pa_mutex_lock(i->mutex);
+
     if (!(b =3D pa_hashmap_get(i->blocks, PA_UINT32_TO_PTR(id))))
         return -1;
 =

     memblock_replace_import(b);
+
+    pa_mutex_unlock(i->mutex);
+
     return 0;
 }
 =

@@ -652,6 +880,7 @@
         return NULL;
 =

     e =3D pa_xnew(pa_memexport, 1);
+    e->mutex =3D pa_mutex_new(1);
     e->pool =3D p;
     PA_LLIST_HEAD_INIT(struct memexport_slot, e->free_slots);
     PA_LLIST_HEAD_INIT(struct memexport_slot, e->used_slots);
@@ -659,51 +888,75 @@
     e->revoke_cb =3D cb;
     e->userdata =3D userdata;
 =

+    pa_mutex_lock(p->mutex);
     PA_LLIST_PREPEND(pa_memexport, p->exports, e);
+    pa_mutex_unlock(p->mutex);
     return e;
 }
 =

 void pa_memexport_free(pa_memexport *e) {
     assert(e);
 =

+    pa_mutex_lock(e->mutex);
     while (e->used_slots)
         pa_memexport_process_release(e, e->used_slots - e->slots);
-
+    pa_mutex_unlock(e->mutex);
+
+    pa_mutex_lock(e->pool->mutex);
     PA_LLIST_REMOVE(pa_memexport, e->pool->exports, e);
+    pa_mutex_unlock(e->pool->mutex);
+
     pa_xfree(e);
 }
 =

+/* Self-locked */
 int pa_memexport_process_release(pa_memexport *e, uint32_t id) {
+    pa_memblock *b;
+
     assert(e);
 =

+    pa_mutex_lock(e->mutex);
+
     if (id >=3D 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) >=3D (int) e->slot=
s[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 =3D e->slots[id].block;
     e->slots[id].block =3D NULL;
 =

     PA_LLIST_REMOVE(struct memexport_slot, e->used_slots, &e->slots[id]);
     PA_LLIST_PREPEND(struct memexport_slot, e->free_slots, &e->slots[id]);
 =

+    pa_mutex_unlock(e->mutex);
+
+/*     pa_log("Processing release for %u", id); */
+
+    assert(pa_atomic_load(&e->pool->stat.n_exported) > 0);
+    assert(pa_atomic_load(&e->pool->stat.exported_size) >=3D (int) b->leng=
th);
+
+    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_mutex_lock(e->mutex);
+
     for (slot =3D e->used_slots; slot; slot =3D next) {
         uint32_t idx;
         next =3D slot->next;
@@ -716,8 +969,11 @@
         e->revoke_cb(e, idx, e->userdata);
         pa_memexport_process_release(e, idx);
     }
-}
-
+
+    pa_mutex_unlock(e->mutex);
+}
+
+/* No lock necessary */
 static pa_memblock *memblock_shared_copy(pa_mempool *p, pa_memblock *b) {
     pa_memblock *n;
 =

@@ -734,13 +990,16 @@
     if (!(n =3D pa_memblock_new_pool(p, b->length)))
         return NULL;
 =

-    memcpy(n->data, b->data, b->length);
+    memcpy(pa_atomic_ptr_load(&n->data), pa_atomic_ptr_load(&b->data), b->=
length);
     return n;
 }
 =

+/* Self-locked */
 int pa_memexport_put(pa_memexport *e, pa_memblock *b, uint32_t *block_id, =
uint32_t *shm_id, size_t *offset, size_t * size) {
     pa_shm *memory;
     struct memexport_slot *slot;
+    void *data;
+    size_t length;
 =

     assert(e);
     assert(b);
@@ -753,12 +1012,15 @@
     if (!(b =3D memblock_shared_copy(e->pool, b)))
         return -1;
 =

+    pa_mutex_lock(e->mutex);
+
     if (e->free_slots) {
         slot =3D 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 =3D &e->slots[e->n_init++];
-    } else {
+    else {
+        pa_mutex_unlock(e->mutex);
         pa_memblock_unref(b);
         return -1;
     }
@@ -767,7 +1029,10 @@
     slot->block =3D b;
     *block_id =3D slot - e->slots;
 =

+    pa_mutex_unlock(e->mutex);
 /*     pa_log("Got block id %u", *block_id); */
+
+    data =3D pa_memblock_acquire(b);
 =

     if (b->type =3D=3D PA_MEMBLOCK_IMPORTED) {
         assert(b->per_type.imported.segment);
@@ -778,15 +1043,17 @@
         memory =3D &b->pool->memory;
     }
 =

-    assert(b->data >=3D memory->ptr);
-    assert((uint8_t*) b->data + b->length <=3D (uint8_t*) memory->ptr + me=
mory->size);
+    assert(data >=3D memory->ptr);
+    assert((uint8_t*) data + length <=3D (uint8_t*) memory->ptr + memory->=
size);
 =

     *shm_id =3D memory->id;
-    *offset =3D (uint8_t*) b->data - (uint8_t*) memory->ptr;
-    *size =3D b->length;
+    *offset =3D (uint8_t*) data - (uint8_t*) memory->ptr;
+    *size =3D length;
+
+    pa_memblock_release(b);
 =

     pa_atomic_inc(&e->pool->stat.n_exported);
-    pa_atomic_add(&e->pool->stat.exported_size, b->length);
+    pa_atomic_add(&e->pool->stat.exported_size, length);
 =

     return 0;
 }

Modified: branches/lennart/src/pulsecore/memblock.h
URL: http://0pointer.de/cgi-bin/viewcvs.cgi/branches/lennart/src/pulsecore/=
memblock.h?rev=3D1469&root=3Dpulseaudio&r1=3D1468&r2=3D1469&view=3Ddiff
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D
--- branches/lennart/src/pulsecore/memblock.h (original)
+++ branches/lennart/src/pulsecore/memblock.h Mon Jun 11 14:08:37 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_i=
d, 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 =3D=3D 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,16 @@
 /* This special unref function has to be called by the owner of the
 memory of a static memory block when he wants to release all
 references to the memory. This causes the memory to be copied and
-converted into a PA_MEMBLOCK_DYNAMIC type memory block */
+converted into a pool or malloc'ed memory block. Please note that this
+function is not multiple caller safe, i.e. needs to be locked
+manually if called from more than one thread at the same time.  */
 void pa_memblock_unref_fixed(pa_memblock*b);
+
+int pa_memblock_is_read_only(pa_memblock *b);
+void* pa_memblock_acquire(pa_memblock *b);
+void pa_memblock_release(pa_memblock *b);
+size_t pa_memblock_get_length(pa_memblock *b);
+pa_mempool * pa_memblock_get_pool(pa_memblock *b);
 =

 /* The memory block manager */
 pa_mempool* pa_mempool_new(int shared);

Modified: branches/lennart/src/pulsecore/memblockq.c
URL: http://0pointer.de/cgi-bin/viewcvs.cgi/branches/lennart/src/pulsecore/=
memblockq.c?rev=3D1469&root=3Dpulseaudio&r1=3D1468&r2=3D1469&view=3Ddiff
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D
--- branches/lennart/src/pulsecore/memblockq.c (original)
+++ branches/lennart/src/pulsecore/memblockq.c Mon Jun 11 14:08:37 2007
@@ -178,7 +178,7 @@
     assert(uchunk);
     assert(uchunk->memblock);
     assert(uchunk->length > 0);
-    assert(uchunk->index + uchunk->length <=3D uchunk->memblock->length);
+    assert(uchunk->index + uchunk->length <=3D pa_memblock_get_length(uchu=
nk->memblock));
 =

     if (uchunk->length % bq->base)
         return -1;
@@ -362,8 +362,8 @@
         if (bq->silence) {
             chunk->memblock =3D pa_memblock_ref(bq->silence);
 =

-            if (!length || length > chunk->memblock->length)
-                length =3D chunk->memblock->length;
+            if (!length || length > pa_memblock_get_length(chunk->memblock=
))
+                length =3D pa_memblock_get_length(chunk->memblock);
 =

             chunk->length =3D length;
         } else {
@@ -415,8 +415,8 @@
 =

             if (bq->silence) {
 =

-                if (!l || l > bq->silence->length)
-                    l =3D bq->silence->length;
+                if (!l || l > pa_memblock_get_length(bq->silence))
+                    l =3D pa_memblock_get_length(bq->silence);
 =

             }
 =


Modified: branches/lennart/src/pulsecore/memchunk.c
URL: http://0pointer.de/cgi-bin/viewcvs.cgi/branches/lennart/src/pulsecore/=
memchunk.c?rev=3D1469&root=3Dpulseaudio&r1=3D1468&r2=3D1469&view=3Ddiff
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D
--- branches/lennart/src/pulsecore/memchunk.c (original)
+++ branches/lennart/src/pulsecore/memchunk.c Mon Jun 11 14:08:37 2007
@@ -37,22 +37,25 @@
 void pa_memchunk_make_writable(pa_memchunk *c, size_t min) {
     pa_memblock *n;
     size_t l;
+    void *tdata, *sdata;
 =

     assert(c);
     assert(c->memblock);
-    assert(PA_REFCNT_VALUE(c->memblock) > 0);
 =

-    if (PA_REFCNT_VALUE(c->memblock) =3D=3D 1 &&
-        !c->memblock->read_only &&
-        c->memblock->length >=3D c->index+min)
+    if (pa_memblock_is_read_only(c->memblock) &&
+        pa_memblock_get_length(c->memblock) >=3D c->index+min)
         return;
 =

     l =3D c->length;
     if (l < min)
         l =3D min;
 =

-    n =3D pa_memblock_new(c->memblock->pool, l);
-    memcpy(n->data, (uint8_t*) c->memblock->data + c->index, c->length);
+    n =3D pa_memblock_new(pa_memblock_get_pool(c->memblock), l);
+    tdata =3D pa_memblock_acquire(n);
+    sdata =3D 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 =3D n;
     c->index =3D 0;

Added: branches/lennart/src/pulsecore/msgobject.c
URL: http://0pointer.de/cgi-bin/viewcvs.cgi/branches/lennart/src/pulsecore/=
msgobject.c?rev=3D1469&root=3Dpulseaudio&view=3Dauto
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D
--- branches/lennart/src/pulsecore/msgobject.c (added)
+++ branches/lennart/src/pulsecore/msgobject.c Mon Jun 11 14:08:37 2007
@@ -1,0 +1,40 @@
+/* $Id$ */
+
+/***
+  This file is part of PulseAudio.
+
+  Copyright 2004-2006 Lennart Poettering
+  Copyright 2006 Pierre Ossman <ossman at cendio.se> for Cendio AB
+
+  PulseAudio is free software; you can redistribute it and/or modify
+  it under the terms of the GNU Lesser General Public License as published
+  by the Free Software Foundation; either version 2 of the License,
+  or (at your option) any later version.
+
+  PulseAudio is distributed in the hope that it will be useful, but
+  WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+  General Public License for more details.
+
+  You should have received a copy of the GNU Lesser General Public License
+  along with PulseAudio; if not, write to the Free Software
+  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+  USA.
+***/
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "msgobject.h"
+
+pa_msgobject *pa_msgobject_new_internal(size_t size, const char *type_name=
) {
+    pa_msgobject *o;
+    =

+    pa_assert(size > sizeof(pa_msgobject));
+    pa_assert(type_name);
+
+    o =3D PA_MSGOBJECT(pa_object_new_internal(size, type_name));
+    o->process_msg =3D NULL;
+    return o;
+}

Propchange: branches/lennart/src/pulsecore/msgobject.c
---------------------------------------------------------------------------=
---
    svn:keywords =3D Id

Added: branches/lennart/src/pulsecore/msgobject.h
URL: http://0pointer.de/cgi-bin/viewcvs.cgi/branches/lennart/src/pulsecore/=
msgobject.h?rev=3D1469&root=3Dpulseaudio&view=3Dauto
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D
--- branches/lennart/src/pulsecore/msgobject.h (added)
+++ branches/lennart/src/pulsecore/msgobject.h Mon Jun 11 14:08:37 2007
@@ -1,0 +1,52 @@
+#ifndef foopulsemsgobjecthfoo
+#define foopulsemsgobjecthfoo
+
+/* $Id$ */
+
+/***
+  This file is part of PulseAudio.
+
+  Copyright 2004-2006 Lennart Poettering
+  Copyright 2006 Pierre Ossman <ossman at cendio.se> for Cendio AB
+
+  PulseAudio is free software; you can redistribute it and/or modify
+  it under the terms of the GNU Lesser General Public License as published
+  by the Free Software Foundation; either version 2 of the License,
+  or (at your option) any later version.
+
+  PulseAudio is distributed in the hope that it will be useful, but
+  WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+  General Public License for more details.
+
+  You should have received a copy of the GNU Lesser General Public License
+  along with PulseAudio; if not, write to the Free Software
+  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+  USA.
+***/
+
+#include <sys/types.h>
+
+#include <pulse/xmalloc.h>
+#include <pulsecore/refcnt.h>
+#include <pulsecore/macro.h>
+#include <pulsecore/object.h>
+#include <pulsecore/memchunk.h>
+
+typedef struct pa_msgobject pa_msgobject;
+
+struct pa_msgobject {
+    pa_object parent;
+    int (*process_msg)(pa_msgobject *o, int code, void *userdata, pa_memch=
unk *chunk);
+};
+
+pa_msgobject *pa_msgobject_new_internal(size_t size, const char *type_name=
);
+
+#define pa_msgobject_new(type) ((type*) pa_msgobject_new_internal(sizeof(t=
ype), #type))
+#define pa_msgobject_free ((void (*) (pa_msgobject* o)) pa_object_free)
+
+#define PA_MSGOBJECT(o) ((pa_msgobject*) (o))
+
+PA_DECLARE_CLASS(pa_msgobject);
+
+#endif

Propchange: branches/lennart/src/pulsecore/msgobject.h
---------------------------------------------------------------------------=
---
    svn:keywords =3D Id

Modified: branches/lennart/src/pulsecore/mutex-posix.c
URL: http://0pointer.de/cgi-bin/viewcvs.cgi/branches/lennart/src/pulsecore/=
mutex-posix.c?rev=3D1469&root=3Dpulseaudio&r1=3D1468&r2=3D1469&view=3Ddiff
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D
--- branches/lennart/src/pulsecore/mutex-posix.c (original)
+++ branches/lennart/src/pulsecore/mutex-posix.c Mon Jun 11 14:08:37 2007
@@ -27,8 +27,6 @@
 =

 #include <assert.h>
 #include <pthread.h>
-
-#include <atomic_ops.h>
 =

 #include <pulse/xmalloc.h>
 =


Added: branches/lennart/src/pulsecore/object.c
URL: http://0pointer.de/cgi-bin/viewcvs.cgi/branches/lennart/src/pulsecore/=
object.c?rev=3D1469&root=3Dpulseaudio&view=3Dauto
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D
--- branches/lennart/src/pulsecore/object.c (added)
+++ branches/lennart/src/pulsecore/object.c Mon Jun 11 14:08:37 2007
@@ -1,0 +1,61 @@
+/* $Id$ */
+
+/***
+  This file is part of PulseAudio.
+
+  Copyright 2004-2006 Lennart Poettering
+  Copyright 2006 Pierre Ossman <ossman at cendio.se> for Cendio AB
+
+  PulseAudio is free software; you can redistribute it and/or modify
+  it under the terms of the GNU Lesser General Public License as published
+  by the Free Software Foundation; either version 2 of the License,
+  or (at your option) any later version.
+
+  PulseAudio is distributed in the hope that it will be useful, but
+  WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+  General Public License for more details.
+
+  You should have received a copy of the GNU Lesser General Public License
+  along with PulseAudio; if not, write to the Free Software
+  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+  USA.
+***/
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "object.h"
+
+pa_object *pa_object_new_internal(size_t size, const char *type_name) {
+    pa_object *o;
+    =

+    pa_assert(size > sizeof(pa_object));
+    pa_assert(type_name);
+
+    o =3D pa_xmalloc(size);
+    PA_REFCNT_INIT(o);
+    o->type_name =3D type_name;
+    o->free =3D pa_object_free;
+
+    return o;
+}
+
+pa_object *pa_object_ref(pa_object *o) {
+    pa_assert(o);
+    pa_assert(PA_REFCNT_VALUE(o) >=3D 1);
+
+    PA_REFCNT_INC(o);
+    return o;
+}
+
+void pa_object_unref(pa_object *o) {
+    pa_assert(o);
+    pa_assert(PA_REFCNT_VALUE(o) >=3D 1);
+
+    if (PA_REFCNT_DEC(o) <=3D 0) {
+        pa_assert(o->free);
+        o->free(o);
+    }
+}

Propchange: branches/lennart/src/pulsecore/object.c
---------------------------------------------------------------------------=
---
    svn:keywords =3D Id

Added: branches/lennart/src/pulsecore/object.h
URL: http://0pointer.de/cgi-bin/viewcvs.cgi/branches/lennart/src/pulsecore/=
object.h?rev=3D1469&root=3Dpulseaudio&view=3Dauto
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D
--- branches/lennart/src/pulsecore/object.h (added)
+++ branches/lennart/src/pulsecore/object.h Mon Jun 11 14:08:37 2007
@@ -1,0 +1,72 @@
+#ifndef foopulseobjecthfoo
+#define foopulseobjecthfoo
+
+/* $Id$ */
+
+/***
+  This file is part of PulseAudio.
+
+  Copyright 2004-2006 Lennart Poettering
+  Copyright 2006 Pierre Ossman <ossman at cendio.se> for Cendio AB
+
+  PulseAudio is free software; you can redistribute it and/or modify
+  it under the terms of the GNU Lesser General Public License as published
+  by the Free Software Foundation; either version 2 of the License,
+  or (at your option) any later version.
+
+  PulseAudio is distributed in the hope that it will be useful, but
+  WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+  General Public License for more details.
+
+  You should have received a copy of the GNU Lesser General Public License
+  along with PulseAudio; if not, write to the Free Software
+  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+  USA.
+***/
+
+#include <sys/types.h>
+#include <pulse/xmalloc.h>
+#include <pulsecore/refcnt.h>
+#include <pulsecore/macro.h>
+
+typedef struct pa_object pa_object;
+
+struct pa_object {
+    PA_REFCNT_DECLARE;
+    const char *type_name;
+    void (*free)(pa_object *o);
+};
+
+pa_object *pa_object_new_internal(size_t size, const char *type_name);
+#define pa_object_new(type) ((type*) pa_object_new_internal(sizeof(type), =
#type))
+
+#define pa_object_free ((void (*) (pa_object* o)) pa_xfree)
+
+pa_object *pa_object_ref(pa_object *o);
+void pa_object_unref(pa_object *o);
+
+static inline int pa_object_refcnt(pa_object *o) {
+    return o ? PA_REFCNT_VALUE(o) : 0;
+}
+
+#define pa_object_assert_ref(o) pa_assert(pa_object_refcnt(o))
+
+#define PA_OBJECT(o) ((pa_object*) (o))
+
+#define PA_DECLARE_CLASS(c) \
+    static inline c* c##_ref(c *o) {                            \
+        return (c*) pa_object_ref(PA_OBJECT(o));                \
+    }                                                           \
+    static inline void c##_unref(c* o) {                        \
+        pa_object_unref(PA_OBJECT(o));                          \
+    }                                                           \
+    static inline int c##_refcnt(c* o) {                        \
+        return pa_object_refcnt(PA_OBJECT(o));                  \
+    }                                                           \
+    static inline void c##_assert_ref(c *o) {                   \
+        pa_object_assert_ref(PA_OBJECT(o));                     \
+    }                                                           \
+    struct __stupid_useless_struct_to_allow_trailing_semicolon
+        =

+#endif

Propchange: branches/lennart/src/pulsecore/object.h
---------------------------------------------------------------------------=
---
    svn:keywords =3D Id

Modified: branches/lennart/src/pulsecore/once-posix.c
URL: http://0pointer.de/cgi-bin/viewcvs.cgi/branches/lennart/src/pulsecore/=
once-posix.c?rev=3D1469&root=3Dpulseaudio&r1=3D1468&r2=3D1469&view=3Ddiff
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D
--- branches/lennart/src/pulsecore/once-posix.c (original)
+++ branches/lennart/src/pulsecore/once-posix.c Mon Jun 11 14:08:37 2007
@@ -26,44 +26,56 @@
 #endif
 =

 #include <pthread.h>
-#include <assert.h>
 =

+#include <pulsecore/macro.h>
 #include <pulsecore/mutex.h>
 =

 #include "once.h"
 =

-#define ASSERT_SUCCESS(x) do { \
-    int _r =3D (x); \
-    assert(_r =3D=3D 0); \
-} while(0)
+/* Not reentrant -- how could it be? */
+void pa_once(pa_once_t *control, pa_once_func_t func) {
+    pa_mutex *m;
+    =

+    pa_assert(control);
+    pa_assert(func);
 =

-static pa_mutex *global_mutex;
-static pthread_once_t global_mutex_once =3D PTHREAD_ONCE_INIT;
+    if (pa_atomic_load(&control->done))
+        return;
+    =

+    pa_atomic_inc(&control->ref);
+        =

+    for (;;) {
+        =

+        if ((m =3D pa_atomic_ptr_load(&control->mutex))) {
 =

-static void global_mutex_once_func(void) {
-    global_mutex =3D pa_mutex_new(0);
-}
+            /* The mutex is stored in locked state, hence let's just
+             * wait until it is unlocked */
+            pa_mutex_lock(m);
+            pa_mutex_unlock(m);
+            break;
+        }
 =

-void pa_once(pa_once_t *control, pa_once_func_t func) {
-    assert(control);
-    assert(func);
+        pa_assert_se(m =3D pa_mutex_new(0));
+        pa_mutex_lock(m);
+        =

+        if (pa_atomic_ptr_cmpxchg(&control->mutex, NULL, m)) {
+            func();
+            pa_atomic_store(&control->done, 1);
+            pa_mutex_unlock(m);
 =

-    /* Create the global mutex */
-    ASSERT_SUCCESS(pthread_once(&global_mutex_once, global_mutex_once_func=
));
+            break;
+        }
 =

-    /* Create the local mutex */
-    pa_mutex_lock(global_mutex);
-    if (!control->mutex)
-        control->mutex =3D pa_mutex_new(1);
-    pa_mutex_unlock(global_mutex);
+        pa_mutex_unlock(m);
+        pa_mutex_free(m);
+    }
 =

-    /* Execute function */
-    pa_mutex_lock(control->mutex);
-    if (!control->once_value) {
-        control->once_value =3D 1;
-        func();
+    pa_assert(pa_atomic_load(&control->done));
+    =

+    if (pa_atomic_dec(&control->ref) <=3D 1) {
+        pa_assert(pa_atomic_ptr_cmpxchg(&control->mutex, m, NULL));
+        pa_mutex_free(m);
     }
-    pa_mutex_unlock(control->mutex);
 =

     /* Caveat: We have to make sure that the once func has completed
      * before returning, even if the once func is not actually

Modified: branches/lennart/src/pulsecore/once.h
URL: http://0pointer.de/cgi-bin/viewcvs.cgi/branches/lennart/src/pulsecore/=
once.h?rev=3D1469&root=3Dpulseaudio&r1=3D1468&r2=3D1469&view=3Ddiff
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D
--- branches/lennart/src/pulsecore/once.h (original)
+++ branches/lennart/src/pulsecore/once.h Mon Jun 11 14:08:37 2007
@@ -25,13 +25,19 @@
 ***/
 =

 #include <pulsecore/mutex.h>
+#include <pulsecore/atomic.h>
 =

 typedef struct pa_once {
-    unsigned int once_value;
-    pa_mutex *mutex;
+    pa_atomic_ptr_t mutex;
+    pa_atomic_t ref, done;
 } pa_once_t;
 =

-#define PA_ONCE_INIT { .once_value =3D 0, .mutex =3D NULL }
+#define PA_ONCE_INIT                                                    \
+    {                                                                   \
+        .mutex =3D PA_ATOMIC_PTR_INIT(NULL),                              \
+        .ref =3D PA_ATOMIC_INIT(0),                                   \
+        .done =3D PA_ATOMIC_INIT(0)                                   \
+    }
 =

 typedef void (*pa_once_func_t) (void);
 =


Modified: branches/lennart/src/pulsecore/play-memblockq.c
URL: http://0pointer.de/cgi-bin/viewcvs.cgi/branches/lennart/src/pulsecore/=
play-memblockq.c?rev=3D1469&root=3Dpulseaudio&r1=3D1468&r2=3D1469&view=3Ddi=
ff
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D
--- branches/lennart/src/pulsecore/play-memblockq.c (original)
+++ branches/lennart/src/pulsecore/play-memblockq.c Mon Jun 11 14:08:37 2007
@@ -122,7 +122,5 @@
 =

     si->userdata =3D q;
 =

-    pa_sink_notify(si->sink);
-
     return 0;
 }

Modified: branches/lennart/src/pulsecore/play-memchunk.c
URL: http://0pointer.de/cgi-bin/viewcvs.cgi/branches/lennart/src/pulsecore/=
play-memchunk.c?rev=3D1469&root=3Dpulseaudio&r1=3D1468&r2=3D1469&view=3Ddiff
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D
--- branches/lennart/src/pulsecore/play-memchunk.c (original)
+++ branches/lennart/src/pulsecore/play-memchunk.c Mon Jun 11 14:08:37 2007
@@ -57,7 +57,7 @@
     if (c->length <=3D 0)
         return -1;
 =

-    assert(c->memblock && c->memblock->length);
+    assert(c->memblock);
     *chunk =3D *c;
     pa_memblock_ref(c->memblock);
 =

@@ -122,7 +122,5 @@
 =

     pa_memblock_ref(chunk->memblock);
 =

-    pa_sink_notify(si->sink);
-
     return 0;
 }

Modified: branches/lennart/src/pulsecore/protocol-esound.c
URL: http://0pointer.de/cgi-bin/viewcvs.cgi/branches/lennart/src/pulsecore/=
protocol-esound.c?rev=3D1469&root=3Dpulseaudio&r1=3D1468&r2=3D1469&view=3Dd=
iff
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D
--- branches/lennart/src/pulsecore/protocol-esound.c (original)
+++ branches/lennart/src/pulsecore/protocol-esound.c Mon Jun 11 14:08:37 20=
07
@@ -894,13 +894,21 @@
         }
     } else if (c->state =3D=3D ESD_CACHING_SAMPLE) {
         ssize_t r;
-
-        assert(c->scache.memchunk.memblock && c->scache.name && c->scache.=
memchunk.index < c->scache.memchunk.length);
-
-        if ((r =3D pa_iochannel_read(c->io, (uint8_t*) c->scache.memchunk.=
memblock->data+c->scache.memchunk.index, c->scache.memchunk.length-c->scach=
e.memchunk.index)) <=3D 0) {
+        void *p;
+
+        assert(c->scache.memchunk.memblock);
+        assert(c->scache.name);
+        assert(c->scache.memchunk.index < c->scache.memchunk.length);
+
+        p =3D pa_memblock_acquire(c->scache.memchunk.memblock);
+
+        if ((r =3D pa_iochannel_read(c->io, (uint8_t*) p+c->scache.memchun=
k.index, c->scache.memchunk.length-c->scache.memchunk.index)) <=3D 0) {
+            pa_memblock_release(c->scache.memchunk.memblock);
             pa_log_debug("read(): %s", r < 0 ? pa_cstrerror(errno) : "EOF"=
);
             return -1;
         }
+
+        pa_memblock_release(c->scache.memchunk.memblock);
 =

         c->scache.memchunk.index +=3D r;
         assert(c->scache.memchunk.index <=3D c->scache.memchunk.length);
@@ -928,6 +936,7 @@
         pa_memchunk chunk;
         ssize_t r;
         size_t l;
+        void *p;
 =

         assert(c->input_memblockq);
 =

@@ -940,7 +949,7 @@
             l =3D c->playback.fragment_size;
 =

         if (c->playback.current_memblock)
-            if (c->playback.current_memblock->length - c->playback.membloc=
k_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 =3D NULL;
                 c->playback.memblock_index =3D 0;
@@ -948,14 +957,19 @@
 =

         if (!c->playback.current_memblock) {
             c->playback.current_memblock =3D pa_memblock_new(c->protocol->=
core->mempool, c->playback.fragment_size*2);
-            assert(c->playback.current_memblock && c->playback.current_mem=
block->length >=3D l);
+            assert(c->playback.current_memblock);
+            assert(pa_memblock_get_length(c->playback.current_memblock) >=
=3D l);
             c->playback.memblock_index =3D 0;
         }
 =

-        if ((r =3D pa_iochannel_read(c->io, (uint8_t*) c->playback.current=
_memblock->data+c->playback.memblock_index, l)) <=3D 0) {
+        p =3D pa_memblock_acquire(c->playback.current_memblock);
+
+        if ((r =3D pa_iochannel_read(c->io, (uint8_t*) p+c->playback.membl=
ock_index, l)) <=3D 0) {
+            pa_memblock_release(c->playback.current_memblock);
             pa_log_debug("read(): %s", r < 0 ? pa_cstrerror(errno) : "EOF"=
);
             return -1;
         }
+        pa_memblock_release(c->playback.current_memblock);
 =

         chunk.memblock =3D c->playback.current_memblock;
         chunk.index =3D c->playback.memblock_index;
@@ -993,18 +1007,25 @@
     } else if (c->state =3D=3D ESD_STREAMING_DATA && c->source_output) {
         pa_memchunk chunk;
         ssize_t r;
+        void *p;
 =

         assert(c->output_memblockq);
         if (pa_memblockq_peek(c->output_memblockq, &chunk) < 0)
             return 0;
 =

-        assert(chunk.memblock && chunk.length);
-
-        if ((r =3D pa_iochannel_write(c->io, (uint8_t*) chunk.memblock->da=
ta+chunk.index, chunk.length)) < 0) {
+        assert(chunk.memblock);
+        assert(chunk.length);
+
+        p =3D pa_memblock_acquire(chunk.memblock);
+
+        if ((r =3D pa_iochannel_write(c->io, (uint8_t*) p+chunk.index, chu=
nk.length)) < 0) {
+            pa_memblock_release(chunk.memblock);
             pa_memblock_unref(chunk.memblock);
             pa_log("write(): %s", pa_cstrerror(errno));
             return -1;
         }
+
+        pa_memblock_release(chunk.memblock);
 =

         pa_memblockq_drop(c->output_memblockq, &chunk, r);
         pa_memblock_unref(chunk.memblock);

Modified: branches/lennart/src/pulsecore/protocol-native.c
URL: http://0pointer.de/cgi-bin/viewcvs.cgi/branches/lennart/src/pulsecore/=
protocol-native.c?rev=3D1469&root=3Dpulseaudio&r1=3D1468&r2=3D1469&view=3Dd=
iff
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D
--- branches/lennart/src/pulsecore/protocol-native.c (original)
+++ branches/lennart/src/pulsecore/protocol-native.c Mon Jun 11 14:08:37 20=
07
@@ -2278,6 +2278,7 @@
     } else {
         struct upload_stream *u =3D (struct upload_stream*) stream;
         size_t l;
+
         assert(u->type =3D=3D UPLOAD_STREAM);
 =

         if (!u->memchunk.memblock) {
@@ -2297,9 +2298,18 @@
         if (l > chunk->length)
             l =3D chunk->length;
 =

+
         if (l > 0) {
-            memcpy((uint8_t*) u->memchunk.memblock->data + u->memchunk.ind=
ex + u->memchunk.length,
-                   (uint8_t*) chunk->memblock->data+chunk->index, l);
+            void *src, *dst;
+            dst =3D pa_memblock_acquire(u->memchunk.memblock);
+            src =3D 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 +=3D l;
             u->length -=3D l;
         }

Modified: branches/lennart/src/pulsecore/protocol-simple.c
URL: http://0pointer.de/cgi-bin/viewcvs.cgi/branches/lennart/src/pulsecore/=
protocol-simple.c?rev=3D1469&root=3Dpulseaudio&r1=3D1468&r2=3D1469&view=3Dd=
iff
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D
--- branches/lennart/src/pulsecore/protocol-simple.c (original)
+++ branches/lennart/src/pulsecore/protocol-simple.c Mon Jun 11 14:08:37 20=
07
@@ -25,7 +25,6 @@
 #include <config.h>
 #endif
 =

-#include <assert.h>
 #include <stdlib.h>
 #include <limits.h>
 #include <stdio.h>
@@ -54,13 +53,13 @@
     pa_source_output *source_output;
     pa_client *client;
     pa_memblockq *input_memblockq, *output_memblockq;
-    pa_defer_event *defer_event;
 =

     int dead;
 =

     struct {
         pa_memblock *current_memblock;
         size_t memblock_index, fragment_size;
+        pa_atomic_int missing;
     } playback;
 };
 =

@@ -69,35 +68,52 @@
     pa_core *core;
     pa_socket_server*server;
     pa_idxset *connections;
+
+    pa_asyncmsgq *asyncmsgq;
+
     enum {
         RECORD =3D 1,
         PLAYBACK =3D 2,
         DUPLEX =3D 3
     } mode;
+
     pa_sample_spec sample_spec;
     char *source_name, *sink_name;
 };
 =

+enum {
+    SINK_INPUT_MESSAGE_POST_DATA =3D PA_SINK_INPUT_MESSAGE_MAX, /* data fr=
om main loop to sink input */
+};
+
+enum {
+    MESSAGE_REQUEST_DATA,   /* data from source output to main loop */ =

+    MESSAGE_POST_DATA       /* data from source output to main loop */
+};
+
+    =

 #define PLAYBACK_BUFFER_SECONDS (.5)
 #define PLAYBACK_BUFFER_FRAGMENTS (10)
 #define RECORD_BUFFER_SECONDS (5)
 #define RECORD_BUFFER_FRAGMENTS (100)
 =

 static void connection_free(struct connection *c) {
-    assert(c);
+    pa_assert(c);
 =

     pa_idxset_remove_by_data(c->protocol->connections, c, NULL);
 =

-    if (c->playback.current_memblock)
-        pa_memblock_unref(c->playback.current_memblock);
     if (c->sink_input) {
         pa_sink_input_disconnect(c->sink_input);
         pa_sink_input_unref(c->sink_input);
     }
+    =

     if (c->source_output) {
         pa_source_output_disconnect(c->source_output);
         pa_source_output_unref(c->source_output);
     }
+    =

+    if (c->playback.current_memblock)
+        pa_memblock_unref(c->playback.current_memblock);
+    =

     if (c->client)
         pa_client_free(c->client);
     if (c->io)
@@ -106,8 +122,7 @@
         pa_memblockq_free(c->input_memblockq);
     if (c->output_memblockq)
         pa_memblockq_free(c->output_memblockq);
-    if (c->defer_event)
-        c->protocol->core->mainloop->defer_free(c->defer_event);
+    =

     pa_xfree(c);
 }
 =

@@ -115,27 +130,37 @@
     pa_memchunk chunk;
     ssize_t r;
     size_t l;
-
-    if (!c->sink_input || !(l =3D pa_memblockq_missing(c->input_memblockq)=
))
+    void *p;
+
+    pa_assert(c);
+    =

+    if (!c->sink_input || !(l =3D pa_atomic_load(&c->playback.missing)))
         return 0;
 =

     if (l > c->playback.fragment_size)
         l =3D c->playback.fragment_size;
 =

     if (c->playback.current_memblock)
-        if (c->playback.current_memblock->length - c->playback.memblock_in=
dex < l) {
+        if (pa_memblock_get_length(c->playback.current_memblock) - c->play=
back.memblock_index < l) {
             pa_memblock_unref(c->playback.current_memblock);
             c->playback.current_memblock =3D NULL;
             c->playback.memblock_index =3D 0;
         }
 =

     if (!c->playback.current_memblock) {
-        c->playback.current_memblock =3D pa_memblock_new(c->protocol->core=
->mempool, c->playback.fragment_size*2);
-        assert(c->playback.current_memblock && c->playback.current_membloc=
k->length >=3D l);
+        pa_assert_se(c->playback.current_memblock =3D pa_memblock_new(c->p=
rotocol->core->mempool, l));
         c->playback.memblock_index =3D 0;
     }
 =

-    if ((r =3D pa_iochannel_read(c->io, (uint8_t*) c->playback.current_mem=
block->data+c->playback.memblock_index, l)) <=3D 0) {
+    p =3D pa_memblock_acquire(c->playback.current_memblock);
+    r =3D pa_iochannel_read(c->io, (uint8_t*) p + c->playback.memblock_ind=
ex, l);
+    pa_memblock_release(c->playback.current_memblock);
+    =

+    if (r <=3D 0) {
+
+        if (errno =3D=3D EINTR || errno =3D=3D EAGAIN)
+            return 0;
+        =

         pa_log_debug("read(): %s", r =3D=3D 0 ? "EOF" : pa_cstrerror(errno=
));
         return -1;
     }
@@ -143,14 +168,10 @@
     chunk.memblock =3D c->playback.current_memblock;
     chunk.index =3D c->playback.memblock_index;
     chunk.length =3D r;
-    assert(chunk.memblock);
 =

     c->playback.memblock_index +=3D r;
 =

-    assert(c->input_memblockq);
-    pa_memblockq_push_align(c->input_memblockq, &chunk);
-    assert(c->sink_input);
-    pa_sink_notify(c->sink_input->sink);
+    pa_asyncmsgq_post(c->protocol->asyncmsgq, c, MESSAGE_POST_DATA, NULL, =
&chunk, NULL, NULL);
 =

     return 0;
 }
@@ -158,35 +179,41 @@
 static int do_write(struct connection *c) {
     pa_memchunk chunk;
     ssize_t r;
+    void *p;
+
+    p_assert(c);
 =

     if (!c->source_output)
         return 0;
 =

-    assert(c->output_memblockq);
     if (pa_memblockq_peek(c->output_memblockq, &chunk) < 0)
         return 0;
 =

-    assert(chunk.memblock && chunk.length);
-
-    if ((r =3D pa_iochannel_write(c->io, (uint8_t*) chunk.memblock->data+c=
hunk.index, chunk.length)) < 0) {
-        pa_memblock_unref(chunk.memblock);
+    pa_assert(chunk.memblock);
+    pa_assert(chunk.length);
+
+    p =3D pa_memblock_acquire(chunk.memblock);
+    r =3D 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 =3D=3D EINTR || errno =3D=3D 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);
-
+    =

     return 0;
 }
 =

 static void do_work(struct connection *c) {
-    assert(c);
-
-    assert(c->protocol && c->protocol->core && c->protocol->core->mainloop=
 && c->protocol->core->mainloop->defer_enable);
-    c->protocol->core->mainloop->defer_enable(c->defer_event, 0);
+    pa_assert(c);
 =

     if (c->dead)
         return;
@@ -207,103 +234,148 @@
 fail:
 =

     if (c->sink_input) {
+
+        /* If there is a sink input, we first drain what we already have r=
ead before shutting down the connection */
         c->dead =3D 1;
 =

         pa_iochannel_free(c->io);
         c->io =3D NULL;
 =

         pa_memblockq_prebuf_disable(c->input_memblockq);
-        pa_sink_notify(c->sink_input->sink);
     } else
         connection_free(c);
 }
 =

 /*** sink_input callbacks ***/
 =

+/* Called from thread context */
+static int sink_input_process_msg(pa_sink_input *i, int code, void *userda=
ta, const pa_memchunk *chunk) {
+    struct connection*c;
+    =

+    pa_assert(i);
+    c =3D i->userdata;
+    pa_assert(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);
+            return 0;
+        }
+        =

+        case PA_SINK_INPUT_MESSAGE_GET_LATENCY: {
+            pa_usec_t *r =3D userdata;
+            =

+            *r =3D pa_bytes_to_usec(pa_memblockq_get_length(c->input_membl=
ockq), &c->sink_input->sample_spec);
+
+            /* Fall through, the default handler will add in the extra
+             * latency added by the resampler */
+        }
+
+        default:
+            return pa_sink_input_process_msg(i, code, userdata);
+    }
+}
+
+/* Called from thread context */
 static int sink_input_peek_cb(pa_sink_input *i, pa_memchunk *chunk) {
     struct connection*c;
-    assert(i && i->userdata && chunk);
+    =

+    pa_assert(i);
     c =3D i->userdata;
-
-    if (pa_memblockq_peek(c->input_memblockq, chunk) < 0) {
-
-        if (c->dead)
-            connection_free(c);
-
-        return -1;
-    }
-
-    return 0;
-}
-
+    pa_assert(c);
+    pa_assert(chunk);
+
+    r =3D pa_memblockq_peek(c->input_memblockq, chunk);
+
+    if (c->dead && r < 0)
+        connection_free(c);
+
+    return r;
+}
+
+/* Called from thread context */
 static void sink_input_drop_cb(pa_sink_input *i, const pa_memchunk *chunk,=
 size_t length) {
     struct connection*c =3D i->userdata;
-    assert(i && c && length);
-
+    size_t old, new;
+    =

+    pa_assert(i);
+    pa_assert(c);
+    pa_assert(length);
+
+    old =3D pa_memblockq_missing(c->input_memblockq);
     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);
-}
-
+    new =3D pa_memblockq_missing(c->input_memblockq);
+
+    pa_atomic_store(&c->playback.missing, &new);
+
+    if (new > old)
+        pa_asyncmsgq_post(c->protocol->asyncmsgq, c, MESSAGE_REQUEST_DATA,=
 NULL, NULL, NULL, NULL);
+}
+
+/* Called from main context */
 static void sink_input_kill_cb(pa_sink_input *i) {
-    assert(i && i->userdata);
+    pa_assert(i);
+    pa_assert(i->userdata);
+    =

     connection_free((struct connection *) i->userdata);
 }
 =

-
-static pa_usec_t sink_input_get_latency_cb(pa_sink_input *i) {
-    struct connection*c =3D i->userdata;
-    assert(i && c);
-    return pa_bytes_to_usec(pa_memblockq_get_length(c->input_memblockq), &=
c->sink_input->sample_spec);
-}
-
 /*** source_output callbacks ***/
 =

 static void source_output_push_cb(pa_source_output *o, const pa_memchunk *=
chunk) {
-    struct connection *c =3D 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);
+    struct connection *c;
+    =

+    pa_assert(o);
+    c =3D o->userdata;
+    pa_assert(c);
+    pa_assert(chunk);
+
+    pa_asyncmsgq_post(c->protocol->asyncmsgq, c, MESSAGE_REQUEST_DATA, NUL=
L, chunk, NULL, NULL);
 }
 =

 static void source_output_kill_cb(pa_source_output *o) {
-    assert(o && o->userdata);
-    connection_free((struct connection *) o->userdata);
+    struct connection*c;
+
+    pa_assert(o);
+    c =3D o->userdata;
+    pa_assert(c);
+    =

+    connection_free(c);
 }
 =

 static pa_usec_t source_output_get_latency_cb(pa_source_output *o) {
-    struct connection*c =3D o->userdata;
-    assert(o && c);
+    struct connection*c;
+    =

+    pa_assert(o);
+    c =3D o->userdata;
+    pa_assert(c);
+    =

     return pa_bytes_to_usec(pa_memblockq_get_length(c->output_memblockq), =
&c->source_output->sample_spec);
 }
 =

 /*** client callbacks ***/
 =

-static void client_kill_cb(pa_client *c) {
-    assert(c && c->userdata);
-    connection_free((struct connection *) c->userdata);
+static void client_kill_cb(pa_client *client) {
+    struct connection*c;
+    =

+    pa_assert(client);
+    c =3D client->userdata;
+    pa_assert(c);
+
+    connection_free(client);
 }
 =

 /*** pa_iochannel callbacks ***/
 =

 static void io_callback(pa_iochannel*io, void *userdata) {
     struct connection *c =3D userdata;
-    assert(io && c && c->io =3D=3D io);
-
-    do_work(c);
-}
-
-/*** fixed callback ***/
-
-static void defer_callback(pa_mainloop_api*a, pa_defer_event *e, void *use=
rdata) {
-    struct connection *c =3D userdata;
-    assert(a && c && c->defer_event =3D=3D e);
+
+    pa_assert(io);
+    pa_assert(c);
 =

     do_work(c);
 }
@@ -314,7 +386,10 @@
     pa_protocol_simple *p =3D userdata;
     struct connection *c =3D 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 conn=
ection.", MAX_CONNECTIONS);
@@ -322,25 +397,25 @@
         return;
     }
 =

-    c =3D pa_xmalloc(sizeof(struct connection));
+    c =3D pa_xnew(struct connection, 1);
     c->io =3D io;
     c->sink_input =3D NULL;
     c->source_output =3D NULL;
-    c->defer_event =3D NULL;
     c->input_memblockq =3D c->output_memblockq =3D NULL;
     c->protocol =3D p;
     c->playback.current_memblock =3D NULL;
     c->playback.memblock_index =3D 0;
     c->playback.fragment_size =3D 0;
     c->dead =3D 0;
+    pa_atomic_store(&c->playback.missing, 0);
 =

     pa_iochannel_socket_peer_to_string(io, cname, sizeof(cname));
-    c->client =3D pa_client_new(p->core, __FILE__, cname);
-    assert(c->client);
+    pa_assert_se(c->client =3D pa_client_new(p->core, __FILE__, cname));
     c->client->owner =3D p->module;
     c->client->kill =3D client_kill_cb;
     c->client->userdata =3D c;
 =

+    =

     if (p->mode & PLAYBACK) {
         pa_sink_input_new_data data;
         size_t l;
@@ -372,11 +447,13 @@
                 (size_t) -1,
                 l/PLAYBACK_BUFFER_FRAGMENTS,
                 NULL);
-        assert(c->input_memblockq);
+        pa_assert(c->input_memblockq);
         pa_iochannel_socket_set_rcvbuf(io, l/PLAYBACK_BUFFER_FRAGMENTS*5);
         c->playback.fragment_size =3D l/10;
 =

-        pa_sink_notify(c->sink_input->sink);
+        pa_atomic_store(&c->playback.missing, pa_memblockq_missing(c->inpu=
t_memblockq));
+
+        pa_sink_input_put(c->sink_input);
     }
 =

     if (p->mode & RECORD) {
@@ -409,16 +486,14 @@
                 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 =3D p->core->mainloop->defer_new(p->core->mainloop, def=
er_callback, c);
-    assert(c->defer_event);
-    p->core->mainloop->defer_enable(c->defer_event, 0);
-
+    =

     return;
 =

 fail:
@@ -426,16 +501,60 @@
         connection_free(c);
 }
 =

+static void asyncmsgq_cb(pa_mainloop_api*api, pa_io_event* e, int fd, pa_i=
o_event_flags_t events, void *userdata) {
+    pa_protocol_simple *p =3D userdata;
+    int do_some_work =3D 0;
+    =

+    pa_assert(pa_asyncmsgq_get_fd(p->asyncmsgq) =3D=3D fd);
+    pa_assert(events =3D=3D PA_IO_EVENT_INPUT);
+
+    pa_asyncmsgq_after_poll(p->asyncmsgq);
+
+    for (;;) {
+        int code;
+        void *object, *data;
+
+        /* Check whether there is a message for us to process */
+        while (pa_asyncmsgq_get(p->asyncmsgq, &object, &code, &data) =3D=
=3D 0) {
+
+            connection *c =3D object;
+
+            pa_assert(c);
+            =

+            switch (code) {
+
+                case MESSAGE_REQUEST_DATA:
+                    do_work(c);
+                    break;
+
+                case MESSAGE_POST_DATA:
+                    pa_memblockq_push(c->output_memblockq, chunk);
+                    do_work(c);
+                    break;
+            }
+
+            pa_asyncmsgq_done(p->asyncmsgq);
+        }
+        =

+        if (pa_asyncmsgq_before_poll(p->asyncmsgq) =3D=3D 0)
+            break;
+    }
+}
+
 pa_protocol_simple* pa_protocol_simple_new(pa_core *core, pa_socket_server=
 *server, pa_module *m, pa_modargs *ma) {
     pa_protocol_simple* p =3D NULL;
     int enable;
-    assert(core && server && ma);
-
-    p =3D pa_xmalloc0(sizeof(pa_protocol_simple));
+    =

+    pa_assert(core);
+    pa_assert(server);
+    pa_assert(ma);
+
+    p =3D pa_xnew0(pa_protocol_simple, 1);
     p->module =3D m;
     p->core =3D core;
     p->server =3D server;
     p->connections =3D pa_idxset_new(NULL, NULL);
+    pa_assert_se(p->asyncmsgq =3D pa_asyncmsgq_new(0));
 =

     p->sample_spec =3D core->default_sample_spec;
     if (pa_modargs_get_sample_spec(ma, &p->sample_spec) < 0) {
@@ -467,18 +586,22 @@
 =

     pa_socket_server_set_callback(p->server, on_connection, p);
 =

+    pa_assert_se(pa_asyncmsgq_before_poll(p->asyncmsgq) =3D=3D 0);
+    pa_assert_se(p->asyncmsgq_event =3D core->mainloop->io_event_new(core-=
>mainloop, pa_asyncmsgq_get_fd(p->asyncmsgq), PA_IO_EVENT_INPUT, p));
+    =

     return p;
 =

 fail:
     if (p)
         pa_protocol_simple_free(p);
+    =

     return NULL;
 }
 =

 =

 void pa_protocol_simple_free(pa_protocol_simple *p) {
     struct connection *c;
-    assert(p);
+    pa_assert(p);
 =

     if (p->connections) {
         while((c =3D pa_idxset_first(p->connections, NULL)))
@@ -489,6 +612,13 @@
 =

     if (p->server)
         pa_socket_server_unref(p->server);
+
+    if (p->asyncmsgq) {
+        c->mainloop->io_event_free(c->asyncmsgq_event);
+        pa_asyncmsgq_after_poll(c->asyncmsgq);
+        pa_asyncmsgq_free(p->asyncmsgq);
+    }
+    =

     pa_xfree(p);
 }
 =


Modified: branches/lennart/src/pulsecore/pstream.c
URL: http://0pointer.de/cgi-bin/viewcvs.cgi/branches/lennart/src/pulsecore/=
pstream.c?rev=3D1469&root=3Dpulseaudio&r1=3D1468&r2=3D1469&view=3Ddiff
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D
--- branches/lennart/src/pulsecore/pstream.c (original)
+++ branches/lennart/src/pulsecore/pstream.c Mon Jun 11 14:08:37 2007
@@ -49,7 +49,6 @@
 #include <pulsecore/log.h>
 #include <pulsecore/core-scache.h>
 #include <pulsecore/creds.h>
-#include <pulsecore/mutex.h>
 #include <pulsecore/refcnt.h>
 =

 #include "pstream.h"
@@ -118,8 +117,8 @@
     pa_mainloop_api *mainloop;
     pa_defer_event *defer_event;
     pa_iochannel *io;
+
     pa_queue *send_queue;
-    pa_mutex *mutex;
 =

     int dead;
 =

@@ -129,6 +128,7 @@
         uint32_t shm_info[PA_PSTREAM_SHM_MAX];
         void *data;
         size_t index;
+        pa_memchunk memchunk;
     } write;
 =

     struct {
@@ -173,8 +173,6 @@
 =

     pa_pstream_ref(p);
 =

-    pa_mutex_lock(p->mutex);
-
     p->mainloop->defer_enable(p->defer_event, 0);
 =

     if (!p->dead && pa_iochannel_is_readable(p->io)) {
@@ -188,8 +186,6 @@
             goto fail;
     }
 =

-    pa_mutex_unlock(p->mutex);
-
     pa_pstream_unref(p);
     return;
 =

@@ -200,8 +196,6 @@
     if (p->die_callback)
         p->die_callback(p, p->die_callback_userdata);
 =

-    pa_mutex_unlock(p->mutex);
-
     pa_pstream_unref(p);
 }
 =

@@ -210,16 +204,6 @@
 =

     assert(p);
     assert(p->io =3D=3D io);
-
-    do_something(p);
-}
-
-static void defer_callback(pa_mainloop_api *m, pa_defer_event *e, void*use=
rdata) {
-    pa_pstream *p =3D userdata;
-
-    assert(p);
-    assert(p->defer_event =3D=3D e);
-    assert(p->mainloop =3D=3D m);
 =

     do_something(p);
 }
@@ -239,17 +223,14 @@
     pa_iochannel_set_callback(io, io_callback, p);
     p->dead =3D 0;
 =

-    p->mutex =3D pa_mutex_new(1);
-
     p->mainloop =3D m;
-    p->defer_event =3D m->defer_new(m, defer_callback, p);
-    m->defer_enable(p->defer_event, 0);
 =

     p->send_queue =3D pa_queue_new();
     assert(p->send_queue);
 =

     p->write.current =3D NULL;
     p->write.index =3D 0;
+    pa_memchunk_reset(&p->write.memchunk);
     p->read.memblock =3D NULL;
     p->read.packet =3D NULL;
     p->read.index =3D 0;
@@ -312,8 +293,8 @@
     if (p->read.packet)
         pa_packet_unref(p->read.packet);
 =

-    if (p->mutex)
-        pa_mutex_free(p->mutex);
+    if (p->write.memchunk.memblock)
+        pa_memblock_unref(p->write.memchunk.memblock);
 =

     pa_xfree(p);
 }
@@ -325,10 +306,8 @@
     assert(PA_REFCNT_VALUE(p) > 0);
     assert(packet);
 =

-    pa_mutex_lock(p->mutex);
-
     if (p->dead)
-        goto finish;
+        return;
 =

     i =3D pa_xnew(struct item_info, 1);
     i->type =3D PA_PSTREAM_ITEM_PACKET;
@@ -340,11 +319,6 @@
 #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 offs=
et, pa_seek_mode_t seek_mode, const pa_memchunk *chunk) {
@@ -355,12 +329,9 @@
     assert(channel !=3D (uint32_t) -1);
     assert(chunk);
 =

-    pa_mutex_lock(p->mutex);
-
     if (p->dead)
-        goto finish;
-
-    length =3D chunk->length;
+        return;
+
     idx =3D 0;
 =

     while (length > 0) {
@@ -389,10 +360,6 @@
     }
 =

     p->mainloop->defer_enable(p->defer_event, 1);
-
-finish:
-
-    pa_mutex_unlock(p->mutex);
 }
 =

 static void memimport_release_cb(pa_memimport *i, uint32_t block_id, void =
*userdata) {
@@ -402,10 +369,8 @@
     assert(p);
     assert(PA_REFCNT_VALUE(p) > 0);
 =

-    pa_mutex_lock(p->mutex);
-
     if (p->dead)
-        goto finish;
+        return;
 =

 /*     pa_log("Releasing block %u", block_id); */
 =

@@ -417,11 +382,6 @@
 #endif
 =

     pa_queue_push(p->send_queue, item);
-    p->mainloop->defer_enable(p->defer_event, 1);
-
-finish:
-
-    pa_mutex_unlock(p->mutex);
 }
 =

 static void memexport_revoke_cb(pa_memexport *e, uint32_t block_id, void *=
userdata) {
@@ -431,11 +391,8 @@
     assert(p);
     assert(PA_REFCNT_VALUE(p) > 0);
 =

-    pa_mutex_lock(p->mutex);
-
     if (p->dead)
-        goto finish;
-
+        return;
 /*     pa_log("Revoking block %u", block_id); */
 =

     item =3D pa_xnew(struct item_info, 1);
@@ -446,22 +403,20 @@
 #endif
 =

     pa_queue_push(p->send_queue, item);
-    p->mainloop->defer_enable(p->defer_event, 1);
-
-finish:
-
-    pa_mutex_unlock(p->mutex);
 }
 =

 static void prepare_next_write_item(pa_pstream *p) {
     assert(p);
     assert(PA_REFCNT_VALUE(p) > 0);
 =

-    if (!(p->write.current =3D pa_queue_pop(p->send_queue)))
+    p->write.current =3D pa_queue_pop(p->send_queue);
+
+    if (!p->write.current)
         return;
 =

     p->write.index =3D 0;
     p->write.data =3D NULL;
+    pa_memchunk_reset(&p->write.memchunk);
 =

     p->write.descriptor[PA_PSTREAM_DESCRIPTOR_LENGTH] =3D 0;
     p->write.descriptor[PA_PSTREAM_DESCRIPTOR_CHANNEL] =3D htonl((uint32_t=
) -1);
@@ -528,7 +483,9 @@
 =

         if (send_payload) {
             p->write.descriptor[PA_PSTREAM_DESCRIPTOR_LENGTH] =3D htonl(p-=
>write.current->chunk.length);
-            p->write.data =3D (uint8_t*) p->write.current->chunk.memblock-=
>data + p->write.current->chunk.index;
+            p->write.memchunk =3D p->write.current->chunk;
+            pa_memblock_ref(p->write.memchunk.memblock);
+            p->write.data =3D NULL;
         }
 =

         p->write.descriptor[PA_PSTREAM_DESCRIPTOR_FLAGS] =3D htonl(flags);
@@ -544,6 +501,7 @@
     void *d;
     size_t l;
     ssize_t r;
+    pa_memblock *release_memblock =3D NULL;
 =

     assert(p);
     assert(PA_REFCNT_VALUE(p) > 0);
@@ -558,9 +516,16 @@
         d =3D (uint8_t*) p->write.descriptor + p->write.index;
         l =3D PA_PSTREAM_DESCRIPTOR_SIZE - p->write.index;
     } else {
-        assert(p->write.data);
-
-        d =3D (uint8_t*) p->write.data + p->write.index - PA_PSTREAM_DESCR=
IPTOR_SIZE;
+        assert(p->write.data || p->write.memchunk.memblock);
+
+        if (p->write.data)
+            d =3D p->write.data;
+        else {
+            d =3D (uint8_t*) pa_memblock_acquire(p->write.memchunk.membloc=
k) + p->write.memchunk.index;
+            release_memblock =3D p->write.memchunk.memblock;
+        }
+
+        d =3D (uint8_t*) d + p->write.index - PA_PSTREAM_DESCRIPTOR_SIZE;
         l =3D ntohl(p->write.descriptor[PA_PSTREAM_DESCRIPTOR_LENGTH]) - (=
p->write.index - PA_PSTREAM_DESCRIPTOR_SIZE);
     }
 =

@@ -570,14 +535,17 @@
     if (p->send_creds_now) {
 =

         if ((r =3D pa_iochannel_write_with_creds(p->io, d, l, &p->write_cr=
eds)) < 0)
-            return -1;
+            goto fail;
 =

         p->send_creds_now =3D 0;
     } else
 #endif
 =

     if ((r =3D pa_iochannel_write(p->io, d, l)) < 0)
-        return -1;
+        goto fail;
+
+    if (release_memblock)
+        pa_memblock_release(release_memblock);
 =

     p->write.index +=3D r;
 =

@@ -591,13 +559,20 @@
     }
 =

     return 0;
+
+fail:
+
+    if (release_memblock)
+        pa_memblock_release(release_memblock);
+
+    return -1;
 }
 =

 static int do_read(pa_pstream *p) {
     void *d;
     size_t l;
     ssize_t r;
-
+    pa_memblock *release_memblock =3D NULL;
     assert(p);
     assert(PA_REFCNT_VALUE(p) > 0);
 =

@@ -605,8 +580,16 @@
         d =3D (uint8_t*) p->read.descriptor + p->read.index;
         l =3D PA_PSTREAM_DESCRIPTOR_SIZE - p->read.index;
     } else {
-        assert(p->read.data);
-        d =3D (uint8_t*) p->read.data + p->read.index - PA_PSTREAM_DESCRIP=
TOR_SIZE;
+        assert(p->read.data || p->read.memblock);
+
+        if (p->read.data)
+            d =3D p->read.data;
+        else {
+            d =3D pa_memblock_acquire(p->read.memblock);
+            release_memblock =3D p->read.memblock;
+        }
+
+        d =3D (uint8_t*) d + p->read.index - PA_PSTREAM_DESCRIPTOR_SIZE;
         l =3D ntohl(p->read.descriptor[PA_PSTREAM_DESCRIPTOR_LENGTH]) - (p=
->read.index - PA_PSTREAM_DESCRIPTOR_SIZE);
     }
 =

@@ -615,14 +598,17 @@
         int b =3D 0;
 =

         if ((r =3D pa_iochannel_read_with_creds(p->io, d, l, &p->read_cred=
s, &b)) <=3D 0)
-            return -1;
+            goto fail;
 =

         p->read_creds_valid =3D p->read_creds_valid || b;
     }
 #else
     if ((r =3D pa_iochannel_read(p->io, d, l)) <=3D 0)
-        return -1;
-#endif
+        goto fail;
+#endif
+
+    if (release_memblock)
+        pa_memblock_release(release_memblock);
 =

     p->read.index +=3D r;
 =

@@ -704,7 +690,7 @@
                 /* Frame is a memblock frame */
 =

                 p->read.memblock =3D pa_memblock_new(p->mempool, length);
-                p->read.data =3D p->read.memblock->data;
+                p->read.data =3D NULL;
             } else {
 =

                 pa_log_warn("Recieved memblock frame with invalid flags va=
lue.");
@@ -791,7 +777,7 @@
 =

                     chunk.memblock =3D b;
                     chunk.index =3D 0;
-                    chunk.length =3D b->length;
+                    chunk.length =3D pa_memblock_get_length(b);
 =

                     offset =3D (int64_t) (
                             (((uint64_t) ntohl(p->read.descriptor[PA_PSTRE=
AM_DESCRIPTOR_OFFSET_HI])) << 32) |
@@ -819,52 +805,51 @@
     p->read.memblock =3D NULL;
     p->read.packet =3D NULL;
     p->read.index =3D 0;
+    p->read.data =3D NULL;
 =

 #ifdef HAVE_CREDS
     p->read_creds_valid =3D 0;
 #endif
 =

     return 0;
+
+fail:
+    if (release_memblock)
+        pa_memblock_release(release_memblock);
+
+    return -1;
 }
 =

 void pa_pstream_set_die_callback(pa_pstream *p, pa_pstream_notify_cb_t cb,=
 void *userdata) {
     assert(p);
     assert(PA_REFCNT_VALUE(p) > 0);
 =

-    pa_mutex_lock(p->mutex);
     p->die_callback =3D cb;
     p->die_callback_userdata =3D userdata;
-    pa_mutex_unlock(p->mutex);
 }
 =

 void pa_pstream_set_drain_callback(pa_pstream *p, pa_pstream_notify_cb_t c=
b, void *userdata) {
     assert(p);
     assert(PA_REFCNT_VALUE(p) > 0);
 =

-    pa_mutex_lock(p->mutex);
     p->drain_callback =3D cb;
     p->drain_callback_userdata =3D userdata;
-    pa_mutex_unlock(p->mutex);
 }
 =

 void pa_pstream_set_recieve_packet_callback(pa_pstream *p, pa_pstream_pack=
et_cb_t cb, void *userdata) {
     assert(p);
     assert(PA_REFCNT_VALUE(p) > 0);
 =

-    pa_mutex_lock(p->mutex);
     p->recieve_packet_callback =3D cb;
     p->recieve_packet_callback_userdata =3D userdata;
-    pa_mutex_unlock(p->mutex);
 }
 =

 void pa_pstream_set_recieve_memblock_callback(pa_pstream *p, pa_pstream_me=
mblock_cb_t cb, void *userdata) {
     assert(p);
     assert(PA_REFCNT_VALUE(p) > 0);
 =

-    pa_mutex_lock(p->mutex);
     p->recieve_memblock_callback =3D cb;
     p->recieve_memblock_callback_userdata =3D userdata;
-    pa_mutex_unlock(p->mutex);
 }
 =

 int pa_pstream_is_pending(pa_pstream *p) {
@@ -872,16 +857,12 @@
 =

     assert(p);
     assert(PA_REFCNT_VALUE(p) > 0);
-
-    pa_mutex_lock(p->mutex);
 =

     if (p->dead)
         b =3D 0;
     else
         b =3D p->write.current || !pa_queue_is_empty(p->send_queue);
 =

-    pa_mutex_unlock(p->mutex);
-
     return b;
 }
 =

@@ -903,8 +884,6 @@
 =

 void pa_pstream_close(pa_pstream *p) {
     assert(p);
-
-    pa_mutex_lock(p->mutex);
 =

     p->dead =3D 1;
 =

@@ -921,26 +900,17 @@
     if (p->io) {
         pa_iochannel_free(p->io);
         p->io =3D NULL;
-    }
-
-    if (p->defer_event) {
-        p->mainloop->defer_free(p->defer_event);
-        p->defer_event =3D NULL;
     }
 =

     p->die_callback =3D NULL;
     p->drain_callback =3D NULL;
     p->recieve_packet_callback =3D NULL;
     p->recieve_memblock_callback =3D NULL;
-
-    pa_mutex_unlock(p->mutex);
 }
 =

 void pa_pstream_use_shm(pa_pstream *p, int enable) {
     assert(p);
     assert(PA_REFCNT_VALUE(p) > 0);
-
-    pa_mutex_lock(p->mutex);
 =

     p->use_shm =3D enable;
 =

@@ -956,6 +926,4 @@
             p->export =3D NULL;
         }
     }
-
-    pa_mutex_unlock(p->mutex);
-}
+}

Modified: branches/lennart/src/pulsecore/refcnt.h
URL: http://0pointer.de/cgi-bin/viewcvs.cgi/branches/lennart/src/pulsecore/=
refcnt.h?rev=3D1469&root=3Dpulseaudio&r1=3D1468&r2=3D1469&view=3Ddiff
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D
--- branches/lennart/src/pulsecore/refcnt.h (original)
+++ branches/lennart/src/pulsecore/refcnt.h Mon Jun 11 14:08:37 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: branches/lennart/src/pulsecore/resampler.c
URL: http://0pointer.de/cgi-bin/viewcvs.cgi/branches/lennart/src/pulsecore/=
resampler.c?rev=3D1469&root=3Dpulseaudio&r1=3D1468&r2=3D1469&view=3Ddiff
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D
--- branches/lennart/src/pulsecore/resampler.c (original)
+++ branches/lennart/src/pulsecore/resampler.c Mon Jun 11 14:08:37 2007
@@ -53,8 +53,7 @@
 };
 =

 struct impl_libsamplerate {
-    pa_memblock *buf1_block, *buf2_block, *buf3_block, *buf4_block;
-    float* buf1, *buf2, *buf3, *buf4;
+    pa_memchunk buf1, buf2, buf3, buf4;
     unsigned buf1_samples, buf2_samples, buf3_samples, buf4_samples;
 =

     pa_convert_to_float32ne_func_t to_float32ne_func;
@@ -226,14 +225,14 @@
     if (u->src_state)
         src_delete(u->src_state);
 =

-    if (u->buf1_block)
-        pa_memblock_unref(u->buf1_block);
-    if (u->buf2_block)
-        pa_memblock_unref(u->buf2_block);
-    if (u->buf3_block)
-        pa_memblock_unref(u->buf3_block);
-    if (u->buf4_block)
-        pa_memblock_unref(u->buf4_block);
+    if (u->buf1.memblock)
+        pa_memblock_unref(u->buf1.memblock);
+    if (u->buf2.memblock)
+        pa_memblock_unref(u->buf2.memblock);
+    if (u->buf3.memblock)
+        pa_memblock_unref(u->buf3.memblock);
+    if (u->buf4.memblock)
+        pa_memblock_unref(u->buf4.memblock);
     pa_xfree(u);
 }
 =

@@ -272,64 +271,80 @@
     }
 }
 =

-static float * convert_to_float(pa_resampler *r, void *input, unsigned n_f=
rames) {
+static pa_memchunk* convert_to_float(pa_resampler *r, pa_memchunk *input) {
     struct impl_libsamplerate *u;
     unsigned n_samples;
+    void *src, *dst;
 =

     assert(r);
     assert(input);
+    assert(input->memblock);
+
     assert(r->impl_data);
     u =3D r->impl_data;
 =

     /* Convert the incoming sample into floats and place them in buf1 */
 =

-    if (!u->to_float32ne_func)
+    if (!u->to_float32ne_func || !input->length)
         return input;
 =

-    n_samples =3D n_frames * r->i_ss.channels;
-
-    if (u->buf1_samples < n_samples) {
-        if (u->buf1_block)
-            pa_memblock_unref(u->buf1_block);
+    n_samples =3D (input->length / r->i_fz) * r->i_ss.channels;
+
+    if (!u->buf1.memblock || u->buf1_samples < n_samples) {
+        if (u->buf1.memblock)
+            pa_memblock_unref(u->buf1.memblock);
 =

         u->buf1_samples =3D n_samples;
-        u->buf1_block =3D pa_memblock_new(r->mempool, sizeof(float) * n_sa=
mples);
-        u->buf1 =3D 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_fra=
mes) {
-    struct impl_libsamplerate *u;
-    unsigned n_samples;
+        u->buf1.memblock =3D pa_memblock_new(r->mempool, u->buf1.length =
=3D sizeof(float) * n_samples);
+        u->buf1.index =3D 0;
+    }
+
+    src =3D (uint8_t*) pa_memblock_acquire(input->memblock) + input->index;
+    dst =3D (uint8_t*) pa_memblock_acquire(u->buf1.memblock);
+    u->to_float32ne_func(n_samples, src, dst);
+    pa_memblock_release(input->memblock);
+    pa_memblock_release(u->buf1.memblock);
+
+    u->buf1.length =3D sizeof(float) * n_samples;
+
+    return &u->buf1;
+}
+
+static pa_memchunk *remap_channels(pa_resampler *r, pa_memchunk *input) {
+    struct impl_libsamplerate *u;
+    unsigned n_samples, n_frames;
     int i_skip, o_skip;
     unsigned oc;
+    float *src, *dst;
 =

     assert(r);
     assert(input);
+    assert(input->memblock);
+
     assert(r->impl_data);
     u =3D r->impl_data;
 =

     /* Remap channels and place the result int buf2 */
 =

-    if (!u->map_required)
+    if (!u->map_required || !input->length)
         return input;
 =

-    n_samples =3D n_frames * r->o_ss.channels;
-
-    if (u->buf2_samples < n_samples) {
-        if (u->buf2_block)
-            pa_memblock_unref(u->buf2_block);
+    n_samples =3D input->length / sizeof(float);
+    n_frames =3D n_samples / r->o_ss.channels;
+
+    if (!u->buf2.memblock || u->buf2_samples < n_samples) {
+        if (u->buf2.memblock)
+            pa_memblock_unref(u->buf2.memblock);
 =

         u->buf2_samples =3D n_samples;
-        u->buf2_block =3D pa_memblock_new(r->mempool, sizeof(float) * n_sa=
mples);
-        u->buf2 =3D u->buf2_block->data;
-    }
-
-    memset(u->buf2, 0, n_samples * sizeof(float));
+        u->buf2.memblock =3D pa_memblock_new(r->mempool, u->buf2.length =
=3D sizeof(float) * n_samples);
+        u->buf2.index =3D 0;
+    }
+
+    src =3D (float*) ((uint8_t*) pa_memblock_acquire(input->memblock) + in=
put->index);
+    dst =3D (float*) pa_memblock_acquire(u->buf2.memblock);
+
+    memset(dst, 0, n_samples * sizeof(float));
 =

     o_skip =3D sizeof(float) * r->o_ss.channels;
     i_skip =3D sizeof(float) * r->i_ss.channels;
@@ -340,49 +355,57 @@
 =

         for (i =3D 0; i < PA_CHANNELS_MAX && u->map_table[oc][i] >=3D 0; i=
++)
             oil_vectoradd_f32(
-                u->buf2 + oc, o_skip,
-                u->buf2 + oc, o_skip,
-                input + u->map_table[oc][i], i_skip,
+                dst + oc, o_skip,
+                dst + oc, o_skip,
+                src + u->map_table[oc][i], i_skip,
                 n_frames,
                 &one, &one);
     }
 =

-    return u->buf2;
-}
-
-static float *resample(pa_resampler *r, float *input, unsigned *n_frames) {
+    pa_memblock_release(input->memblock);
+    pa_memblock_release(u->buf2.memblock);
+
+    u->buf2.length =3D n_frames * sizeof(float) * r->o_ss.channels;
+
+    return &u->buf2;
+}
+
+static pa_memchunk *resample(pa_resampler *r, pa_memchunk *input) {
     struct impl_libsamplerate *u;
     SRC_DATA data;
+    unsigned in_n_frames, in_n_samples;
     unsigned out_n_frames, out_n_samples;
     int ret;
 =

     assert(r);
     assert(input);
-    assert(n_frames);
     assert(r->impl_data);
     u =3D r->impl_data;
 =

     /* Resample the data and place the result in buf3 */
 =

-    if (!u->src_state)
+    if (!u->src_state || !input->length)
         return input;
 =

-    out_n_frames =3D (*n_frames*r->o_ss.rate/r->i_ss.rate)+1024;
+    in_n_samples =3D input->length / sizeof(float);
+    in_n_frames =3D in_n_samples * r->o_ss.channels;
+
+    out_n_frames =3D (in_n_frames*r->o_ss.rate/r->i_ss.rate)+1024;
     out_n_samples =3D out_n_frames * r->o_ss.channels;
 =

-    if (u->buf3_samples < out_n_samples) {
-        if (u->buf3_block)
-            pa_memblock_unref(u->buf3_block);
+    if (!u->buf3.memblock || u->buf3_samples < out_n_samples) {
+        if (u->buf3.memblock)
+            pa_memblock_unref(u->buf3.memblock);
 =

         u->buf3_samples =3D out_n_samples;
-        u->buf3_block =3D pa_memblock_new(r->mempool, sizeof(float) * out_=
n_samples);
-        u->buf3 =3D u->buf3_block->data;
-    }
-
-    data.data_in =3D input;
-    data.input_frames =3D *n_frames;
-
-    data.data_out =3D u->buf3;
+        u->buf3.memblock =3D pa_memblock_new(r->mempool, u->buf3.length =
=3D sizeof(float) * out_n_samples);
+        u->buf3.index =3D 0;
+    }
+
+    data.data_in =3D (float*) ((uint8_t*) pa_memblock_acquire(input->membl=
ock) + input->index);
+    data.input_frames =3D in_n_frames;
+
+    data.data_out =3D (float*) pa_memblock_acquire(u->buf3.memblock);
     data.output_frames =3D out_n_frames;
 =

     data.src_ratio =3D (double) r->o_ss.rate / r->i_ss.rate;
@@ -390,16 +413,20 @@
 =

     ret =3D src_process(u->src_state, &data);
     assert(ret =3D=3D 0);
-    assert((unsigned) data.input_frames_used =3D=3D *n_frames);
-
-    *n_frames =3D 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((unsigned) data.input_frames_used =3D=3D in_n_frames);
+
+    pa_memblock_release(input->memblock);
+    pa_memblock_release(u->buf3.memblock);
+
+    u->buf3.length =3D data.output_frames_gen * sizeof(float) * r->o_ss.ch=
annels;
+
+    return &u->buf3;
+}
+
+static pa_memchunk *convert_from_float(pa_resampler *r, pa_memchunk *input=
) {
+    struct impl_libsamplerate *u;
+    unsigned n_samples, n_frames;
+    void *src, *dst;
 =

     assert(r);
     assert(input);
@@ -408,30 +435,35 @@
 =

     /* Convert the data into the correct sample type and place the result =
in buf4 */
 =

-    if (!u->from_float32ne_func)
+    if (!u->from_float32ne_func || !input->length)
         return input;
 =

+    n_frames =3D input->length / sizeof(float) / r->o_ss.channels;
     n_samples =3D n_frames * r->o_ss.channels;
 =

     if (u->buf4_samples < n_samples) {
-        if (u->buf4_block)
-            pa_memblock_unref(u->buf4_block);
+        if (u->buf4.memblock)
+            pa_memblock_unref(u->buf4.memblock);
 =

         u->buf4_samples =3D n_samples;
-        u->buf4_block =3D pa_memblock_new(r->mempool, sizeof(float) * n_sa=
mples);
-        u->buf4 =3D u->buf4_block->data;
-    }
-
-    u->from_float32ne_func(n_samples, input, u->buf4);
-
-    return u->buf4;
+        u->buf4.memblock =3D pa_memblock_new(r->mempool, u->buf4.length =
=3D r->o_fz * n_frames);
+        u->buf4.index =3D 0;
+    }
+
+    src =3D (uint8_t*) pa_memblock_acquire(input->memblock) + input->lengt=
h;
+    dst =3D pa_memblock_acquire(u->buf4.memblock);
+    u->from_float32ne_func(n_samples, src, dst);
+    pa_memblock_release(input->memblock);
+    pa_memblock_release(u->buf4.memblock);
+
+    u->buf4.length =3D r->o_fz * n_frames;
+
+    return &u->buf4;
 }
 =

 static void libsamplerate_run(pa_resampler *r, const pa_memchunk *in, pa_m=
emchunk *out) {
     struct impl_libsamplerate *u;
-    float *buf;
-    void *input, *output;
-    unsigned n_frames;
+    pa_memchunk *buf;
 =

     assert(r);
     assert(in);
@@ -443,55 +475,23 @@
 =

     u =3D r->impl_data;
 =

-    input =3D ((uint8_t*) in->memblock->data + in->index);
-    n_frames =3D in->length / r->i_fz;
-    assert(n_frames > 0);
-
-    buf =3D convert_to_float(r, input, n_frames);
-    buf =3D remap_channels(r, buf, n_frames);
-    buf =3D resample(r, buf, &n_frames);
-
-    if (n_frames) {
-        output =3D convert_from_float(r, buf, n_frames);
-
-        if (output =3D=3D input) {
-            /* Mm, no adjustment has been necessary, so let's return the o=
riginal block */
-            out->memblock =3D pa_memblock_ref(in->memblock);
-            out->index =3D in->index;
-            out->length =3D in->length;
-        } else {
-            out->length =3D n_frames * r->o_fz;
-            out->index =3D 0;
-            out->memblock =3D NULL;
-
-            if (output =3D=3D u->buf1) {
-                u->buf1 =3D NULL;
-                u->buf1_samples =3D 0;
-                out->memblock =3D u->buf1_block;
-                u->buf1_block =3D NULL;
-            } else if (output =3D=3D u->buf2) {
-                u->buf2 =3D NULL;
-                u->buf2_samples =3D 0;
-                out->memblock =3D u->buf2_block;
-                u->buf2_block =3D NULL;
-            } else if (output =3D=3D u->buf3) {
-                u->buf3 =3D NULL;
-                u->buf3_samples =3D 0;
-                out->memblock =3D u->buf3_block;
-                u->buf3_block =3D NULL;
-            } else if (output =3D=3D u->buf4) {
-                u->buf4 =3D NULL;
-                u->buf4_samples =3D 0;
-                out->memblock =3D u->buf4_block;
-                u->buf4_block =3D NULL;
-            }
-
-            assert(out->memblock);
-        }
-    } else {
-        out->memblock =3D NULL;
-        out->index =3D out->length =3D 0;
-    }
+    buf =3D convert_to_float(r, (pa_memchunk*) in);
+    buf =3D remap_channels(r, buf);
+    buf =3D resample(r, buf);
+
+    if (buf->length) {
+        buf =3D convert_from_float(r, buf);
+        *out =3D *buf;
+
+        if (buf =3D=3D in)
+            pa_memblock_ref(buf->memblock);
+        else
+            pa_memchunk_reset(buf);
+    } else
+        pa_memchunk_reset(out);
+
+    pa_memblock_release(in->memblock);
+
 }
 =

 static void libsamplerate_update_input_rate(pa_resampler *r, uint32_t rate=
) {
@@ -518,8 +518,10 @@
 =

     r->impl_data =3D u =3D pa_xnew(struct impl_libsamplerate, 1);
 =

-    u->buf1 =3D u->buf2 =3D u->buf3 =3D u->buf4 =3D NULL;
-    u->buf1_block =3D u->buf2_block =3D u->buf3_block =3D u->buf4_block =
=3D NULL;
+    pa_memchunk_reset(&u->buf1);
+    pa_memchunk_reset(&u->buf2);
+    pa_memchunk_reset(&u->buf3);
+    pa_memchunk_reset(&u->buf4);
     u->buf1_samples =3D u->buf2_samples =3D u->buf3_samples =3D u->buf4_sa=
mples =3D 0;
 =

     if (r->i_ss.format =3D=3D PA_SAMPLE_FLOAT32NE)
@@ -580,6 +582,7 @@
         /* Do real resampling */
         size_t l;
         unsigned o_index;
+        void *src, *dst;
 =

         /* The length of the new memory block rounded up */
         l =3D ((((n_frames+1) * r->o_ss.rate) / r->i_ss.rate) + 1) * fz;
@@ -587,6 +590,9 @@
         out->index =3D 0;
         out->memblock =3D pa_memblock_new(r->mempool, l);
 =

+        src =3D (uint8_t*) pa_memblock_acquire(in->memblock) + in->index;
+        dst =3D pa_memblock_acquire(out->memblock);
+
         for (o_index =3D 0;; o_index++, u->o_counter++) {
             unsigned j;
 =

@@ -596,12 +602,15 @@
             if (j >=3D 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);
+            assert(o_index*fz < pa_memblock_get_length(out->memblock));
+
+            memcpy((uint8_t*) dst + fz*o_index,
+                   (uint8_t*) src + fz*j, fz);
 =

         }
+
+        pa_memblock_release(in->memblock);
+        pa_memblock_release(out->memblock);
 =

         out->length =3D o_index*fz;
     }

Modified: branches/lennart/src/pulsecore/sample-util.c
URL: http://0pointer.de/cgi-bin/viewcvs.cgi/branches/lennart/src/pulsecore/=
sample-util.c?rev=3D1469&root=3Dpulseaudio&r1=3D1468&r2=3D1469&view=3Ddiff
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D
--- branches/lennart/src/pulsecore/sample-util.c (original)
+++ branches/lennart/src/pulsecore/sample-util.c Mon Jun 11 14:08:37 2007
@@ -61,15 +61,27 @@
 }
 =

 pa_memblock *pa_silence_memblock(pa_memblock* b, const pa_sample_spec *spe=
c) {
-    assert(b && b->data && spec);
-    pa_silence_memory(b->data, b->length, spec);
+    void *data;
+
+    assert(b);
+    assert(spec);
+
+    data =3D 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, sp=
ec);
+    void *data;
+
+    assert(c);
+    assert(c->memblock);
+    assert(spec);
+
+    data =3D pa_memblock_acquire(c->memblock);
+    pa_silence_memory((uint8_t*) data+c->index, c->length, spec);
+    pa_memblock_release(c->memblock);
 }
 =

 void pa_silence_memory(void *p, size_t length, const pa_sample_spec *spec)=
 {
@@ -98,26 +110,38 @@
 }
 =

 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 =3D 0;
+    unsigned k;
+
+    assert(streams);
+    assert(data);
+    assert(length);
+    assert(spec);
+
+    if (!volume)
+        volume =3D pa_cvolume_reset(&full_volume, spec->channels);
+
+    for (k =3D 0; k < nstreams; k++)
+        streams[k].internal =3D pa_memblock_acquire(streams[k].chunk.membl=
ock);
 =

     switch (spec->format) {
         case PA_SAMPLE_S16NE:{
-            size_t d;
             unsigned channel =3D 0;
 =

             for (d =3D 0;; d +=3D sizeof(int16_t)) {
                 int32_t sum =3D 0;
 =

                 if (d >=3D length)
-                    return d;
+                    goto finish;
 =

                 if (!mute && volume->values[channel] !=3D PA_VOLUME_MUTED)=
 {
                     unsigned i;
@@ -127,12 +151,12 @@
                         pa_volume_t cvolume =3D streams[i].volume.values[c=
hannel];
 =

                         if (d >=3D streams[i].chunk.length)
-                            return d;
+                            goto finish;
 =

                         if (cvolume =3D=3D PA_VOLUME_MUTED)
                             v =3D 0;
                         else {
-                            v =3D *((int16_t*) ((uint8_t*) streams[i].chun=
k.memblock->data + streams[i].chunk.index + d));
+                            v =3D *((int16_t*) ((uint8_t*) streams[i].inte=
rnal + streams[i].chunk.index + d));
 =

                             if (cvolume !=3D PA_VOLUME_NORM)
                                 v =3D (int32_t) (v * pa_sw_volume_to_linea=
r(cvolume));
@@ -155,17 +179,18 @@
                 if (++channel >=3D spec->channels)
                     channel =3D 0;
             }
+
+            break;
         }
 =

         case PA_SAMPLE_S16RE:{
-            size_t d;
             unsigned channel =3D 0;
 =

             for (d =3D 0;; d +=3D sizeof(int16_t)) {
                 int32_t sum =3D 0;
 =

                 if (d >=3D length)
-                    return d;
+                    goto finish;
 =

                 if (!mute && volume->values[channel] !=3D PA_VOLUME_MUTED)=
 {
                     unsigned i;
@@ -175,12 +200,12 @@
                         pa_volume_t cvolume =3D streams[i].volume.values[c=
hannel];
 =

                         if (d >=3D streams[i].chunk.length)
-                            return d;
+                            goto finish;
 =

                         if (cvolume =3D=3D PA_VOLUME_MUTED)
                             v =3D 0;
                         else {
-                            v =3D INT16_SWAP(*((int16_t*) ((uint8_t*) stre=
ams[i].chunk.memblock->data + streams[i].chunk.index + d)));
+                            v =3D INT16_SWAP(*((int16_t*) ((uint8_t*) stre=
ams[i].internal + streams[i].chunk.index + d)));
 =

                             if (cvolume !=3D PA_VOLUME_NORM)
                                 v =3D (int32_t) (v * pa_sw_volume_to_linea=
r(cvolume));
@@ -203,17 +228,18 @@
                 if (++channel >=3D spec->channels)
                     channel =3D 0;
             }
+
+            break;
         }
 =

         case PA_SAMPLE_U8: {
-            size_t d;
             unsigned channel =3D 0;
 =

             for (d =3D 0;; d ++) {
                 int32_t sum =3D 0;
 =

                 if (d >=3D length)
-                    return d;
+                    goto finish;
 =

                 if (!mute && volume->values[channel] !=3D PA_VOLUME_MUTED)=
 {
                     unsigned i;
@@ -223,12 +249,12 @@
                         pa_volume_t cvolume =3D streams[i].volume.values[c=
hannel];
 =

                         if (d >=3D streams[i].chunk.length)
-                            return d;
+                            goto finish;
 =

                         if (cvolume =3D=3D PA_VOLUME_MUTED)
                             v =3D 0;
                         else {
-                            v =3D (int32_t) *((uint8_t*) streams[i].chunk.=
memblock->data + streams[i].chunk.index + d) - 0x80;
+                            v =3D (int32_t) *((uint8_t*) streams[i].intern=
al + streams[i].chunk.index + d) - 0x80;
 =

                             if (cvolume !=3D PA_VOLUME_NORM)
                                 v =3D (int32_t) (v * pa_sw_volume_to_linea=
r(cvolume));
@@ -251,17 +277,18 @@
                 if (++channel >=3D spec->channels)
                     channel =3D 0;
             }
+
+            break;
         }
 =

         case PA_SAMPLE_FLOAT32NE: {
-            size_t d;
             unsigned channel =3D 0;
 =

             for (d =3D 0;; d +=3D sizeof(float)) {
                 float sum =3D 0;
 =

                 if (d >=3D length)
-                    return d;
+                    goto finish;
 =

                 if (!mute && volume->values[channel] !=3D PA_VOLUME_MUTED)=
 {
                     unsigned i;
@@ -271,12 +298,12 @@
                         pa_volume_t cvolume =3D streams[i].volume.values[c=
hannel];
 =

                         if (d >=3D streams[i].chunk.length)
-                            return d;
+                            goto finish;
 =

                         if (cvolume =3D=3D PA_VOLUME_MUTED)
                             v =3D 0;
                         else {
-                            v =3D *((float*) ((uint8_t*) streams[i].chunk.=
memblock->data + streams[i].chunk.index + d));
+                            v =3D *((float*) ((uint8_t*) streams[i].intern=
al + streams[i].chunk.index + d));
 =

                             if (cvolume !=3D PA_VOLUME_NORM)
                                 v *=3D pa_sw_volume_to_linear(cvolume);
@@ -295,17 +322,34 @@
                 if (++channel >=3D spec->channels)
                     channel =3D 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 p=
a_cvolume *volume) {
-    assert(c && spec && (c->length % pa_frame_size(spec) =3D=3D 0));
+
+finish:
+
+    for (k =3D 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;
+
+    assert(c);
+    assert(spec);
+    assert(c->length % pa_frame_size(spec) =3D=3D 0);
     assert(volume);
 =

     if (pa_cvolume_channels_equal_to(volume, PA_VOLUME_NORM))
@@ -315,6 +359,8 @@
         pa_silence_memchunk(c, spec);
         return;
     }
+
+    ptr =3D pa_memblock_acquire(c->memblock);
 =

     switch (spec->format) {
         case PA_SAMPLE_S16NE: {
@@ -326,7 +372,7 @@
             for (channel =3D 0; channel < spec->channels; channel++)
                 linear[channel] =3D pa_sw_volume_to_linear(volume->values[=
channel]);
 =

-            for (channel =3D 0, d =3D (int16_t*) ((uint8_t*) c->memblock->=
data+c->index), n =3D c->length/sizeof(int16_t); n > 0; d++, n--) {
+            for (channel =3D 0, d =3D (int16_t*) ((uint8_t*) ptr + c->inde=
x), n =3D c->length/sizeof(int16_t); n > 0; d++, n--) {
                 int32_t t =3D (int32_t)(*d);
 =

                 t =3D (int32_t) (t * linear[channel]);
@@ -351,7 +397,7 @@
             for (channel =3D 0; channel < spec->channels; channel++)
                 linear[channel] =3D pa_sw_volume_to_linear(volume->values[=
channel]);
 =

-            for (channel =3D 0, d =3D (int16_t*) ((uint8_t*) c->memblock->=
data+c->index), n =3D c->length/sizeof(int16_t); n > 0; d++, n--) {
+            for (channel =3D 0, d =3D (int16_t*) ((uint8_t*) ptr + c->inde=
x), n =3D c->length/sizeof(int16_t); n > 0; d++, n--) {
                 int32_t t =3D (int32_t)(INT16_SWAP(*d));
 =

                 t =3D (int32_t) (t * linear[channel]);
@@ -373,7 +419,7 @@
             size_t n;
             unsigned channel =3D 0;
 =

-            for (d =3D (uint8_t*) c->memblock->data + c->index, n =3D c->l=
ength; n > 0; d++, n--) {
+            for (d =3D (uint8_t*) ptr + c->index, n =3D c->length; n > 0; =
d++, n--) {
                 int32_t t =3D (int32_t) *d - 0x80;
 =

                 t =3D (int32_t) (t * pa_sw_volume_to_linear(volume->values=
[channel]));
@@ -395,7 +441,7 @@
             unsigned n;
             unsigned channel;
 =

-            d =3D (float*) ((uint8_t*) c->memblock->data + c->index);
+            d =3D (float*) ((uint8_t*) ptr + c->index);
             skip =3D spec->channels * sizeof(float);
             n =3D c->length/sizeof(float)/spec->channels;
 =

@@ -418,5 +464,7 @@
                 pa_sample_format_to_string(spec->format));
             abort();
     }
-}
-
+
+    pa_memblock_release(c->memblock);
+}
+

Modified: branches/lennart/src/pulsecore/sample-util.h
URL: http://0pointer.de/cgi-bin/viewcvs.cgi/branches/lennart/src/pulsecore/=
sample-util.h?rev=3D1469&root=3Dpulseaudio&r1=3D1468&r2=3D1469&view=3Ddiff
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D
--- branches/lennart/src/pulsecore/sample-util.h (original)
+++ branches/lennart/src/pulsecore/sample-util.h Mon Jun 11 14:08:37 2007
@@ -39,10 +39,11 @@
     pa_memchunk chunk;
     pa_cvolume volume;
     void *userdata;
+    void *internal; /* Used internally by pa_mix(), should not be initiali=
sed 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,

Added: branches/lennart/src/pulsecore/semaphore-posix.c
URL: http://0pointer.de/cgi-bin/viewcvs.cgi/branches/lennart/src/pulsecore/=
semaphore-posix.c?rev=3D1469&root=3Dpulseaudio&view=3Dauto
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D
--- branches/lennart/src/pulsecore/semaphore-posix.c (added)
+++ branches/lennart/src/pulsecore/semaphore-posix.c Mon Jun 11 14:08:37 20=
07
@@ -1,0 +1,69 @@
+/* $Id$ */
+
+/***
+  This file is part of PulseAudio.
+
+  Copyright 2006 Lennart Poettering
+
+  PulseAudio is free software; you can redistribute it and/or modify
+  it under the terms of the GNU Lesser General Public License as published
+  by the Free Software Foundation; either version 2 of the License,
+  or (at your option) any later version.
+
+  PulseAudio is distributed in the hope that it will be useful, but
+  WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+  General Public License for more details.
+
+  You should have received a copy of the GNU Lesser General Public License
+  along with PulseAudio; if not, write to the Free Software
+  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+  USA.
+***/
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <errno.h>
+#include <pthread.h>
+#include <semaphore.h>
+
+#include <pulse/xmalloc.h>
+#include <pulsecore/macro.h>
+
+#include "semaphore.h"
+
+struct pa_semaphore {
+    sem_t sem;
+};
+
+pa_semaphore* pa_semaphore_new(unsigned value) {
+    pa_semaphore *s;
+
+    s =3D pa_xnew(pa_semaphore, 1);
+    pa_assert_se(sem_init(&s->sem, 0, value) =3D=3D 0);
+    return s;
+}
+
+void pa_semaphore_free(pa_semaphore *s) {
+    pa_assert(s);
+    pa_assert_se(sem_destroy(&s->sem) =3D=3D 0);
+    pa_xfree(s);
+}
+
+void pa_semaphore_post(pa_semaphore *s) {
+    pa_assert(s);
+    pa_assert_se(sem_post(&s->sem) =3D=3D 0);
+}
+
+void pa_semaphore_wait(pa_semaphore *s) {
+    int ret;
+    pa_assert(s);
+    =

+    do {
+        ret =3D sem_wait(&s->sem);
+    } while (ret < 0 && errno =3D=3D EINTR);
+
+    pa_assert(ret =3D=3D 0);
+}

Propchange: branches/lennart/src/pulsecore/semaphore-posix.c
---------------------------------------------------------------------------=
---
    svn:keywords =3D Id

Added: branches/lennart/src/pulsecore/semaphore.h
URL: http://0pointer.de/cgi-bin/viewcvs.cgi/branches/lennart/src/pulsecore/=
semaphore.h?rev=3D1469&root=3Dpulseaudio&view=3Dauto
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D
--- branches/lennart/src/pulsecore/semaphore.h (added)
+++ branches/lennart/src/pulsecore/semaphore.h Mon Jun 11 14:08:37 2007
@@ -1,0 +1,35 @@
+#ifndef foopulsesemaphorehfoo
+#define foopulsesemaphorehfoo
+
+/* $Id$ */
+
+/***
+  This file is part of PulseAudio.
+
+  Copyright 2006 Lennart Poettering
+
+  PulseAudio is free software; you can redistribute it and/or modify
+  it under the terms of the GNU Lesser General Public License as
+  published by the Free Software Foundation; either version 2 of the
+  License, or (at your option) any later version.
+
+  PulseAudio is distributed in the hope that it will be useful, but
+  WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+  General Public License for more details.
+
+  You should have received a copy of the GNU Lesser General Public
+  License along with PulseAudio; if not, write to the Free Software
+  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+  USA.
+***/
+
+typedef struct pa_semaphore pa_semaphore;
+
+pa_semaphore* pa_semaphore_new(unsigned value);
+void pa_semaphore_free(pa_semaphore *m);
+
+void pa_semaphore_post(pa_semaphore *m);
+void pa_semaphore_wait(pa_semaphore *m);
+
+#endif

Propchange: branches/lennart/src/pulsecore/semaphore.h
---------------------------------------------------------------------------=
---
    svn:keywords =3D Id

Modified: branches/lennart/src/pulsecore/sink-input.c
URL: http://0pointer.de/cgi-bin/viewcvs.cgi/branches/lennart/src/pulsecore/=
sink-input.c?rev=3D1469&root=3Dpulseaudio&r1=3D1468&r2=3D1469&view=3Ddiff
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D
--- branches/lennart/src/pulsecore/sink-input.c (original)
+++ branches/lennart/src/pulsecore/sink-input.c Mon Jun 11 14:08:37 2007
@@ -27,7 +27,6 @@
 #endif
 =

 #include <stdio.h>
-#include <assert.h>
 #include <stdlib.h>
 #include <string.h>
 =

@@ -46,39 +45,43 @@
 #define MOVE_BUFFER_LENGTH (1024*1024)
 #define SILENCE_BUFFER_LENGTH (64*1024)
 =

-#define CHECK_VALIDITY_RETURN_NULL(condition) \
-do {\
-if (!(condition)) \
-    return NULL; \
-} while (0)
+static void sink_input_free(pa_msgobject *o);
 =

 pa_sink_input_new_data* pa_sink_input_new_data_init(pa_sink_input_new_data=
 *data) {
-    assert(data);
+    pa_assert(data);
 =

     memset(data, 0, sizeof(*data));
     data->resample_method =3D 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 =3D !!map))
         data->channel_map =3D *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 =3D !!volume))
         data->volume =3D *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 =3D !!spec))
         data->sample_spec =3D *spec;
+}
+
+void pa_sink_input_new_data_set_muted(pa_sink_input_new_data *data, int mu=
te) {
+    pa_assert(data);
+
+    data->muted_is_set =3D 1;
+    data->muted =3D !!mute;
 }
 =

 pa_sink_input* pa_sink_input_new(
@@ -88,46 +91,52 @@
 =

     pa_sink_input *i;
     pa_resampler *resampler =3D NULL;
-    int r;
     char st[PA_SAMPLE_SPEC_SNPRINT_MAX];
 =

-    assert(core);
-    assert(data);
+    pa_assert(core);
+    pa_assert(data);
 =

     if (!(flags & PA_SINK_INPUT_NO_HOOKS))
         if (pa_hook_fire(&core->hook_sink_input_new, data) < 0)
             return NULL;
 =

-    CHECK_VALIDITY_RETURN_NULL(!data->driver || pa_utf8_valid(data->driver=
));
-    CHECK_VALIDITY_RETURN_NULL(!data->name || pa_utf8_valid(data->name));
+    pa_return_null_if_fail(!data->driver || pa_utf8_valid(data->driver));
+    pa_return_null_if_fail(!data->name || pa_utf8_valid(data->name));
 =

     if (!data->sink)
         data->sink =3D pa_namereg_get(core, NULL, PA_NAMEREG_SINK, 1);
 =

-    CHECK_VALIDITY_RETURN_NULL(data->sink);
-    CHECK_VALIDITY_RETURN_NULL(data->sink->state =3D=3D PA_SINK_RUNNING);
+    pa_return_null_if_fail(data->sink);
+    pa_return_null_if_fail(pa_sink_get_state(data->sink) !=3D PA_SINK_DISC=
ONNECTED);
 =

     if (!data->sample_spec_is_set)
         data->sample_spec =3D 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.cha=
nnels, PA_CHANNEL_MAP_DEFAULT);
-
-    CHECK_VALIDITY_RETURN_NULL(pa_channel_map_valid(&data->channel_map));
-    CHECK_VALIDITY_RETURN_NULL(data->channel_map.channels =3D=3D data->sam=
ple_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 =3D=3D data->sample_spec.chan=
nels)
+            data->channel_map =3D 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 =3D=3D 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 =3D=3D data->sample_s=
pec.channels);
-
+    pa_return_null_if_fail(pa_cvolume_valid(&data->volume));
+    pa_return_null_if_fail(data->volume.channels =3D=3D data->sample_spec.=
channels);
+
+    if (!data->muted_is_set)
+        data->muted =3D 0;
+    =

     if (data->resample_method =3D=3D PA_RESAMPLER_INVALID)
         data->resample_method =3D 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) >=3D PA_MAX_INPUTS_PER_SINK) {
         pa_log_warn("Failed to create sink input: too many inputs per sink=
.");
@@ -136,7 +145,7 @@
 =

     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 =3D pa_resampler_new(
                       core->mempool,
@@ -147,20 +156,31 @@
             return NULL;
         }
 =

-    i =3D pa_xnew(pa_sink_input, 1);
-    i->ref =3D 1;
-    i->state =3D PA_SINK_INPUT_DRAINED;
+        data->resample_method =3D pa_resampler_get_method(resampler);
+    }
+
+    i =3D pa_msgobject_new(pa_sink_input);
+
+    i->parent.parent.free =3D sink_input_free;
+    i->parent.process_msg =3D pa_sink_input_process_msg;
+    =

+    i->core =3D core;
+    pa_atomic_load(&i->state, PA_SINK_INPUT_DRAINED);
     i->flags =3D flags;
     i->name =3D pa_xstrdup(data->name);
     i->driver =3D pa_xstrdup(data->driver);
     i->module =3D data->module;
     i->sink =3D data->sink;
     i->client =3D data->client;
-
+    =

+    i->resample_method =3D data->resample_method;
     i->sample_spec =3D data->sample_spec;
     i->channel_map =3D data->channel_map;
+
     i->volume =3D data->volume;
-
+    i->muted =3D data->muted;
+    =

+    i->process_msg =3D NULL;
     i->peek =3D NULL;
     i->drop =3D NULL;
     i->kill =3D NULL;
@@ -168,94 +188,87 @@
     i->underrun =3D NULL;
     i->userdata =3D NULL;
 =

-    i->move_silence =3D 0;
-
-    pa_memchunk_reset(&i->resampled_chunk);
-    i->resampler =3D resampler;
-    i->resample_method =3D data->resample_method;
-    i->silence_memblock =3D NULL;
-
-    r =3D pa_idxset_put(core->sink_inputs, i, &i->index);
-    assert(r =3D=3D 0);
-    r =3D pa_idxset_put(i->sink->inputs, i, NULL);
-    assert(r =3D=3D 0);
-
-    pa_log_info("created %u \"%s\" on %s with sample spec %s",
+    i->thread_info.silence_memblock =3D NULL;
+    i->thread_info.move_silence =3D 0;
+    pa_memchunk_reset(&i->thread_info.resampled_chunk);
+    i->thread_info.resampler =3D resampler;
+    i->thread_info.soft_volume =3D i->volume;
+    i->thread_info.soft_muted =3D i->muted;
+
+    pa_assert_se(pa_idxset_put(core->sink_inputs, i, &i->index) =3D=3D 0);
+    pa_assert_se(pa_idxset_put(i->sink->inputs, i, NULL) =3D=3D 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_SUBSCRI=
PTION_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 !=3D PA_SINK_INPUT_DISCONNECTED);
-    assert(i->sink);
-    assert(i->sink->core);
-
+    pa_assert(i);
+    pa_return_if_fail(pa_sink_input_get_state(i) !=3D PA_SINK_INPUT_DISCON=
NECTED);
+
+    pa_asyncmsgq_send(i->sink->asyncmsgq, i->sink, PA_SINK_MESSAGE_REMOVE_=
INPUT, i, NULL);
+    =

     pa_idxset_remove_by_data(i->sink->core->sink_inputs, i, NULL);
     pa_idxset_remove_by_data(i->sink->inputs, i, NULL);
 =

     pa_subscription_post(i->sink->core, PA_SUBSCRIPTION_EVENT_SINK_INPUT|P=
A_SUBSCRIPTION_EVENT_REMOVE, i->index);
     i->sink =3D NULL;
 =

+    i->process_msg =3D NULL;
     i->peek =3D NULL;
     i->drop =3D NULL;
     i->kill =3D NULL;
     i->get_latency =3D NULL;
     i->underrun =3D NULL;
 =

-    i->state =3D PA_SINK_INPUT_DISCONNECTED;
-}
-
-static void sink_input_free(pa_sink_input* i) {
-    assert(i);
-
-    if (i->state !=3D PA_SINK_INPUT_DISCONNECTED)
-        pa_sink_input_disconnect(i);
-
-    pa_log_info("freed %u \"%s\"", i->index, i->name);
+    pa_atomic_load(&i->state, PA_SINK_INPUT_DISCONNECTED);
+}
+
+static void sink_input_free(pa_msgobject *o) {
+    pa_sink_input* i =3D PA_SINK_INPUT(o);
+
+    pa_assert(i);
+    pa_assert(pa_sink_input_refcnt(i) =3D=3D 0);
+    =

+    pa_sink_input_disconnect(i);
+
+    pa_log_info("Freeing output %u \"%s\"", i->index, i->name);
 =

     if (i->resampled_chunk.memblock)
         pa_memblock_unref(i->resampled_chunk.memblock);
 =

-    if (i->resampler)
-        pa_resampler_free(i->resampler);
-
-    if (i->silence_memblock)
-        pa_memblock_unref(i->silence_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 >=3D 1);
-
-    if (!(--i->ref))
-        sink_input_free(i);
-}
-
-pa_sink_input* pa_sink_input_ref(pa_sink_input *i) {
-    assert(i);
-    assert(i->ref >=3D 1);
-
-    i->ref++;
-    return i;
+void pa_sink_input_put(pa_sink_input *i) {
+    pa_sink_input_assert_ref(i);
+
+    i->thread_info.volume =3D i->volume;
+    i->thread_info.muted =3D i->muted;
+
+    pa_asyncmsgq_post(i->sink->asyncmsgq, i->sink, PA_SINK_MESSAGE_ADD_INP=
UT, i, NULL, pa_sink_unref, pa_sink_input_unref);
+    pa_sink_update_status(i->sink);
+
+    pa_subscription_post(core, PA_SUBSCRIPTION_EVENT_SINK_INPUT|PA_SUBSCRI=
PTION_EVENT_NEW, i->index);
 }
 =

 void pa_sink_input_kill(pa_sink_input*i) {
-    assert(i);
-    assert(i->ref >=3D 1);
+    pa_sink_input_assert_ref(i);
 =

     if (i->kill)
         i->kill(i);
@@ -264,17 +277,13 @@
 pa_usec_t pa_sink_input_get_latency(pa_sink_input *i) {
     pa_usec_t r =3D 0;
 =

-    assert(i);
-    assert(i->ref >=3D 1);
-
+    pa_sink_input_assert_ref(i);
+
+    if (pa_asyncmsgq_send(i->sink->asyncmsgq, i->sink, PA_SINK_INPUT_MESSA=
GE_GET_LATENCY, &r, NULL) < 0)
+        r =3D 0;
+    =

     if (i->get_latency)
         r +=3D i->get_latency(i);
-
-    if (i->resampled_chunk.memblock)
-        r +=3D pa_bytes_to_usec(i->resampled_chunk.length, &i->sink->sampl=
e_spec);
-
-    if (i->move_silence)
-        r +=3D pa_bytes_to_usec(i->move_silence, &i->sink->sample_spec);
 =

     return r;
 }
@@ -283,35 +292,40 @@
     int ret =3D -1;
     int do_volume_adj_here;
     int volume_is_norm;
-
-    assert(i);
-    assert(i->ref >=3D 1);
-    assert(chunk);
-    assert(volume);
-
-    pa_sink_input_ref(i);
-
-    if (!i->peek || !i->drop || i->state =3D=3D PA_SINK_INPUT_CORKED)
+    pa_sink_input_state_t state;
+    =

+    pa_sink_input_assert_ref(i);
+    pa_assert(chunk);
+    pa_assert(volume);
+
+    state =3D pa_sink_input_get_state(i);
+
+    if (state =3D=3D PA_SINK_INPUT_DISCONNECTED)
+        return -1;
+
+    if (!i->peek || !i->drop || state =3D=3D PA_SINK_INPUT_CORKED)
         goto finish;
 =

-    assert(i->state =3D=3D PA_SINK_INPUT_RUNNING || i->state =3D=3D PA_SIN=
K_INPUT_DRAINED);
-
-    if (i->move_silence > 0) {
-
-        /* 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 =3D pa_silence_memblock_new(i->sink->core-=
>mempool, &i->sink->sample_spec, SILENCE_BUFFER_LENGTH);
-
-        chunk->memblock =3D pa_memblock_ref(i->silence_memblock);
-        chunk->index =3D 0;
-        chunk->length =3D i->move_silence < chunk->memblock->length ? i->m=
ove_silence : chunk->memblock->length;
-
-        ret =3D 0;
-        do_volume_adj_here =3D 1;
-        goto finish;
-    }
+    pa_assert(state =3D=3D PA_SINK_INPUT_RUNNING || state =3D=3D PA_SINK_I=
NPUT_DRAINED);
+
+/*     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->thread_info.silence_memblock) */
+/*             i->thread_info.silence_memblock =3D pa_silence_memblock_new=
(i->sink->core->mempool, &i->sink->sample_spec, SILENCE_BUFFER_LENGTH); */
+
+/*         chunk->memblock =3D pa_memblock_ref(i->thread_info.silence_memb=
lock); */
+/*         chunk->index =3D 0; */
+/*         l =3D pa_memblock_get_length(chunk->memblock); */
+/*         chunk->length =3D i->move_silence < l ? i->move_silence : l; */
+
+/*         ret =3D 0; */
+/*         do_volume_adj_here =3D 1; */
+/*         goto finish; */
+/*     } */
 =

     if (!i->resampler) {
         do_volume_adj_here =3D 0;
@@ -320,16 +334,16 @@
     }
 =

     do_volume_adj_here =3D !pa_channel_map_equal(&i->channel_map, &i->sink=
->channel_map);
-    volume_is_norm =3D pa_cvolume_is_norm(&i->volume);
-
-    while (!i->resampled_chunk.memblock) {
+    volume_is_norm =3D pa_cvolume_is_norm(&i->thread_info.soft_volume) && =
!i->thread_info.soft_muted;
+
+    while (!i->thread_info.resampled_chunk.memblock) {
         pa_memchunk tchunk;
         size_t l;
 =

         if ((ret =3D i->peek(i, &tchunk)) < 0)
             goto finish;
 =

-        assert(tchunk.length);
+        pa_assert(tchunk.length);
 =

         l =3D pa_resampler_request(i->resampler, CONVERT_BUFFER_LENGTH);
 =

@@ -342,30 +356,30 @@
         /* It might be necessary to adjust the volume here */
         if (do_volume_adj_here && !volume_is_norm) {
             pa_memchunk_make_writable(&tchunk, 0);
-            pa_volume_memchunk(&tchunk, &i->sample_spec, &i->volume);
+            pa_volume_memchunk(&tchunk, &i->sample_spec, &i->thread_info.s=
oft_volume);
         }
 =

-        pa_resampler_run(i->resampler, &tchunk, &i->resampled_chunk);
+        pa_resampler_run(i->resampler, &tchunk, &i->thread_info.resampled_=
chunk);
         pa_memblock_unref(tchunk.memblock);
     }
 =

-    assert(i->resampled_chunk.memblock);
-    assert(i->resampled_chunk.length);
-
-    *chunk =3D 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);
+
+    *chunk =3D i->thread_info.resampled_chunk;
+    pa_memblock_ref(i->thread_info.resampled_chunk.memblock);
 =

     ret =3D 0;
 =

 finish:
 =

-    if (ret < 0 && i->state =3D=3D PA_SINK_INPUT_RUNNING && i->underrun)
+    if (ret < 0 && state =3D=3D PA_SINK_INPUT_RUNNING && i->underrun)
         i->underrun(i);
 =

     if (ret >=3D 0)
-        i->state =3D PA_SINK_INPUT_RUNNING;
+        pa_atomic_cmpxchg(&i->state, state, PA_SINK_INPUT_RUNNING);
     else if (ret < 0 && i->state =3D=3D PA_SINK_INPUT_RUNNING)
-        i->state =3D PA_SINK_INPUT_DRAINED;
+        pa_atomic_cmpxchg(&i->state, state, PA_SINK_INPUT_DRAINED);
 =

     if (ret >=3D 0) {
         /* Let's see if we had to apply the volume adjustment
@@ -376,42 +390,42 @@
             pa_cvolume_reset(volume, i->sink->sample_spec.channels);
         else
             /* We've both the same channel map, so let's have the sink do =
the adjustment for us*/
-            *volume =3D i->volume;
-    }
-
-    pa_sink_input_unref(i);
+            *volume =3D 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 >=3D 1);
-    assert(length > 0);
-
-    if (i->move_silence > 0) {
-
-        if (chunk) {
-
-            if (chunk->memblock !=3D i->silence_memblock ||
-                chunk->index !=3D 0 ||
-                (chunk->memblock && (chunk->length !=3D (i->silence_memblo=
ck->length < i->move_silence ? i->silence_memblock->length : i->move_silenc=
e))))
-                return;
-
-        }
-
-        assert(i->move_silence >=3D length);
-
-        i->move_silence -=3D length;
-
-        if (i->move_silence <=3D 0) {
-            assert(i->silence_memblock);
-            pa_memblock_unref(i->silence_memblock);
-            i->silence_memblock =3D NULL;
-        }
-
-        return;
-    }
+    pa_sink_input_assert_ref(i);
+    pa_assert(length > 0);
+
+/*     if (i->move_silence > 0) { */
+
+/*         if (chunk) { */
+/*             size_t l; */
+
+/*             l =3D pa_memblock_get_length(i->silence_memblock); */
+
+/*             if (chunk->memblock !=3D i->silence_memblock || */
+/*                 chunk->index !=3D 0 || */
+/*                 (chunk->memblock && (chunk->length !=3D (l < i->move_si=
lence ? l : i->move_silence)))) */
+/*                 return; */
+
+/*         } */
+
+/*         pa_assert(i->move_silence >=3D length); */
+
+/*         i->move_silence -=3D length; */
+
+/*         if (i->move_silence <=3D 0) { */
+/*             pa_assert(i->silence_memblock); */
+/*             pa_memblock_unref(i->silence_memblock); */
+/*             i->silence_memblock =3D NULL; */
+/*         } */
+
+/*         return; */
+/*     } */
 =

     if (!i->resampler) {
         if (i->drop)
@@ -419,75 +433,88 @@
         return;
     }
 =

-    assert(i->resampled_chunk.memblock);
-    assert(i->resampled_chunk.length >=3D length);
-
-    i->resampled_chunk.index +=3D length;
-    i->resampled_chunk.length -=3D length;
-
-    if (i->resampled_chunk.length <=3D 0) {
-        pa_memblock_unref(i->resampled_chunk.memblock);
-        i->resampled_chunk.memblock =3D NULL;
-        i->resampled_chunk.index =3D i->resampled_chunk.length =3D 0;
+    pa_assert(i->thread_info.resampled_chunk.memblock);
+    pa_assert(i->thread_info.resampled_chunk.length >=3D length);
+
+    i->thread_info.resampled_chunk.index +=3D length;
+    i->thread_info.resampled_chunk.length -=3D length;
+
+    if (i->thread_info.resampled_chunk.length <=3D 0) {
+        pa_memblock_unref(i->thread_info.resampled_chunk.memblock);
+        i->thread_info.resampled_chunk.memblock =3D NULL;
+        i->thread_info.resampled_chunk.index =3D i->thread_info.resampled_=
chunk.length =3D 0;
     }
 }
 =

 void pa_sink_input_set_volume(pa_sink_input *i, const pa_cvolume *volume) {
-    assert(i);
-    assert(i->ref >=3D 1);
-    assert(i->sink);
-    assert(i->sink->core);
+    pa_sink_input_assert_ref(i);
 =

     if (pa_cvolume_equal(&i->volume, volume))
         return;
 =

     i->volume =3D *volume;
+
+    pa_asyncmsgq_post(s->asyncmsgq, pa_sink_input_ref(i), PA_SINK_INPUT_ME=
SSAGE_SET_VOLUME, pa_xnewdup(struct pa_cvolume, volume, 1), pa_sink_input_u=
nref, pa_xfree);
     pa_subscription_post(i->sink->core, PA_SUBSCRIPTION_EVENT_SINK_INPUT|P=
A_SUBSCRIPTION_EVENT_CHANGE, i->index);
 }
 =

-const pa_cvolume * pa_sink_input_get_volume(pa_sink_input *i) {
-    assert(i);
-    assert(i->ref >=3D 1);
+const pa_cvolume *pa_sink_input_get_volume(pa_sink_input *i) {
+    pa_sink_input_assert_ref(i);
 =

     return &i->volume;
+}
+
+void pa_sink_input_set_mute(pa_sink_input *i, int mute) {
+    pa_assert(i);
+    pa_sink_input_assert_ref(i);
+
+    if (!i->muted =3D=3D !mute)
+        return;
+
+    i->muted =3D mute;
+
+    pa_asyncmsgq_post(s->asyncmsgq, pa_sink_input_ref(i), PA_SINK_INPUT_ME=
SSAGE_SET_MUTE, PA_UINT_TO_PTR(mute), pa_sink_input_unref, NULL);
+    pa_subscription_post(i->sink->core, PA_SUBSCRIPTION_EVENT_SINK_INPUT|P=
A_SUBSCRIPTION_EVENT_CHANGE, i->index);
+}
+
+int pa_sink_input_get_mute(pa_sink_input *i) {
+    pa_sink_input_assert_ref(i);
+
+    return !!i->mute;
 }
 =

 void pa_sink_input_cork(pa_sink_input *i, int b) {
     int n;
-
-    assert(i);
-    assert(i->ref >=3D 1);
-
-    assert(i->state !=3D PA_SINK_INPUT_DISCONNECTED);
-
-    n =3D i->state =3D=3D PA_SINK_INPUT_CORKED && !b;
-
-    if (b)
-        i->state =3D PA_SINK_INPUT_CORKED;
-    else if (i->state =3D=3D PA_SINK_INPUT_CORKED)
-        i->state =3D 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 >=3D 1);
+    pa_sink_input_state_t state;
+
+    pa_sink_input_assert_ref(i);
+
+    state =3D pa_sink_input_get_state(i);
+    pa_assert(state !=3D PA_SINK_INPUT_DISCONNECTED);
+
+    if (b && state !=3D PA_SINK_INPUT_CORKED)
+        pa_atomic_store(i->state, PA_SINK_INPUT_CORKED);
+    else if (!b && state =3D=3D PA_SINK_INPUT_CORKED)
+        pa_atomic_cmpxchg(i->state, state, PA_SINK_INPUT_DRAINED);
+}
+
+int pa_sink_input_set_rate(pa_sink_input *i, uint32_t rate) {
+    pa_sink_input_assert_ref(i);
+    pa_return_val_if_fail(u->thread_info.resampler, -1);
 =

     if (i->sample_spec.rate =3D=3D rate)
-        return;
+        return 0;
 =

     i->sample_spec.rate =3D rate;
-    pa_resampler_set_input_rate(i->resampler, rate);
-
+
+    pa_asyncmsgq_post(s->asyncmsgq, pa_sink_input_ref(i), PA_SINK_INPUT_ME=
SSAGE_SET_RATE, PA_UINT_TO_PTR(rate), NULL, pa_sink_input_unref, NULL);
+    =

     pa_subscription_post(i->sink->core, PA_SUBSCRIPTION_EVENT_SINK_INPUT|P=
A_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 >=3D 1);
+    pa_sink_input_assert_ref(i);
 =

     if (!i->name && !name)
         return;
@@ -502,13 +529,9 @@
 }
 =

 pa_resample_method_t pa_sink_input_get_resample_method(pa_sink_input *i) {
-    assert(i);
-    assert(i->ref >=3D 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=
) {
@@ -516,156 +539,196 @@
     pa_memblockq *buffer =3D NULL;
     pa_sink *origin;
 =

-    assert(i);
-    assert(dest);
-
-    origin =3D i->sink;
-
-    if (dest =3D=3D origin)
-        return 0;
-
-    if (pa_idxset_size(dest->inputs) >=3D PA_MAX_INPUTS_PER_SINK) {
-        pa_log_warn("Failed to move sink input: too many inputs per sink."=
);
-        return -1;
-    }
-
-    if (i->resampler &&
-        pa_sample_spec_equal(&origin->sample_spec, &dest->sample_spec) &&
-        pa_channel_map_equal(&origin->channel_map, &dest->channel_map))
-
-        /* Try to reuse the old resampler if possible */
-        new_resampler =3D i->resampler;
-
-    else if ((i->flags & PA_SINK_INPUT_VARIABLE_RATE) ||
-        !pa_sample_spec_equal(&i->sample_spec, &dest->sample_spec) ||
-        !pa_channel_map_equal(&i->channel_map, &dest->channel_map)) {
-
-        /* Okey, we need a new resampler for the new sink */
-
-        if (!(new_resampler =3D pa_resampler_new(
-                      dest->core->mempool,
-                      &i->sample_spec, &i->channel_map,
-                      &dest->sample_spec, &dest->channel_map,
-                      i->resample_method))) {
-            pa_log_warn("Unsupported resampling operation.");
-            return -1;
+    pa_sink_input_assert_ref(i);
+    pa_sink_assert_ref(dest);
+
+    return -1;
+    =

+/*     origin =3D i->sink; */
+
+/*     if (dest =3D=3D origin) */
+/*         return 0; */
+
+/*     if (pa_idxset_size(dest->inputs) >=3D PA_MAX_INPUTS_PER_SINK) { */
+/*         pa_log_warn("Failed to move sink input: too many inputs per sin=
k."); */
+/*         return -1; */
+/*     } */
+
+/*     if (i->resampler && */
+/*         pa_sample_spec_equal(&origin->sample_spec, &dest->sample_spec) =
&& */
+/*         pa_channel_map_equal(&origin->channel_map, &dest->channel_map))=
 */
+
+/*         /\* Try to reuse the old resampler if possible *\/ */
+/*         new_resampler =3D i->resampler; */
+
+/*     else if ((i->flags & PA_SINK_INPUT_VARIABLE_RATE) || */
+/*         !pa_sample_spec_equal(&i->sample_spec, &dest->sample_spec) || */
+/*         !pa_channel_map_equal(&i->channel_map, &dest->channel_map)) { */
+
+/*         /\* Okey, we need a new resampler for the new sink *\/ */
+
+/*         if (!(new_resampler =3D pa_resampler_new( */
+/*                       dest->core->mempool, */
+/*                       &i->sample_spec, &i->channel_map, */
+/*                       &dest->sample_spec, &dest->channel_map, */
+/*                       i->resample_method))) { */
+/*             pa_log_warn("Unsupported resampling operation."); */
+/*             return -1; */
+/*         } */
+/*     } */
+
+/*     if (!immediately) { */
+/*         pa_usec_t old_latency, new_latency; */
+/*         pa_usec_t silence_usec =3D 0; */
+
+/*         buffer =3D 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 *\/ */
+
+/*         old_latency =3D pa_sink_get_latency(origin); */
+/*         new_latency =3D pa_sink_get_latency(dest); */
+
+/*         /\* The already resampled data should go to the old sink *\/ */
+
+/*         if (old_latency >=3D new_latency) { */
+
+/*             /\* The latency of the old sink is larger than the latency =
*/
+/*              * of the new sink. Therefore to compensate for the */
+/*              * difference we to play silence on the new one for a */
+/*              * while *\/ */
+
+/*             silence_usec =3D 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 */
+/*              * and make sure that this is still played on the old */
+/*              * sink, until we can play the first sample on the new */
+/*              * sink.*\/ */
+
+/*             l =3D pa_usec_to_bytes(new_latency - old_latency, &origin->=
sample_spec); */
+
+/*             volume_is_norm =3D 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 =3D chunk.length > l ? l : chunk.length; */
+/*                 pa_sink_input_drop(i, &chunk, n); */
+/*                 chunk.length =3D n; */
+
+/*                 if (!volume_is_norm) { */
+/*                     pa_memchunk_make_writable(&chunk, 0); */
+/*                     pa_volume_memchunk(&chunk, &origin->sample_spec, &v=
olume); */
+/*                 } */
+
+/*                 if (pa_memblockq_push(buffer, &chunk) < 0) { */
+/*                     pa_memblock_unref(chunk.memblock); */
+/*                     break; */
+/*                 } */
+
+/*                 pa_memblock_unref(chunk.memblock); */
+/*                 l -=3D 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 +=3D pa_bytes_to_usec(i->resampled_chunk.lengt=
h, &origin->sample_spec); */
+/*         } */
+
+/*         /\* Calculate the new sleeping time *\/ */
+/*         i->move_silence =3D pa_usec_to_bytes( */
+/*                 pa_bytes_to_usec(i->move_silence, &i->sample_spec) + */
+/*                 silence_usec, */
+/*                 &i->sample_spec); */
+/*     } */
+
+/*     /\* Okey, let's move it *\/ */
+/*     pa_idxset_remove_by_data(origin->inputs, i, NULL); */
+/*     pa_idxset_put(dest->inputs, i, NULL); */
+/*     i->sink =3D dest; */
+
+/*     /\* Replace resampler *\/ */
+/*     if (new_resampler !=3D i->resampler) { */
+/*         if (i->resampler) */
+/*             pa_resampler_free(i->resampler); */
+/*         i->resampler =3D 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 =3D NULL; */
+/*         } */
+/*     } */
+
+/*     /\* Dump already resampled data *\/ */
+/*     if (i->resampled_chunk.memblock) { */
+/*         pa_memblock_unref(i->resampled_chunk.memblock); */
+/*         i->resampled_chunk.memblock =3D NULL; */
+/*         i->resampled_chunk.index =3D i->resampled_chunk.length =3D 0; */
+/*     } */
+
+/*     /\* Notify everyone *\/ */
+/*     pa_subscription_post(i->sink->core, PA_SUBSCRIPTION_EVENT_SINK_INPU=
T|PA_SUBSCRIPTION_EVENT_CHANGE, i->index); */
+/*     pa_sink_notify(i->sink); */
+
+/*     /\* Ok, now let's feed the precomputed buffer to the old sink *\/ */
+/*     if (buffer) */
+/*         pa_play_memblockq(origin, "Ghost Stream", &origin->sample_spec,=
 &origin->channel_map, buffer, NULL); */
+
+/*     return 0; */
+}
+
+int pa_sink_input_process_msg(pa_msgobject *o, int code, void *userdata, p=
a_memchunk *chunk) {
+    pa_sink_input *i =3D PA_SINK_INPUT(o);
+    =

+    pa_sink_input_assert_ref(i);
+
+    switch (code) {
+        case PA_SINK_INPUT_MESSAGE_SET_VOLUME:
+            s->thread_info.soft_volume =3D *((pa_cvolume*) userdata);
+            return 0;
+            =

+        case PA_SINK_INPUT_MESSAGE_SET_MUTE:
+            s->thread_info.soft_muted =3D PA_PTR_TO_UINT(userdata);
+            return 0;
+            =

+        case PA_SINK_INPUT_MESSAGE_GET_LATENCY: {
+            pa_usec_t *r =3D userdata;
+            =

+            if (i->thread_info.resampled_chunk.memblock)
+                *r +=3D pa_bytes_to_usec(i->resampled_chunk.length, &i->si=
nk->sample_spec);
+
+/*             if (i->move_silence) */
+/*                 r +=3D pa_bytes_to_usec(i->move_silence, &i->sink->samp=
le_spec); */
+            =

+            return 0;
         }
-    }
-
-    if (!immediately) {
-        pa_usec_t old_latency, new_latency;
-        pa_usec_t silence_usec =3D 0;
-
-        buffer =3D pa_memblockq_new(0, MOVE_BUFFER_LENGTH, 0, pa_frame_siz=
e(&origin->sample_spec), 0, 0, NULL);
-
-        /* Let's do a little bit of Voodoo for compensating latency
-         * differences */
-
-        old_latency =3D pa_sink_get_latency(origin);
-        new_latency =3D pa_sink_get_latency(dest);
-
-        /* The already resampled data should go to the old sink */
-
-        if (old_latency >=3D new_latency) {
-
-            /* The latency of the old sink is larger than the latency
-             * of the new sink. Therefore to compensate for the
-             * difference we to play silence on the new one for a
-             * while */
-
-            silence_usec =3D 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
-             * and make sure that this is still played on the old
-             * sink, until we can play the first sample on the new
-             * sink.*/
-
-            l =3D pa_usec_to_bytes(new_latency - old_latency, &origin->sam=
ple_spec);
-
-            volume_is_norm =3D 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 =3D chunk.length > l ? l : chunk.length;
-                pa_sink_input_drop(i, &chunk, n);
-                chunk.length =3D n;
-
-                if (!volume_is_norm) {
-                    pa_memchunk_make_writable(&chunk, 0);
-                    pa_volume_memchunk(&chunk, &origin->sample_spec, &volu=
me);
-                }
-
-                if (pa_memblockq_push(buffer, &chunk) < 0) {
-                    pa_memblock_unref(chunk.memblock);
-                    break;
-                }
-
-                pa_memblock_unref(chunk.memblock);
-                l -=3D n;
-            }
+            =

+        case PA_SINK_INPUT_MESSAGE_SET_RATE: {
+            =

+            i->thread_info.sample_spec.rate =3D PA_PTR_TO_UINT(userdata);
+            pa_resampler_set_input_rate(i->resampler, PA_PTR_TO_UINT(userd=
ata));
+
+            return 0;
         }
-
-        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 +=3D pa_bytes_to_usec(i->resampled_chunk.length, =
&origin->sample_spec);
-        }
-
-        /* Calculate the new sleeping time */
-        i->move_silence =3D pa_usec_to_bytes(
-                pa_bytes_to_usec(i->move_silence, &i->sample_spec) +
-                silence_usec,
-                &i->sample_spec);
-    }
-
-    /* Okey, let's move it */
-    pa_idxset_remove_by_data(origin->inputs, i, NULL);
-    pa_idxset_put(dest->inputs, i, NULL);
-    i->sink =3D dest;
-
-    /* Replace resampler */
-    if (new_resampler !=3D i->resampler) {
-        if (i->resampler)
-            pa_resampler_free(i->resampler);
-        i->resampler =3D 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 =3D NULL;
-        }
-    }
-
-    /* Dump already resampled data */
-    if (i->resampled_chunk.memblock) {
-        pa_memblock_unref(i->resampled_chunk.memblock);
-        i->resampled_chunk.memblock =3D NULL;
-        i->resampled_chunk.index =3D i->resampled_chunk.length =3D 0;
-    }
-
-    /* Notify everyone */
-    pa_subscription_post(i->sink->core, PA_SUBSCRIPTION_EVENT_SINK_INPUT|P=
A_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, &o=
rigin->channel_map, buffer, NULL);
-
-    return 0;
-}
+    }
+
+    return -1;
+}

Modified: branches/lennart/src/pulsecore/sink-input.h
URL: http://0pointer.de/cgi-bin/viewcvs.cgi/branches/lennart/src/pulsecore/=
sink-input.h?rev=3D1469&root=3Dpulseaudio&r1=3D1468&r2=3D1469&view=3Ddiff
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D
--- branches/lennart/src/pulsecore/sink-input.h (original)
+++ branches/lennart/src/pulsecore/sink-input.h Mon Jun 11 14:08:37 2007
@@ -1,5 +1,5 @@
-#ifndef foosinkinputhfoo
-#define foosinkinputhfoo
+#ifndef foopulsesinkinputhfoo
+#define foopulsesinkinputhfoo
 =

 /* $Id$ */
 =

@@ -51,9 +51,11 @@
 } pa_sink_input_flags_t;
 =

 struct pa_sink_input {
-    int ref;
+    pa_msgobject parent;
+    =

     uint32_t index;
-    pa_sink_input_state_t state;
+    pa_core *core;
+    pa_atomic_t state;
     pa_sink_input_flags_t flags;
 =

     char *name, *driver;                /* may be NULL */
@@ -64,27 +66,47 @@
 =

     pa_sample_spec sample_spec;
     pa_channel_map channel_map;
+    =

     pa_cvolume volume;
+    int muted;
 =

-    /* Some silence to play before the actual data. This is used to
-     * compensate for latency differences when moving a sink input
-     * "hot" between sinks. */
-    size_t move_silence;
-
+    int (*process_msg)(pa_sink_input *i, int code, void *userdata); =

     int (*peek) (pa_sink_input *i, pa_memchunk *chunk);
     void (*drop) (pa_sink_input *i, const pa_memchunk *chunk, size_t lengt=
h);
     void (*kill) (pa_sink_input *i);             /* may be NULL */
     pa_usec_t (*get_latency) (pa_sink_input *i); /* may be NULL */
     void (*underrun) (pa_sink_input *i);         /* may be NULL */
 =

-    void *userdata;
-
-    pa_memchunk resampled_chunk;
-    pa_resampler *resampler;                     /* may be NULL */
-
     pa_resample_method_t resample_method;
 =

-    pa_memblock *silence_memblock;               /* may be NULL */
+    struct {
+        pa_sample_spec sample_spec;
+        =

+        pa_memchunk resampled_chunk;
+        pa_resampler *resampler;                     /* may be NULL */
+        =

+        /* Some silence to play before the actual data. This is used to
+         * compensate for latency differences when moving a sink input
+         * "hot" between sinks. */
+        /*         size_t move_silence; */
+        pa_memblock *silence_memblock;               /* may be NULL */
+
+        pa_cvolume volume;
+        int muted;
+    } thread_info;
+    =

+    void *userdata;
+};
+
+PA_DECLARE_CLASS(pa_sink_input);
+#define PA_SINK_INPUT(o) ((pa_sink_input*) (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_MAX
 };
 =

 typedef struct pa_sink_input_new_data {
@@ -100,6 +122,8 @@
     int channel_map_is_set;
     pa_cvolume volume;
     int volume_is_set;
+    int muted;
+    int muted_is_set;
 =

     pa_resample_method_t resample_method;
 } pa_sink_input_new_data;
@@ -108,37 +132,46 @@
 void pa_sink_input_new_data_set_sample_spec(pa_sink_input_new_data *data, =
const pa_sample_spec *spec);
 void pa_sink_input_new_data_set_channel_map(pa_sink_input_new_data *data, =
const pa_channel_map *map);
 void pa_sink_input_new_data_set_volume(pa_sink_input_new_data *data, const=
 pa_cvolume *volume);
+void pa_sink_input_new_data_set_muted(pa_sink_input_new_data *data, int mu=
te);
+
+/* To be called by the implementing module only */
 =

 pa_sink_input* pa_sink_input_new(
         pa_core *core,
         pa_sink_input_new_data *data,
         pa_sink_input_flags_t flags);
 =

-void pa_sink_input_unref(pa_sink_input* i);
-pa_sink_input* pa_sink_input_ref(pa_sink_input* i);
-
-/* To be called by the implementing module only */
+void pa_sink_input_put(pa_sink_input *i);
 void pa_sink_input_disconnect(pa_sink_input* i);
 =

-/* External code may request disconnection with this funcion */
+void pa_sink_input_set_name(pa_sink_input *i, const char *name);
+
+/* Callable by everyone */
+
+/* External code may request disconnection with this function */
 void pa_sink_input_kill(pa_sink_input*i);
 =

 pa_usec_t pa_sink_input_get_latency(pa_sink_input *i);
 =

-int pa_sink_input_peek(pa_sink_input *i, pa_memchunk *chunk, pa_cvolume *v=
olume);
-void pa_sink_input_drop(pa_sink_input *i, const pa_memchunk *chunk, size_t=
 length);
-
 void pa_sink_input_set_volume(pa_sink_input *i, const pa_cvolume *volume);
-const pa_cvolume * pa_sink_input_get_volume(pa_sink_input *i);
+const pa_cvolume *pa_sink_input_get_volume(pa_sink_input *i);
+void pa_sink_input_set_mute(pa_sink_input *i, int mute);
+int pa_sink_input_get_mute(pa_sink_input *i);
 =

 void pa_sink_input_cork(pa_sink_input *i, int b);
 =

 void pa_sink_input_set_rate(pa_sink_input *i, uint32_t rate);
 =

-void pa_sink_input_set_name(pa_sink_input *i, const char *name);
-
 pa_resample_method_t pa_sink_input_get_resample_method(pa_sink_input *i);
 =

 int pa_sink_input_move_to(pa_sink_input *i, pa_sink *dest, int immediately=
);
 =

+#define pa_sink_input_get_state(i) ((pa_sink_input_state_t) pa_atomic_load=
(&i->state))
+
+/* To be used exclusively by the sink driver thread */
+
+int pa_sink_input_peek(pa_sink_input *i, pa_memchunk *chunk, pa_cvolume *v=
olume);
+void pa_sink_input_drop(pa_sink_input *i, const pa_memchunk *chunk, size_t=
 length);
+int pa_sink_input_process_msg(pa_msgobject *o, int code, void *userdata, p=
a_memchunk *chunk);
+
 #endif

Modified: branches/lennart/src/pulsecore/sink.c
URL: http://0pointer.de/cgi-bin/viewcvs.cgi/branches/lennart/src/pulsecore/=
sink.c?rev=3D1469&root=3Dpulseaudio&r1=3D1468&r2=3D1469&view=3Ddiff
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D
--- branches/lennart/src/pulsecore/sink.c (original)
+++ branches/lennart/src/pulsecore/sink.c Mon Jun 11 14:08:37 2007
@@ -41,16 +41,13 @@
 #include <pulsecore/sample-util.h>
 #include <pulsecore/core-subscribe.h>
 #include <pulsecore/log.h>
+#include <pulsecore/macro.h>
 =

 #include "sink.h"
 =

 #define MAX_MIX_CHANNELS 32
 =

-#define CHECK_VALIDITY_RETURN_NULL(condition) \
-do {\
-if (!(condition)) \
-    return NULL; \
-} while (0)
+static void sink_free(pa_object *s);
 =

 pa_sink* pa_sink_new(
         pa_core *core,
@@ -66,60 +63,64 @@
     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 =3D 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 =3D=3D spec->channels);
-    CHECK_VALIDITY_RETURN_NULL(!driver || pa_utf8_valid(driver));
-    CHECK_VALIDITY_RETURN_NULL(pa_utf8_valid(name) && *name);
-
-    s =3D pa_xnew(pa_sink, 1);
+    pa_return_null_if_fail(map && pa_channel_map_valid(map));
+    pa_return_null_if_fail(map->channels =3D=3D spec->channels);
+    pa_return_null_if_fail(!driver || pa_utf8_valid(driver));
+    pa_return_null_if_fail(name && pa_utf8_valid(name) && *name);
+
+    s =3D pa_msgobject_new(pa_sink);
 =

     if (!(name =3D pa_namereg_register(core, name, PA_NAMEREG_SINK, s, fai=
l))) {
         pa_xfree(s);
         return NULL;
     }
 =

-    s->ref =3D 1;
+    s->parent.parent.free =3D sink_free;
+    s->parent.process_msg =3D pa_sink_process_msg;
+    =

     s->core =3D core;
-    s->state =3D PA_SINK_RUNNING;
+    pa_atomic_store(&s->state, PA_SINK_IDLE);
     s->name =3D pa_xstrdup(name);
     s->description =3D NULL;
     s->driver =3D pa_xstrdup(driver);
-    s->owner =3D NULL;
+    s->module =3D NULL;
 =

     s->sample_spec =3D *spec;
     s->channel_map =3D *map;
 =

     s->inputs =3D pa_idxset_new(NULL, NULL);
 =

-    pa_cvolume_reset(&s->sw_volume, spec->channels);
-    pa_cvolume_reset(&s->hw_volume, spec->channels);
-    s->sw_muted =3D 0;
-    s->hw_muted =3D 0;
+    pa_cvolume_reset(&s->volume, spec->channels);
+    s->muted =3D 0;
+    s->refresh_volume =3D s->refresh_mute =3D 0;
 =

     s->is_hardware =3D 0;
 =

     s->get_latency =3D NULL;
-    s->notify =3D NULL;
-    s->set_hw_volume =3D NULL;
-    s->get_hw_volume =3D NULL;
-    s->set_hw_mute =3D NULL;
-    s->get_hw_mute =3D NULL;
+    s->set_volume =3D NULL;
+    s->get_volume =3D NULL;
+    s->set_mute =3D NULL;
+    s->get_mute =3D NULL;
+    s->start =3D NULL;
+    s->stop =3D NULL;
     s->userdata =3D NULL;
 =

+    pa_assert_se(s->asyncmsgq =3D pa_asyncmsgq_new(0));
+    =

     r =3D pa_idxset_put(core->sinks, s, &s->index);
-    assert(s->index !=3D PA_IDXSET_INVALID && r >=3D 0);
+    pa_assert(s->index !=3D PA_IDXSET_INVALID && r >=3D 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 =3D pa_sprintf_malloc("%s.monitor", name);
 =

@@ -135,24 +136,64 @@
 =

     pa_xfree(n);
 =

+    s->thread_info.inputs =3D pa_hashmap_new(pa_idxset_trivial_hash_func, =
pa_idxset_trivial_compare_func);
+    s->thread_info.soft_volume =3D s->volume;
+    s->thread_info.soft_muted =3D s->muted;
+    =

     pa_subscription_post(core, PA_SUBSCRIPTION_EVENT_SINK | PA_SUBSCRIPTIO=
N_EVENT_NEW, s->index);
 =

     return s;
+}
+
+static void sink_start(pa_sink *s) {
+    pa_sink_state_t state;
+    pa_assert(s);
+
+    state =3D pa_sink_get_state(s);
+    pa_return_if_fail(state =3D=3D PA_SINK_IDLE || state =3D=3D PA_SINK_SU=
SPENDED);
+
+    pa_atomic_store(&s->state, PA_SINK_RUNNING);
+
+    if (s->start)
+        s->start(s);
+    else
+        pa_asyncmsgq_post(s->asyncmsgq, PA_MSGOBJECT(s), PA_SINK_MESSAGE_S=
TART, NULL, NULL, NULL);
+}
+
+static void sink_stop(pa_sink *s) {
+    pa_sink_state_t state;
+    int stop;
+    =

+    pa_assert(s);
+    state =3D pa_sink_get_state(s);
+    pa_return_if_fail(state =3D=3D PA_SINK_RUNNING || state =3D=3D PA_SINK=
_SUSPENDED);
+
+    stop =3D state =3D=3D PA_SINK_RUNNING;
+    pa_atomic_store(&s->state, PA_SINK_IDLE);
+
+    if (stop) {
+        if (s->stop)
+            s->stop(s);
+        else
+            pa_asyncmsgq_post(s->asyncmsgq, PA_MSGOBJECT(s), PA_SINK_MESSA=
GE_STOP, NULL, NULL, NULL);
+    }
 }
 =

 void pa_sink_disconnect(pa_sink* s) {
     pa_sink_input *i, *j =3D NULL;
 =

-    assert(s);
-    assert(s->state =3D=3D PA_SINK_RUNNING);
-
-    s->state =3D PA_SINK_DISCONNECTED;
+    pa_assert(s);
+    pa_return_if_fail(pa_sink_get_state(s) !=3D PA_SINK_DISCONNECTED);
+
+    sink_stop(s);
+
+    pa_atomic_store(&s->state, PA_SINK_DISCONNECTED);
     pa_namereg_unregister(s->core, s->name);
 =

     pa_hook_fire(&s->core->hook_sink_disconnect, s);
 =

     while ((i =3D pa_idxset_first(s->inputs, NULL))) {
-        assert(i !=3D j);
+        pa_assert(i !=3D j);
         pa_sink_input_kill(i);
         j =3D i;
     }
@@ -163,23 +204,25 @@
     pa_idxset_remove_by_data(s->core->sinks, s, NULL);
 =

     s->get_latency =3D NULL;
-    s->notify =3D NULL;
-    s->get_hw_volume =3D NULL;
-    s->set_hw_volume =3D NULL;
-    s->set_hw_mute =3D NULL;
-    s->get_hw_mute =3D NULL;
+    s->get_volume =3D NULL;
+    s->set_volume =3D NULL;
+    s->set_mute =3D NULL;
+    s->get_mute =3D NULL;
+    s->start =3D NULL;
+    s->stop =3D NULL;
 =

     pa_subscription_post(s->core, PA_SUBSCRIPTION_EVENT_SINK | PA_SUBSCRIP=
TION_EVENT_REMOVE, s->index);
 }
 =

-static void sink_free(pa_sink *s) {
-    assert(s);
-    assert(!s->ref);
-
-    if (s->state !=3D PA_SINK_DISCONNECTED)
-        pa_sink_disconnect(s);
-
-    pa_log_info("freed %u \"%s\"", s->index, s->name);
+static void sink_free(pa_object *o) {
+    pa_sink *s =3D PA_SINK(o);
+            =

+    pa_assert(s);
+    pa_assert(pa_sink_refcnt(s) =3D=3D 0);
+
+    pa_sink_disconnect(s);
+
+    pa_log_info("Freeing sink %u \"%s\"", s->index, s->name);
 =

     if (s->monitor_source) {
         pa_source_unref(s->monitor_source);
@@ -187,47 +230,66 @@
     }
 =

     pa_idxset_free(s->inputs, NULL, NULL);
-
+    =

+    pa_hashmap_free(s->thread_info.inputs, (pa_free2_cb_t) pa_sink_input_u=
nref, NULL);
+
+    pa_asyncmsgq_free(s->asyncmsgq);
+    =

     pa_xfree(s->name);
     pa_xfree(s->description);
     pa_xfree(s->driver);
     pa_xfree(s);
 }
 =

-void pa_sink_unref(pa_sink*s) {
-    assert(s);
-    assert(s->ref >=3D 1);
-
-    if (!(--s->ref))
-        sink_free(s);
-}
-
-pa_sink* pa_sink_ref(pa_sink *s) {
-    assert(s);
-    assert(s->ref >=3D 1);
-
-    s->ref++;
-    return s;
-}
-
-void pa_sink_notify(pa_sink*s) {
-    assert(s);
-    assert(s->ref >=3D 1);
-
-    if (s->notify)
-        s->notify(s);
+void pa_sink_update_status(pa_sink*s) {
+    pa_sink_assert_ref(s);
+
+    if (pa_sink_get_state(s) =3D=3D PA_SINK_SUSPENDED)
+        return;
+    =

+    if (pa_sink_used_by(s) > 0)
+        sink_start(s);
+    else
+        sink_stop(s);
+}
+
+void pa_sink_suspend(pa_sink *s, int suspend) {
+    pa_sink_state_t state;
+
+    pa_sink_assert_ref(s);
+
+    state =3D pa_sink_get_state(s);
+    pa_return_if_fail(suspend && (state =3D=3D PA_SINK_RUNNING || state =
=3D=3D PA_SINK_IDLE));
+    pa_return_if_fail(!suspend && (state =3D=3D PA_SINK_SUSPENDED));
+
+
+    if (suspend) {
+        pa_atomic_store(&s->state, PA_SINK_SUSPENDED);
+
+        if (s->stop)
+            s->stop(s);
+        else
+            pa_asyncmsgq_post(s->asyncmsgq, PA_MSGOBJECT(s), PA_SINK_MESSA=
GE_STOP, NULL, NULL, NULL);
+        =

+    } else {
+        pa_atomic_store(&s->state, PA_SINK_RUNNING);
+
+        if (s->start)
+            s->start(s);
+        else
+            pa_asyncmsgq_post(s->asyncmsgq, PA_MSGOBJECT(s), PA_SINK_MESSA=
GE_START, NULL, NULL, NULL);
+    }
 }
 =

 static unsigned fill_mix_info(pa_sink *s, pa_mix_info *info, unsigned maxi=
nfo) {
-    uint32_t idx =3D PA_IDXSET_INVALID;
     pa_sink_input *i;
     unsigned n =3D 0;
-
-    assert(s);
-    assert(s->ref >=3D 1);
-    assert(info);
-
-    for (i =3D pa_idxset_first(s->inputs, &idx); maxinfo > 0 && i; i =3D p=
a_idxset_next(s->inputs, &idx)) {
+    void *state =3D NULL;
+
+    pa_sink_assert_ref(s);
+    pa_assert(info);
+
+    while ((i =3D pa_hashmap_iterate(s->thread_info.inputs, &state, NULL))=
) {
         /* Increase ref counter, to make sure that this input doesn't
          * vanish while we still need it */
         pa_sink_input_ref(i);
@@ -239,9 +301,8 @@
 =

         info->userdata =3D i;
 =

-        assert(info->chunk.memblock);
-        assert(info->chunk.memblock->data);
-        assert(info->chunk.length);
+        pa_assert(info->chunk.memblock);
+        pa_assert(info->chunk.length);
 =

         info++;
         maxinfo--;
@@ -252,15 +313,14 @@
 }
 =

 static void inputs_drop(pa_sink *s, pa_mix_info *info, unsigned maxinfo, s=
ize_t length) {
-    assert(s);
-    assert(s->ref >=3D 1);
-    assert(info);
+    pa_sink_assert_ref(s);
+    pa_assert(info);
 =

     for (; maxinfo > 0; maxinfo--, info++) {
         pa_sink_input *i =3D info->userdata;
 =

-        assert(i);
-        assert(info->chunk.memblock);
+        pa_assert(i);
+        pa_assert(info->chunk.memblock);
 =

         /* Drop read data */
         pa_sink_input_drop(i, &info->chunk, length);
@@ -277,10 +337,9 @@
     unsigned n;
     int r =3D -1;
 =

-    assert(s);
-    assert(s->ref >=3D 1);
-    assert(length);
-    assert(result);
+    pa_sink_assert_ref(s);
+    pa_assert(length);
+    pa_assert(result);
 =

     pa_sink_ref(s);
 =

@@ -298,23 +357,23 @@
         if (result->length > length)
             result->length =3D 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 =3D pa_memblock_new(s->core->mempool, length);
-        assert(result->memblock);
-
-/*          pa_log("mixing %i", n);  */
-
-        result->length =3D pa_mix(info, n, result->memblock->data, length,
-            &s->sample_spec, &s->sw_volume, s->sw_muted);
+
+        ptr =3D pa_memblock_acquire(result->memblock);
+        result->length =3D 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 =3D 0;
     }
 =

@@ -336,12 +395,10 @@
     unsigned n;
     int r =3D -1;
 =

-    assert(s);
-    assert(s->ref >=3D 1);
-    assert(target);
-    assert(target->memblock);
-    assert(target->length);
-    assert(target->memblock->data);
+    pa_sink_assert_ref(s);
+    pa_assert(target);
+    pa_assert(target->memblock);
+    pa_assert(target->length);
 =

     pa_sink_ref(s);
 =

@@ -350,30 +407,48 @@
     if (n <=3D 0)
         goto finish;
 =

+
     if (n =3D=3D 1) {
-        pa_cvolume volume;
-
         if (target->length > info[0].chunk.length)
             target->length =3D info[0].chunk.length;
 =

-        memcpy((uint8_t*) target->memblock->data + target->index,
-               (uint8_t*) info[0].chunk.memblock->data + info[0].chunk.ind=
ex,
-               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 =3D pa_memblock_acquire(target->memblock);
+            src =3D 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 =3D pa_memblock_acquire(target->memblock);
+        =

         target->length =3D pa_mix(info, n,
-                                (uint8_t*) target->memblock->data + target=
->index,
+                                (uint8_t*) ptr + target->index,
                                 target->length,
                                 &s->sample_spec,
-                                &s->sw_volume,
-                                s->sw_muted);
-
+                                &s->thread_info.soft_volume,
+                                s->thread_info.soft_muted);
+    =

+        pa_memblock_release(target->memblock);
+    }
+    =

     inputs_drop(s, info, n, target->length);
 =

     if (s->monitor_source)
@@ -391,12 +466,10 @@
     pa_memchunk chunk;
     size_t l, d;
 =

-    assert(s);
-    assert(s->ref >=3D 1);
-    assert(target);
-    assert(target->memblock);
-    assert(target->length);
-    assert(target->memblock->data);
+    pa_sink_assert_ref(s);
+    pa_assert(target);
+    pa_assert(target->memblock);
+    pa_assert(target->length);
 =

     pa_sink_ref(s);
 =

@@ -425,10 +498,9 @@
 }
 =

 void pa_sink_render_full(pa_sink *s, size_t length, pa_memchunk *result) {
-    assert(s);
-    assert(s->ref >=3D 1);
-    assert(length);
-    assert(result);
+    pa_sink_assert_ref(s);
+    pa_assert(length);
+    pa_assert(result);
 =

     /*** This needs optimization ***/
 =

@@ -439,108 +511,109 @@
 }
 =

 pa_usec_t pa_sink_get_latency(pa_sink *s) {
-    assert(s);
-    assert(s->ref >=3D 1);
-
-    if (!s->get_latency)
+    pa_usec_t usec =3D 0;
+    =

+    pa_sink_assert_ref(s);
+
+    if (s->get_latency)
+        return s->get_latency(s);
+    =

+    if (pa_asyncmsgq_send(s->asyncmsgq, PA_MSGOBJECT(s), PA_SINK_MESSAGE_G=
ET_LATENCY, &usec, NULL) < 0)
         return 0;
 =

-    return s->get_latency(s);
-}
-
-void pa_sink_set_owner(pa_sink *s, pa_module *m) {
-    assert(s);
-    assert(s->ref >=3D 1);
-
-    if (s->owner =3D=3D m)
+    return usec;
+}
+
+void pa_sink_set_volume(pa_sink *s, const pa_cvolume *volume) {
+    int changed;
+
+    pa_sink_assert_ref(s);
+    pa_assert(volume);
+
+    changed =3D !pa_cvolume_equal(volume, &s->volume);
+    s->volume =3D *volume;
+    =

+    if (s->set_volume && s->set_volume(s) < 0)
+        s->set_volume =3D NULL;
+
+    if (!s->set_volume)
+        pa_asyncmsgq_post(s->asyncmsgq, PA_MSGOBJECT(s), PA_SINK_MESSAGE_S=
ET_VOLUME, pa_xnewdup(struct pa_cvolume, volume, 1), NULL, pa_xfree);
+
+    if (changed)
+        pa_subscription_post(s->core, PA_SUBSCRIPTION_EVENT_SINK|PA_SUBSCR=
IPTION_EVENT_CHANGE, s->index);
+}
+
+const pa_cvolume *pa_sink_get_volume(pa_sink *s) {
+    struct pa_cvolume old_volume;
+
+    pa_sink_assert_ref(s);
+
+    old_volume =3D s->volume;
+    =

+    if (s->get_volume && s->get_volume(s) < 0)
+        s->get_volume =3D NULL;
+
+    if (!s->get_volume && s->refresh_volume)
+        pa_asyncmsgq_send(s->asyncmsgq, PA_MSGOBJECT(s), PA_SINK_MESSAGE_G=
ET_VOLUME, &s->volume, NULL);
+
+    if (!pa_cvolume_equal(&old_volume, &s->volume))
+        pa_subscription_post(s->core, PA_SUBSCRIPTION_EVENT_SINK|PA_SUBSCR=
IPTION_EVENT_CHANGE, s->index);
+    =

+    return &s->volume;
+}
+
+void pa_sink_set_mute(pa_sink *s, int mute) {
+    int changed;
+    =

+    pa_sink_assert_ref(s);
+
+    changed =3D s->muted !=3D mute;
+
+    if (s->set_mute && s->set_mute(s) < 0)
+        s->set_mute =3D NULL;
+
+    if (!s->set_mute)
+        pa_asyncmsgq_post(s->asyncmsgq, PA_MSGOBJECT(s), PA_SINK_MESSAGE_S=
ET_MUTE, PA_UINT_TO_PTR(mute), NULL, NULL);
+
+    if (changed)
+        pa_subscription_post(s->core, PA_SUBSCRIPTION_EVENT_SINK|PA_SUBSCR=
IPTION_EVENT_CHANGE, s->index);
+}
+
+int pa_sink_get_mute(pa_sink *s) {
+    int old_muted;
+    =

+    pa_sink_assert_ref(s);
+
+    old_muted =3D s->muted;
+    =

+    if (s->get_mute && s->get_mute(s) < 0)
+        s->get_mute =3D NULL;
+
+    if (!s->get_mute && s->refresh_mute)
+        pa_asyncmsgq_send(s->asyncmsgq, PA_MSGOBJECT(s), PA_SINK_MESSAGE_G=
ET_MUTE, &s->muted, NULL);
+
+    if (old_muted !=3D s->muted)
+        pa_subscription_post(s->core, PA_SUBSCRIPTION_EVENT_SINK|PA_SUBSCR=
IPTION_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 =3D=3D m)
         return;
 =

-    s->owner =3D m;
+    s->module =3D 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_SUBSCRIPTI=
ON_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 >=3D 1);
-    assert(volume);
-
-    if (m =3D=3D PA_MIXER_HARDWARE && s->set_hw_volume)
-        v =3D &s->hw_volume;
-    else
-        v =3D &s->sw_volume;
-
-    if (pa_cvolume_equal(v, volume))
-        return;
-
-    *v =3D *volume;
-
-    if (v =3D=3D &s->hw_volume)
-        if (s->set_hw_volume(s) < 0)
-            s->sw_volume =3D  *volume;
-
-    pa_subscription_post(s->core, PA_SUBSCRIPTION_EVENT_SINK|PA_SUBSCRIPTI=
ON_EVENT_CHANGE, s->index);
-}
-
-const pa_cvolume *pa_sink_get_volume(pa_sink *s, pa_mixer_t m) {
-    assert(s);
-    assert(s->ref >=3D 1);
-
-    if (m =3D=3D 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 >=3D 1);
-
-    if (m =3D=3D PA_MIXER_HARDWARE && s->set_hw_mute)
-        t =3D &s->hw_muted;
-    else
-        t =3D &s->sw_muted;
-
-    if (!!*t =3D=3D !!mute)
-        return;
-
-    *t =3D !!mute;
-
-    if (t =3D=3D &s->hw_muted)
-        if (s->set_hw_mute(s) < 0)
-            s->sw_muted =3D !!mute;
-
-    pa_subscription_post(s->core, PA_SUBSCRIPTION_EVENT_SINK|PA_SUBSCRIPTI=
ON_EVENT_CHANGE, s->index);
-}
-
-int pa_sink_get_mute(pa_sink *s, pa_mixer_t m) {
-    assert(s);
-    assert(s->ref >=3D 1);
-
-    if (m =3D=3D 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 >=3D 1);
+    pa_sink_assert_ref(s);
 =

     if (!description && !s->description)
         return;
@@ -565,8 +638,7 @@
 unsigned pa_sink_used_by(pa_sink *s) {
     unsigned ret;
 =

-    assert(s);
-    assert(s->ref >=3D 1);
+    pa_sink_assert_ref(s);
 =

     ret =3D pa_idxset_size(s->inputs);
 =

@@ -575,3 +647,41 @@
 =

     return ret;
 }
+
+int pa_sink_process_msg(pa_msgobject *o, int code, void *userdata, pa_memc=
hunk *chunk) {
+    pa_sink *s =3D PA_SINK(o);
+    pa_sink_assert_ref(s);
+
+    switch (code) {
+        case PA_SINK_MESSAGE_ADD_INPUT: {
+            pa_sink_input *i =3D userdata;
+            pa_hashmap_put(s->thread_info.inputs, PA_UINT32_TO_PTR(i->inde=
x), pa_sink_input_ref(i));
+            return 0;
+        }
+            =

+        case PA_SINK_MESSAGE_REMOVE_INPUT: {
+            pa_sink_input *i =3D userdata;
+            pa_hashmap_remove(s->thread_info.inputs, PA_UINT32_TO_PTR(i->i=
ndex));
+            return 0;
+        }
+            =

+        case PA_SINK_MESSAGE_SET_VOLUME:
+            s->thread_info.soft_volume =3D *((pa_cvolume*) userdata);
+            return 0;
+            =

+        case PA_SINK_MESSAGE_SET_MUTE:
+            s->thread_info.soft_muted =3D PA_PTR_TO_UINT(userdata);
+            return 0;
+            =

+        case PA_SINK_MESSAGE_GET_VOLUME:
+            *((pa_cvolume*) userdata) =3D s->thread_info.soft_volume;
+            return 0;
+            =

+        case PA_SINK_MESSAGE_GET_MUTE:
+            *((int*) userdata) =3D s->thread_info.soft_muted;
+            return 0;
+            =

+        default:
+            return -1;
+    }
+}

Modified: branches/lennart/src/pulsecore/sink.h
URL: http://0pointer.de/cgi-bin/viewcvs.cgi/branches/lennart/src/pulsecore/=
sink.h?rev=3D1469&root=3Dpulseaudio&r1=3D1468&r2=3D1469&view=3Ddiff
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D
--- branches/lennart/src/pulsecore/sink.h (original)
+++ branches/lennart/src/pulsecore/sink.h Mon Jun 11 14:08:37 2007
@@ -1,5 +1,5 @@
-#ifndef foosinkhfoo
-#define foosinkhfoo
+#ifndef foopulsesinkhfoo
+#define foopulsesinkhfoo
 =

 /* $Id$ */
 =

@@ -25,37 +25,43 @@
   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>
 =

 #define PA_MAX_INPUTS_PER_SINK 32
 =

 typedef enum pa_sink_state {
     PA_SINK_RUNNING,
+    PA_SINK_SUSPENDED,
+    PA_SINK_IDLE,
     PA_SINK_DISCONNECTED
 } pa_sink_state_t;
 =

 struct pa_sink {
-    int ref;
+    pa_msgobject parent;
+
     uint32_t index;
     pa_core *core;
-    pa_sink_state_t state;
+    pa_atomic_t state;
 =

     char *name;
     char *description, *driver;            /* may be NULL */
     int is_hardware;
 =

-    pa_module *owner;                      /* may be NULL */
+    pa_module *module;                      /* may be NULL */
 =

     pa_sample_spec sample_spec;
     pa_channel_map channel_map;
@@ -63,49 +69,85 @@
     pa_idxset *inputs;
     pa_source *monitor_source;             /* may be NULL */
 =

-    pa_cvolume hw_volume, sw_volume;
-    int hw_muted, sw_muted;
+    pa_cvolume volume;
+    int muted;
+    int refresh_volume;
+    int 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 (*start)(pa_sink *s);
+    int (*stop)(pa_sink *s);
+    int (*set_volume)(pa_sink *s);      /* dito */
+    int (*get_volume)(pa_sink *s);      /* dito */
+    int (*get_mute)(pa_sink *s);        /* dito */
+    int (*set_mute)(pa_sink *s);        /* dito */
+    pa_usec_t (*get_latency)(pa_sink *s);    /* dito */
+
+    pa_asyncmsgq *asyncmsgq;
+
+    /* Contains copies of the above data so that the real-time worker
+     * thread can work without access locking */
+    struct {
+        pa_hashmap *inputs;
+        pa_cvolume soft_volume;
+        int soft_muted;
+    } thread_info;
 =

     void *userdata;
 };
 =

+PA_DECLARE_CLASS(pa_sink);
+#define PA_SINK(s) ((pa_sink*) (s))
+
+typedef enum pa_sink_message {
+    PA_SINK_MESSAGE_ADD_INPUT,
+    PA_SINK_MESSAGE_REMOVE_INPUT,
+    PA_SINK_MESSAGE_GET_VOLUME,
+    PA_SINK_MESSAGE_SET_VOLUME,
+    PA_SINK_MESSAGE_GET_MUTE,
+    PA_SINK_MESSAGE_SET_MUTE,
+    PA_SINK_MESSAGE_GET_LATENCY,
+    PA_SINK_MESSAGE_START,
+    PA_SINK_MESSAGE_STOP,
+    PA_SINK_MESSAGE_MAX
+} pa_sink_message_t;
+
+/* To be used exclusively by the sink driver */
+
 pa_sink* pa_sink_new(
-    pa_core *core,
-    const char *driver,
-    const char *name,
-    int namereg_fail,
-    const pa_sample_spec *spec,
-    const pa_channel_map *map);
+        pa_core *core,
+        const char *driver,
+        const char *name,
+        int namereg_fail,
+        const pa_sample_spec *spec,
+        const pa_channel_map *map);
 =

 void pa_sink_disconnect(pa_sink* s);
-void pa_sink_unref(pa_sink*s);
-pa_sink* pa_sink_ref(pa_sink *s);
+
+void pa_sink_set_module(pa_sink *sink, pa_module *m);
+void pa_sink_set_description(pa_sink *s, const char *description);
+
+/* Usable by everyone */
+
+pa_usec_t pa_sink_get_latency(pa_sink *s);
+
+void pa_sink_update_status(pa_sink*s);
+void pa_sink_suspend(pa_sink *s, int suspend);
+
+void pa_sink_set_volume(pa_sink *sink, const pa_cvolume *volume);
+const pa_cvolume *pa_sink_get_volume(pa_sink *sink);
+void pa_sink_set_mute(pa_sink *sink, int mute);
+int pa_sink_get_mute(pa_sink *sink);
+
+unsigned pa_sink_used_by(pa_sink *s);
+#define pa_sink_get_state(s) ((pa_sink_state_t) pa_atomic_load(&(s)->state=
))
+
+/* To be used exclusively by the sink driver thread */
 =

 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);
 =

-pa_usec_t pa_sink_get_latency(pa_sink *s);
-
-void pa_sink_notify(pa_sink*s);
-
-void pa_sink_set_owner(pa_sink *sink, pa_module *m);
-
-void pa_sink_set_volume(pa_sink *sink, pa_mixer_t m, const pa_cvolume *vol=
ume);
-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_description(pa_sink *s, const char *description);
-
-unsigned pa_sink_used_by(pa_sink *s);
+int pa_sink_process_msg(pa_msgobject *o, int code, void *userdata, pa_memc=
hunk *chunk);
 =

 #endif

Modified: branches/lennart/src/pulsecore/sound-file-stream.c
URL: http://0pointer.de/cgi-bin/viewcvs.cgi/branches/lennart/src/pulsecore/=
sound-file-stream.c?rev=3D1469&root=3Dpulseaudio&r1=3D1468&r2=3D1469&view=
=3Ddiff
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D
--- branches/lennart/src/pulsecore/sound-file-stream.c (original)
+++ branches/lennart/src/pulsecore/sound-file-stream.c Mon Jun 11 14:08:37 =
2007
@@ -76,21 +76,25 @@
     if (!u->memchunk.memblock) {
         uint32_t fs =3D pa_frame_size(&i->sample_spec);
         sf_count_t n;
+        void *p;
 =

         u->memchunk.memblock =3D pa_memblock_new(i->sink->core->mempool, B=
UF_SIZE);
         u->memchunk.index =3D 0;
 =

+        p =3D pa_memblock_acquire(u->memchunk.memblock);
+
         if (u->readf_function) {
-            if ((n =3D u->readf_function(u->sndfile, u->memchunk.memblock-=
>data, BUF_SIZE/fs)) <=3D 0)
+            if ((n =3D u->readf_function(u->sndfile, p, BUF_SIZE/fs)) <=3D=
 0)
                 n =3D 0;
 =

             u->memchunk.length =3D n * fs;
         } else {
-            if ((n =3D sf_read_raw(u->sndfile, u->memchunk.memblock->data,=
 BUF_SIZE)) <=3D 0)
+            if ((n =3D sf_read_raw(u->sndfile, p, BUF_SIZE)) <=3D 0)
                 n =3D 0;
 =

             u->memchunk.length =3D n;
         }
+        pa_memblock_release(u->memchunk.memblock);
 =

         if (!u->memchunk.length) {
             free_userdata(u);

Modified: branches/lennart/src/pulsecore/sound-file.c
URL: http://0pointer.de/cgi-bin/viewcvs.cgi/branches/lennart/src/pulsecore/=
sound-file.c?rev=3D1469&root=3Dpulseaudio&r1=3D1468&r2=3D1469&view=3Ddiff
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D
--- branches/lennart/src/pulsecore/sound-file.c (original)
+++ branches/lennart/src/pulsecore/sound-file.c Mon Jun 11 14:08:37 2007
@@ -42,7 +42,11 @@
     int ret =3D -1;
     size_t l;
     sf_count_t (*readf_function)(SNDFILE *sndfile, void *ptr, sf_count_t f=
rames) =3D NULL;
-    assert(fname && ss && chunk);
+    void *ptr =3D NULL;
+
+    assert(fname);
+    assert(ss);
+    assert(chunk);
 =

     chunk->memblock =3D NULL;
     chunk->index =3D chunk->length =3D 0;
@@ -99,8 +103,10 @@
     chunk->index =3D 0;
     chunk->length =3D l;
 =

-    if ((readf_function && readf_function(sf, chunk->memblock->data, sfinf=
o.frames) !=3D sfinfo.frames) ||
-        (!readf_function && sf_read_raw(sf, chunk->memblock->data, l) !=3D=
 l)) {
+    ptr =3D pa_memblock_acquire(chunk->memblock);
+
+    if ((readf_function && readf_function(sf, ptr, sfinfo.frames) !=3D sfi=
nfo.frames) ||
+        (!readf_function && sf_read_raw(sf, ptr, l) !=3D l)) {
         pa_log("Premature file end");
         goto finish;
     }
@@ -111,6 +117,9 @@
 =

     if (sf)
         sf_close(sf);
+
+    if (ptr)
+        pa_memblock_release(chunk->memblock);
 =

     if (ret !=3D 0 && chunk->memblock)
         pa_memblock_unref(chunk->memblock);

Modified: branches/lennart/src/pulsecore/source-output.c
URL: http://0pointer.de/cgi-bin/viewcvs.cgi/branches/lennart/src/pulsecore/=
source-output.c?rev=3D1469&root=3Dpulseaudio&r1=3D1468&r2=3D1469&view=3Ddiff
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D
--- branches/lennart/src/pulsecore/source-output.c (original)
+++ branches/lennart/src/pulsecore/source-output.c Mon Jun 11 14:08:37 2007
@@ -26,7 +26,6 @@
 #endif
 =

 #include <stdio.h>
-#include <assert.h>
 #include <stdlib.h>
 #include <string.h>
 =

@@ -39,14 +38,8 @@
 =

 #include "source-output.h"
 =

-#define CHECK_VALIDITY_RETURN_NULL(condition) \
-do {\
-if (!(condition)) \
-    return NULL; \
-} while (0)
-
 pa_source_output_new_data* pa_source_output_new_data_init(pa_source_output=
_new_data *data) {
-    assert(data);
+    pa_assert(data);
 =

     memset(data, 0, sizeof(*data));
     data->resample_method =3D PA_RESAMPLER_INVALID;
@@ -54,14 +47,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 =3D !!map))
         data->channel_map =3D *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 =3D !!spec))
         data->sample_spec =3D *spec;
@@ -74,48 +67,53 @@
 =

     pa_source_output *o;
     pa_resampler *resampler =3D NULL;
-    int r;
     char st[PA_SAMPLE_SPEC_SNPRINT_MAX];
 =

-    assert(core);
-    assert(data);
+    pa_assert(core);
+    pa_assert(data);
 =

     if (!(flags & PA_SOURCE_OUTPUT_NO_HOOKS))
         if (pa_hook_fire(&core->hook_source_output_new, data) < 0)
             return NULL;
 =

-    CHECK_VALIDITY_RETURN_NULL(!data->driver || pa_utf8_valid(data->driver=
));
-    CHECK_VALIDITY_RETURN_NULL(!data->name || pa_utf8_valid(data->name));
+    pa_return_null_if_fail(!data->driver || pa_utf8_valid(data->driver));
+    pa_return_null_if_fail(!data->name || pa_utf8_valid(data->name));
 =

     if (!data->source)
         data->source =3D pa_namereg_get(core, NULL, PA_NAMEREG_SOURCE, 1);
 =

-    CHECK_VALIDITY_RETURN_NULL(data->source);
-    CHECK_VALIDITY_RETURN_NULL(data->source->state =3D=3D PA_SOURCE_RUNNIN=
G);
+    pa_return_null_if_fail(data->source);
+    pa_return_null_if_fail(pa_source_get_state(data->source) !=3D PA_SOURC=
E_DISCONNECTED);
 =

     if (!data->sample_spec_is_set)
         data->sample_spec =3D 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.cha=
nnels, PA_CHANNEL_MAP_DEFAULT);
-
-    CHECK_VALIDITY_RETURN_NULL(pa_channel_map_valid(&data->channel_map));
-    CHECK_VALIDITY_RETURN_NULL(data->channel_map.channels =3D=3D data->sam=
ple_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 =3D=3D data->sample_spec.ch=
annels)
+            data->channel_map =3D 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 =3D=3D data->sample_=
spec.channels);
 =

     if (data->resample_method =3D=3D PA_RESAMPLER_INVALID)
         data->resample_method =3D 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) >=3D PA_MAX_OUTPUTS_PER_SOUR=
CE) {
         pa_log("Failed to create source output: too many outputs per sourc=
e.");
         return NULL;
     }
 =

-    if (!pa_sample_spec_equal(&data->sample_spec, &data->source->sample_sp=
ec) ||
-        !pa_channel_map_equal(&data->channel_map, &data->source->channel_m=
ap))
+    if ((flags & PA_SOURCE_OUTPUT_VARIABLE_RATE) ||
+        !pa_sample_spec_equal(&data->sample_spec, &data->source->sample_sp=
ec) ||
+        !pa_channel_map_equal(&data->channel_map, &data->source->channel_m=
ap)) {
+        =

         if (!(resampler =3D pa_resampler_new(
                       core->mempool,
                       &data->source->sample_spec, &data->source->channel_m=
ap,
@@ -125,115 +123,133 @@
             return NULL;
         }
 =

-    o =3D pa_xnew(pa_source_output, 1);
-    o->ref =3D 1;
-    o->state =3D PA_SOURCE_OUTPUT_RUNNING;
+        data->resample_method =3D pa_resampler_get_method(resampler);
+    }
+
+    o =3D pa_source_output_new(pa_source_output);
+    =

+    o->parent.parent.free =3D source_output_free;
+    o->parent.process_msg =3D pa_source_output_process_msg;
+    =

+    o->core =3D core;
+    pa_atomic_load(&o->state, PA_SOURCE_OUTPUT_RUNNING);
+    o->flags =3D flags;
     o->name =3D pa_xstrdup(data->name);
     o->driver =3D pa_xstrdup(data->driver);
     o->module =3D data->module;
     o->source =3D data->source;
     o->client =3D data->client;
 =

+    o->resample_method =3D data->resample_method;
     o->sample_spec =3D data->sample_spec;
     o->channel_map =3D data->channel_map;
 =

+    o->process_msg =3D NULL;
     o->push =3D NULL;
     o->kill =3D NULL;
     o->get_latency =3D NULL;
     o->userdata =3D NULL;
 =

-    o->resampler =3D resampler;
-    o->resample_method =3D data->resample_method;
-
-    r =3D pa_idxset_put(core->source_outputs, o, &o->index);
-    assert(r =3D=3D 0);
-    r =3D pa_idxset_put(o->source->outputs, o, NULL);
-    assert(r =3D=3D 0);
-
-    pa_log_info("created %u \"%s\" on %s with sample spec %s",
+    o->thread_info.resampler =3D resampler;
+
+    pa_assert_se(pa_idxset_put(core->source_outputs, o, &o->index) =3D=3D =
0);
+    pa_assert_se( pa_idxset_put(o->source->outputs, o, NULL) =3D=3D 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_SUBS=
CRIPTION_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 !=3D PA_SOURCE_OUTPUT_DISCONNECTED);
-    assert(o->source);
-    assert(o->source->core);
-
+    pa_assert(o);
+    pa_return_if_fail(pa_source_output_get_state(i) !=3D PA_SOURCE_OUTPUT_=
DISCONNECTED);
+    pa_assert(o->source);
+    pa_assert(o->source->core);
+
+    pa_asyncmsgq_send(i->sink->asyncmsgq, i->sink, PA_SOURCE_MESSAGE_REMOV=
E_OUTPUT, o, NULL);
+    =

     pa_idxset_remove_by_data(o->source->core->source_outputs, o, NULL);
     pa_idxset_remove_by_data(o->source->outputs, o, NULL);
 =

     pa_subscription_post(o->source->core, PA_SUBSCRIPTION_EVENT_SOURCE_OUT=
PUT|PA_SUBSCRIPTION_EVENT_REMOVE, o->index);
     o->source =3D NULL;
 =

+    o->process_msg =3D NULL;
     o->push =3D NULL;
     o->kill =3D NULL;
     o->get_latency =3D NULL;
 =

-    o->state =3D PA_SOURCE_OUTPUT_DISCONNECTED;
-}
-
-static void source_output_free(pa_source_output* o) {
-    assert(o);
-
-    if (o->state !=3D 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);
+    pa_atomic_load(&i->state, PA_SOURCE_OUTPUT_DISCONNECTED);
+}
+
+static void source_output_free(pa_msgobject* mo) {
+    pa_source_output *o =3D PA_SOURCE_OUTPUT(mo);
+    =

+    pa_assert(pa_source_output_refcnt(o) =3D=3D 0);
+
+    pa_source_output_disconnect(o);
+
+    pa_log_info("Freeing output %u \"%s\"", o->index, o->name);
+
+    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 >=3D 1);
-
-    if (!(--o->ref))
-        source_output_free(o);
-}
-
-pa_source_output* pa_source_output_ref(pa_source_output *o) {
-    assert(o);
-    assert(o->ref >=3D 1);
-
-    o->ref++;
-    return o;
+void pa_source_output_put(pa_source_output *o) {
+    pa_source_output_assert_ref(o);
+    =

+    pa_asyncmsgq_post(o->source->asyncmsgq, o->source, PA_SOURCE_MESSAGE_A=
DD_OUTPUT, o, NULL, pa_source_unref, pa_source_output_unref);
+    pa_source_update_status(o->source);
+
+    pa_subscription_post(core, PA_SUBSCRIPTION_EVENT_SOURCE_OUTPUT|PA_SUBS=
CRIPTION_EVENT_NEW, o->index);
 }
 =

 void pa_source_output_kill(pa_source_output*o) {
-    assert(o);
-    assert(o->ref >=3D 1);
+    pa_source_output_assert_ref(o);
 =

     if (o->kill)
         o->kill(o);
 }
 =

+pa_usec_t pa_source_output_get_latency(pa_source_output *o) {
+    pa_usec_t r =3D 0;
+
+    pa_source_output_assert_ref(o);
+
+    if (pa_asyncmsgq_send(o->source->asyncmsgq, i->source, PA_SOURCE_OUTPU=
T_MESSAGE_GET_LATENCY, &r, NULL) < 0)
+        r =3D 0;
+    =

+    if (o->get_latency)
+        r +=3D o->get_latency(o);
+
+    return r;
+}
+
 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 =3D=3D PA_SOURCE_OUTPUT_CORKED)
-        return;
-
+    pa_source_output_state_t state;
+
+    pa_source_output_assert_ref(o);
+    pa_assert(chunk);
+    pa_assert(chunk->length);
+
+    state =3D pa_source_output_get_state(o);
+    =

+    if (!o->push || state =3D=3D PA_SOURCE_OUTPUT_DISCONNECTED || state =
=3D=3D PA_SOURCE_OUTPUT_CORKED)
+        return;
+
+    pa_assert(state =3D PA_SOURCE_OUTPUT_RUNNING);
+    =

     if (!o->resampler) {
         o->push(o, chunk);
         return;
@@ -243,14 +259,43 @@
     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, int b) {
+    int n;
+    pa_source_output_state_t state;
+
+    pa_source_output_assert_ref(o);
+
+    state =3D pa_source_output_get_state(o);
+    pa_assert(state !=3D PA_SOURCE_OUTPUT_DISCONNECTED);
+
+    if (b && state !=3D PA_SOURCE_OUTPUT_CORKED)
+        pa_atomic_store(o->state, PA_SOURCE_OUTPUT_CORKED);
+    else if (!b && state =3D=3D PA_SOURCE_OUTPUT_CORKED)
+        pa_atomic_cmpxchg(o->state, state, PA_SOURCE_OUTPUT_RUNNING);
+}
+
+int pa_source_output_set_rate(pa_source_output *o, uint32_t rate) {
+    pa_source_output_assert_ref(o);
+    pa_return_val_if_fail(o->thread_info.resampler, -1);
+
+    if (i->sample_spec.rate =3D=3D rate)
+        return 0;
+
+    i->sample_spec.rate =3D rate;
+
+    pa_asyncmsgq_post(s->asyncmsgq, pa_source_output_ref(i), PA_SOURCE_OUT=
PUT_MESSAGE_SET_RATE, PA_UINT_TO_PTR(rate), NULL, pa_source_output_unref, N=
ULL);
+    =

+    pa_subscription_post(o->source->core, PA_SUBSCRIPTION_EVENT_SOURCE_OUT=
PUT!|PA_SUBSCRIPTION_EVENT_CHANGE, i->index);
+    return 0;
+}
+
 void pa_source_output_set_name(pa_source_output *o, const char *name) {
-    assert(o);
-    assert(o->ref >=3D 1);
+    pa_source_output_assert_ref(o);
 =

     if (!o->name && !name)
         return;
@@ -264,98 +309,87 @@
     pa_subscription_post(o->source->core, PA_SUBSCRIPTION_EVENT_SOURCE_OUT=
PUT|PA_SUBSCRIPTION_EVENT_CHANGE, o->index);
 }
 =

-pa_usec_t pa_source_output_get_latency(pa_source_output *o) {
-    assert(o);
-    assert(o->ref >=3D 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 >=3D 1);
-
-    if (o->state =3D=3D PA_SOURCE_OUTPUT_DISCONNECTED)
-        return;
-
-    n =3D o->state =3D=3D PA_SOURCE_OUTPUT_CORKED && !b;
-
-    o->state =3D b ? PA_SOURCE_OUTPUT_CORKED : PA_SOURCE_OUTPUT_RUNNING;
-
-    if (n)
-        pa_source_notify(o->source);
-}
-
 pa_resample_method_t pa_source_output_get_resample_method(pa_source_output=
 *o) {
-    assert(o);
-    assert(o->ref >=3D 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 =3D NULL;
 =

-    assert(o);
-    assert(o->ref >=3D 1);
-    assert(dest);
-
-    origin =3D o->source;
-
-    if (dest =3D=3D origin)
-        return 0;
-
-    if (pa_idxset_size(dest->outputs) >=3D PA_MAX_OUTPUTS_PER_SOURCE) {
-        pa_log_warn("Failed to move source output: too many outputs per so=
urce.");
-        return -1;
-    }
-
-    if (o->resampler &&
-        pa_sample_spec_equal(&origin->sample_spec, &dest->sample_spec) &&
-        pa_channel_map_equal(&origin->channel_map, &dest->channel_map))
-
-        /* Try to reuse the old resampler if possible */
-        new_resampler =3D 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 */
-
-        if (!(new_resampler =3D pa_resampler_new(
-                      dest->core->mempool,
-                      &dest->sample_spec, &dest->channel_map,
-                      &o->sample_spec, &o->channel_map,
-                      o->resample_method))) {
-            pa_log_warn("Unsupported resampling operation.");
-            return -1;
+    pa_source_output_assert_ref(o);
+    pa_source_assert_ref(dest);
+
+    return -1;
+    =

+/*     origin =3D o->source; */
+
+/*     if (dest =3D=3D origin) */
+/*         return 0; */
+
+/*     if (pa_idxset_size(dest->outputs) >=3D PA_MAX_OUTPUTS_PER_SOURCE) {=
 */
+/*         pa_log_warn("Failed to move source output: too many outputs per=
 source."); */
+/*         return -1; */
+/*     } */
+
+/*     if (o->resampler && */
+/*         pa_sample_spec_equal(&origin->sample_spec, &dest->sample_spec) =
&& */
+/*         pa_channel_map_equal(&origin->channel_map, &dest->channel_map))=
 */
+
+/*         /\* Try to reuse the old resampler if possible *\/ */
+/*         new_resampler =3D 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 *\/ */
+
+/*         if (!(new_resampler =3D pa_resampler_new( */
+/*                       dest->core->mempool, */
+/*                       &dest->sample_spec, &dest->channel_map, */
+/*                       &o->sample_spec, &o->channel_map, */
+/*                       o->resample_method))) { */
+/*             pa_log_warn("Unsupported resampling operation."); */
+/*             return -1; */
+/*         } */
+/*     } */
+
+/*     /\* Okey, let's move it *\/ */
+/*     pa_idxset_remove_by_data(origin->outputs, o, NULL); */
+/*     pa_idxset_put(dest->outputs, o, NULL); */
+/*     o->source =3D dest; */
+
+/*     /\* Replace resampler *\/ */
+/*     if (new_resampler !=3D o->resampler) { */
+/*         if (o->resampler) */
+/*             pa_resampler_free(o->resampler); */
+/*         o->resampler =3D new_resampler; */
+/*     } */
+
+/*     /\* Notify everyone *\/ */
+/*     pa_subscription_post(o->source->core, PA_SUBSCRIPTION_EVENT_SOURCE_=
OUTPUT|PA_SUBSCRIPTION_EVENT_CHANGE, o->index); */
+/*     pa_source_notify(o->source); */
+
+/*     return 0; */
+}
+
+int pa_source_output_process_msg(pa_msgobject *mo, int code, void *userdat=
a, pa_memchunk* chunk) {
+    pa_source_output *o =3D PA_SOURCE_OUTPUT(o);
+    =

+    pa_source_output_assert_ref(i);
+
+    switch (code) {
+
+        case PA_SOURCE_OUTPUT_MESSAGE_SET_RATE: {
+            =

+            i->thread_info.sample_spec.rate =3D PA_PTR_TO_UINT(userdata);
+            pa_resampler_set_output_rate(i->resampler, PA_PTR_TO_UINT(user=
data));
+
+            return 0;
         }
     }
 =

-    /* Okey, let's move it */
-    pa_idxset_remove_by_data(origin->outputs, o, NULL);
-    pa_idxset_put(dest->outputs, o, NULL);
-    o->source =3D dest;
-
-    /* Replace resampler */
-    if (new_resampler !=3D o->resampler) {
-        if (o->resampler)
-            pa_resampler_free(o->resampler);
-        o->resampler =3D new_resampler;
-    }
-
-    /* Notify everyone */
-    pa_subscription_post(o->source->core, PA_SUBSCRIPTION_EVENT_SOURCE_OUT=
PUT|PA_SUBSCRIPTION_EVENT_CHANGE, o->index);
-    pa_source_notify(o->source);
-
-    return 0;
-}
+    return -1;
+}

Modified: branches/lennart/src/pulsecore/source-output.h
URL: http://0pointer.de/cgi-bin/viewcvs.cgi/branches/lennart/src/pulsecore/=
source-output.h?rev=3D1469&root=3Dpulseaudio&r1=3D1468&r2=3D1469&view=3Ddiff
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D
--- branches/lennart/src/pulsecore/source-output.h (original)
+++ branches/lennart/src/pulsecore/source-output.h Mon Jun 11 14:08:37 2007
@@ -1,5 +1,5 @@
-#ifndef foosourceoutputhfoo
-#define foosourceoutputhfoo
+#ifndef foopulsesourceoutputhfoo
+#define foopulsesourceoutputhfoo
 =

 /* $Id$ */
 =

@@ -35,38 +35,57 @@
 #include <pulsecore/module.h>
 #include <pulsecore/client.h>
 =

-typedef enum {
+typedef enum pa_source_output_state {
     PA_SOURCE_OUTPUT_RUNNING,
     PA_SOURCE_OUTPUT_CORKED,
     PA_SOURCE_OUTPUT_DISCONNECTED
 } pa_source_output_state_t;
 =

 typedef enum pa_source_output_flags {
-    PA_SOURCE_OUTPUT_NO_HOOKS =3D 1
+    PA_SOURCE_OUTPUT_NO_HOOKS =3D 1,
+    PA_SOURCE_OUTPUT_VARIABLE_RATE =3D 2
 } pa_source_output_flags_t;
 =

 struct pa_source_output {
-    int ref;
+    pa_msgobject parent;
+    =

     uint32_t index;
-    pa_source_output_state_t state;
+    pa_core *core;
+    pa_atomic_t state;
+    pa_source_output_flags_t flags;
 =

     char *name, *driver;                  /* may be NULL */
     pa_module *module;                    /* may be NULL */
+    pa_client *client;                    /* may be NULL */
 =

     pa_source *source;
-    pa_client *client;                    /* may be NULL */
 =

     pa_sample_spec sample_spec;
     pa_channel_map channel_map;
 =

+    int (*process_msg)(pa_sink_input *i, int code, void *userdata);
     void (*push)(pa_source_output *o, const pa_memchunk *chunk);
     void (*kill)(pa_source_output* o);              /* may be NULL */
     pa_usec_t (*get_latency) (pa_source_output *o); /* may be NULL */
 =

-    pa_resampler* resampler;              /* may be NULL */
     pa_resample_method_t resample_method;
 =

+    struct {
+        pa_sample_spec sample_spec;
+        =

+        pa_resampler* resampler;              /* may be NULL */
+    } thread_info;
+        =

     void *userdata;
+};
+
+PA_DECLARE_CLASS(pa_source_output);
+#define PA_SOURCE_OUTPUT(o) ((pa_source_output*) (o))
+
+enum {
+    PA_SOURCE_OUTPUT_MESSAGE_GET_LATENCY,
+    PA_SOURCE_OUTPUT_MESSAGE_SET_RATE,
+    PA_SOURCE_OUTPUT_MESSAGE_MAX
 };
 =

 typedef struct pa_source_output_new_data {
@@ -89,30 +108,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_disconnect(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_set_rate(pa_source_output *o, uint32_t rate);
+
 pa_resample_method_t pa_source_output_get_resample_method(pa_source_output=
 *o);
 =

 int pa_source_output_move_to(pa_source_output *o, pa_source *dest);
 =

+#define pa_source_output_get_state(o) ((pa_source_output_state_t) pa_atomi=
c_load(&o->state))
+
+/* To be used exclusively by the source driver thread */
+
+void pa_source_output_push(pa_source_output *o, const pa_memchunk *chunk);
+int pa_source_output_process_msg(pa_msgobject *mo, int code, void *userdat=
a, pa_memchunk *chunk);
+
 #endif

Modified: branches/lennart/src/pulsecore/source.c
URL: http://0pointer.de/cgi-bin/viewcvs.cgi/branches/lennart/src/pulsecore/=
source.c?rev=3D1469&root=3Dpulseaudio&r1=3D1468&r2=3D1469&view=3Ddiff
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D
--- branches/lennart/src/pulsecore/source.c (original)
+++ branches/lennart/src/pulsecore/source.c Mon Jun 11 14:08:37 2007
@@ -41,12 +41,6 @@
 #include <pulsecore/sample-util.h>
 =

 #include "source.h"
-
-#define CHECK_VALIDITY_RETURN_NULL(condition) \
-do {\
-if (!(condition)) \
-    return NULL; \
-} while (0)
 =

 pa_source* pa_source_new(
         pa_core *core,
@@ -65,30 +59,32 @@
     assert(name);
     assert(spec);
 =

-    CHECK_VALIDITY_RETURN_NULL(pa_sample_spec_valid(spec));
+    pa_return_null_if_fail(pa_sample_spec_valid(spec));
 =

     if (!map)
         map =3D 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 =3D=3D spec->channels);
-    CHECK_VALIDITY_RETURN_NULL(!driver || pa_utf8_valid(driver));
-    CHECK_VALIDITY_RETURN_NULL(pa_utf8_valid(name) && *name);
-
-    s =3D pa_xnew(pa_source, 1);
+    pa_return_null_if_fail(map && pa_channel_map_valid(map));
+    pa_return_null_if_fail(map->channels =3D=3D spec->channels);
+    pa_return_null_if_fail(!driver || pa_utf8_valid(driver));
+    pa_return_null_if_fail(pa_utf8_valid(name) && *name);
+
+    s =3D pa_msgobject_new(pa_source);
 =

     if (!(name =3D pa_namereg_register(core, name, PA_NAMEREG_SOURCE, s, f=
ail))) {
         pa_xfree(s);
         return NULL;
     }
 =

-    s->ref =3D 1;
+    s->parent.parent.free =3D source_free;
+    s->parent.process_msg =3D pa_source_process_msg;
+    =

     s->core =3D core;
-    s->state =3D PA_SOURCE_RUNNING;
+    pa_atomic_store(&s->state, PA_SOURCE_IDLE);
     s->name =3D pa_xstrdup(name);
     s->description =3D NULL;
     s->driver =3D pa_xstrdup(driver);
-    s->owner =3D NULL;
+    s->module =3D NULL;
 =

     s->sample_spec =3D *spec;
     s->channel_map =3D *map;
@@ -96,45 +92,87 @@
     s->outputs =3D pa_idxset_new(NULL, NULL);
     s->monitor_of =3D NULL;
 =

-    pa_cvolume_reset(&s->sw_volume, spec->channels);
-    pa_cvolume_reset(&s->hw_volume, spec->channels);
-    s->sw_muted =3D 0;
-    s->hw_muted =3D 0;
+    pa_cvolume_reset(&s->volume, spec->channels);
+    s->muted =3D 0;
+    s->refresh_volume =3D s->refresh_mute =3D 0;
 =

     s->is_hardware =3D 0;
 =

     s->get_latency =3D NULL;
-    s->notify =3D NULL;
-    s->set_hw_volume =3D NULL;
-    s->get_hw_volume =3D NULL;
-    s->set_hw_mute =3D NULL;
-    s->get_hw_mute =3D NULL;
+    s->set_volume =3D NULL;
+    s->get_volume =3D NULL;
+    s->set_mute =3D NULL;
+    s->get_mute =3D NULL;
+    s->start =3D NULL;
+    s->stop =3D NULL;
     s->userdata =3D NULL;
 =

+    pa_assert_se(s->asyncmsgq =3D pa_asyncmsgq_new(0));
+    =

     r =3D pa_idxset_put(core->sources, s, &s->index);
     assert(s->index !=3D PA_IDXSET_INVALID && r >=3D 0);
 =

     pa_sample_spec_snprint(st, sizeof(st), spec);
-    pa_log_info("created %u \"%s\" with sample spec \"%s\"", s->index, s->=
name, st);
-
+    pa_log_info("Created source %u \"%s\" with sample spec \"%s\"", s->ind=
ex, s->name, st);
+
+    s->thread_info.outputs =3D pa_hashmap_new(pa_idxset_trivial_hash_func,=
 pa_idxset_trivial_compare_func);
+    s->thread_info.soft_volume =3D s->volume;
+    s->thread_info.soft_muted =3D s->muted;
+    =

     pa_subscription_post(core, PA_SUBSCRIPTION_EVENT_SOURCE | PA_SUBSCRIPT=
ION_EVENT_NEW, s->index);
 =

     return s;
+}
+
+static void source_start(pa_source *s) {
+    pa_source_state_t state;
+    pa_assert(s);
+
+    state =3D pa_source_get_state(s);
+    pa_return_if_fail(state =3D=3D PA_SOURCE_IDLE || state =3D=3D PA_SOURC=
E_SUSPENDED);
+
+    pa_atomic_store(&s->state, PA_SOURCE_RUNNING);
+
+    if (s->start)
+        s->start(s);
+    else
+        pa_asyncmsgq_post(s->asyncmsgq, s, PA_SOURCE_MESSAGE_START, NULL, =
NULL, pa_source_unref, NULL);
+}
+
+static void source_stop(pa_source *s) {
+    pa_source_state_t state;
+    int stop;
+    =

+    pa_assert(s);
+    state =3D pa_source_get_state(s);
+    pa_return_if_fail(state =3D=3D PA_SOURCE_RUNNING || state =3D=3D PA_SO=
URCE_SUSPENDED);
+
+    stop =3D state =3D=3D PA_SOURCE_RUNNING;
+    pa_atomic_store(&s->state, PA_SOURCE_IDLE);
+
+    if (stop) {
+        if (s->stop)
+            s->stop(s);
+        else
+            pa_asyncmsgq_post(s->asyncmsgq, s, PA_SOURCE_MESSAGE_STOP, NUL=
L, NULL, pa_source_unref, NULL);
+    }
 }
 =

 void pa_source_disconnect(pa_source *s) {
     pa_source_output *o, *j =3D NULL;
 =

-    assert(s);
-    assert(s->state =3D=3D PA_SOURCE_RUNNING);
-
-    s->state =3D PA_SOURCE_DISCONNECTED;
+    pa_assert(s);
+    pa_return_if_fail(pa_sink_get_state(s) !=3D PA_SINK_DISCONNECT);
+
+    source_stop(s);
+    =

+    pa_atomic_store(&s->state, PA_SOURCE_DISCONNECTED);
     pa_namereg_unregister(s->core, s->name);
 =

     pa_hook_fire(&s->core->hook_source_disconnect, s);
 =

     while ((o =3D pa_idxset_first(s->outputs, NULL))) {
-        assert(o !=3D j);
+        pa_assert(o !=3D j);
         pa_source_output_kill(o);
         j =3D o;
     }
@@ -142,190 +180,206 @@
     pa_idxset_remove_by_data(s->core->sources, s, NULL);
 =

     s->get_latency =3D NULL;
-    s->notify =3D NULL;
-    s->get_hw_volume =3D NULL;
-    s->set_hw_volume =3D NULL;
-    s->set_hw_mute =3D NULL;
-    s->get_hw_mute =3D NULL;
+    s->get_volume =3D NULL;
+    s->set_volume =3D NULL;
+    s->set_mute =3D NULL;
+    s->get_mute =3D NULL;
+    s->start =3D NULL;
+    s->stop =3D NULL;
 =

     pa_subscription_post(s->core, PA_SUBSCRIPTION_EVENT_SOURCE | PA_SUBSCR=
IPTION_EVENT_REMOVE, s->index);
 }
 =

-static void source_free(pa_source *s) {
-    assert(s);
-    assert(!s->ref);
-
-    if (s->state !=3D PA_SOURCE_DISCONNECTED)
-        pa_source_disconnect(s);
-
-    pa_log_info("freed %u \"%s\"", s->index, s->name);
+static void source_free(pa_msgobject *o) {
+    pa_source *s =3D PA_SOURCE(o);
+    =

+    pa_assert(s);
+    pa_assert(pa_source_refcnt(s) =3D=3D 0);
+
+    pa_source_disconnect(s);
+
+    pa_log_info("Freeing source %u \"%s\"", s->index, s->name);
 =

     pa_idxset_free(s->outputs, NULL, NULL);
-
+    pa_hashmap_free(s->thread_info.outputs, pa_sink_output_unref, NULL);
+
+    pa_asyncmsgq_free(s->asyncmsgq);
+    =

     pa_xfree(s->name);
     pa_xfree(s->description);
     pa_xfree(s->driver);
     pa_xfree(s);
 }
 =

-void pa_source_unref(pa_source *s) {
-    assert(s);
-    assert(s->ref >=3D 1);
-
-    if (!(--s->ref))
-        source_free(s);
-}
-
-pa_source* pa_source_ref(pa_source *s) {
-    assert(s);
-    assert(s->ref >=3D 1);
-
-    s->ref++;
-    return s;
-}
-
-void pa_source_notify(pa_source*s) {
-    assert(s);
-    assert(s->ref >=3D 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 =3D p;
-    const pa_memchunk *chunk =3D userdata;
-
-    assert(o);
-    assert(chunk);
-
-    pa_source_output_push(o, chunk);
-    return 0;
+void pa_source_update_status(pa_source*s) {
+    pa_source_assert_ref(s);
+
+    if (pa_source_get_state(s) =3D=3D PA_SOURCE_STATE_SUSPENDED)
+        return;
+    =

+    if (pa_source_used_by(s) > 0)
+        source_start(s);
+    else
+        source_stop(s);
+}
+
+void pa_source_suspend(pa_source *s, int suspend) {
+    pa_source_state_t state;
+
+    pa_source_assert_ref(s);
+
+    state =3D pa_source_get_state(s);
+    pa_return_if_fail(suspend && (s->state =3D=3D PA_SOURCE_RUNNING || s->=
state =3D=3D PA_SOURCE_IDLE));
+    pa_return_if_fail(!suspend && (s->state =3D=3D PA_SOURCE_SUSPENDED));
+
+
+    if (suspend) {
+        pa_atomic_store(&s->state, PA_SOURCE_SUSPENDED);
+
+        if (s->stop)
+            s->stop(s);
+        else
+            pa_asyncmsgq_post(s->asyncmsgq, s, PA_SOURCE_MESSAGE_STOP, NUL=
L, NULL, pa_source_unref, NULL);
+        =

+    } else {
+        pa_atomic_store(&s->state, PA_SOURCE_RUNNING);
+
+        if (s->start)
+            s->start(s);
+        else
+            pa_asyncmsgq_post(s->asyncmsgq, s, PA_SOURCE_MESSAGE_START, NU=
LL, NULL, pa_source_unref, NULL);
+    }
 }
 =

 void pa_source_post(pa_source*s, const pa_memchunk *chunk) {
-    assert(s);
-    assert(s->ref >=3D 1);
-    assert(chunk);
-
-    pa_source_ref(s);
+    pa_source_output *o;
+    void *state =3D NULL;
+    =

+    pa_source_assert_ref(s);
+    pa_assert(chunk);
 =

     if (s->sw_muted || !pa_cvolume_is_norm(&s->sw_volume)) {
         pa_memchunk vchunk =3D *chunk;
 =

         pa_memblock_ref(vchunk.memblock);
         pa_memchunk_make_writable(&vchunk, 0);
-        if (s->sw_muted)
+        =

+        if (s->thread_info.muted || pa_cvolume_is_muted(s->thread_info.vol=
ume))
             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.v=
olume);
+
+        while ((o =3D pa_hashmap_iterate(s->thread_info.outputs, &state, N=
ULL)))
+            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 >=3D 1);
-
-    if (m =3D=3D s->owner)
+    } else {
+        =

+        while ((o =3D pa_hashmap_iterate(s->thread_info.outputs, &state, N=
ULL)))
+            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);
+
+    if (s->get_latency)
+        return s->get_latency(s);
+
+    if (pa_asyncmsgq_send(s->asyncmsgq, s, PA_SOURCE_MESSAGE_GET_LATENCY, =
&usec, NULL) < 0)
+        return 0;
+
+    return usec;
+}
+
+void pa_source_set_volume(pa_source *s, const pa_cvolume *volume) {
+    pa_cvolume *v;
+
+    pa_source_assert_ref(s);
+    pa_assert(volume);
+
+    changed =3D !pa_cvolume_equal(volume, s->volume);
+    s->volume =3D *volume;
+    =

+    if (s->set_volume && s->set_volume(s) < 0)
+        s->set_volume =3D NULL;
+
+    if (!s->set_volume)
+        pa_asyncmsgq_post(s->asyncmsgq, pa_source_ref(s), PA_SOURCE_MESSAG=
E_SET_VOLUME, pa_xnewdup(struct pa_cvolume, volume, 1), pa_source_unref, pa=
_xfree);
+
+    if (changed)
+        pa_subscription_post(s->core, PA_SUBSCRIPTION_EVENT_SOURCE|PA_SUBS=
CRIPTION_EVENT_CHANGE, s->index);
+}
+
+const pa_cvolume *pa_source_get_volume(pa_source *s) {
+    pa_source_assert_ref(s);
+
+    old_volume =3D s->volume;
+    =

+    if (s->get_volume && s->get_volume(s) < 0)
+        s->get_volume =3D NULL;
+
+    if (!s->get_volume && s->refresh_volume)
+        pa_asyncmsgq_send(s->asyncmsgq, s, PA_SOURCE_MESSAGE_GET_VOLUME, &=
s->volume);
+
+    if (!pa_cvolume_equal(&old_volume, &s->volume))
+        pa_subscription_post(s->core, PA_SUBSCRIPTION_EVENT_SOURCE|PA_SUBS=
CRIPTION_EVENT_CHANGE, s->index);
+    =

+    return &s->volume;
+}
+
+void pa_source_set_mute(pa_source *s, pa_mixer_t m, int mute) {
+    int changed;
+    =

+    pa_source_assert_ref(s);
+
+    changed =3D s->muted !=3D mute;
+
+    if (s->set_mute && s->set_mute(s) < 0)
+        s->set_mute =3D NULL;
+
+    if (!s->set_mute)
+        pa_asyncmsgq_post(s->asyncmsgq, pa_source_ref(s), PA_SOURCE_MESSAG=
E_SET_MUTE, PA_UINT_TO_PTR(mute), pa_source_unref, NULL);
+
+    if (changed)
+        pa_subscription_post(s->core, PA_SUBSCRIPTION_EVENT_SOURCE|PA_SUBS=
CRIPTION_EVENT_CHANGE, s->index);
+}
+
+int pa_source_get_mute(pa_source *s, pa_mixer_t m) {
+    int old_muted;
+    =

+    pa_source_assert_ref(s);
+
+    old_muted =3D s->muted;
+    =

+    if (s->get_mute && s->get_mute(s) < 0)
+        s->get_mute =3D NULL;
+
+    if (!s->get_mute && s->refresh_mute)
+        pa_asyncmsgq_send(s->asyncmsgq, s, PA_SOURCE_MESSAGE_GET_MUTE, &s-=
>muted);
+
+    if (old_muted !=3D s->muted)
+        pa_subscription_post(s->core, PA_SUBSCRIPTION_EVENT_SOURCE|PA_SUBS=
CRIPTION_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 =3D=3D s->module)
         return;
 =

-    s->owner =3D m;
+    s->module =3D m;
+    =

     pa_subscription_post(s->core, PA_SUBSCRIPTION_EVENT_SOURCE|PA_SUBSCRIP=
TION_EVENT_CHANGE, s->index);
 }
 =

-pa_usec_t pa_source_get_latency(pa_source *s) {
-    assert(s);
-    assert(s->ref >=3D 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 *vo=
lume) {
-    pa_cvolume *v;
-
-    assert(s);
-    assert(s->ref >=3D 1);
-    assert(volume);
-
-    if (m =3D=3D PA_MIXER_HARDWARE && s->set_hw_volume)
-        v =3D &s->hw_volume;
-    else
-        v =3D &s->sw_volume;
-
-    if (pa_cvolume_equal(v, volume))
-        return;
-
-    *v =3D *volume;
-
-    if (v =3D=3D &s->hw_volume)
-        if (s->set_hw_volume(s) < 0)
-            s->sw_volume =3D  *volume;
-
-    pa_subscription_post(s->core, PA_SUBSCRIPTION_EVENT_SOURCE|PA_SUBSCRIP=
TION_EVENT_CHANGE, s->index);
-}
-
-const pa_cvolume *pa_source_get_volume(pa_source *s, pa_mixer_t m) {
-    assert(s);
-    assert(s->ref >=3D 1);
-
-    if (m =3D=3D 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 >=3D 1);
-
-    if (m =3D=3D PA_MIXER_HARDWARE && s->set_hw_mute)
-        t =3D &s->hw_muted;
-    else
-        t =3D &s->sw_muted;
-
-    if (!!*t =3D=3D !!mute)
-        return;
-
-    *t =3D !!mute;
-
-    if (t =3D=3D &s->hw_muted)
-        if (s->set_hw_mute(s) < 0)
-            s->sw_muted =3D !!mute;
-
-    pa_subscription_post(s->core, PA_SUBSCRIPTION_EVENT_SOURCE|PA_SUBSCRIP=
TION_EVENT_CHANGE, s->index);
-}
-
-int pa_source_get_mute(pa_source *s, pa_mixer_t m) {
-    assert(s);
-    assert(s->ref >=3D 1);
-
-    if (m =3D=3D 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 >=3D 1);
+    pa_source_assert_ref(s);
 =

     if (!description && !s->description)
         return;
@@ -340,8 +394,45 @@
 }
 =

 unsigned pa_source_used_by(pa_source *s) {
-    assert(s);
-    assert(s->ref >=3D 1);
+    pa_source_assert_ref(s);
 =

     return pa_idxset_size(s->outputs);
 }
+
+int pa_source_process_msg(pa_msgobject *o, void *object, int code, pa_memc=
hunk *chunk, void *userdata) {
+    pa_source *s =3D PA_SOURCE(o);
+    pa_source_assert_ref(s);
+
+    switch (code) {
+        case PA_SOURCE_MESSAGE_ADD_OUTPUT: {
+            pa_source_output *i =3D userdata;
+            pa_hashmap_put(s->thread_info.outputs, PA_UINT32_TO_PTR(i->ind=
ex), pa_source_output_ref(i));
+            return 0;
+        }
+            =

+        case PA_SOURCE_MESSAGE_REMOVE_INPUT: {
+            pa_source_input *i =3D userdata;
+            pa_hashmap_remove(s->thread_info.outputs, PA_UINT32_TO_PTR(i->=
index), pa_source_output_ref(i));
+            return 0;
+        }
+            =

+        case PA_SOURCE_MESSAGE_SET_VOLUME:
+            s->thread_info.soft_volume =3D *((pa_cvolume*) userdata);
+            return 0;
+            =

+        case PA_SOURCE_MESSAGE_SET_MUTE:
+            s->thread_info.soft_muted =3D PA_PTR_TO_UINT(userdata);
+            return 0;
+            =

+        case PA_SOURCE_MESSAGE_GET_VOLUME:
+            *((pa_cvolume*) userdata) =3D s->thread_info.soft_volume;
+            return 0;
+            =

+        case PA_SOURCE_MESSAGE_GET_MUTE:
+            *((int*) userdata) =3D s->thread_info.soft_muted;
+            return 0;
+            =

+        default:
+            return -1;
+    }
+}

Modified: branches/lennart/src/pulsecore/source.h
URL: http://0pointer.de/cgi-bin/viewcvs.cgi/branches/lennart/src/pulsecore/=
source.h?rev=3D1469&root=3Dpulseaudio&r1=3D1468&r2=3D1469&view=3Ddiff
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D
--- branches/lennart/src/pulsecore/source.h (original)
+++ branches/lennart/src/pulsecore/source.h Mon Jun 11 14:08:37 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,24 +40,30 @@
 #include <pulsecore/memchunk.h>
 #include <pulsecore/sink.h>
 #include <pulsecore/module.h>
+#include <pulsecore/asyncmsgq.h>
+#include <pulsecore/msgobject.h>
 =

-#define PA_MAX_OUTPUTS_PER_SOURCE 16
+#define PA_MAX_OUTPUTS_PER_SOURCE 32
 =

 typedef enum pa_source_state {
     PA_SOURCE_RUNNING,
+    PA_SOURCE_SUSPENDED,
+    PA_SOURCE_IDLE,
     PA_SOURCE_DISCONNECTED
 } pa_source_state_t;
 =

 struct pa_source {
-    int ref;
+    pa_msgobject parent;
+    =

     uint32_t index;
     pa_core *core;
-    pa_source_state_t state;
+    pa_atomic_t state;
 =

     char *name;
     char *description, *driver;              /* may be NULL */
+    int is_hardware;
 =

-    pa_module *owner;                        /* may be NULL */
+    pa_module *module;                        /* may be NULL */
 =

     pa_sample_spec sample_spec;
     pa_channel_map channel_map;
@@ -64,48 +71,79 @@
     pa_idxset *outputs;
     pa_sink *monitor_of;                     /* may be NULL */
 =

-    pa_cvolume hw_volume, sw_volume;
-    int hw_muted, sw_muted;
+    pa_cvolume volume;
+    int muted;
+    int refresh_volume;
+    int referesh_mute;
 =

-    int is_hardware;
+    void (*start)(pa_source*source);         /* may be NULL */
+    void (*stop)(pa_source*source);          /* may be NULL */
+    int (*set_volume)(pa_source *s);         /* dito */
+    int (*get_volume)(pa_source *s);         /* dito */
+    int (*set_mute)(pa_source *s);           /* dito */
+    int (*get_mute)(pa_source *s);           /* dito */
+    pa_usec_t (*get_latency)(pa_source *s);  /* dito */
 =

-    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;
 =

+    struct {
+        pa_hashmap *outputs;
+        pa_cvolume soft_volume;
+        int soft_muted;
+    } thread_info;
+    =

     void *userdata;
 };
 =

+PA_DECLARE_CLASS(pa_source);
+#define PA_SOURCE(s) ((pa_source*) (s))
+
+typedef enum pa_source_message {
+    PA_SOURCE_MESSAGE_ADD_OUTPUT,
+    PA_SOURCE_MESSAGE_REMOVE_OUTPUT,
+    PA_SOURCE_MESSAGE_GET_VOLUME,
+    PA_SOURCE_MESSAGE_SET_VOLUME,
+    PA_SOURCE_MESSAGE_GET_MUTE,
+    PA_SOURCE_MESSAGE_SET_MUTE,
+    PA_SOURCE_MESSAGE_GET_LATENCY,
+    PA_SOURCE_MESSAGE_START,
+    PA_SOURCE_MESSAGE_STOP,
+    PA_SOURCE_MESSAGE_MAX
+} pa_source_message_t;
+
+/* To be used exclusively by the source driver */
+
 pa_source* pa_source_new(
-    pa_core *core,
-    const char *driver,
-    const char *name,
-    int namereg_fail,
-    const pa_sample_spec *spec,
-    const pa_channel_map *map);
+        pa_core *core,
+        const char *driver,
+        const char *name,
+        int namereg_fail,
+        const pa_sample_spec *spec,
+        const pa_channel_map *map);
 =

 void pa_source_disconnect(pa_source *s);
-void pa_source_unref(pa_source *s);
-pa_source* pa_source_ref(pa_source *c);
 =

-/* Pass a new memory block to all output streams */
-void pa_source_post(pa_source*s, const pa_memchunk *b);
+void pa_source_set_module(pa_source *s, pa_module *m);
+void pa_source_set_description(pa_source *s, const char *description);
 =

-void pa_source_notify(pa_source *s);
-
-void pa_source_set_owner(pa_source *s, pa_module *m);
+/* Callable by everyone */
 =

 pa_usec_t pa_source_get_latency(pa_source *s);
 =

-void pa_source_set_volume(pa_source *source, pa_mixer_t m, const pa_cvolum=
e *volume);
-const pa_cvolume *pa_source_get_volume(pa_source *source, pa_mixer_t m);
-void pa_source_set_mute(pa_source *source, pa_mixer_t m, int mute);
-int pa_source_get_mute(pa_source *source, pa_mixer_t m);
+void pa_source_update_status(pa_source*s);
+void pa_source_suspend(pa_source *s);
 =

-void pa_source_set_description(pa_source *s, const char *description);
+void pa_source_set_volume(pa_source *source, const pa_cvolume *volume);
+const pa_cvolume *pa_source_get_volume(pa_source *source);
+void pa_source_set_mute(pa_source *source, int mute);
+int pa_source_get_mute(pa_source *source);
 =

 unsigned pa_source_used_by(pa_source *s);
+#define pa_source_get_state(s) ((pa_source_state_t) pa_atomic_load(&(s)->s=
tate))
+
+/* To be used exclusively by the source driver thread */
+
+void pa_source_post(pa_source*s, const pa_memchunk *b);
+void pa_source_process_msg(pa_msgobject *o, int code, void *userdata, pa_m=
emchunk *chunk);
+
 #endif

Modified: branches/lennart/src/pulsecore/thread-posix.c
URL: http://0pointer.de/cgi-bin/viewcvs.cgi/branches/lennart/src/pulsecore/=
thread-posix.c?rev=3D1469&root=3Dpulseaudio&r1=3D1468&r2=3D1469&view=3Ddiff
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D
--- branches/lennart/src/pulsecore/thread-posix.c (original)
+++ branches/lennart/src/pulsecore/thread-posix.c Mon Jun 11 14:08:37 2007
@@ -26,7 +26,6 @@
 #include <config.h>
 #endif
 =

-#include <assert.h>
 #include <pthread.h>
 #include <sched.h>
 #include <errno.h>
@@ -35,56 +34,50 @@
 #include <pulsecore/mutex.h>
 #include <pulsecore/once.h>
 #include <pulsecore/atomic.h>
+#include <pulsecore/macro.h>
 =

 #include "thread.h"
-
-#define ASSERT_SUCCESS(x) do { \
-    int _r =3D (x); \
-    assert(_r =3D=3D 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 =3D PA_ONCE_INIT;
-
-static void tls_free_cb(void *p) {
+static pthread_key_t thread_key;
+static pthread_once_t thread_once =3D PTHREAD_ONCE_INIT;
+
+static void thread_free_cb(void *p) {
     pa_thread *t =3D 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 =3D pa_tls_new(tls_free_cb);
-    assert(thread_tls);
+static void thread_once_func(void) {
+    pa_assert_se(pthread_key_create(&thread_key, thread_free_cb) =3D=3D 0);
 }
 =

 static void* internal_thread_func(void *userdata) {
     pa_thread *t =3D userdata;
-    assert(t);
+    pa_assert(t);
 =

     t->id =3D pthread_self();
 =

-    pa_once(&thread_tls_once, thread_tls_once_func);
-
-    pa_tls_set(thread_tls, t);
+    pthread_once(&thread_once, thread_once_func);
+    pthread_setspecific(thread_key, t);
 =

     pa_atomic_inc(&t->running);
     t->thread_func(t->userdata);
-    pa_atomic_add(&t->running, -2);
+    pa_atomic_sub(&t->running, 2);
 =

     return NULL;
 }
@@ -92,7 +85,7 @@
 pa_thread* pa_thread_new(pa_thread_func_t thread_func, void *userdata) {
     pa_thread *t;
 =

-    assert(thread_func);
+    pa_assert(thread_func);
 =

     t =3D pa_xnew(pa_thread, 1);
     t->thread_func =3D thread_func;
@@ -110,26 +103,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 +130,9 @@
 pa_thread* pa_thread_self(void) {
     pa_thread *t;
 =

-    pa_once(&thread_tls_once, thread_tls_once_func);
-
-    if ((t =3D pa_tls_get(thread_tls)))
+    pthread_once(&thread_once, thread_once_func);
+
+    if ((t =3D pthread_getspecific(thread_key)))
         return t;
 =

     /* This is a foreign thread, let's create a pthread structure to
@@ -151,19 +144,19 @@
     t->userdata =3D NULL;
     pa_atomic_store(&t->running, 2);
 =

-    pa_tls_set(thread_tls, t);
+    pthread_setspecific(thread_key, t);
 =

     return t;
 }
 =

 void* pa_thread_get_data(pa_thread *t) {
-    assert(t);
+    pa_assert(t);
 =

     return t->userdata;
 }
 =

 void pa_thread_set_data(pa_thread *t, void *userdata) {
-    assert(t);
+    pa_assert(t);
 =

     t->userdata =3D userdata;
 }
@@ -172,7 +165,7 @@
 #ifdef HAVE_PTHREAD_YIELD
     pthread_yield();
 #else
-    ASSERT_SUCCESS(sched_yield());
+    pa_assert_se(sched_yield() =3D=3D 0);
 #endif
 }
 =

@@ -190,14 +183,14 @@
 }
 =

 void pa_tls_free(pa_tls *t) {
-    assert(t);
-
-    ASSERT_SUCCESS(pthread_key_delete(t->key));
+    pa_assert(t);
+
+    pa_assert_se(pthread_key_delete(t->key) =3D=3D 0);
     pa_xfree(t);
 }
 =

 void *pa_tls_get(pa_tls *t) {
-    assert(t);
+    pa_assert(t);
 =

     return pthread_getspecific(t->key);
 }
@@ -206,7 +199,7 @@
     void *r;
 =

     r =3D pthread_getspecific(t->key);
-    ASSERT_SUCCESS(pthread_setspecific(t->key, userdata));
+    pa_assert_se(pthread_setspecific(t->key, userdata) =3D=3D 0);
     return r;
 }
 =


Added: branches/lennart/src/tests/asyncmsgq-test.c
URL: http://0pointer.de/cgi-bin/viewcvs.cgi/branches/lennart/src/tests/asyn=
cmsgq-test.c?rev=3D1469&root=3Dpulseaudio&view=3Dauto
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D
--- branches/lennart/src/tests/asyncmsgq-test.c (added)
+++ branches/lennart/src/tests/asyncmsgq-test.c Mon Jun 11 14:08:37 2007
@@ -1,0 +1,110 @@
+/* $Id$ */
+
+/***
+  This file is part of PulseAudio.
+
+  PulseAudio is free software; you can redistribute it and/or modify
+  it under the terms of the GNU Lesser General Public License as published
+  by the Free Software Foundation; either version 2 of the License,
+  or (at your option) any later version.
+
+  PulseAudio is distributed in the hope that it will be useful, but
+  WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+  General Public License for more details.
+
+  You should have received a copy of the GNU Lesser General Public License
+  along with PulseAudio; if not, write to the Free Software
+  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+  USA.
+***/
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <assert.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+#include <pulse/util.h>
+#include <pulse/xmalloc.h>
+#include <pulsecore/asyncmsgq.h>
+#include <pulsecore/thread.h>
+#include <pulsecore/log.h>
+#include <pulsecore/core-util.h>
+#include <pulsecore/macro.h>
+
+enum {
+    OPERATION_A,
+    OPERATION_B,
+    OPERATION_C,
+    QUIT
+};
+
+static void the_thread(void *_q) {
+    pa_asyncmsgq *q =3D _q;
+    int quit =3D 0;
+
+    do {
+        int code =3D 0;
+        =

+        pa_assert_se(pa_asyncmsgq_get(q, NULL, &code, NULL, 1) =3D=3D 0);
+
+        switch (code) {
+            =

+            case OPERATION_A:
+                printf("Operation A\n");
+                break;
+
+            case OPERATION_B:
+                printf("Operation B\n");
+                break;
+
+            case OPERATION_C:
+                printf("Operation C\n");
+                break;
+                =

+            case QUIT:
+                printf("quit\n");
+                quit =3D 1;
+                break;
+        }
+
+        pa_asyncmsgq_done(q);
+
+    } while (!quit);
+}
+
+int main(int argc, char *argv[]) {
+    pa_asyncmsgq *q;
+    pa_thread *t;
+    =

+    pa_assert_se(q =3D pa_asyncmsgq_new(0));
+
+    pa_assert_se(t =3D pa_thread_new(the_thread, q));
+
+    printf("Operation A post\n");
+    pa_asyncmsgq_post(q, NULL, OPERATION_A, NULL, NULL, NULL);
+
+    pa_thread_yield();
+
+    printf("Operation B post\n");
+    pa_asyncmsgq_post(q, NULL, OPERATION_B, NULL, NULL, NULL);
+
+    pa_thread_yield();
+
+    printf("Operation C send\n");
+    pa_asyncmsgq_send(q, NULL, OPERATION_C, NULL);
+
+    pa_thread_yield();
+
+    printf("Quit post\n");
+    pa_asyncmsgq_post(q, NULL, QUIT, NULL, NULL, NULL);
+
+    pa_thread_free(t);
+
+    pa_asyncmsgq_free(q);
+
+    return 0;
+}

Propchange: branches/lennart/src/tests/asyncmsgq-test.c
---------------------------------------------------------------------------=
---
    svn:keywords =3D Id

Added: branches/lennart/src/tests/asyncq-test.c
URL: http://0pointer.de/cgi-bin/viewcvs.cgi/branches/lennart/src/tests/asyn=
cq-test.c?rev=3D1469&root=3Dpulseaudio&view=3Dauto
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D
--- branches/lennart/src/tests/asyncq-test.c (added)
+++ branches/lennart/src/tests/asyncq-test.c Mon Jun 11 14:08:37 2007
@@ -1,0 +1,87 @@
+/* $Id$ */
+
+/***
+  This file is part of PulseAudio.
+
+  PulseAudio is free software; you can redistribute it and/or modify
+  it under the terms of the GNU Lesser General Public License as published
+  by the Free Software Foundation; either version 2 of the License,
+  or (at your option) any later version.
+
+  PulseAudio is distributed in the hope that it will be useful, but
+  WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+  General Public License for more details.
+
+  You should have received a copy of the GNU Lesser General Public License
+  along with PulseAudio; if not, write to the Free Software
+  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+  USA.
+***/
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <assert.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+#include <pulse/util.h>
+#include <pulse/xmalloc.h>
+#include <pulsecore/asyncq.h>
+#include <pulsecore/thread.h>
+#include <pulsecore/log.h>
+#include <pulsecore/core-util.h>
+#include <pulsecore/macro.h>
+
+static void producer(void *_q) {
+    pa_asyncq *q =3D _q;
+    int i;
+    =

+    for (i =3D 0; i < 1000; i++) {
+        pa_asyncq_push(q, (void*) (i+1), 1);
+        printf("pushed %i\n", i);
+    }
+
+    pa_asyncq_push(q, (void*) -1, 1);
+    printf("pushed end\n");
+}
+
+static void consumer(void *_q) {
+    pa_asyncq *q =3D _q;
+    void *p;
+    int i;
+
+    sleep(1);
+    =

+    for (i =3D 0;; i++) {
+        p =3D pa_asyncq_pop(q, 1);
+
+        if (p =3D=3D (void*) -1)
+            break;
+
+        pa_assert(p =3D=3D (void *) (i+1));
+        =

+        printf("popped %i\n", i);
+    }
+
+    printf("popped end\n");
+}
+
+int main(int argc, char *argv[]) {
+    pa_asyncq *q;
+    pa_thread *t1, *t2;
+    =

+    pa_assert_se(q =3D pa_asyncq_new(0));
+
+    pa_assert_se(t1 =3D pa_thread_new(producer, q));
+    pa_assert_se(t2 =3D pa_thread_new(consumer, q));
+
+    pa_thread_free(t1);
+    pa_thread_free(t2);
+
+    pa_asyncq_free(q, NULL);
+
+    return 0;
+}

Propchange: branches/lennart/src/tests/asyncq-test.c
---------------------------------------------------------------------------=
---
    svn:keywords =3D Id

Modified: branches/lennart/src/tests/mcalign-test.c
URL: http://0pointer.de/cgi-bin/viewcvs.cgi/branches/lennart/src/tests/mcal=
ign-test.c?rev=3D1469&root=3Dpulseaudio&r1=3D1468&r2=3D1469&view=3Ddiff
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D
--- branches/lennart/src/tests/mcalign-test.c (original)
+++ branches/lennart/src/tests/mcalign-test.c Mon Jun 11 14:08:37 2007
@@ -59,16 +59,21 @@
             c.index =3D c.length =3D 0;
         }
 =

-        assert(c.index < c.memblock->length);
+        assert(c.index < pa_memblock_get_length(c.memblock));
 =

-        l =3D c.memblock->length - c.index;
+        l =3D pa_memblock_get_length(c.memblock) - c.index;
 =

         l =3D l <=3D 1 ? l : rand() % (l-1) +1 ;
 =

-        if ((r =3D read(STDIN_FILENO, (uint8_t*) c.memblock->data + c.inde=
x, l)) <=3D 0) {
+        p =3D pa_memblock_acquire(c.memblock);
+
+        if ((r =3D read(STDIN_FILENO, (uint8_t*) p + c.index, l)) <=3D 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 =3D r;
         pa_mcalign_push(a, &c);
@@ -76,7 +81,7 @@
 =

         c.index +=3D r;
 =

-        if (c.index >=3D c.memblock->length) {
+        if (c.index >=3D 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.i=
ndex, t.length, NULL);
+            p =3D 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: branches/lennart/src/tests/memblock-test.c
URL: http://0pointer.de/cgi-bin/viewcvs.cgi/branches/lennart/src/tests/memb=
lock-test.c?rev=3D1469&root=3Dpulseaudio&r1=3D1468&r2=3D1469&view=3Ddiff
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D
--- branches/lennart/src/tests/memblock-test.c (original)
+++ branches/lennart/src/tests/memblock-test.c Mon Jun 11 14:08:37 2007
@@ -76,6 +76,7 @@
     pa_memblock* blocks[5];
     uint32_t id, shm_id;
     size_t offset, size;
+    char *x;
 =

     const char txt[] =3D "This is a test!";
 =

@@ -90,10 +91,17 @@
     assert(pool_a && pool_b && pool_c);
 =

     blocks[0] =3D pa_memblock_new_fixed(pool_a, (void*) txt, sizeof(txt), =
1);
+
     blocks[1] =3D pa_memblock_new(pool_a, sizeof(txt));
-    snprintf(blocks[1]->data, blocks[1]->length, "%s", txt);
+    x =3D pa_memblock_acquire(blocks[1]);
+    snprintf(x, pa_memblock_get_length(blocks[1]), "%s", txt);
+    pa_memblock_release(blocks[1]);
+
     blocks[2] =3D pa_memblock_new_pool(pool_a, sizeof(txt));
-    snprintf(blocks[2]->data, blocks[2]->length, "%s", txt);
+    x =3D pa_memblock_acquire(blocks[2]);
+    snprintf(x, pa_memblock_get_length(blocks[2]), "%s", txt);
+    pa_memblock_release(blocks[1]);
+
     blocks[3] =3D pa_memblock_new_malloced(pool_a, pa_xstrdup(txt), sizeof=
(txt));
     blocks[4] =3D NULL;
 =

@@ -130,14 +138,18 @@
 =

         mb_c =3D pa_memimport_get(import_c, id, shm_id, offset, size);
         assert(mb_c);
-        printf("1 data=3D%s\n", (char*) mb_c->data);
+        x =3D pa_memblock_acquire(mb_c);
+        printf("1 data=3D%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=3D%s\n", (char*) mb_c->data);
+        x =3D pa_memblock_acquire(mb_c);
+        printf("2 data=3D%s\n", x);
+        pa_memblock_release(mb_c);
         pa_memblock_unref(mb_c);
 =

         pa_memimport_free(import_b);

Modified: branches/lennart/src/tests/memblockq-test.c
URL: http://0pointer.de/cgi-bin/viewcvs.cgi/branches/lennart/src/tests/memb=
lockq-test.c?rev=3D1469&root=3Dpulseaudio&r1=3D1468&r2=3D1469&view=3Ddiff
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D
--- branches/lennart/src/tests/memblockq-test.c (original)
+++ branches/lennart/src/tests/memblockq-test.c Mon Jun 11 14:08:37 2007
@@ -131,8 +131,10 @@
         if (pa_memblockq_peek(bq, &out) < 0)
             break;
 =

-        for (e =3D (char*) out.memblock->data + out.index, n =3D 0; n < ou=
t.length; n++)
+        p =3D pa_memblock_acquire(out.memblock);
+        for (e =3D (char*) p + out.index, n =3D 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);




More information about the pulseaudio-commits mailing list