[pulseaudio-commits] [SCM] PulseAudio Sound Server branch, master, updated. v0.9.11-30-g98fbd24

Lennart Poettering gitmailer-noreply at 0pointer.de
Sun Aug 3 07:49:10 PDT 2008


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

The master branch has been updated
      from  d36c5c97e53ac8865971bdd34ea27bf11bde49e1 (commit)

- Log -----------------------------------------------------------------
98fbd24... fix iteration over random devices
065e764... make all protocol objects global singletons
aaaafb0... use pa_channel_map_init_extend() instead of pa_channel_map_init_auto() to make things more robust
1ae1dfc... simplify a bit
0a2fced... add new api function pa_cli_get_module()
5042284... introduce pa_cli_eof_cb_t
084f429... rename pa_hook_free() to pa_hook_done() since the hook struct is allocated on the stack not via malloc
34c4354... use @ as seperator between shared name variable and instance
5916b5b... make sure we don't leak userdata struct
32f63f2... allow running of PA with a valgring that doesn't know cap_set_caps
06712c2... add new auth cookie singleton
-----------------------------------------------------------------------

Summary of changes:
 src/Makefile.am                                 |   18 +-
 src/daemon/caps.c                               |   13 +
 src/modules/module-default-device-restore.c     |    2 +-
 src/modules/module-native-protocol-fd.c         |   24 +-
 src/modules/module-protocol-stub.c              |  403 ++++++++++++++---------
 src/modules/module-tunnel.c                     |   44 +--
 src/modules/module-x11-publish.c                |  101 +++---
 src/pulsecore/auth-cookie.c                     |  109 ++++++
 src/pulsecore/{protocol-cli.h => auth-cookie.h} |   18 +-
 src/pulsecore/cli.c                             |   18 +-
 src/pulsecore/cli.h                             |    6 +-
 src/pulsecore/core.c                            |    2 +-
 src/pulsecore/hook-list.c                       |    2 +-
 src/pulsecore/hook-list.h                       |    2 +-
 src/pulsecore/modargs.c                         |    3 +-
 src/pulsecore/protocol-cli.c                    |   87 ++++--
 src/pulsecore/protocol-cli.h                    |    9 +-
 src/pulsecore/protocol-esound.c                 |  269 +++++++++++-----
 src/pulsecore/protocol-esound.h                 |   30 ++-
 src/pulsecore/protocol-http.c                   |   96 ++++--
 src/pulsecore/protocol-http.h                   |   12 +-
 src/pulsecore/protocol-native.c                 |  391 +++++++++++++---------
 src/pulsecore/protocol-native.h                 |   42 ++-
 src/pulsecore/protocol-simple.c                 |  218 ++++++++-----
 src/pulsecore/protocol-simple.h                 |   28 ++-
 src/pulsecore/random.c                          |    2 +
 src/pulsecore/x11wrap.c                         |    9 +-
 src/tests/hook-list-test.c                      |    2 +-
 28 files changed, 1294 insertions(+), 666 deletions(-)
 create mode 100644 src/pulsecore/auth-cookie.c
 copy src/pulsecore/{protocol-cli.h => auth-cookie.h} (66%)

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

commit 06712c2a86cb829aa1d7de47bf9a291a157d45b4
Author: Lennart Poettering <lennart at poettering.net>
Date:   Sun Aug 3 16:15:37 2008 +0200

    add new auth cookie singleton

diff --git a/src/pulsecore/auth-cookie.c b/src/pulsecore/auth-cookie.c
new file mode 100644
index 0000000..68b0147
--- /dev/null
+++ b/src/pulsecore/auth-cookie.c
@@ -0,0 +1,109 @@
+/***
+  This file is part of PulseAudio.
+
+  Copyright 2008 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 <sys/types.h>
+
+#include <pulse/xmalloc.h>
+#include <pulse/util.h>
+
+#include <pulsecore/refcnt.h>
+#include <pulsecore/macro.h>
+#include <pulsecore/core-util.h>
+#include <pulsecore/shared.h>
+#include <pulsecore/authkey.h>
+
+#include "auth-cookie.h"
+
+struct pa_auth_cookie {
+    PA_REFCNT_DECLARE;
+    pa_core *core;
+    char *name;
+    size_t size;
+};
+
+pa_auth_cookie* pa_auth_cookie_get(pa_core *core, const char *cn, size_t size) {
+    pa_auth_cookie *c;
+    char *t;
+
+    pa_assert(core);
+    pa_assert(size > 0);
+
+    t = pa_sprintf_malloc("auth-cookie%s%s", cn ? "@" : "", cn ? cn : "");
+
+    if ((c = pa_shared_get(core, t))) {
+
+        pa_xfree(t);
+
+        if (c->size != size)
+            return NULL;
+
+        return pa_auth_cookie_ref(c);
+    }
+
+    c = pa_xmalloc(PA_ALIGN(sizeof(pa_auth_cookie)) + size);
+    PA_REFCNT_INIT(c);
+    c->core = core;
+    c->name = t;
+    c->size = size;
+
+    pa_assert_se(pa_shared_set(core, t, c) >= 0);
+
+    if (pa_authkey_load_auto(cn, (uint8_t*) c + PA_ALIGN(sizeof(pa_auth_cookie)), size) < 0) {
+        pa_auth_cookie_unref(c);
+        return NULL;
+    }
+
+    return c;
+}
+
+pa_auth_cookie* pa_auth_cookie_ref(pa_auth_cookie *c) {
+    pa_assert(c);
+    pa_assert(PA_REFCNT_VALUE(c) >= 1);
+
+    PA_REFCNT_INC(c);
+
+    return c;
+}
+
+void pa_auth_cookie_unref(pa_auth_cookie *c) {
+    pa_assert(c);
+    pa_assert(PA_REFCNT_VALUE(c) >= 1);
+
+    if (PA_REFCNT_DEC(c) > 0)
+        return;
+
+    pa_assert_se(pa_shared_remove(c->core, c->name) >= 0);
+
+    pa_xfree(c->name);
+    pa_xfree(c);
+}
+
+const uint8_t* pa_auth_cookie_read(pa_auth_cookie *c, size_t size) {
+    pa_assert(c);
+    pa_assert(PA_REFCNT_VALUE(c) >= 1);
+    pa_assert(c->size == size);
+
+    return (const uint8_t*) c + PA_ALIGN(sizeof(pa_auth_cookie));
+}
diff --git a/src/pulsecore/auth-cookie.h b/src/pulsecore/auth-cookie.h
new file mode 100644
index 0000000..c08cbd8
--- /dev/null
+++ b/src/pulsecore/auth-cookie.h
@@ -0,0 +1,35 @@
+#ifndef fooauthcookiehfoo
+#define fooauthcookiehfoo
+
+/***
+  This file is part of PulseAudio.
+
+  Copyright 2008 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 <pulsecore/core.h>
+
+typedef struct pa_auth_cookie pa_auth_cookie;
+
+pa_auth_cookie* pa_auth_cookie_get(pa_core *c, const char *cn, size_t size);
+pa_auth_cookie* pa_auth_cookie_ref(pa_auth_cookie *c);
+void pa_auth_cookie_unref(pa_auth_cookie *c);
+
+const uint8_t* pa_auth_cookie_read(pa_auth_cookie *, size_t size);
+
+#endif

commit 32f63f2a61e91b37e1725923f3894ee41d8a8cb7
Author: Lennart Poettering <lennart at poettering.net>
Date:   Sun Aug 3 16:16:22 2008 +0200

    allow running of PA with a valgring that doesn't know cap_set_caps

diff --git a/src/daemon/caps.c b/src/daemon/caps.c
index ae07119..8a49e37 100644
--- a/src/daemon/caps.c
+++ b/src/daemon/caps.c
@@ -109,6 +109,14 @@ void pa_limit_caps(void) {
 void pa_drop_caps(void) {
     cap_t caps;
 
+#ifndef __OPTIMIZE__
+    /* Valgrind doesn't not know set_caps, so we bypass it here -- but
+     *  only in development builts.*/
+
+    if (getenv("VALGRIND") && !pa_have_caps())
+        return;
+#endif
+
     pa_assert_se(prctl(PR_SET_KEEPCAPS, 0, 0, 0, 0) == 0);
 
     pa_assert_se(caps = cap_init());
@@ -123,7 +131,12 @@ pa_bool_t pa_have_caps(void) {
     cap_t caps;
     cap_flag_value_t flag = CAP_CLEAR;
 
+#ifdef __OPTIMIZE__
     pa_assert_se(caps = cap_get_proc());
+#else
+    if (!(caps = cap_get_proc()))
+        return FALSE;
+#endif
     pa_assert_se(cap_get_flag(caps, CAP_SYS_NICE, CAP_EFFECTIVE, &flag) >= 0);
     pa_assert_se(cap_free(caps) == 0);
 

commit 5916b5bc2d66da7cf4acfac00e5b784c5476df5f
Author: Lennart Poettering <lennart at poettering.net>
Date:   Sun Aug 3 16:17:17 2008 +0200

    make sure we don't leak userdata struct

diff --git a/src/modules/module-default-device-restore.c b/src/modules/module-default-device-restore.c
index 2168ac7..7f21efa 100644
--- a/src/modules/module-default-device-restore.c
+++ b/src/modules/module-default-device-restore.c
@@ -158,7 +158,7 @@ int pa__init(pa_module *m) {
 
     pa_assert(m);
 
-    u = pa_xnew0(struct userdata, 1);
+    m->userdata = u = pa_xnew0(struct userdata, 1);
     u->core = m->core;
 
     if (!(u->sink_filename = pa_state_path(DEFAULT_SINK_FILE)))

commit 34c435480fc2c6110994efac5ab85e27bcd653d9
Author: Lennart Poettering <lennart at poettering.net>
Date:   Sun Aug 3 16:17:50 2008 +0200

    use @ as seperator between shared name variable and instance

diff --git a/src/pulsecore/x11wrap.c b/src/pulsecore/x11wrap.c
index 1519aa8..353b120 100644
--- a/src/pulsecore/x11wrap.c
+++ b/src/pulsecore/x11wrap.c
@@ -223,7 +223,8 @@ pa_x11_wrapper* pa_x11_wrapper_get(pa_core *c, const char *name) {
 
     pa_core_assert_ref(c);
 
-    pa_snprintf(t, sizeof(t), "x11-wrapper%s%s", name ? "-" : "", name ? name : "");
+    pa_snprintf(t, sizeof(t), "x11-wrapper%s%s", name ? "@" : "", name ? name : "");
+
     if ((w = pa_shared_get(c, t)))
         return pa_x11_wrapper_ref(w);
 

commit 084f4292f6d1f36ae175b9fd1de070dc942ff29e
Author: Lennart Poettering <lennart at poettering.net>
Date:   Sun Aug 3 16:21:08 2008 +0200

    rename pa_hook_free() to pa_hook_done() since the hook struct is allocated on the stack not via malloc

diff --git a/src/pulsecore/core.c b/src/pulsecore/core.c
index fd836fb..1907fca 100644
--- a/src/pulsecore/core.c
+++ b/src/pulsecore/core.c
@@ -192,7 +192,7 @@ static void core_free(pa_object *o) {
     pa_shared_cleanup(c);
 
     for (j = 0; j < PA_CORE_HOOK_MAX; j++)
-        pa_hook_free(&c->hooks[j]);
+        pa_hook_done(&c->hooks[j]);
 
     pa_xfree(c);
 }
diff --git a/src/pulsecore/hook-list.c b/src/pulsecore/hook-list.c
index 0aac475..3969403 100644
--- a/src/pulsecore/hook-list.c
+++ b/src/pulsecore/hook-list.c
@@ -44,7 +44,7 @@ static void slot_free(pa_hook *hook, pa_hook_slot *slot) {
     pa_xfree(slot);
 }
 
-void pa_hook_free(pa_hook *hook) {
+void pa_hook_done(pa_hook *hook) {
     pa_assert(hook);
     pa_assert(hook->n_firing == 0);
 
diff --git a/src/pulsecore/hook-list.h b/src/pulsecore/hook-list.h
index cf85aca..de947ad 100644
--- a/src/pulsecore/hook-list.h
+++ b/src/pulsecore/hook-list.h
@@ -64,7 +64,7 @@ struct pa_hook {
 };
 
 void pa_hook_init(pa_hook *hook, void *data);
-void pa_hook_free(pa_hook *hook);
+void pa_hook_done(pa_hook *hook);
 
 pa_hook_slot* pa_hook_connect(pa_hook *hook, pa_hook_priority_t prio, pa_hook_cb_t cb, void *data);
 void pa_hook_slot_free(pa_hook_slot *slot);
diff --git a/src/tests/hook-list-test.c b/src/tests/hook-list-test.c
index 60b965c..452e477 100644
--- a/src/tests/hook-list-test.c
+++ b/src/tests/hook-list-test.c
@@ -31,7 +31,7 @@ int main(int argc, char *argv[]) {
 
     pa_hook_fire(&hook, (void*) "call2");
 
-    pa_hook_free(&hook);
+    pa_hook_done(&hook);
 
     return 0;
 }

commit 5042284d45b524f1201232f6c09fda65977b70cc
Author: Lennart Poettering <lennart at poettering.net>
Date:   Sun Aug 3 16:41:52 2008 +0200

    introduce pa_cli_eof_cb_t

diff --git a/src/pulsecore/cli.c b/src/pulsecore/cli.c
index b3c639f..2057b67 100644
--- a/src/pulsecore/cli.c
+++ b/src/pulsecore/cli.c
@@ -52,7 +52,7 @@ struct pa_cli {
     pa_core *core;
     pa_ioline *line;
 
-    void (*eof_callback)(pa_cli *c, void *userdata);
+    pa_cli_eof_cb_t eof_callback;
     void *userdata;
 
     pa_client *client;
@@ -107,12 +107,11 @@ static void client_kill(pa_client *client) {
     pa_assert_se(c = client->userdata);
 
     pa_log_debug("CLI client killed.");
+
     if (c->defer_kill)
         c->kill_requested = TRUE;
-    else {
-        if (c->eof_callback)
-            c->eof_callback(c, c->userdata);
-    }
+    else if (c->eof_callback)
+        c->eof_callback(c, c->userdata);
 }
 
 static void line_callback(pa_ioline *line, const char *s, void *userdata) {
@@ -125,6 +124,7 @@ static void line_callback(pa_ioline *line, const char *s, void *userdata) {
 
     if (!s) {
         pa_log_debug("CLI got EOF from user.");
+
         if (c->eof_callback)
             c->eof_callback(c, c->userdata);
 
@@ -145,7 +145,7 @@ static void line_callback(pa_ioline *line, const char *s, void *userdata) {
         pa_ioline_puts(line, PROMPT);
 }
 
-void pa_cli_set_eof_callback(pa_cli *c, void (*cb)(pa_cli*c, void *userdata), void *userdata) {
+void pa_cli_set_eof_callback(pa_cli *c, pa_cli_eof_cb_t cb, void *userdata) {
     pa_assert(c);
 
     c->eof_callback = cb;
diff --git a/src/pulsecore/cli.h b/src/pulsecore/cli.h
index 6077a8e..3f7a6fa 100644
--- a/src/pulsecore/cli.h
+++ b/src/pulsecore/cli.h
@@ -28,6 +28,8 @@
 
 typedef struct pa_cli pa_cli;
 
+typedef void (*pa_cli_eof_cb_t)(pa_cli *c, void *userdata);
+
 /* Create a new command line session on the specified io channel owned by the specified module */
 pa_cli* pa_cli_new(pa_core *core, pa_iochannel *io, pa_module *m);
 void pa_cli_free(pa_cli *cli);

commit 0a2fced2ee54917819a5cbbfd631419c7540965b
Author: Lennart Poettering <lennart at poettering.net>
Date:   Sun Aug 3 16:42:16 2008 +0200

    add new api function pa_cli_get_module()

diff --git a/src/pulsecore/cli.c b/src/pulsecore/cli.c
index 2057b67..67bf1e7 100644
--- a/src/pulsecore/cli.c
+++ b/src/pulsecore/cli.c
@@ -151,3 +151,9 @@ void pa_cli_set_eof_callback(pa_cli *c, pa_cli_eof_cb_t cb, void *userdata) {
     c->eof_callback = cb;
     c->userdata = userdata;
 }
+
+pa_module *pa_cli_get_module(pa_cli *c) {
+    pa_assert(c);
+
+    return c->client->module;
+}
diff --git a/src/pulsecore/cli.h b/src/pulsecore/cli.h
index 3f7a6fa..d860461 100644
--- a/src/pulsecore/cli.h
+++ b/src/pulsecore/cli.h
@@ -35,6 +35,8 @@ pa_cli* pa_cli_new(pa_core *core, pa_iochannel *io, pa_module *m);
 void pa_cli_free(pa_cli *cli);
 
 /* Set a callback function that is called whenever the command line session is terminated */
-void pa_cli_set_eof_callback(pa_cli *cli, void (*cb)(pa_cli*c, void *userdata), void *userdata);
+void pa_cli_set_eof_callback(pa_cli *cli, pa_cli_eof_cb_t cb, void *userdata);
+
+pa_module *pa_cli_get_module(pa_cli *c);
 
 #endif

commit 1ae1dfcc1062d08360c8253e885993d2a693d81c
Author: Lennart Poettering <lennart at poettering.net>
Date:   Sun Aug 3 16:42:41 2008 +0200

    simplify a bit

diff --git a/src/pulsecore/x11wrap.c b/src/pulsecore/x11wrap.c
index 353b120..17f8e6a 100644
--- a/src/pulsecore/x11wrap.c
+++ b/src/pulsecore/x11wrap.c
@@ -243,8 +243,10 @@ void pa_x11_wrapper_unref(pa_x11_wrapper* w) {
     pa_assert(w);
     pa_assert(PA_REFCNT_VALUE(w) >= 1);
 
-    if (PA_REFCNT_DEC(w) <= 0)
-        x11_wrapper_free(w);
+    if (PA_REFCNT_DEC(w) > 0)
+        return;
+
+    x11_wrapper_free(w);
 }
 
 Display *pa_x11_wrapper_get_display(pa_x11_wrapper *w) {

commit aaaafb059cfb523d8034425f1429af47b9e55e1a
Author: Lennart Poettering <lennart at poettering.net>
Date:   Sun Aug 3 16:43:51 2008 +0200

    use pa_channel_map_init_extend() instead of pa_channel_map_init_auto() to make things more robust

diff --git a/src/pulsecore/modargs.c b/src/pulsecore/modargs.c
index 5f5902c..d257b4c 100644
--- a/src/pulsecore/modargs.c
+++ b/src/pulsecore/modargs.c
@@ -322,8 +322,7 @@ int pa_modargs_get_sample_spec_and_channel_map(pa_modargs *ma, pa_sample_spec *r
     if (pa_modargs_get_sample_spec(ma, &ss) < 0)
         return -1;
 
-    if (!pa_channel_map_init_auto(&map, ss.channels, def))
-        map.channels = 0;
+    pa_channel_map_init_extend(&map, ss.channels, def);
 
     if (pa_modargs_get_channel_map(ma, NULL, &map) < 0)
         return -1;

commit 065e7644acf6cdbda0611b69ef06f97cda960110
Author: Lennart Poettering <lennart at poettering.net>
Date:   Sun Aug 3 16:44:38 2008 +0200

    make all protocol objects global singletons

diff --git a/src/Makefile.am b/src/Makefile.am
index 268409b..2770b93 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -827,7 +827,7 @@ noinst_HEADERS += \
 		pulsecore/pstream-util.h \
 		pulsecore/pdispatch.h \
 		pulsecore/authkey.h \
-		pulsecore/authkey-prop.h \
+		pulsecore/auth-cookie.h \
 		pulsecore/strlist.h \
 		pulsecore/protocol-simple.h \
 		pulsecore/esound.h \
@@ -857,7 +857,7 @@ modlibexec_LTLIBRARIES = \
 		libpstream-util.la \
 		libpdispatch.la \
 		libauthkey.la \
-		libauthkey-prop.la \
+		libauth-cookie.la \
 		libstrlist.la \
 		libprotocol-simple.la \
 		libprotocol-http.la \
@@ -958,7 +958,7 @@ libprotocol_http_la_LIBADD = $(AM_LIBADD) libsocket-server.la libioline.la libpu
 
 libprotocol_native_la_SOURCES = pulsecore/protocol-native.c pulsecore/protocol-native.h pulsecore/native-common.h
 libprotocol_native_la_LDFLAGS = -avoid-version
-libprotocol_native_la_LIBADD = $(AM_LIBADD) libsocket-server.la libpstream.la libpstream-util.la libpdispatch.la libtagstruct.la libauthkey.la libauthkey-prop.la libstrlist.la libpulsecore.la libiochannel.la libipacl.la
+libprotocol_native_la_LIBADD = $(AM_LIBADD) libsocket-server.la libpstream.la libpstream-util.la libpdispatch.la libtagstruct.la libauthkey.la libauth-cookie.la libstrlist.la libpulsecore.la libiochannel.la libipacl.la
 
 libtagstruct_la_SOURCES = pulsecore/tagstruct.c pulsecore/tagstruct.h
 libtagstruct_la_LDFLAGS = -avoid-version
@@ -972,9 +972,9 @@ libauthkey_la_SOURCES = pulsecore/authkey.c pulsecore/authkey.h
 libauthkey_la_LDFLAGS = -avoid-version
 libauthkey_la_LIBADD = $(AM_LIBADD) libpulsecore.la
 
-libauthkey_prop_la_SOURCES = pulsecore/authkey-prop.c pulsecore/authkey-prop.h
-libauthkey_prop_la_LDFLAGS = -avoid-version
-libauthkey_prop_la_LIBADD = $(AM_LIBADD) libpulsecore.la
+libauth_cookie_la_SOURCES = pulsecore/auth-cookie.c pulsecore/auth-cookie.h
+libauth_cookie_la_LDFLAGS = -avoid-version
+libauth_cookie_la_LIBADD = $(AM_LIBADD) libpulsecore.la
 
 libsocket_util_la_SOURCES = \
 		pulsecore/inet_ntop.c pulsecore/inet_ntop.h \
@@ -1339,11 +1339,11 @@ module_match_la_LIBADD = $(AM_LIBADD) libpulsecore.la
 module_tunnel_sink_la_SOURCES = modules/module-tunnel.c
 module_tunnel_sink_la_CFLAGS = -DTUNNEL_SINK=1 $(AM_CFLAGS)
 module_tunnel_sink_la_LDFLAGS = -module -avoid-version
-module_tunnel_sink_la_LIBADD = $(AM_LIBADD) libpulsecore.la libsocket-client.la libpstream.la libpstream-util.la libpdispatch.la libtagstruct.la libauthkey.la libauthkey-prop.la libsocket-util.la libiochannel.la
+module_tunnel_sink_la_LIBADD = $(AM_LIBADD) libpulsecore.la libsocket-client.la libpstream.la libpstream-util.la libpdispatch.la libtagstruct.la libauthkey.la libauth-cookie.la libsocket-util.la libiochannel.la
 
 module_tunnel_source_la_SOURCES = modules/module-tunnel.c
 module_tunnel_source_la_LDFLAGS = -module -avoid-version
-module_tunnel_source_la_LIBADD = $(AM_LIBADD) libpulsecore.la libsocket-client.la libpstream.la libpstream-util.la libpdispatch.la libtagstruct.la libauthkey.la libauthkey-prop.la libsocket-util.la libiochannel.la
+module_tunnel_source_la_LIBADD = $(AM_LIBADD) libpulsecore.la libsocket-client.la libpstream.la libpstream-util.la libpdispatch.la libtagstruct.la libauthkey.la libauth-cookie.la libsocket-util.la libiochannel.la
 
 # X11
 
@@ -1355,7 +1355,7 @@ module_x11_bell_la_LIBADD = $(AM_LIBADD) $(X_PRE_LIBS) -lX11 $(X_LIBS) $(X_EXTRA
 module_x11_publish_la_SOURCES = modules/module-x11-publish.c
 module_x11_publish_la_CFLAGS = $(AM_CFLAGS) $(X_CFLAGS)
 module_x11_publish_la_LDFLAGS = -module -avoid-version
-module_x11_publish_la_LIBADD = $(AM_LIBADD) $(X_PRE_LIBS) -lX11 $(X_LIBS) $(X_EXTRA_LIBS) libx11wrap.la libauthkey.la libauthkey-prop.la libx11prop.la libstrlist.la libpulsecore.la
+module_x11_publish_la_LIBADD = $(AM_LIBADD) $(X_PRE_LIBS) -lX11 $(X_LIBS) $(X_EXTRA_LIBS) libx11wrap.la libauthkey.la libauth-cookie.la libx11prop.la libstrlist.la libpulsecore.la
 
 module_x11_xsmp_la_SOURCES = modules/module-x11-xsmp.c
 module_x11_xsmp_la_CFLAGS = $(AM_CFLAGS) $(X_CFLAGS)
diff --git a/src/modules/module-native-protocol-fd.c b/src/modules/module-native-protocol-fd.c
index 1a6f536..fa9c0e4 100644
--- a/src/modules/module-native-protocol-fd.c
+++ b/src/modules/module-native-protocol-fd.c
@@ -42,8 +42,6 @@ PA_MODULE_LOAD_ONCE(TRUE);
 
 static const char* const valid_modargs[] = {
     "fd",
-    "public",
-    "cookie",
     NULL,
 };
 
@@ -51,6 +49,7 @@ int pa__init(pa_module*m) {
     pa_iochannel *io;
     pa_modargs *ma;
     int fd, r = -1;
+    pa_native_options *options = NULL;
 
     pa_assert(m);
 
@@ -64,12 +63,17 @@ int pa__init(pa_module*m) {
         goto finish;
     }
 
+    options = pa_native_options_new();
+    options->module = m;
+    options->auth_anonymous = TRUE;
+
     io = pa_iochannel_new(m->core->mainloop, fd, fd);
 
-    if (!(m->userdata = pa_protocol_native_new_iochannel(m->core, io, m, ma))) {
-        pa_iochannel_free(io);
-        goto finish;
-    }
+    m->userdata = pa_native_protocol_get(m->core);
+
+    pa_native_protocol_connect(m->userdata, io, options);
+
+    pa_native_options_unref(options);
 
     r = 0;
 
@@ -77,11 +81,17 @@ finish:
     if (ma)
         pa_modargs_free(ma);
 
+    if (options)
+        pa_native_options_unref(options);
+
     return r;
 }
 
 void pa__done(pa_module*m) {
     pa_assert(m);
 
-    pa_protocol_native_free(m->userdata);
+    if (m->userdata) {
+        pa_native_protocol_disconnect(m->userdata, m);
+        pa_native_protocol_unref(m->userdata);
+    }
 }
diff --git a/src/modules/module-protocol-stub.c b/src/modules/module-protocol-stub.c
index 0c9529c..8136c6f 100644
--- a/src/modules/module-protocol-stub.c
+++ b/src/modules/module-protocol-stub.c
@@ -62,19 +62,19 @@
 #endif
 
 #if defined(USE_PROTOCOL_SIMPLE)
-  #include <pulsecore/protocol-simple.h>
-  #define protocol_new pa_protocol_simple_new
-  #define protocol_free pa_protocol_simple_free
-  #define TCPWRAP_SERVICE "pulseaudio-simple"
-  #define IPV4_PORT 4711
-  #define UNIX_SOCKET "simple"
-  #define MODULE_ARGUMENTS "rate", "format", "channels", "sink", "source", "playback", "record",
-  #if defined(USE_TCP_SOCKETS)
-    #include "module-simple-protocol-tcp-symdef.h"
-  #else
-    #include "module-simple-protocol-unix-symdef.h"
-  #endif
-PA_MODULE_DESCRIPTION("Simple protocol "SOCKET_DESCRIPTION);
+#  include <pulsecore/protocol-simple.h>
+#  define TCPWRAP_SERVICE "pulseaudio-simple"
+#  define IPV4_PORT 4711
+#  define UNIX_SOCKET "simple"
+#  define MODULE_ARGUMENTS "rate", "format", "channels", "sink", "source", "playback", "record",
+
+#  if defined(USE_TCP_SOCKETS)
+#    include "module-simple-protocol-tcp-symdef.h"
+#  else
+#    include "module-simple-protocol-unix-symdef.h"
+#  endif
+
+  PA_MODULE_DESCRIPTION("Simple protocol "SOCKET_DESCRIPTION);
   PA_MODULE_USAGE("rate=<sample rate> "
                   "format=<sample format> "
                   "channels=<number of channels> "
@@ -84,96 +84,96 @@ PA_MODULE_DESCRIPTION("Simple protocol "SOCKET_DESCRIPTION);
                   "record=<enable record?> "
                   SOCKET_USAGE);
 #elif defined(USE_PROTOCOL_CLI)
-  #include <pulsecore/protocol-cli.h>
-  #define protocol_new pa_protocol_cli_new
-  #define protocol_free pa_protocol_cli_free
-  #define TCPWRAP_SERVICE "pulseaudio-cli"
-  #define IPV4_PORT 4712
-  #define UNIX_SOCKET "cli"
-  #define MODULE_ARGUMENTS
-  #ifdef USE_TCP_SOCKETS
-    #include "module-cli-protocol-tcp-symdef.h"
-  #else
-    #include "module-cli-protocol-unix-symdef.h"
-  #endif
+#  include <pulsecore/protocol-cli.h>
+#  define TCPWRAP_SERVICE "pulseaudio-cli"
+#  define IPV4_PORT 4712
+#  define UNIX_SOCKET "cli"
+#  define MODULE_ARGUMENTS
+
+#  ifdef USE_TCP_SOCKETS
+#    include "module-cli-protocol-tcp-symdef.h"
+#  else
+#   include "module-cli-protocol-unix-symdef.h"
+#  endif
+
   PA_MODULE_DESCRIPTION("Command line interface protocol "SOCKET_DESCRIPTION);
   PA_MODULE_USAGE(SOCKET_USAGE);
 #elif defined(USE_PROTOCOL_HTTP)
-  #include <pulsecore/protocol-http.h>
-  #define protocol_new pa_protocol_http_new
-  #define protocol_free pa_protocol_http_free
-  #define TCPWRAP_SERVICE "pulseaudio-http"
-  #define IPV4_PORT 4714
-  #define UNIX_SOCKET "http"
-  #define MODULE_ARGUMENTS
-  #ifdef USE_TCP_SOCKETS
-    #include "module-http-protocol-tcp-symdef.h"
-  #else
-    #include "module-http-protocol-unix-symdef.h"
-  #endif
+#  include <pulsecore/protocol-http.h>
+#  define TCPWRAP_SERVICE "pulseaudio-http"
+#  define IPV4_PORT 4714
+#  define UNIX_SOCKET "http"
+#  define MODULE_ARGUMENTS
+
+#  ifdef USE_TCP_SOCKETS
+#    include "module-http-protocol-tcp-symdef.h"
+#  else
+#    include "module-http-protocol-unix-symdef.h"
+#  endif
+
   PA_MODULE_DESCRIPTION("HTTP "SOCKET_DESCRIPTION);
   PA_MODULE_USAGE(SOCKET_USAGE);
 #elif defined(USE_PROTOCOL_NATIVE)
-  #include <pulsecore/protocol-native.h>
-  #define protocol_new pa_protocol_native_new
-  #define protocol_free pa_protocol_native_free
-  #define TCPWRAP_SERVICE "pulseaudio-native"
-  #define IPV4_PORT PA_NATIVE_DEFAULT_PORT
-  #define UNIX_SOCKET PA_NATIVE_DEFAULT_UNIX_SOCKET
-  #define MODULE_ARGUMENTS_COMMON "cookie", "auth-anonymous",
-  #ifdef USE_TCP_SOCKETS
-    #include "module-native-protocol-tcp-symdef.h"
-  #else
-    #include "module-native-protocol-unix-symdef.h"
-  #endif
-
-  #if defined(HAVE_CREDS) && !defined(USE_TCP_SOCKETS)
-    #define MODULE_ARGUMENTS MODULE_ARGUMENTS_COMMON "auth-group", "auth-group-enable",
-    #define AUTH_USAGE "auth-group=<system group to allow access> auth-group-enable=<enable auth by UNIX group?> "
-  #elif defined(USE_TCP_SOCKETS)
-    #define MODULE_ARGUMENTS MODULE_ARGUMENTS_COMMON "auth-ip-acl",
-    #define AUTH_USAGE "auth-ip-acl=<IP address ACL to allow access> "
-  #else
-    #define MODULE_ARGUMENTS MODULE_ARGUMENTS_COMMON
-    #define AUTH_USAGE
-  #endif
+#  include <pulsecore/protocol-native.h>
+#  define TCPWRAP_SERVICE "pulseaudio-native"
+#  define IPV4_PORT PA_NATIVE_DEFAULT_PORT
+#  define UNIX_SOCKET PA_NATIVE_DEFAULT_UNIX_SOCKET
+#  define MODULE_ARGUMENTS_COMMON "cookie", "auth-cookie", "auth-cookie-enabled", "auth-anonymous",
+
+#  ifdef USE_TCP_SOCKETS
+#    include "module-native-protocol-tcp-symdef.h"
+#  else
+#    include "module-native-protocol-unix-symdef.h"
+#  endif
+
+#  if defined(HAVE_CREDS) && !defined(USE_TCP_SOCKETS)
+#    define MODULE_ARGUMENTS MODULE_ARGUMENTS_COMMON "auth-group", "auth-group-enable",
+#    define AUTH_USAGE "auth-group=<system group to allow access> auth-group-enable=<enable auth by UNIX group?> "
+#  elif defined(USE_TCP_SOCKETS)
+#    define MODULE_ARGUMENTS MODULE_ARGUMENTS_COMMON "auth-ip-acl",
+#    define AUTH_USAGE "auth-ip-acl=<IP address ACL to allow access> "
+#  else
+#    define MODULE_ARGUMENTS MODULE_ARGUMENTS_COMMON
+#    define AUTH_USAGE
+#    endif
 
   PA_MODULE_DESCRIPTION("Native protocol "SOCKET_DESCRIPTION);
   PA_MODULE_USAGE("auth-anonymous=<don't check for cookies?> "
-                  "cookie=<path to cookie file> "
+                  "auth-cookie=<path to cookie file> "
+                  "auth-cookie-enabled=<enable cookie authentification? "
                   AUTH_USAGE
                   SOCKET_USAGE);
 #elif defined(USE_PROTOCOL_ESOUND)
-  #include <pulsecore/protocol-esound.h>
-  #include <pulsecore/esound.h>
-  #define protocol_new pa_protocol_esound_new
-  #define protocol_free pa_protocol_esound_free
-  #define TCPWRAP_SERVICE "esound"
-  #define IPV4_PORT ESD_DEFAULT_PORT
-  #define MODULE_ARGUMENTS_COMMON "sink", "source", "auth-anonymous", "cookie",
-  #ifdef USE_TCP_SOCKETS
-    #include "module-esound-protocol-tcp-symdef.h"
-  #else
-    #include "module-esound-protocol-unix-symdef.h"
-  #endif
-
-  #if defined(USE_TCP_SOCKETS)
-    #define MODULE_ARGUMENTS MODULE_ARGUMENTS_COMMON "auth-ip-acl",
-    #define AUTH_USAGE "auth-ip-acl=<IP address ACL to allow access> "
-  #else
-    #define MODULE_ARGUMENTS MODULE_ARGUMENTS_COMMON
-    #define AUTH_USAGE
-  #endif
+#  include <pulsecore/protocol-esound.h>
+#  include <pulsecore/esound.h>
+#  define TCPWRAP_SERVICE "esound"
+#  define IPV4_PORT ESD_DEFAULT_PORT
+#  define MODULE_ARGUMENTS_COMMON "sink", "source", "auth-anonymous", "cookie", "auth-cookie", "auth-cookie-enabled"
+
+#  ifdef USE_TCP_SOCKETS
+#    include "module-esound-protocol-tcp-symdef.h"
+#  else
+#    include "module-esound-protocol-unix-symdef.h"
+#  endif
+
+#  if defined(USE_TCP_SOCKETS)
+#    define MODULE_ARGUMENTS MODULE_ARGUMENTS_COMMON "auth-ip-acl",
+#    define AUTH_USAGE "auth-ip-acl=<IP address ACL to allow access> "
+#  else
+#    define MODULE_ARGUMENTS MODULE_ARGUMENTS_COMMON
+#    define AUTH_USAGE
+#  endif
 
   PA_MODULE_DESCRIPTION("ESOUND protocol "SOCKET_DESCRIPTION);
   PA_MODULE_USAGE("sink=<sink to connect to> "
                   "source=<source to connect to> "
                   "auth-anonymous=<don't verify cookies?> "
-                  "cookie=<path to cookie file> "
+                  "auth-cookie=<path to cookie file> "
+                  "auth-cookie-enabled=<enable cookie authentification? "
                   AUTH_USAGE
                   SOCKET_USAGE);
 #else
-  #error "Broken build system"
+#  error "Broken build system"
 #endif
 
 PA_MODULE_LOAD_ONCE(FALSE);
@@ -192,37 +192,103 @@ static const char* const valid_modargs[] = {
 };
 
 struct userdata {
+    pa_module *module;
+
+#if defined(USE_PROTOCOL_SIMPLE)
+    pa_simple_protocol *simple_protocol;
+    pa_simple_options *simple_options;
+#elif defined(USE_PROTOCOL_CLI)
+    pa_cli_protocol *cli_protocol;
+#elif defined(USE_PROTOCOL_HTTP)
+    pa_http_protocol *http_protocol;
+#elif defined(USE_PROTOCOL_NATIVE)
+    pa_native_protocol *native_protocol;
+    pa_native_options *native_options;
+#else
+    pa_esound_protocol *esound_protocol;
+    pa_esound_options *esound_options;
+#endif
+
 #if defined(USE_TCP_SOCKETS)
-    void *protocol_ipv4;
-    void *protocol_ipv6;
+    pa_socket_server *socket_server_ipv4;
+    pa_socket_server *socket_server_ipv6;
 #else
-    void *protocol_unix;
+    pa_socket_server *socket_server_unix;
     char *socket_path;
 #endif
 };
 
+static void socket_server_on_connection_cb(pa_socket_server*s, pa_iochannel *io, void *userdata) {
+    struct userdata *u = userdata;
+
+    pa_assert(s);
+    pa_assert(io);
+    pa_assert(u);
+
+#if defined(USE_PROTOCOL_SIMPLE)
+    pa_simple_protocol_connect(u->simple_protocol, io, u->simple_options);
+#elif defined(USE_PROTOCOL_CLI)
+    pa_cli_protocol_connect(u->cli_protocol, io, u->module);
+#elif defined(USE_PROTOCOL_HTTP)
+    pa_http_protocol_connect(u->http_protocol, io, u->module);
+#elif defined(USE_PROTOCOL_NATIVE)
+    pa_native_protocol_connect(u->native_protocol, io, u->native_options);
+#else
+    pa_esound_protocol_connect(u->esound_protocol, io, u->esound_options);
+#endif
+}
+
 int pa__init(pa_module*m) {
     pa_modargs *ma = NULL;
-    int ret = -1;
     struct userdata *u = NULL;
 
 #if defined(USE_TCP_SOCKETS)
-    pa_socket_server *s_ipv4 = NULL, *s_ipv6 = NULL;
     uint32_t port = IPV4_PORT;
     const char *listen_on;
 #else
-    pa_socket_server *s;
     int r;
 #endif
 
+#if defined(USE_PROTOCOL_NATIVE)
+    char t[256];
+#endif
+
     pa_assert(m);
 
     if (!(ma = pa_modargs_new(m->argument, valid_modargs))) {
         pa_log("Failed to parse module arguments");
-        goto finish;
+        goto fail;
     }
 
     u = pa_xnew0(struct userdata, 1);
+    u->module = m;
+
+#if defined(USE_PROTOCOL_SIMPLE)
+    u->simple_protocol = pa_simple_protocol_get(m->core);
+
+    u->simple_options = pa_simple_options_new();
+    if (pa_simple_options_parse(u->simple_options, m->core, ma) < 0)
+        goto fail;
+    u->simple_options->module = m;
+#elif defined(USE_PROTOCOL_CLI)
+    u->cli_protocol = pa_cli_protocol_get(m->core);
+#elif defined(USE_PROTOCOL_HTTP)
+    u->http_protocol = pa_http_protocol_get(m->core);
+#elif defined(USE_PROTOCOL_NATIVE)
+    u->native_protocol = pa_native_protocol_get(m->core);
+
+    u->native_options = pa_native_options_new();
+    if (pa_native_options_parse(u->native_options, m->core, ma) < 0)
+        goto fail;
+    u->native_options->module = m;
+#else
+    u->esound_protocol = pa_esound_protocol_get(m->core);
+
+    u->esound_options = pa_esound_options_new();
+    if (pa_esound_options_parse(u->esound_options, m->core, ma) < 0)
+        goto fail;
+    u->esound_options->module = m;
+#endif
 
 #if defined(USE_TCP_SOCKETS)
     if (pa_modargs_get_value_u32(ma, "port", &port) < 0 || port < 1 || port > 0xFFFF) {
@@ -233,38 +299,30 @@ int pa__init(pa_module*m) {
     listen_on = pa_modargs_get_value(ma, "listen", NULL);
 
     if (listen_on) {
-        s_ipv6 = pa_socket_server_new_ipv6_string(m->core->mainloop, listen_on, port, TCPWRAP_SERVICE);
-        s_ipv4 = pa_socket_server_new_ipv4_string(m->core->mainloop, listen_on, port, TCPWRAP_SERVICE);
+        u->socket_server_ipv6 = pa_socket_server_new_ipv6_string(m->core->mainloop, listen_on, port, TCPWRAP_SERVICE);
+        u->socket_server_ipv4 = pa_socket_server_new_ipv4_string(m->core->mainloop, listen_on, port, TCPWRAP_SERVICE);
     } else {
-        s_ipv6 = pa_socket_server_new_ipv6_any(m->core->mainloop, port, TCPWRAP_SERVICE);
-        s_ipv4 = pa_socket_server_new_ipv4_any(m->core->mainloop, port, TCPWRAP_SERVICE);
+        u->socket_server_ipv6 = pa_socket_server_new_ipv6_any(m->core->mainloop, port, TCPWRAP_SERVICE);
+        u->socket_server_ipv4 = pa_socket_server_new_ipv4_any(m->core->mainloop, port, TCPWRAP_SERVICE);
     }
 
-    if (!s_ipv4 && !s_ipv6)
+    if (!u->socket_server_ipv4 && !u->socket_server_ipv6)
         goto fail;
 
-    if (s_ipv4)
-        u->protocol_ipv4 = protocol_new(m->core, s_ipv4, m, ma);
-    if (s_ipv6)
-        u->protocol_ipv6 = protocol_new(m->core, s_ipv6, m, ma);
-
-    if (!u->protocol_ipv4 && !u->protocol_ipv6)
-        goto fail;
-
-    if (s_ipv6)
-        pa_socket_server_unref(s_ipv6);
-    if (s_ipv6)
-        pa_socket_server_unref(s_ipv4);
+    if (u->socket_server_ipv4)
+        pa_socket_server_set_callback(u->socket_server_ipv4, socket_server_on_connection_cb, u);
+    if (u->socket_server_ipv6)
+        pa_socket_server_set_callback(u->socket_server_ipv6, socket_server_on_connection_cb, u);
 
 #else
 
-#if defined(USE_PROTOCOL_ESOUND)
+#  if defined(USE_PROTOCOL_ESOUND)
 
-#if defined(USE_PER_USER_ESOUND_SOCKET)
+#    if defined(USE_PER_USER_ESOUND_SOCKET)
     u->socket_path = pa_sprintf_malloc("/tmp/.esd-%lu/socket", (unsigned long) getuid());
-#else
+#    else
     u->socket_path = pa_xstrdup("/tmp/.esd/socket");
-#endif
+#    endif
 
     /* This socket doesn't reside in our own runtime dir but in
      * /tmp/.esd/, hence we have to create the dir first */
@@ -274,12 +332,12 @@ int pa__init(pa_module*m) {
         goto fail;
     }
 
-#else
+#  else
     if (!(u->socket_path = pa_runtime_path(pa_modargs_get_value(ma, "socket", UNIX_SOCKET)))) {
         pa_log("Failed to generate socket path.");
         goto fail;
     }
-#endif
+#  endif
 
     if ((r = pa_unix_socket_remove_stale(u->socket_path)) < 0) {
         pa_log("Failed to remove stale UNIX socket '%s': %s", u->socket_path, pa_cstrerror(errno));
@@ -287,53 +345,44 @@ int pa__init(pa_module*m) {
     } else if (r > 0)
         pa_log_info("Removed stale UNIX socket '%s'.", u->socket_path);
 
-    if (!(s = pa_socket_server_new_unix(m->core->mainloop, u->socket_path)))
+    if (!(u->socket_server_unix = pa_socket_server_new_unix(m->core->mainloop, u->socket_path)))
         goto fail;
 
-    if (!(u->protocol_unix = protocol_new(m->core, s, m, ma)))
-        goto fail;
+    pa_socket_server_set_callback(u->socket_server_unix, socket_server_on_connection_cb, u);
 
-    pa_socket_server_unref(s);
+#endif
+
+#if defined(USE_PROTOCOL_NATIVE)
+#  if defined(USE_TCP_SOCKETS)
+    if (u->socket_server_ipv4)
+        if (pa_socket_server_get_address(u->socket_server_ipv4, t, sizeof(t)))
+            pa_native_protocol_add_server_string(u->native_protocol, t);
+
+    if (u->socket_server_ipv6)
+        if (pa_socket_server_get_address(u->socket_server_ipv6, t, sizeof(t)))
+            pa_native_protocol_add_server_string(u->native_protocol, t);
+#  else
+    if (pa_socket_server_get_address(u->socket_server_unix, t, sizeof(t)))
+        pa_native_protocol_add_server_string(u->native_protocol, t);
 
+#  endif
 #endif
 
     m->userdata = u;
 
-    ret = 0;
-
-finish:
     if (ma)
         pa_modargs_free(ma);
 
-    return ret;
+    return 0;
 
 fail:
-    if (u) {
-#if defined(USE_TCP_SOCKETS)
-        if (u->protocol_ipv4)
-            protocol_free(u->protocol_ipv4);
-        if (u->protocol_ipv6)
-            protocol_free(u->protocol_ipv6);
-#else
-        if (u->protocol_unix)
-            protocol_free(u->protocol_unix);
-        pa_xfree(u->socket_path);
-#endif
 
-        pa_xfree(u);
-    }
+    if (ma)
+        pa_modargs_free(ma);
 
-#if defined(USE_TCP_SOCKETS)
-    if (s_ipv4)
-        pa_socket_server_unref(s_ipv4);
-    if (s_ipv6)
-        pa_socket_server_unref(s_ipv6);
-#else
-    if (s)
-        pa_socket_server_unref(s);
-#endif
+    pa__done(m);
 
-    goto finish;
+    return -1;
 }
 
 void pa__done(pa_module*m) {
@@ -343,22 +392,72 @@ void pa__done(pa_module*m) {
 
     u = m->userdata;
 
+#if defined(USE_PROTOCOL_SIMPLE)
+    if (u->simple_protocol) {
+        pa_simple_protocol_disconnect(u->simple_protocol, u->module);
+        pa_simple_protocol_unref(u->simple_protocol);
+    }
+    if (u->simple_options)
+        pa_simple_options_unref(u->simple_options);
+#elif defined(USE_PROTOCOL_CLI)
+    if (u->cli_protocol) {
+        pa_cli_protocol_disconnect(u->cli_protocol, u->module);
+        pa_cli_protocol_unref(u->cli_protocol);
+    }
+#elif defined(USE_PROTOCOL_HTTP)
+    if (u->http_protocol) {
+        pa_http_protocol_disconnect(u->http_protocol, u->module);
+        pa_http_protocol_unref(u->http_protocol);
+    }
+#elif defined(USE_PROTOCOL_NATIVE)
+    if (u->native_protocol) {
+
+        char t[256];
+
+#  if defined(USE_TCP_SOCKETS)
+        if (u->socket_server_ipv4)
+            if (pa_socket_server_get_address(u->socket_server_ipv4, t, sizeof(t)))
+                pa_native_protocol_remove_server_string(u->native_protocol, t);
+
+        if (u->socket_server_ipv6)
+            if (pa_socket_server_get_address(u->socket_server_ipv6, t, sizeof(t)))
+                pa_native_protocol_remove_server_string(u->native_protocol, t);
+#  else
+        if (u->socket_server_unix)
+            if (pa_socket_server_get_address(u->socket_server_unix, t, sizeof(t)))
+                pa_native_protocol_remove_server_string(u->native_protocol, t);
+#  endif
+
+        pa_native_protocol_disconnect(u->native_protocol, u->module);
+        pa_native_protocol_unref(u->native_protocol);
+    }
+    if (u->native_options)
+        pa_native_options_unref(u->native_options);
+#else
+    if (u->esound_protocol) {
+        pa_esound_protocol_disconnect(u->esound_protocol, u->module);
+        pa_esound_protocol_unref(u->esound_protocol);
+    }
+    if (u->esound_options)
+        pa_esound_options_unref(u->esound_options);
+#endif
+
 #if defined(USE_TCP_SOCKETS)
-    if (u->protocol_ipv4)
-        protocol_free(u->protocol_ipv4);
-    if (u->protocol_ipv6)
-        protocol_free(u->protocol_ipv6);
+    if (u->socket_server_ipv4)
+        pa_socket_server_unref(u->socket_server_ipv4);
+    if (u->socket_server_ipv6)
+        pa_socket_server_unref(u->socket_server_ipv6);
 #else
-    if (u->protocol_unix)
-        protocol_free(u->protocol_unix);
+    if (u->socket_server_unix)
+        pa_socket_server_unref(u->socket_server_unix);
 
-#if defined(USE_PROTOCOL_ESOUND) && !defined(USE_PER_USER_ESOUND_SOCKET)
+# if defined(USE_PROTOCOL_ESOUND) && !defined(USE_PER_USER_ESOUND_SOCKET)
     if (u->socket_path) {
         char *p = pa_parent_dir(u->socket_path);
         rmdir(p);
         pa_xfree(p);
     }
-#endif
+# endif
 
     pa_xfree(u->socket_path);
 #endif
diff --git a/src/modules/module-tunnel.c b/src/modules/module-tunnel.c
index 21f2f84..af27ce7 100644
--- a/src/modules/module-tunnel.c
+++ b/src/modules/module-tunnel.c
@@ -45,16 +45,15 @@
 #include <pulsecore/pdispatch.h>
 #include <pulsecore/pstream.h>
 #include <pulsecore/pstream-util.h>
-#include <pulsecore/authkey.h>
 #include <pulsecore/socket-client.h>
 #include <pulsecore/socket-util.h>
-#include <pulsecore/authkey-prop.h>
 #include <pulsecore/time-smoother.h>
 #include <pulsecore/thread.h>
 #include <pulsecore/thread-mq.h>
 #include <pulsecore/rtclock.h>
 #include <pulsecore/core-error.h>
 #include <pulsecore/proplist-util.h>
+#include <pulsecore/auth-cookie.h>
 
 #ifdef TUNNEL_SINK
 #include "module-tunnel-sink-symdef.h"
@@ -185,7 +184,7 @@ struct userdata {
     pa_source *source;
 #endif
 
-    uint8_t auth_cookie[PA_NATIVE_COOKIE_LENGTH];
+    pa_auth_cookie *auth_cookie;
 
     uint32_t version;
     uint32_t ctag;
@@ -204,8 +203,6 @@ struct userdata {
 
     pa_time_event *time_event;
 
-    pa_bool_t auth_cookie_in_property;
-
     pa_smoother *smoother;
 
     char *device_description;
@@ -1588,7 +1585,8 @@ static void on_connection(pa_socket_client *sc, pa_iochannel *io, void *userdata
     pa_tagstruct_putu32(t, PA_COMMAND_AUTH);
     pa_tagstruct_putu32(t, tag = u->ctag++);
     pa_tagstruct_putu32(t, PA_PROTOCOL_VERSION);
-    pa_tagstruct_put_arbitrary(t, u->auth_cookie, sizeof(u->auth_cookie));
+
+    pa_tagstruct_put_arbitrary(t, pa_auth_cookie_read(u->auth_cookie, PA_NATIVE_COOKIE_LENGTH), PA_NATIVE_COOKIE_LENGTH);
 
 #ifdef HAVE_CREDS
 {
@@ -1658,33 +1656,6 @@ static int sink_set_mute(pa_sink *sink) {
 
 #endif
 
-/* Called from main context */
-static int load_key(struct userdata *u, const char*fn) {
-    pa_assert(u);
-
-    u->auth_cookie_in_property = FALSE;
-
-    if (!fn && pa_authkey_prop_get(u->core, PA_NATIVE_COOKIE_PROPERTY_NAME, u->auth_cookie, sizeof(u->auth_cookie)) >= 0) {
-        pa_log_debug("Using already loaded auth cookie.");
-        pa_authkey_prop_ref(u->core, PA_NATIVE_COOKIE_PROPERTY_NAME);
-        u->auth_cookie_in_property = 1;
-        return 0;
-    }
-
-    if (!fn)
-        fn = PA_NATIVE_COOKIE_FILE;
-
-    if (pa_authkey_load_auto(fn, u->auth_cookie, sizeof(u->auth_cookie)) < 0)
-        return -1;
-
-    pa_log_debug("Loading cookie from disk.");
-
-    if (pa_authkey_prop_put(u->core, PA_NATIVE_COOKIE_PROPERTY_NAME, u->auth_cookie, sizeof(u->auth_cookie)) >= 0)
-        u->auth_cookie_in_property = TRUE;
-
-    return 0;
-}
-
 int pa__init(pa_module*m) {
     pa_modargs *ma = NULL;
     struct userdata *u = NULL;
@@ -1722,7 +1693,6 @@ int pa__init(pa_module*m) {
     u->smoother = pa_smoother_new(PA_USEC_PER_SEC, PA_USEC_PER_SEC*2, TRUE, 10);
     u->ctag = 1;
     u->device_index = u->channel = PA_INVALID_INDEX;
-    u->auth_cookie_in_property = FALSE;
     u->time_event = NULL;
     u->ignore_latency_before = 0;
     u->transport_usec = 0;
@@ -1733,7 +1703,7 @@ int pa__init(pa_module*m) {
     u->rtpoll = pa_rtpoll_new();
     pa_thread_mq_init(&u->thread_mq, m->core->mainloop, u->rtpoll);
 
-    if (load_key(u, pa_modargs_get_value(ma, "cookie", NULL)) < 0)
+    if (!(u->auth_cookie = pa_auth_cookie_get(u->core, pa_modargs_get_value(ma, "cookie", PA_NATIVE_COOKIE_FILE), PA_NATIVE_COOKIE_LENGTH)))
         goto fail;
 
     if (!(u->server_name = pa_xstrdup(pa_modargs_get_value(ma, "server", NULL)))) {
@@ -1911,8 +1881,8 @@ void pa__done(pa_module*m) {
     if (u->client)
         pa_socket_client_unref(u->client);
 
-    if (u->auth_cookie_in_property)
-        pa_authkey_prop_unref(m->core, PA_NATIVE_COOKIE_PROPERTY_NAME);
+    if (u->auth_cookie)
+        pa_auth_cookie_unref(u->auth_cookie);
 
     if (u->smoother)
         pa_smoother_free(u->smoother);
diff --git a/src/modules/module-x11-publish.c b/src/modules/module-x11-publish.c
index 4ef4873..c29535e 100644
--- a/src/modules/module-x11-publish.c
+++ b/src/modules/module-x11-publish.c
@@ -43,11 +43,11 @@
 #include <pulsecore/x11wrap.h>
 #include <pulsecore/core-util.h>
 #include <pulsecore/native-common.h>
-#include <pulsecore/authkey-prop.h>
-#include <pulsecore/authkey.h>
+#include <pulsecore/auth-cookie.h>
 #include <pulsecore/x11prop.h>
 #include <pulsecore/strlist.h>
 #include <pulsecore/shared.h>
+#include <pulsecore/protocol-native.h>
 
 #include "module-x11-publish-symdef.h"
 
@@ -68,15 +68,48 @@ static const char* const valid_modargs[] = {
 struct userdata {
     pa_core *core;
     pa_module *module;
+    pa_native_protocol *protocol;
 
     char *id;
-    uint8_t auth_cookie[PA_NATIVE_COOKIE_LENGTH];
-    pa_bool_t auth_cookie_in_property;
+    pa_auth_cookie *auth_cookie;
 
     pa_x11_wrapper *x11_wrapper;
     pa_x11_client *x11_client;
+
+    pa_hook_slot *hook_slot;
 };
 
+static void publish_servers(struct userdata *u, pa_strlist *l) {
+
+    if (l) {
+        char *s;
+
+        l = pa_strlist_reverse(l);
+        s = pa_strlist_tostring(l);
+        l = pa_strlist_reverse(l);
+
+        pa_x11_set_prop(pa_x11_wrapper_get_display(u->x11_wrapper), "PULSE_SERVER", s);
+        pa_xfree(s);
+    } else
+        pa_x11_del_prop(pa_x11_wrapper_get_display(u->x11_wrapper), "PULSE_SERVER");
+}
+
+static pa_hook_result_t servers_changed_cb(void *hook_data, void *call_data, void *slot_data) {
+    pa_strlist *servers = call_data;
+    struct userdata *u = slot_data;
+    char t[256];
+
+    pa_assert(u);
+
+    if (!pa_x11_get_prop(pa_x11_wrapper_get_display(u->x11_wrapper), "PULSE_ID", t, sizeof(t)) || strcmp(t, u->id)) {
+        pa_log_warn("PulseAudio information vanished from X11!");
+        return PA_HOOK_OK;
+    }
+
+    publish_servers(u, servers);
+    return PA_HOOK_OK;
+}
+
 static void x11_kill_cb(pa_x11_wrapper *w, void *userdata) {
     struct userdata *u = userdata;
 
@@ -96,40 +129,12 @@ static void x11_kill_cb(pa_x11_wrapper *w, void *userdata) {
     pa_module_unload_request(u->module);
 }
 
-static int load_key(struct userdata *u, const char*fn) {
-    pa_assert(u);
-
-    u->auth_cookie_in_property = FALSE;
-
-    if (!fn && pa_authkey_prop_get(u->core, PA_NATIVE_COOKIE_PROPERTY_NAME, u->auth_cookie, sizeof(u->auth_cookie)) >= 0) {
-        pa_log_debug("using already loaded auth cookie.");
-        pa_authkey_prop_ref(u->core, PA_NATIVE_COOKIE_PROPERTY_NAME);
-        u->auth_cookie_in_property = 1;
-        return 0;
-    }
-
-    if (!fn)
-        fn = PA_NATIVE_COOKIE_FILE;
-
-    if (pa_authkey_load_auto(fn, u->auth_cookie, sizeof(u->auth_cookie)) < 0)
-        return -1;
-
-    pa_log_debug("Loading cookie from disk.");
-
-    if (pa_authkey_prop_put(u->core, PA_NATIVE_COOKIE_PROPERTY_NAME, u->auth_cookie, sizeof(u->auth_cookie)) >= 0)
-        u->auth_cookie_in_property = TRUE;
-
-    return 0;
-}
-
 int pa__init(pa_module*m) {
     struct userdata *u;
     pa_modargs *ma = NULL;
     char hn[256], un[128];
     char hx[PA_NATIVE_COOKIE_LENGTH*2+1];
     const char *t;
-    char *s;
-    pa_strlist *l;
 
     pa_assert(m);
 
@@ -141,40 +146,36 @@ int pa__init(pa_module*m) {
     m->userdata = u = pa_xnew(struct userdata, 1);
     u->core = m->core;
     u->module = m;
+    u->protocol = pa_native_protocol_get(m->core);
     u->id = NULL;
-    u->auth_cookie_in_property = FALSE;
+    u->auth_cookie = NULL;
     u->x11_client = NULL;
     u->x11_wrapper = NULL;
 
-    if (load_key(u, pa_modargs_get_value(ma, "cookie", NULL)) < 0)
-        goto fail;
+    u->hook_slot = pa_hook_connect(pa_native_protocol_servers_changed(u->protocol), PA_HOOK_NORMAL, servers_changed_cb, u);
 
-    if (!(u->x11_wrapper = pa_x11_wrapper_get(m->core, pa_modargs_get_value(ma, "display", NULL))))
+    if (!(u->auth_cookie = pa_auth_cookie_get(m->core, pa_modargs_get_value(ma, "cookie", PA_NATIVE_COOKIE_FILE), PA_NATIVE_COOKIE_LENGTH)))
         goto fail;
 
-    if (!(l = pa_shared_get(m->core, PA_NATIVE_SERVER_PROPERTY_NAME)))
+    if (!(u->x11_wrapper = pa_x11_wrapper_get(m->core, pa_modargs_get_value(ma, "display", NULL))))
         goto fail;
 
-    l = pa_strlist_reverse(l);
-    s = pa_strlist_tostring(l);
-    l = pa_strlist_reverse(l);
-
-    pa_x11_set_prop(pa_x11_wrapper_get_display(u->x11_wrapper), "PULSE_SERVER", s);
-    pa_xfree(s);
-
     if (!pa_get_fqdn(hn, sizeof(hn)) || !pa_get_user_name(un, sizeof(un)))
         goto fail;
 
     u->id = pa_sprintf_malloc("%s@%s/%u", un, hn, (unsigned) getpid());
     pa_x11_set_prop(pa_x11_wrapper_get_display(u->x11_wrapper), "PULSE_ID", u->id);
 
+    publish_servers(u, pa_native_protocol_servers(u->protocol));
+
     if ((t = pa_modargs_get_value(ma, "source", NULL)))
         pa_x11_set_prop(pa_x11_wrapper_get_display(u->x11_wrapper), "PULSE_SOURCE", t);
 
     if ((t = pa_modargs_get_value(ma, "sink", NULL)))
         pa_x11_set_prop(pa_x11_wrapper_get_display(u->x11_wrapper), "PULSE_SINK", t);
 
-    pa_x11_set_prop(pa_x11_wrapper_get_display(u->x11_wrapper), "PULSE_COOKIE", pa_hexstr(u->auth_cookie, sizeof(u->auth_cookie), hx, sizeof(hx)));
+    pa_x11_set_prop(pa_x11_wrapper_get_display(u->x11_wrapper), "PULSE_COOKIE",
+                    pa_hexstr(pa_auth_cookie_read(u->auth_cookie, PA_NATIVE_COOKIE_LENGTH), PA_NATIVE_COOKIE_LENGTH, hx, sizeof(hx)));
 
     u->x11_client = pa_x11_client_new(u->x11_wrapper, NULL, x11_kill_cb, u);
 
@@ -220,8 +221,14 @@ void pa__done(pa_module*m) {
         pa_x11_wrapper_unref(u->x11_wrapper);
     }
 
-    if (u->auth_cookie_in_property)
-        pa_authkey_prop_unref(m->core, PA_NATIVE_COOKIE_PROPERTY_NAME);
+    if (u->auth_cookie)
+        pa_auth_cookie_unref(u->auth_cookie);
+
+    if (u->hook_slot)
+        pa_hook_slot_free(u->hook_slot);
+
+    if (u->protocol)
+        pa_native_protocol_unref(u->protocol);
 
     pa_xfree(u->id);
     pa_xfree(u);
diff --git a/src/pulsecore/protocol-cli.c b/src/pulsecore/protocol-cli.c
index 30cb475..9247bb4 100644
--- a/src/pulsecore/protocol-cli.c
+++ b/src/pulsecore/protocol-cli.c
@@ -30,34 +30,41 @@
 #include <pulsecore/cli.h>
 #include <pulsecore/log.h>
 #include <pulsecore/macro.h>
+#include <pulsecore/shared.h>
 
 #include "protocol-cli.h"
 
 /* Don't allow more than this many concurrent connections */
 #define MAX_CONNECTIONS 25
 
-struct pa_protocol_cli {
-    pa_module *module;
+struct pa_cli_protocol {
+    PA_REFCNT_DECLARE;
+
     pa_core *core;
-    pa_socket_server*server;
     pa_idxset *connections;
 };
 
-static void cli_eof_cb(pa_cli*c, void*userdata) {
-    pa_protocol_cli *p = userdata;
+static void cli_unlink(pa_cli_protocol *p, pa_cli *c) {
     pa_assert(p);
+    pa_assert(c);
 
     pa_idxset_remove_by_data(p->connections, c, NULL);
     pa_cli_free(c);
 }
 
-static void on_connection(pa_socket_server*s, pa_iochannel *io, void *userdata) {
-    pa_protocol_cli *p = userdata;
+static void cli_eof_cb(pa_cli*c, void*userdata) {
+    pa_cli_protocol *p = userdata;
+    pa_assert(p);
+
+    cli_unlink(p, c);
+}
+
+void pa_cli_protocol_connect(pa_cli_protocol *p, pa_iochannel *io, pa_module *m) {
     pa_cli *c;
 
-    pa_assert(s);
-    pa_assert(io);
     pa_assert(p);
+    pa_assert(io);
+    pa_assert(m);
 
     if (pa_idxset_size(p->connections)+1 > MAX_CONNECTIONS) {
         pa_log("Warning! Too many connections (%u), dropping incoming connection.", MAX_CONNECTIONS);
@@ -65,39 +72,71 @@ static void on_connection(pa_socket_server*s, pa_iochannel *io, void *userdata)
         return;
     }
 
-    c = pa_cli_new(p->core, io, p->module);
+    c = pa_cli_new(p->core, io, m);
     pa_cli_set_eof_callback(c, cli_eof_cb, p);
 
     pa_idxset_put(p->connections, c, NULL);
 }
 
-pa_protocol_cli* pa_protocol_cli_new(pa_core *core, pa_socket_server *server, pa_module *m, PA_GCC_UNUSED pa_modargs *ma) {
-    pa_protocol_cli* p;
+void pa_cli_protocol_disconnect(pa_cli_protocol *p, pa_module *m) {
+    pa_cli *c;
+    void *state = NULL;
+
+    pa_assert(p);
+    pa_assert(m);
+
+    while ((c = pa_idxset_iterate(p->connections, &state, NULL)))
+        if (pa_cli_get_module(c) == m)
+            cli_unlink(p, c);
+}
 
-    pa_core_assert_ref(core);
-    pa_assert(server);
+static pa_cli_protocol* cli_protocol_new(pa_core *c) {
+    pa_cli_protocol *p;
 
-    p = pa_xnew(pa_protocol_cli, 1);
-    p->module = m;
-    p->core = core;
-    p->server = pa_socket_server_ref(server);
+    pa_assert(c);
+
+    p = pa_xnew(pa_cli_protocol, 1);
+    PA_REFCNT_INIT(p);
+    p->core = c;
     p->connections = pa_idxset_new(NULL, NULL);
 
-    pa_socket_server_set_callback(p->server, on_connection, p);
+    pa_assert_se(pa_shared_set(c, "cli-protocol", p) >= 0);
 
     return p;
 }
 
-static void free_connection(void *p, PA_GCC_UNUSED void *userdata) {
+pa_cli_protocol* pa_cli_protocol_get(pa_core *c) {
+    pa_cli_protocol *p;
+
+    if ((p = pa_shared_get(c, "cli-protocol")))
+        return pa_cli_protocol_ref(p);
+
+    return cli_protocol_new(c);
+}
+
+pa_cli_protocol* pa_cli_protocol_ref(pa_cli_protocol *p) {
     pa_assert(p);
+    pa_assert(PA_REFCNT_VALUE(p) >= 1);
+
+    PA_REFCNT_INC(p);
 
-    pa_cli_free(p);
+    return p;
 }
 
-void pa_protocol_cli_free(pa_protocol_cli *p) {
+void pa_cli_protocol_unref(pa_cli_protocol *p) {
+    pa_cli *c;
     pa_assert(p);
+    pa_assert(PA_REFCNT_VALUE(p) >= 1);
+
+    if (PA_REFCNT_DEC(p) > 0)
+        return;
+
+    while ((c = pa_idxset_first(p->connections, NULL)))
+        cli_unlink(p, c);
+
+    pa_idxset_free(p->connections, NULL, NULL);
+
+    pa_assert_se(pa_shared_remove(p->core, "cli-protocol") >= 0);
 
-    pa_idxset_free(p->connections, free_connection, NULL);
-    pa_socket_server_unref(p->server);
     pa_xfree(p);
 }
diff --git a/src/pulsecore/protocol-cli.h b/src/pulsecore/protocol-cli.h
index 8922ac6..9e26dcd 100644
--- a/src/pulsecore/protocol-cli.h
+++ b/src/pulsecore/protocol-cli.h
@@ -27,9 +27,12 @@
 #include <pulsecore/module.h>
 #include <pulsecore/modargs.h>
 
-typedef struct pa_protocol_cli pa_protocol_cli;
+typedef struct pa_cli_protocol pa_cli_protocol;
 
-pa_protocol_cli* pa_protocol_cli_new(pa_core *core, pa_socket_server *server, pa_module *m, pa_modargs *ma);
-void pa_protocol_cli_free(pa_protocol_cli *n);
+pa_cli_protocol* pa_cli_protocol_get(pa_core *core);
+pa_cli_protocol* pa_cli_protocol_ref(pa_cli_protocol *p);
+void pa_cli_protocol_unref(pa_cli_protocol *p);
+void pa_cli_protocol_connect(pa_cli_protocol *p, pa_iochannel *io, pa_module *m);
+void pa_cli_protocol_disconnect(pa_cli_protocol *o, pa_module *m);
 
 #endif
diff --git a/src/pulsecore/protocol-esound.c b/src/pulsecore/protocol-esound.c
index db1b430..4f121a3 100644
--- a/src/pulsecore/protocol-esound.c
+++ b/src/pulsecore/protocol-esound.c
@@ -52,6 +52,7 @@
 #include <pulsecore/ipacl.h>
 #include <pulsecore/macro.h>
 #include <pulsecore/thread-mq.h>
+#include <pulsecore/shared.h>
 
 #include "endianmacros.h"
 
@@ -83,7 +84,8 @@ typedef struct connection {
 
     uint32_t index;
     pa_bool_t dead;
-    pa_protocol_esound *protocol;
+    pa_esound_protocol *protocol;
+    pa_esound_options *options;
     pa_iochannel *io;
     pa_client *client;
     pa_bool_t authorized, swap_byte_order;
@@ -120,17 +122,12 @@ PA_DECLARE_CLASS(connection);
 #define CONNECTION(o) (connection_cast(o))
 static PA_DEFINE_CHECK_TYPE(connection, pa_msgobject);
 
-struct pa_protocol_esound {
-    pa_module *module;
+struct pa_esound_protocol {
+    PA_REFCNT_DECLARE;
+
     pa_core *core;
-    pa_bool_t public;
-    pa_socket_server *server;
     pa_idxset *connections;
-
-    char *sink_name, *source_name;
     unsigned n_player;
-    uint8_t esd_key[ESD_KEY_LEN];
-    pa_ip_acl *auth_ip_acl;
 };
 
 enum {
@@ -213,6 +210,11 @@ static void connection_unlink(connection *c) {
     if (!c->protocol)
         return;
 
+    if (c->options) {
+        pa_esound_options_unref(c->options);
+        c->options = NULL;
+    }
+
     if (c->sink_input) {
         pa_sink_input_unlink(c->sink_input);
         pa_sink_input_unref(c->sink_input);
@@ -340,17 +342,22 @@ static int esd_proto_connect(connection *c, PA_GCC_UNUSED esd_proto_t request, c
     pa_assert(data);
     pa_assert(length == (ESD_KEY_LEN + sizeof(uint32_t)));
 
+    if (!c->authorized && c->options->auth_cookie) {
+        const uint8_t*key;
+
+        if ((key = pa_auth_cookie_read(c->options->auth_cookie, ESD_KEY_LEN)))
+            if (memcmp(data, key, ESD_KEY_LEN) == 0)
+                c->authorized = TRUE;
+    }
+
     if (!c->authorized) {
-        if (memcmp(data, c->protocol->esd_key, ESD_KEY_LEN) != 0) {
-            pa_log("kicked client with invalid authorization key.");
-            return -1;
-        }
+        pa_log("Kicked client with invalid authorization key.");
+        return -1;
+    }
 
-        c->authorized = TRUE;
-        if (c->auth_timeout_event) {
-            c->protocol->core->mainloop->time_free(c->auth_timeout_event);
-            c->auth_timeout_event = NULL;
-        }
+    if (c->auth_timeout_event) {
+        c->protocol->core->mainloop->time_free(c->auth_timeout_event);
+        c->auth_timeout_event = NULL;
     }
 
     data = (const char*)data + ESD_KEY_LEN;
@@ -395,9 +402,9 @@ static int esd_proto_stream_play(connection *c, PA_GCC_UNUSED esd_proto_t reques
 
     CHECK_VALIDITY(pa_sample_spec_valid(&ss), "Invalid sample specification");
 
-    if (c->protocol->sink_name) {
-        sink = pa_namereg_get(c->protocol->core, c->protocol->sink_name, PA_NAMEREG_SINK, 1);
-        CHECK_VALIDITY(sink, "No such sink: %s", c->protocol->sink_name);
+    if (c->options->default_sink) {
+        sink = pa_namereg_get(c->protocol->core, c->options->default_sink, PA_NAMEREG_SINK, 1);
+        CHECK_VALIDITY(sink, "No such sink: %s", c->options->default_sink);
     }
 
     pa_strlcpy(name, data, sizeof(name));
@@ -412,7 +419,7 @@ static int esd_proto_stream_play(connection *c, PA_GCC_UNUSED esd_proto_t reques
 
     pa_sink_input_new_data_init(&sdata);
     sdata.driver = __FILE__;
-    sdata.module = c->protocol->module;
+    sdata.module = c->options->module;
     sdata.client = c->client;
     sdata.sink = sink;
     pa_proplist_update(sdata.proplist, PA_UPDATE_MERGE, c->client->proplist);
@@ -483,7 +490,7 @@ static int esd_proto_stream_record(connection *c, esd_proto_t request, const voi
     if (request == ESD_PROTO_STREAM_MON) {
         pa_sink* sink;
 
-        if (!(sink = pa_namereg_get(c->protocol->core, c->protocol->sink_name, PA_NAMEREG_SINK, 1))) {
+        if (!(sink = pa_namereg_get(c->protocol->core, c->options->default_sink, PA_NAMEREG_SINK, 1))) {
             pa_log("no such sink.");
             return -1;
         }
@@ -495,8 +502,8 @@ static int esd_proto_stream_record(connection *c, esd_proto_t request, const voi
     } else {
         pa_assert(request == ESD_PROTO_STREAM_REC);
 
-        if (c->protocol->source_name) {
-            if (!(source = pa_namereg_get(c->protocol->core, c->protocol->source_name, PA_NAMEREG_SOURCE, 1))) {
+        if (c->options->default_source) {
+            if (!(source = pa_namereg_get(c->protocol->core, c->options->default_source, PA_NAMEREG_SOURCE, 1))) {
                 pa_log("no such source.");
                 return -1;
             }
@@ -515,7 +522,7 @@ static int esd_proto_stream_record(connection *c, esd_proto_t request, const voi
 
     pa_source_output_new_data_init(&sdata);
     sdata.driver = __FILE__;
-    sdata.module = c->protocol->module;
+    sdata.module = c->options->module;
     sdata.client = c->client;
     sdata.source = source;
     pa_proplist_update(sdata.proplist, PA_UPDATE_MERGE, c->client->proplist);
@@ -562,7 +569,7 @@ static int esd_proto_get_latency(connection *c, PA_GCC_UNUSED esd_proto_t reques
     pa_assert(!data);
     pa_assert(length == 0);
 
-    if (!(sink = pa_namereg_get(c->protocol->core, c->protocol->sink_name, PA_NAMEREG_SINK, 1)))
+    if (!(sink = pa_namereg_get(c->protocol->core, c->options->default_sink, PA_NAMEREG_SINK, 1)))
         latency = 0;
     else {
         double usec = pa_sink_get_latency(sink);
@@ -583,7 +590,7 @@ static int esd_proto_server_info(connection *c, PA_GCC_UNUSED esd_proto_t reques
     pa_assert(data);
     pa_assert(length == sizeof(int32_t));
 
-    if ((sink = pa_namereg_get(c->protocol->core, c->protocol->sink_name, PA_NAMEREG_SINK, 1))) {
+    if ((sink = pa_namereg_get(c->protocol->core, c->options->default_sink, PA_NAMEREG_SINK, 1))) {
         rate = sink->sample_spec.rate;
         format = format_native2esd(&sink->sample_spec);
     }
@@ -858,7 +865,7 @@ static int esd_proto_sample_free_or_play(connection *c, esd_proto_t request, con
         if (request == ESD_PROTO_SAMPLE_PLAY) {
             pa_sink *sink;
 
-            if ((sink = pa_namereg_get(c->protocol->core, c->protocol->sink_name, PA_NAMEREG_SINK, 1)))
+            if ((sink = pa_namereg_get(c->protocol->core, c->options->default_sink, PA_NAMEREG_SINK, 1)))
                 if (pa_scache_play_item(c->protocol->core, name, sink, PA_VOLUME_NORM, c->client->proplist, NULL) >= 0)
                     ok = idx + 1;
         } else {
@@ -1350,7 +1357,7 @@ static pa_usec_t source_output_get_latency_cb(pa_source_output *o) {
     return pa_bytes_to_usec(pa_memblockq_get_length(c->output_memblockq), &c->source_output->sample_spec);
 }
 
-/*** socket server callback ***/
+/*** entry points ***/
 
 static void auth_timeout(pa_mainloop_api*m, pa_time_event *e, const struct timeval *tv, void *userdata) {
     connection *c = CONNECTION(userdata);
@@ -1364,14 +1371,13 @@ static void auth_timeout(pa_mainloop_api*m, pa_time_event *e, const struct timev
         connection_unlink(c);
 }
 
-static void on_connection(pa_socket_server*s, pa_iochannel *io, void *userdata) {
+void pa_esound_protocol_connect(pa_esound_protocol *p, pa_iochannel *io, pa_esound_options *o) {
     connection *c;
-    pa_protocol_esound *p = userdata;
     char cname[256], pname[128];
 
-    pa_assert(s);
-    pa_assert(io);
     pa_assert(p);
+    pa_assert(io);
+    pa_assert(o);
 
     if (pa_idxset_size(p->connections)+1 > MAX_CONNECTIONS) {
         pa_log("Warning! Too many connections (%u), dropping incoming connection.", MAX_CONNECTIONS);
@@ -1390,11 +1396,12 @@ static void on_connection(pa_socket_server*s, pa_iochannel *io, void *userdata)
     pa_snprintf(cname, sizeof(cname), "EsounD client (%s)", pname);
     c->client = pa_client_new(p->core, __FILE__, cname);
     pa_proplist_sets(c->client->proplist, "esound-protocol.peer", pname);
-    c->client->module = p->module;
+    c->client->module = o->module;
     c->client->kill = client_kill_cb;
     c->client->userdata = c;
 
-    c->authorized = !!p->public;
+    c->options = pa_esound_options_ref(o);
+    c->authorized = FALSE;
     c->swap_byte_order = FALSE;
     c->dead = FALSE;
 
@@ -1423,7 +1430,15 @@ static void on_connection(pa_socket_server*s, pa_iochannel *io, void *userdata)
 
     c->original_name = NULL;
 
-    if (!c->authorized && p->auth_ip_acl && pa_ip_acl_check(p->auth_ip_acl, pa_iochannel_get_recv_fd(io)) > 0) {
+    if (o->auth_anonymous) {
+        pa_log_info("Client authenticated anonymously.");
+        c->authorized = TRUE;
+    }
+
+    if (!c->authorized &&
+        o->auth_ip_acl &&
+        pa_ip_acl_check(o->auth_ip_acl, pa_iochannel_get_recv_fd(io)) > 0) {
+
         pa_log_info("Client authenticated by IP ACL.");
         c->authorized = TRUE;
     }
@@ -1442,71 +1457,163 @@ static void on_connection(pa_socket_server*s, pa_iochannel *io, void *userdata)
     pa_idxset_put(p->connections, c, &c->index);
 }
 
-/*** entry points ***/
-
-pa_protocol_esound* pa_protocol_esound_new(pa_core*core, pa_socket_server *server, pa_module *m, pa_modargs *ma) {
-    pa_protocol_esound *p = NULL;
-    pa_bool_t public = FALSE;
-    const char *acl;
+void pa_esound_protocol_disconnect(pa_esound_protocol *p, pa_module *m) {
+    connection *c;
+    void *state = NULL;
 
-    pa_assert(core);
-    pa_assert(server);
+    pa_assert(p);
     pa_assert(m);
-    pa_assert(ma);
-
-    if (pa_modargs_get_value_boolean(ma, "auth-anonymous", &public) < 0) {
-        pa_log("auth-anonymous= expects a boolean argument.");
-        goto fail;
-    }
-
-    p = pa_xnew(pa_protocol_esound, 1);
 
-    if (pa_authkey_load_auto(pa_modargs_get_value(ma, "cookie", DEFAULT_COOKIE_FILE), p->esd_key, sizeof(p->esd_key)) < 0)
-        goto fail;
+    while ((c = pa_idxset_iterate(p->connections, &state, NULL)))
+        if (c->options->module == m)
+            connection_unlink(c);
+}
 
-    if ((acl = pa_modargs_get_value(ma, "auth-ip-acl", NULL))) {
+static pa_esound_protocol* esound_protocol_new(pa_core *c) {
+    pa_esound_protocol *p;
 
-        if (!(p->auth_ip_acl = pa_ip_acl_new(acl))) {
-            pa_log("Failed to parse IP ACL '%s'", acl);
-            goto fail;
-        }
-    } else
-        p->auth_ip_acl = NULL;
+    pa_assert(c);
 
-    p->core = core;
-    p->module = m;
-    p->public = public;
-    p->server = pa_socket_server_ref(server);
-    pa_socket_server_set_callback(p->server, on_connection, p);
+    p = pa_xnew(pa_esound_protocol, 1);
+    PA_REFCNT_INIT(p);
+    p->core = c;
     p->connections = pa_idxset_new(NULL, NULL);
-
-    p->sink_name = pa_xstrdup(pa_modargs_get_value(ma, "sink", NULL));
-    p->source_name = pa_xstrdup(pa_modargs_get_value(ma, "source", NULL));
     p->n_player = 0;
 
+    pa_assert_se(pa_shared_set(c, "esound-protocol", p) >= 0);
+
     return p;
+}
 
-fail:
-    pa_xfree(p);
-    return NULL;
+pa_esound_protocol* pa_esound_protocol_get(pa_core *c) {
+    pa_esound_protocol *p;
+
+    if ((p = pa_shared_get(c, "esound-protocol")))
+        return pa_esound_protocol_ref(p);
+
+    return esound_protocol_new(c);
 }
 
-void pa_protocol_esound_free(pa_protocol_esound *p) {
+pa_esound_protocol* pa_esound_protocol_ref(pa_esound_protocol *p) {
+    pa_assert(p);
+    pa_assert(PA_REFCNT_VALUE(p) >= 1);
+
+    PA_REFCNT_INC(p);
+
+    return p;
+}
+
+void pa_esound_protocol_unref(pa_esound_protocol *p) {
     connection *c;
     pa_assert(p);
+    pa_assert(PA_REFCNT_VALUE(p) >= 1);
+
+    if (PA_REFCNT_DEC(p) > 0)
+        return;
 
     while ((c = pa_idxset_first(p->connections, NULL)))
         connection_unlink(c);
+
     pa_idxset_free(p->connections, NULL, NULL);
 
-    if (p->server)
-        pa_socket_server_unref(p->server);
+    pa_assert_se(pa_shared_remove(p->core, "esound-protocol") >= 0);
+
+    pa_xfree(p);
+}
+
+pa_esound_options* pa_esound_options_new(void) {
+    pa_esound_options *o;
 
-    if (p->auth_ip_acl)
-        pa_ip_acl_free(p->auth_ip_acl);
+    o = pa_xnew0(pa_esound_options, 1);
+    PA_REFCNT_INIT(o);
 
-    pa_xfree(p->sink_name);
-    pa_xfree(p->source_name);
+    return o;
+}
 
-    pa_xfree(p);
+pa_esound_options* pa_esound_options_ref(pa_esound_options *o) {
+    pa_assert(o);
+    pa_assert(PA_REFCNT_VALUE(o) >= 1);
+
+    PA_REFCNT_INC(o);
+
+    return o;
+}
+
+void pa_esound_options_unref(pa_esound_options *o) {
+    pa_assert(o);
+    pa_assert(PA_REFCNT_VALUE(o) >= 1);
+
+    if (PA_REFCNT_DEC(o) > 0)
+        return;
+
+    if (o->auth_ip_acl)
+        pa_ip_acl_free(o->auth_ip_acl);
+
+    if (o->auth_cookie)
+        pa_auth_cookie_unref(o->auth_cookie);
+
+    pa_xfree(o->default_sink);
+    pa_xfree(o->default_source);
+
+    pa_xfree(o);
+}
+
+int pa_esound_options_parse(pa_esound_options *o, pa_core *c, pa_modargs *ma) {
+    pa_bool_t enabled;
+    const char *acl;
+
+    pa_assert(o);
+    pa_assert(PA_REFCNT_VALUE(o) >= 1);
+    pa_assert(ma);
+
+    if (pa_modargs_get_value_boolean(ma, "auth-anonymous", &o->auth_anonymous) < 0) {
+        pa_log("auth-anonymous= expects a boolean argument.");
+        return -1;
+    }
+
+    if ((acl = pa_modargs_get_value(ma, "auth-ip-acl", NULL))) {
+        pa_ip_acl *ipa;
+
+        if (!(o->auth_ip_acl = pa_ip_acl_new(acl))) {
+            pa_log("Failed to parse IP ACL '%s'", acl);
+            return -1;
+        }
+
+        if (o->auth_ip_acl)
+            pa_ip_acl_free(o->auth_ip_acl);
+
+        o->auth_ip_acl = ipa;
+    }
+
+    enabled = TRUE;
+    if (pa_modargs_get_value_boolean(ma, "auth-cookie-enabled", &enabled) < 0) {
+        pa_log("auth-cookie-enabled= expects a boolean argument.");
+        return -1;
+    }
+
+    if (o->auth_cookie)
+        pa_auth_cookie_unref(o->auth_cookie);
+
+    if (enabled) {
+        const char *cn;
+
+        /* The new name for this is 'auth-cookie', for compat reasons
+         * we check the old name too */
+        if (!(cn = pa_modargs_get_value(ma, "auth-cookie", NULL)))
+            if (!(cn = pa_modargs_get_value(ma, "cookie", NULL)))
+                cn = DEFAULT_COOKIE_FILE;
+
+        if (!(o->auth_cookie = pa_auth_cookie_get(c, cn, ESD_KEY_LEN)))
+            return -1;
+
+    } else
+        o->auth_cookie = NULL;
+
+    pa_xfree(o->default_sink);
+    o->default_sink = pa_xstrdup(pa_modargs_get_value(ma, "sink", NULL));
+
+    pa_xfree(o->default_source);
+    o->default_source = pa_xstrdup(pa_modargs_get_value(ma, "source", NULL));
+
+    return 0;
 }
diff --git a/src/pulsecore/protocol-esound.h b/src/pulsecore/protocol-esound.h
index 0c9447d..232df66 100644
--- a/src/pulsecore/protocol-esound.h
+++ b/src/pulsecore/protocol-esound.h
@@ -24,13 +24,35 @@
 ***/
 
 #include <pulsecore/core.h>
-#include <pulsecore/socket-server.h>
+#include <pulsecore/ipacl.h>
+#include <pulsecore/auth-cookie.h>
+#include <pulsecore/iochannel.h>
 #include <pulsecore/module.h>
 #include <pulsecore/modargs.h>
 
-typedef struct pa_protocol_esound pa_protocol_esound;
+typedef struct pa_esound_protocol pa_esound_protocol;
 
-pa_protocol_esound* pa_protocol_esound_new(pa_core*core, pa_socket_server *server, pa_module *m, pa_modargs *ma);
-void pa_protocol_esound_free(pa_protocol_esound *p);
+typedef struct pa_esound_options {
+    PA_REFCNT_DECLARE;
+
+    pa_module *module;
+
+    pa_bool_t auth_anonymous;
+    pa_ip_acl *auth_ip_acl;
+    pa_auth_cookie *auth_cookie;
+
+    char *default_sink, *default_source;
+} pa_esound_options;
+
+pa_esound_protocol* pa_esound_protocol_get(pa_core*core);
+pa_esound_protocol* pa_esound_protocol_ref(pa_esound_protocol *p);
+void pa_esound_protocol_unref(pa_esound_protocol *p);
+void pa_esound_protocol_connect(pa_esound_protocol *p, pa_iochannel *io, pa_esound_options *o);
+void pa_esound_protocol_disconnect(pa_esound_protocol *p, pa_module *m);
+
+pa_esound_options* pa_esound_options_new(void);
+pa_esound_options* pa_esound_options_ref(pa_esound_options *o);
+void pa_esound_options_unref(pa_esound_options *o);
+int pa_esound_options_parse(pa_esound_options *o, pa_core *c, pa_modargs *ma);
 
 #endif
diff --git a/src/pulsecore/protocol-http.c b/src/pulsecore/protocol-http.c
index 0399043..c89d48b 100644
--- a/src/pulsecore/protocol-http.c
+++ b/src/pulsecore/protocol-http.c
@@ -35,6 +35,7 @@
 #include <pulsecore/log.h>
 #include <pulsecore/namereg.h>
 #include <pulsecore/cli-text.h>
+#include <pulsecore/shared.h>
 
 #include "protocol-http.h"
 
@@ -48,16 +49,21 @@
 #define URL_STATUS "/status"
 
 struct connection {
-    pa_protocol_http *protocol;
+    pa_http_protocol *protocol;
     pa_ioline *line;
-    enum { REQUEST_LINE, MIME_HEADER, DATA } state;
+    enum {
+        REQUEST_LINE,
+        MIME_HEADER,
+        DATA
+    } state;
     char *url;
+    pa_module *module;
 };
 
-struct pa_protocol_http {
-    pa_module *module;
+struct pa_http_protocol {
+    PA_REFCNT_DECLARE;
+
     pa_core *core;
-    pa_socket_server*server;
     pa_idxset *connections;
 };
 
@@ -101,14 +107,13 @@ static void http_message(struct connection *c, int code, const char *msg, const
 }
 
 
-static void connection_free(struct connection *c, int del) {
+static void connection_unlink(struct connection *c) {
     pa_assert(c);
 
     if (c->url)
         pa_xfree(c->url);
 
-    if (del)
-        pa_idxset_remove_by_data(c->protocol->connections, c, NULL);
+    pa_idxset_remove_by_data(c->protocol->connections, c, NULL);
 
     pa_ioline_unref(c->line);
     pa_xfree(c);
@@ -121,7 +126,7 @@ static void line_callback(pa_ioline *line, const char *s, void *userdata) {
 
     if (!s) {
         /* EOF */
-        connection_free(c, 1);
+        connection_unlink(c);
         return;
     }
 
@@ -220,16 +225,15 @@ fail:
     internal_server_error(c);
 }
 
-static void on_connection(pa_socket_server*s, pa_iochannel *io, void *userdata) {
-    pa_protocol_http *p = userdata;
+void pa_http_protocol_connect(pa_http_protocol *p, pa_iochannel *io, pa_module *m) {
     struct connection *c;
 
-    pa_assert(s);
-    pa_assert(io);
     pa_assert(p);
+    pa_assert(io);
+    pa_assert(m);
 
     if (pa_idxset_size(p->connections)+1 > MAX_CONNECTIONS) {
-        pa_log_warn("Warning! Too many connections (%u), dropping incoming connection.", MAX_CONNECTIONS);
+        pa_log("Warning! Too many connections (%u), dropping incoming connection.", MAX_CONNECTIONS);
         pa_iochannel_free(io);
         return;
     }
@@ -239,37 +243,73 @@ static void on_connection(pa_socket_server*s, pa_iochannel *io, void *userdata)
     c->line = pa_ioline_new(io);
     c->state = REQUEST_LINE;
     c->url = NULL;
+    c->module = m;
 
     pa_ioline_set_callback(c->line, line_callback, c);
+
     pa_idxset_put(p->connections, c, NULL);
 }
 
-pa_protocol_http* pa_protocol_http_new(pa_core *core, pa_socket_server *server, pa_module *m, PA_GCC_UNUSED pa_modargs *ma) {
-    pa_protocol_http* p;
+void pa_http_protocol_disconnect(pa_http_protocol *p, pa_module *m) {
+    struct connection *c;
+    void *state = NULL;
+
+    pa_assert(p);
+    pa_assert(m);
+
+    while ((c = pa_idxset_iterate(p->connections, &state, NULL)))
+        if (c->module == m)
+            connection_unlink(c);
+}
+
+static pa_http_protocol* http_protocol_new(pa_core *c) {
+    pa_http_protocol *p;
 
-    pa_core_assert_ref(core);
-    pa_assert(server);
+    pa_assert(c);
 
-    p = pa_xnew(pa_protocol_http, 1);
-    p->module = m;
-    p->core = core;
-    p->server = pa_socket_server_ref(server);
+    p = pa_xnew(pa_http_protocol, 1);
+    PA_REFCNT_INIT(p);
+    p->core = c;
     p->connections = pa_idxset_new(NULL, NULL);
 
-    pa_socket_server_set_callback(p->server, on_connection, p);
+    pa_assert_se(pa_shared_set(c, "http-protocol", p) >= 0);
 
     return p;
 }
 
-static void free_connection(void *p, PA_GCC_UNUSED void *userdata) {
+pa_http_protocol* pa_http_protocol_get(pa_core *c) {
+    pa_http_protocol *p;
+
+    if ((p = pa_shared_get(c, "http-protocol")))
+        return pa_http_protocol_ref(p);
+
+    return http_protocol_new(c);
+}
+
+pa_http_protocol* pa_http_protocol_ref(pa_http_protocol *p) {
     pa_assert(p);
-    connection_free(p, 0);
+    pa_assert(PA_REFCNT_VALUE(p) >= 1);
+
+    PA_REFCNT_INC(p);
+
+    return p;
 }
 
-void pa_protocol_http_free(pa_protocol_http *p) {
+void pa_http_protocol_unref(pa_http_protocol *p) {
+    struct connection *c;
+
     pa_assert(p);
+    pa_assert(PA_REFCNT_VALUE(p) >= 1);
+
+    if (PA_REFCNT_DEC(p) > 0)
+        return;
+
+    while ((c = pa_idxset_first(p->connections, NULL)))
+        connection_unlink(c);
+
+    pa_idxset_free(p->connections, NULL, NULL);
+
+    pa_assert_se(pa_shared_remove(p->core, "http-protocol") >= 0);
 
-    pa_idxset_free(p->connections, free_connection, NULL);
-    pa_socket_server_unref(p->server);
     pa_xfree(p);
 }
diff --git a/src/pulsecore/protocol-http.h b/src/pulsecore/protocol-http.h
index e337233..7e8f976 100644
--- a/src/pulsecore/protocol-http.h
+++ b/src/pulsecore/protocol-http.h
@@ -23,13 +23,17 @@
 ***/
 
 #include <pulsecore/core.h>
-#include <pulsecore/socket-server.h>
 #include <pulsecore/module.h>
 #include <pulsecore/modargs.h>
+#include <pulsecore/iochannel.h>
 
-typedef struct pa_protocol_http pa_protocol_http;
 
-pa_protocol_http* pa_protocol_http_new(pa_core *core, pa_socket_server *server, pa_module *m, pa_modargs *ma);
-void pa_protocol_http_free(pa_protocol_http *n);
+typedef struct pa_http_protocol pa_http_protocol;
+
+pa_http_protocol* pa_http_protocol_get(pa_core *core);
+pa_http_protocol* pa_http_protocol_ref(pa_http_protocol *p);
+void pa_http_protocol_unref(pa_http_protocol *p);
+void pa_http_protocol_connect(pa_http_protocol *p, pa_iochannel *io, pa_module *m);
+void pa_http_protocol_disconnect(pa_http_protocol *p, pa_module *m);
 
 #endif
diff --git a/src/pulsecore/protocol-native.c b/src/pulsecore/protocol-native.c
index 853f244..39a258f 100644
--- a/src/pulsecore/protocol-native.c
+++ b/src/pulsecore/protocol-native.c
@@ -74,7 +74,7 @@
 #define DEFAULT_FRAGSIZE_MSEC DEFAULT_TLENGTH_MSEC
 
 typedef struct connection connection;
-struct pa_protocol_native;
+struct pa_native_protocol;
 
 typedef struct record_stream {
     pa_msgobject parent;
@@ -88,10 +88,18 @@ typedef struct record_stream {
     pa_usec_t source_latency;
 } record_stream;
 
+PA_DECLARE_CLASS(record_stream);
+#define RECORD_STREAM(o) (record_stream_cast(o))
+static PA_DEFINE_CHECK_TYPE(record_stream, pa_msgobject);
+
 typedef struct output_stream {
     pa_msgobject parent;
 } output_stream;
 
+PA_DECLARE_CLASS(output_stream);
+#define OUTPUT_STREAM(o) (output_stream_cast(o))
+static PA_DEFINE_CHECK_TYPE(output_stream, pa_msgobject);
+
 typedef struct playback_stream {
     output_stream parent;
 
@@ -114,6 +122,10 @@ typedef struct playback_stream {
     size_t render_memblockq_length;
 } playback_stream;
 
+PA_DECLARE_CLASS(playback_stream);
+#define PLAYBACK_STREAM(o) (playback_stream_cast(o))
+static PA_DEFINE_CHECK_TYPE(playback_stream, output_stream);
+
 typedef struct upload_stream {
     output_stream parent;
 
@@ -128,13 +140,17 @@ typedef struct upload_stream {
     pa_proplist *proplist;
 } upload_stream;
 
+PA_DECLARE_CLASS(upload_stream);
+#define UPLOAD_STREAM(o) (upload_stream_cast(o))
+static PA_DEFINE_CHECK_TYPE(upload_stream, output_stream);
+
 struct connection {
     pa_msgobject parent;
-
+    pa_native_protocol *protocol;
+    pa_native_options *options;
     pa_bool_t authorized:1;
     pa_bool_t is_local:1;
     uint32_t version;
-    pa_protocol_native *protocol;
     pa_client *client;
     pa_pstream *pstream;
     pa_pdispatch *pdispatch;
@@ -144,38 +160,21 @@ struct connection {
     pa_time_event *auth_timeout_event;
 };
 
-PA_DECLARE_CLASS(record_stream);
-#define RECORD_STREAM(o) (record_stream_cast(o))
-static PA_DEFINE_CHECK_TYPE(record_stream, pa_msgobject);
-
-PA_DECLARE_CLASS(output_stream);
-#define OUTPUT_STREAM(o) (output_stream_cast(o))
-static PA_DEFINE_CHECK_TYPE(output_stream, pa_msgobject);
-
-PA_DECLARE_CLASS(playback_stream);
-#define PLAYBACK_STREAM(o) (playback_stream_cast(o))
-static PA_DEFINE_CHECK_TYPE(playback_stream, output_stream);
-
-PA_DECLARE_CLASS(upload_stream);
-#define UPLOAD_STREAM(o) (upload_stream_cast(o))
-static PA_DEFINE_CHECK_TYPE(upload_stream, output_stream);
-
 PA_DECLARE_CLASS(connection);
 #define CONNECTION(o) (connection_cast(o))
 static PA_DEFINE_CHECK_TYPE(connection, pa_msgobject);
 
-struct pa_protocol_native {
-    pa_module *module;
+struct pa_native_protocol {
+    PA_REFCNT_DECLARE;
+
     pa_core *core;
-    pa_bool_t public;
-    pa_socket_server *server;
     pa_idxset *connections;
-    uint8_t auth_cookie[PA_NATIVE_COOKIE_LENGTH];
-    pa_bool_t auth_cookie_in_property;
-#ifdef HAVE_CREDS
-    char *auth_group;
-#endif
-    pa_ip_acl *auth_ip_acl;
+
+    pa_strlist *servers;
+    pa_hook servers_changed;
+
+    /*     pa_hashmap *extensions; */
+
 };
 
 enum {
@@ -556,7 +555,7 @@ static record_stream* record_stream_new(
     pa_proplist_update(data.proplist, PA_UPDATE_REPLACE, p);
     pa_proplist_update(data.proplist, PA_UPDATE_MERGE, c->client->proplist);
     data.driver = __FILE__;
-    data.module = c->protocol->module;
+    data.module = c->options->module;
     data.client = c->client;
     data.source = source;
     data.direct_on_input = direct_on_input;
@@ -901,7 +900,7 @@ static playback_stream* playback_stream_new(
     pa_proplist_update(data.proplist, PA_UPDATE_REPLACE, p);
     pa_proplist_update(data.proplist, PA_UPDATE_MERGE, c->client->proplist);
     data.driver = __FILE__;
-    data.module = c->protocol->module;
+    data.module = c->options->module;
     data.client = c->client;
     data.sink = sink;
     pa_sink_input_new_data_set_sample_spec(&data, ss);
@@ -1002,6 +1001,9 @@ static void connection_unlink(connection *c) {
     if (!c->protocol)
         return;
 
+    if (c->options)
+        pa_native_options_unref(c->options);
+
     while ((r = pa_idxset_first(c->record_streams, NULL)))
         record_stream_unlink(r);
 
@@ -2007,17 +2009,17 @@ static void command_auth(PA_GCC_UNUSED pa_pdispatch *pd, PA_GCC_UNUSED uint32_t
         if ((creds = pa_pdispatch_creds(pd))) {
             if (creds->uid == getuid())
                 success = TRUE;
-            else if (c->protocol->auth_group) {
+            else if (c->options->auth_group) {
                 int r;
                 gid_t gid;
 
-                if ((gid = pa_get_gid_of_group(c->protocol->auth_group)) == (gid_t) -1)
-                    pa_log_warn("Failed to get GID of group '%s'", c->protocol->auth_group);
+                if ((gid = pa_get_gid_of_group(c->options->auth_group)) == (gid_t) -1)
+                    pa_log_warn("Failed to get GID of group '%s'", c->options->auth_group);
                 else if (gid == creds->gid)
                     success = TRUE;
 
                 if (!success) {
-                    if ((r = pa_uid_in_group(creds->uid, c->protocol->auth_group)) < 0)
+                    if ((r = pa_uid_in_group(creds->uid, c->options->auth_group)) < 0)
                         pa_log_warn("Failed to check group membership.");
                     else if (r > 0)
                         success = TRUE;
@@ -2031,8 +2033,13 @@ static void command_auth(PA_GCC_UNUSED pa_pdispatch *pd, PA_GCC_UNUSED uint32_t
         }
 #endif
 
-        if (!success && memcmp(c->protocol->auth_cookie, cookie, PA_NATIVE_COOKIE_LENGTH) == 0)
-            success = TRUE;
+        if (!success && c->options->auth_cookie) {
+            const uint8_t *ac;
+
+            if ((ac = pa_auth_cookie_read(c->options->auth_cookie, PA_NATIVE_COOKIE_LENGTH)))
+                if (memcmp(ac, cookie, PA_NATIVE_COOKIE_LENGTH) == 0)
+                    success = TRUE;
+        }
 
         if (!success) {
             pa_log_warn("Denied access to client with invalid authorization data.");
@@ -3951,7 +3958,7 @@ static void client_kill_cb(pa_client *c) {
     connection_unlink(CONNECTION(c->userdata));
 }
 
-/*** socket server callbacks ***/
+/*** module entry points ***/
 
 static void auth_timeout(pa_mainloop_api*m, pa_time_event *e, const struct timeval *tv, void *userdata) {
     connection *c = CONNECTION(userdata);
@@ -3965,13 +3972,13 @@ static void auth_timeout(pa_mainloop_api*m, pa_time_event *e, const struct timev
         connection_unlink(c);
 }
 
-static void on_connection(PA_GCC_UNUSED pa_socket_server*s, pa_iochannel *io, void *userdata) {
-    pa_protocol_native *p = userdata;
+void pa_native_protocol_connect(pa_native_protocol *p, pa_iochannel *io, pa_native_options *o) {
     connection *c;
     char cname[256], pname[128];
 
-    pa_assert(io);
     pa_assert(p);
+    pa_assert(io);
+    pa_assert(o);
 
     if (pa_idxset_size(p->connections)+1 > MAX_CONNECTIONS) {
         pa_log_warn("Warning! Too many connections (%u), dropping incoming connection.", MAX_CONNECTIONS);
@@ -3982,10 +3989,19 @@ static void on_connection(PA_GCC_UNUSED pa_socket_server*s, pa_iochannel *io, vo
     c = pa_msgobject_new(connection);
     c->parent.parent.free = connection_free;
     c->parent.process_msg = connection_process_msg;
+    c->protocol = p;
+    c->options = pa_native_options_ref(o);
+    c->authorized = FALSE;
+
+    if (o->auth_anonymous) {
+        pa_log_info("Client authenticated anonymously.");
+        c->authorized = TRUE;
+    }
 
-    c->authorized = p->public;
+    if (!c->authorized &&
+        o->auth_ip_acl &&
+        pa_ip_acl_check(o->auth_ip_acl, pa_iochannel_get_recv_fd(io)) > 0) {
 
-    if (!c->authorized && p->auth_ip_acl && pa_ip_acl_check(p->auth_ip_acl, pa_iochannel_get_recv_fd(io)) > 0) {
         pa_log_info("Client authenticated by IP ACL.");
         c->authorized = TRUE;
     }
@@ -4000,17 +4016,16 @@ static void on_connection(PA_GCC_UNUSED pa_socket_server*s, pa_iochannel *io, vo
 
     c->is_local = pa_iochannel_socket_is_local(io);
     c->version = 8;
-    c->protocol = p;
+
     pa_iochannel_socket_peer_to_string(io, pname, sizeof(pname));
     pa_snprintf(cname, sizeof(cname), "Native client (%s)", pname);
     c->client = pa_client_new(p->core, __FILE__, cname);
     pa_proplist_sets(c->client->proplist, "native-protocol.peer", pname);
     c->client->kill = client_kill_cb;
     c->client->userdata = c;
-    c->client->module = p->module;
+    c->client->module = o->module;
 
     c->pstream = pa_pstream_new(p->core->mainloop, io, p->core->mempool);
-
     pa_pstream_set_recieve_packet_callback(c->pstream, pstream_packet_callback, c);
     pa_pstream_set_recieve_memblock_callback(c->pstream, pstream_memblock_callback, c);
     pa_pstream_set_die_callback(c->pstream, pstream_die_callback, c);
@@ -4034,163 +4049,225 @@ static void on_connection(PA_GCC_UNUSED pa_socket_server*s, pa_iochannel *io, vo
 #endif
 }
 
-/*** module entry points ***/
+void pa_native_protocol_disconnect(pa_native_protocol *p, pa_module *m) {
+    connection *c;
+    void *state = NULL;
 
-static int load_key(pa_protocol_native*p, const char*fn) {
     pa_assert(p);
+    pa_assert(m);
 
-    p->auth_cookie_in_property = FALSE;
+    while ((c = pa_idxset_iterate(p->connections, &state, NULL)))
+        if (c->options->module == m)
+            connection_unlink(c);
+}
 
-    if (!fn && pa_authkey_prop_get(p->core, PA_NATIVE_COOKIE_PROPERTY_NAME, p->auth_cookie, sizeof(p->auth_cookie)) >= 0) {
-        pa_log_info("using already loaded auth cookie.");
-        pa_authkey_prop_ref(p->core, PA_NATIVE_COOKIE_PROPERTY_NAME);
-        p->auth_cookie_in_property = TRUE;
-        return 0;
-    }
+static pa_native_protocol* native_protocol_new(pa_core *c) {
+    pa_native_protocol *p;
 
-    if (!fn)
-        fn = PA_NATIVE_COOKIE_FILE;
+    pa_assert(c);
 
-    if (pa_authkey_load_auto(fn, p->auth_cookie, sizeof(p->auth_cookie)) < 0)
-        return -1;
+    p = pa_xnew(pa_native_protocol, 1);
+    PA_REFCNT_INIT(p);
+    p->core = c;
+    p->connections = pa_idxset_new(NULL, NULL);
 
-    pa_log_info("loading cookie from disk.");
+    p->servers = NULL;
+    pa_hook_init(&p->servers_changed, p);
 
-    if (pa_authkey_prop_put(p->core, PA_NATIVE_COOKIE_PROPERTY_NAME, p->auth_cookie, sizeof(p->auth_cookie)) >= 0)
-        p->auth_cookie_in_property = TRUE;
+    pa_assert_se(pa_shared_set(c, "native-protocol", p) >= 0);
 
-    return 0;
+    return p;
 }
 
-static pa_protocol_native* protocol_new_internal(pa_core *c, pa_module *m, pa_modargs *ma) {
-    pa_protocol_native *p;
-    pa_bool_t public = FALSE;
-    const char *acl;
+pa_native_protocol* pa_native_protocol_get(pa_core *c) {
+    pa_native_protocol *p;
 
-    pa_assert(c);
-    pa_assert(ma);
+    if ((p = pa_shared_get(c, "native-protocol")))
+        return pa_native_protocol_ref(p);
 
-    if (pa_modargs_get_value_boolean(ma, "auth-anonymous", &public) < 0) {
-        pa_log("auth-anonymous= expects a boolean argument.");
-        return NULL;
-    }
+    return native_protocol_new(c);
+}
 
-    p = pa_xnew(pa_protocol_native, 1);
-    p->core = c;
-    p->module = m;
-    p->public = public;
-    p->server = NULL;
-    p->auth_ip_acl = NULL;
+pa_native_protocol* pa_native_protocol_ref(pa_native_protocol *p) {
+    pa_assert(p);
+    pa_assert(PA_REFCNT_VALUE(p) >= 1);
 
-#ifdef HAVE_CREDS
-    {
-        pa_bool_t a = TRUE;
-        if (pa_modargs_get_value_boolean(ma, "auth-group-enabled", &a) < 0) {
-            pa_log("auth-group-enabled= expects a boolean argument.");
-            return NULL;
-        }
-        p->auth_group = a ? pa_xstrdup(pa_modargs_get_value(ma, "auth-group", pa_in_system_mode() ? PA_ACCESS_GROUP : NULL)) : NULL;
+    PA_REFCNT_INC(p);
 
-        if (p->auth_group)
-            pa_log_info("Allowing access to group '%s'.", p->auth_group);
-    }
-#endif
+    return p;
+}
 
+void pa_native_protocol_unref(pa_native_protocol *p) {
+    connection *c;
+    pa_assert(p);
+    pa_assert(PA_REFCNT_VALUE(p) >= 1);
 
-    if ((acl = pa_modargs_get_value(ma, "auth-ip-acl", NULL))) {
+    if (PA_REFCNT_DEC(p) > 0)
+        return;
 
-        if (!(p->auth_ip_acl = pa_ip_acl_new(acl))) {
-            pa_log("Failed to parse IP ACL '%s'", acl);
-            goto fail;
-        }
-    }
+    while ((c = pa_idxset_first(p->connections, NULL)))
+        connection_unlink(c);
 
-    if (load_key(p, pa_modargs_get_value(ma, "cookie", NULL)) < 0)
-        goto fail;
+    pa_idxset_free(p->connections, NULL, NULL);
 
-    p->connections = pa_idxset_new(NULL, NULL);
+    pa_strlist_free(p->servers);
+    pa_hook_done(&p->servers_changed);
 
-    return p;
+    pa_assert_se(pa_shared_remove(p->core, "native-protocol") >= 0);
 
-fail:
-#ifdef HAVE_CREDS
-    pa_xfree(p->auth_group);
-#endif
-    if (p->auth_ip_acl)
-        pa_ip_acl_free(p->auth_ip_acl);
     pa_xfree(p);
-    return NULL;
 }
 
-pa_protocol_native* pa_protocol_native_new(pa_core *core, pa_socket_server *server, pa_module *m, pa_modargs *ma) {
-    char t[256];
-    pa_protocol_native *p;
+void pa_native_protocol_add_server_string(pa_native_protocol *p, const char *name) {
+    pa_assert(p);
+    pa_assert(PA_REFCNT_VALUE(p) >= 1);
+    pa_assert(name);
 
-    if (!(p = protocol_new_internal(core, m, ma)))
-        return NULL;
+    p->servers = pa_strlist_prepend(p->servers, name);
 
-    p->server = pa_socket_server_ref(server);
-    pa_socket_server_set_callback(p->server, on_connection, p);
+    pa_hook_fire(&p->servers_changed, p->servers);
+}
 
-    if (pa_socket_server_get_address(p->server, t, sizeof(t))) {
-        pa_strlist *l;
-        l = pa_shared_get(core, PA_NATIVE_SERVER_PROPERTY_NAME);
-        l = pa_strlist_prepend(l, t);
-        pa_shared_replace(core, PA_NATIVE_SERVER_PROPERTY_NAME, l);
-    }
+void pa_native_protocol_remove_server_string(pa_native_protocol *p, const char *name) {
+    pa_assert(p);
+    pa_assert(PA_REFCNT_VALUE(p) >= 1);
+    pa_assert(name);
 
-    return p;
+    p->servers = pa_strlist_remove(p->servers, name);
+
+    pa_hook_fire(&p->servers_changed, p->servers);
 }
 
-void pa_protocol_native_free(pa_protocol_native *p) {
-    connection *c;
+pa_hook *pa_native_protocol_servers_changed(pa_native_protocol *p) {
     pa_assert(p);
+    pa_assert(PA_REFCNT_VALUE(p) >= 1);
 
-    while ((c = pa_idxset_first(p->connections, NULL)))
-        connection_unlink(c);
-    pa_idxset_free(p->connections, NULL, NULL);
+    return &p->servers_changed;
+}
+
+pa_strlist *pa_native_protocol_servers(pa_native_protocol *p) {
+    pa_assert(p);
+    pa_assert(PA_REFCNT_VALUE(p) >= 1);
 
-    if (p->server) {
-        char t[256];
+    return p->servers;
+}
 
-        if (pa_socket_server_get_address(p->server, t, sizeof(t))) {
-            pa_strlist *l;
-            l = pa_shared_get(p->core, PA_NATIVE_SERVER_PROPERTY_NAME);
-            l = pa_strlist_remove(l, t);
+/* int pa_native_protocol_install_extension(pa_native_protocol *p, pa_module *m, pa_native_protocol_extension_cb_t cb) { */
+/*     pa_assert(p); */
+/*     pa_assert(PA_REFCNT_VALUE(p) >= 1); */
+/*     pa_assert(m); */
+/*     pa_assert(cb); */
 
-            if (l)
-                pa_shared_replace(p->core, PA_NATIVE_SERVER_PROPERTY_NAME, l);
-            else
-                pa_shared_remove(p->core, PA_NATIVE_SERVER_PROPERTY_NAME);
-        }
 
-        pa_socket_server_unref(p->server);
+/* } */
+
+/* void pa_native_protocol_remove_extension(pa_native_protocol *p, pa_module *m) { */
+/*     pa_assert(p); */
+/*     pa_assert(PA_REFCNT_VALUE(p) >= 1); */
+/*     pa_assert(m); */
+
+/* } */
+
+pa_native_options* pa_native_options_new(void) {
+    pa_native_options *o;
+
+    o = pa_xnew0(pa_native_options, 1);
+    PA_REFCNT_INIT(o);
+
+    return o;
+}
+
+pa_native_options* pa_native_options_ref(pa_native_options *o) {
+    pa_assert(o);
+    pa_assert(PA_REFCNT_VALUE(o) >= 1);
+
+    PA_REFCNT_INC(o);
+
+    return o;
+}
+
+void pa_native_options_unref(pa_native_options *o) {
+    pa_assert(o);
+    pa_assert(PA_REFCNT_VALUE(o) >= 1);
+
+    if (PA_REFCNT_DEC(o) > 0)
+        return;
+
+    pa_xfree(o->auth_group);
+
+    if (o->auth_ip_acl)
+        pa_ip_acl_free(o->auth_ip_acl);
+
+    if (o->auth_cookie)
+        pa_auth_cookie_unref(o->auth_cookie);
+
+    pa_xfree(o);
+}
+
+int pa_native_options_parse(pa_native_options *o, pa_core *c, pa_modargs *ma) {
+    pa_bool_t enabled;
+    const char *acl;
+
+    pa_assert(o);
+    pa_assert(PA_REFCNT_VALUE(o) >= 1);
+    pa_assert(ma);
+
+    if (pa_modargs_get_value_boolean(ma, "auth-anonymous", &o->auth_anonymous) < 0) {
+        pa_log("auth-anonymous= expects a boolean argument.");
+        return -1;
     }
 
-    if (p->auth_cookie_in_property)
-        pa_authkey_prop_unref(p->core, PA_NATIVE_COOKIE_PROPERTY_NAME);
+    enabled = TRUE;
+    if (pa_modargs_get_value_boolean(ma, "auth-group-enabled", &enabled) < 0) {
+        pa_log("auth-group-enabled= expects a boolean argument.");
+        return -1;
+    }
 
-    if (p->auth_ip_acl)
-        pa_ip_acl_free(p->auth_ip_acl);
+    pa_xfree(o->auth_group);
+    o->auth_group = enabled ? pa_xstrdup(pa_modargs_get_value(ma, "auth-group", pa_in_system_mode() ? PA_ACCESS_GROUP : NULL)) : NULL;
 
-#ifdef HAVE_CREDS
-    pa_xfree(p->auth_group);
+#ifndef HAVE_CREDS
+    if (o->auth_group)
+        pa_log_warn("Authentication group configured, but not available on local system. Ignoring.");
 #endif
-    pa_xfree(p);
-}
 
-pa_protocol_native* pa_protocol_native_new_iochannel(
-        pa_core*core,
-        pa_iochannel *io,
-        pa_module *m,
-        pa_modargs *ma) {
+    if ((acl = pa_modargs_get_value(ma, "auth-ip-acl", NULL))) {
+        pa_ip_acl *ipa;
 
-    pa_protocol_native *p;
+        if (!(o->auth_ip_acl = pa_ip_acl_new(acl))) {
+            pa_log("Failed to parse IP ACL '%s'", acl);
+            return -1;
+        }
 
-    if (!(p = protocol_new_internal(core, m, ma)))
-        return NULL;
+        if (o->auth_ip_acl)
+            pa_ip_acl_free(o->auth_ip_acl);
 
-    on_connection(NULL, io, p);
+        o->auth_ip_acl = ipa;
+    }
 
-    return p;
+    enabled = TRUE;
+    if (pa_modargs_get_value_boolean(ma, "auth-cookie-enabled", &enabled) < 0) {
+        pa_log("auth-cookie-enabled= expects a boolean argument.");
+        return -1;
+    }
+
+    if (o->auth_cookie)
+        pa_auth_cookie_unref(o->auth_cookie);
+
+    if (enabled) {
+        const char *cn;
+
+        /* The new name for this is 'auth-cookie', for compat reasons
+         * we check the old name too */
+        if (!(cn = pa_modargs_get_value(ma, "auth-cookie", NULL)))
+            if (!(cn = pa_modargs_get_value(ma, "cookie", NULL)))
+                cn = PA_NATIVE_COOKIE_FILE;
+
+        if (!(o->auth_cookie = pa_auth_cookie_get(c, cn, PA_NATIVE_COOKIE_LENGTH)))
+            return -1;
+
+    } else
+          o->auth_cookie = NULL;
+
+    return 0;
 }
diff --git a/src/pulsecore/protocol-native.h b/src/pulsecore/protocol-native.h
index a52fa8c..7f0ef25 100644
--- a/src/pulsecore/protocol-native.h
+++ b/src/pulsecore/protocol-native.h
@@ -24,15 +24,47 @@
 ***/
 
 #include <pulsecore/core.h>
-#include <pulsecore/socket-server.h>
+#include <pulsecore/ipacl.h>
+#include <pulsecore/auth-cookie.h>
+#include <pulsecore/iochannel.h>
 #include <pulsecore/module.h>
 #include <pulsecore/modargs.h>
+#include <pulsecore/strlist.h>
+#include <pulsecore/hook-list.h>
 
-typedef struct pa_protocol_native pa_protocol_native;
+typedef struct pa_native_protocol pa_native_protocol;
 
-pa_protocol_native* pa_protocol_native_new(pa_core*core, pa_socket_server *server, pa_module *m, pa_modargs *ma);
-void pa_protocol_native_free(pa_protocol_native *n);
+typedef struct pa_native_options {
+    PA_REFCNT_DECLARE;
 
-pa_protocol_native* pa_protocol_native_new_iochannel(pa_core*core, pa_iochannel *io, pa_module *m, pa_modargs *ma);
+    pa_module *module;
+
+    pa_bool_t auth_anonymous;
+    char *auth_group;
+    pa_ip_acl *auth_ip_acl;
+    pa_auth_cookie *auth_cookie;
+
+} pa_native_options;
+
+pa_native_protocol* pa_native_protocol_get(pa_core *core);
+pa_native_protocol* pa_native_protocol_ref(pa_native_protocol *p);
+void pa_native_protocol_unref(pa_native_protocol *p);
+void pa_native_protocol_connect(pa_native_protocol *p, pa_iochannel *io, pa_native_options *a);
+void pa_native_protocol_disconnect(pa_native_protocol *p, pa_module *m);
+
+void pa_native_protocol_add_server_string(pa_native_protocol *p, const char *name);
+void pa_native_protocol_remove_server_string(pa_native_protocol *p, const char *name);
+
+pa_hook *pa_native_protocol_servers_changed(pa_native_protocol *p);
+pa_strlist *pa_native_protocol_servers(pa_native_protocol *p);
+
+/* typedef void (*pa_native_protocol_extension_cb_t)(pa_native_protocol *p, pa_module *m, pa_pstream *p, uint32_t tag, pa_tagstruct *t); */
+/* int pa_native_protocol_install_extension(pa_native_protocol *p, pa_module *m, pa_native_protocol_extension_cb_t cb); */
+/* void pa_native_protocol_remove_extension(pa_native_protocol *p, pa_module *m); */
+
+pa_native_options* pa_native_options_new(void);
+pa_native_options* pa_native_options_ref(pa_native_options *o);
+void pa_native_options_unref(pa_native_options *o);
+int pa_native_options_parse(pa_native_options *o, pa_core *c, pa_modargs *ma);
 
 #endif
diff --git a/src/pulsecore/protocol-simple.c b/src/pulsecore/protocol-simple.c
index 020a281..78874bb 100644
--- a/src/pulsecore/protocol-simple.c
+++ b/src/pulsecore/protocol-simple.c
@@ -42,6 +42,7 @@
 #include <pulsecore/atomic.h>
 #include <pulsecore/thread-mq.h>
 #include <pulsecore/core-util.h>
+#include <pulsecore/shared.h>
 
 #include "protocol-simple.h"
 
@@ -50,7 +51,8 @@
 
 typedef struct connection {
     pa_msgobject parent;
-    pa_protocol_simple *protocol;
+    pa_simple_protocol *protocol;
+    pa_simple_options *options;
     pa_iochannel *io;
     pa_sink_input *sink_input;
     pa_source_output *source_output;
@@ -71,20 +73,11 @@ PA_DECLARE_CLASS(connection);
 #define CONNECTION(o) (connection_cast(o))
 static PA_DEFINE_CHECK_TYPE(connection, pa_msgobject);
 
-struct pa_protocol_simple {
-    pa_module *module;
+struct pa_simple_protocol {
+    PA_REFCNT_DECLARE;
+
     pa_core *core;
-    pa_socket_server*server;
     pa_idxset *connections;
-
-    enum {
-        RECORD = 1,
-        PLAYBACK = 2,
-        DUPLEX = 3
-    } mode;
-
-    pa_sample_spec sample_spec;
-    char *source_name, *sink_name;
 };
 
 enum {
@@ -98,7 +91,6 @@ enum {
     CONNECTION_MESSAGE_UNLINK_CONNECTION    /* Please drop a aconnection now */
 };
 
-
 #define PLAYBACK_BUFFER_SECONDS (.5)
 #define PLAYBACK_BUFFER_FRAGMENTS (10)
 #define RECORD_BUFFER_SECONDS (5)
@@ -111,6 +103,11 @@ static void connection_unlink(connection *c) {
     if (!c->protocol)
         return;
 
+    if (c->options) {
+        pa_simple_options_unref(c->options);
+        c->options = NULL;
+    }
+
     if (c->sink_input) {
         pa_sink_input_unlink(c->sink_input);
         pa_sink_input_unref(c->sink_input);
@@ -477,14 +474,13 @@ static void io_callback(pa_iochannel*io, void *userdata) {
 
 /*** socket_server callbacks ***/
 
-static void on_connection(pa_socket_server*s, pa_iochannel *io, void *userdata) {
-    pa_protocol_simple *p = userdata;
+void pa_simple_protocol_connect(pa_simple_protocol *p, pa_iochannel *io, pa_simple_options *o) {
     connection *c = NULL;
     char cname[256], pname[128];
 
-    pa_assert(s);
-    pa_assert(io);
     pa_assert(p);
+    pa_assert(io);
+    pa_assert(o);
 
     if (pa_idxset_size(p->connections)+1 > MAX_CONNECTIONS) {
         pa_log("Warning! Too many connections (%u), dropping incoming connection.", MAX_CONNECTIONS);
@@ -500,6 +496,7 @@ static void on_connection(pa_socket_server*s, pa_iochannel *io, void *userdata)
     c->source_output = NULL;
     c->input_memblockq = c->output_memblockq = NULL;
     c->protocol = p;
+    c->options = pa_simple_options_ref(o);
     c->playback.current_memblock = NULL;
     c->playback.memblock_index = 0;
     c->dead = FALSE;
@@ -510,27 +507,27 @@ static void on_connection(pa_socket_server*s, pa_iochannel *io, void *userdata)
     pa_snprintf(cname, sizeof(cname), "Simple client (%s)", pname);
     pa_assert_se(c->client = pa_client_new(p->core, __FILE__, cname));
     pa_proplist_sets(c->client->proplist, "simple-protocol.peer", pname);
-    c->client->module = p->module;
+    c->client->module = o->module;
     c->client->kill = client_kill_cb;
     c->client->userdata = c;
 
-    if (p->mode & PLAYBACK) {
+    if (o->playback) {
         pa_sink_input_new_data data;
         size_t l;
         pa_sink *sink;
 
-        if (!(sink = pa_namereg_get(c->protocol->core, c->protocol->sink_name, PA_NAMEREG_SINK, TRUE))) {
+        if (!(sink = pa_namereg_get(c->protocol->core, o->default_sink, PA_NAMEREG_SINK, TRUE))) {
             pa_log("Failed to get sink.");
             goto fail;
         }
 
         pa_sink_input_new_data_init(&data);
         data.driver = __FILE__;
-        data.module = p->module;
+        data.module = o->module;
         data.client = c->client;
         data.sink = sink;
         pa_proplist_update(data.proplist, PA_UPDATE_MERGE, c->client->proplist);
-        pa_sink_input_new_data_set_sample_spec(&data, &p->sample_spec);
+        pa_sink_input_new_data_set_sample_spec(&data, &o->sample_spec);
 
         c->sink_input = pa_sink_input_new(p->core, &data, 0);
         pa_sink_input_new_data_done(&data);
@@ -549,12 +546,12 @@ static void on_connection(pa_socket_server*s, pa_iochannel *io, void *userdata)
 
         pa_sink_input_set_requested_latency(c->sink_input, DEFAULT_SINK_LATENCY);
 
-        l = (size_t) (pa_bytes_per_second(&p->sample_spec)*PLAYBACK_BUFFER_SECONDS);
+        l = (size_t) (pa_bytes_per_second(&o->sample_spec)*PLAYBACK_BUFFER_SECONDS);
         c->input_memblockq = pa_memblockq_new(
                 0,
                 l,
                 l,
-                pa_frame_size(&p->sample_spec),
+                pa_frame_size(&o->sample_spec),
                 (size_t) -1,
                 l/PLAYBACK_BUFFER_FRAGMENTS,
                 0,
@@ -566,23 +563,23 @@ static void on_connection(pa_socket_server*s, pa_iochannel *io, void *userdata)
         pa_sink_input_put(c->sink_input);
     }
 
-    if (p->mode & RECORD) {
+    if (o->record) {
         pa_source_output_new_data data;
         size_t l;
         pa_source *source;
 
-        if (!(source = pa_namereg_get(c->protocol->core, c->protocol->source_name, PA_NAMEREG_SOURCE, TRUE))) {
+        if (!(source = pa_namereg_get(c->protocol->core, o->default_source, PA_NAMEREG_SOURCE, TRUE))) {
             pa_log("Failed to get source.");
             goto fail;
         }
 
         pa_source_output_new_data_init(&data);
         data.driver = __FILE__;
-        data.module = p->module;
+        data.module = o->module;
         data.client = c->client;
         data.source = source;
         pa_proplist_update(data.proplist, PA_UPDATE_MERGE, c->client->proplist);
-        pa_source_output_new_data_set_sample_spec(&data, &p->sample_spec);
+        pa_source_output_new_data_set_sample_spec(&data, &o->sample_spec);
 
         c->source_output = pa_source_output_new(p->core, &data, 0);
         pa_source_output_new_data_done(&data);
@@ -598,12 +595,12 @@ static void on_connection(pa_socket_server*s, pa_iochannel *io, void *userdata)
 
         pa_source_output_set_requested_latency(c->source_output, DEFAULT_SOURCE_LATENCY);
 
-        l = (size_t) (pa_bytes_per_second(&p->sample_spec)*RECORD_BUFFER_SECONDS);
+        l = (size_t) (pa_bytes_per_second(&o->sample_spec)*RECORD_BUFFER_SECONDS);
         c->output_memblockq = pa_memblockq_new(
                 0,
                 l,
                 0,
-                pa_frame_size(&p->sample_spec),
+                pa_frame_size(&o->sample_spec),
                 1,
                 0,
                 0,
@@ -623,74 +620,137 @@ fail:
         connection_unlink(c);
 }
 
-pa_protocol_simple* pa_protocol_simple_new(pa_core *core, pa_socket_server *server, pa_module *m, pa_modargs *ma) {
-    pa_protocol_simple* p = NULL;
-    pa_bool_t enable;
+void pa_simple_protocol_disconnect(pa_simple_protocol *p, pa_module *m) {
+    connection *c;
+    void *state = NULL;
 
-    pa_assert(core);
-    pa_assert(server);
+    pa_assert(p);
     pa_assert(m);
-    pa_assert(ma);
 
-    p = pa_xnew0(pa_protocol_simple, 1);
-    p->module = m;
-    p->core = core;
-    p->server = pa_socket_server_ref(server);
+    while ((c = pa_idxset_iterate(p->connections, &state, NULL)))
+        if (c->options->module == m)
+            connection_unlink(c);
+}
+
+static pa_simple_protocol* simple_protocol_new(pa_core *c) {
+    pa_simple_protocol *p;
+
+    pa_assert(c);
+
+    p = pa_xnew(pa_simple_protocol, 1);
+    PA_REFCNT_INIT(p);
+    p->core = c;
     p->connections = pa_idxset_new(NULL, NULL);
 
-    p->sample_spec = core->default_sample_spec;
-    if (pa_modargs_get_sample_spec(ma, &p->sample_spec) < 0) {
-        pa_log("Failed to parse sample type specification.");
-        goto fail;
-    }
+    pa_assert_se(pa_shared_set(c, "simple-protocol", p) >= 0);
 
-    p->source_name = pa_xstrdup(pa_modargs_get_value(ma, "source", NULL));
-    p->sink_name = pa_xstrdup(pa_modargs_get_value(ma, "sink", NULL));
+    return p;
+}
 
-    enable = FALSE;
-    if (pa_modargs_get_value_boolean(ma, "record", &enable) < 0) {
-        pa_log("record= expects a numeric argument.");
-        goto fail;
-    }
-    p->mode = enable ? RECORD : 0;
+pa_simple_protocol* pa_simple_protocol_get(pa_core *c) {
+    pa_simple_protocol *p;
 
-    enable = TRUE;
-    if (pa_modargs_get_value_boolean(ma, "playback", &enable) < 0) {
-        pa_log("playback= expects a numeric argument.");
-        goto fail;
-    }
-    p->mode |= enable ? PLAYBACK : 0;
+    if ((p = pa_shared_get(c, "simple-protocol")))
+        return pa_simple_protocol_ref(p);
 
-    if ((p->mode & (RECORD|PLAYBACK)) == 0) {
-        pa_log("neither playback nor recording enabled for protocol.");
-        goto fail;
-    }
+    return simple_protocol_new(c);
+}
+
+pa_simple_protocol* pa_simple_protocol_ref(pa_simple_protocol *p) {
+    pa_assert(p);
+    pa_assert(PA_REFCNT_VALUE(p) >= 1);
 
-    pa_socket_server_set_callback(p->server, on_connection, p);
+    PA_REFCNT_INC(p);
 
     return p;
+}
 
-fail:
-    if (p)
-        pa_protocol_simple_free(p);
+void pa_simple_protocol_unref(pa_simple_protocol *p) {
+    connection *c;
+    pa_assert(p);
+    pa_assert(PA_REFCNT_VALUE(p) >= 1);
+
+    if (PA_REFCNT_DEC(p) > 0)
+        return;
 
-    return NULL;
+    while ((c = pa_idxset_first(p->connections, NULL)))
+        connection_unlink(c);
+
+    pa_idxset_free(p->connections, NULL, NULL);
+
+    pa_assert_se(pa_shared_remove(p->core, "simple-protocol") >= 0);
+
+    pa_xfree(p);
 }
 
+pa_simple_options* pa_simple_options_new(void) {
+    pa_simple_options *o;
 
-void pa_protocol_simple_free(pa_protocol_simple *p) {
-    connection *c;
-    pa_assert(p);
+    o = pa_xnew0(pa_simple_options, 1);
+    PA_REFCNT_INIT(o);
 
-    if (p->connections) {
-        while((c = pa_idxset_first(p->connections, NULL)))
-            connection_unlink(c);
+    return o;
+}
+
+pa_simple_options* pa_simple_options_ref(pa_simple_options *o) {
+    pa_assert(o);
+    pa_assert(PA_REFCNT_VALUE(o) >= 1);
+
+    PA_REFCNT_INC(o);
+
+    return o;
+}
+
+void pa_simple_options_unref(pa_simple_options *o) {
+    pa_assert(o);
+    pa_assert(PA_REFCNT_VALUE(o) >= 1);
+
+    if (PA_REFCNT_DEC(o) > 0)
+        return;
+
+    pa_xfree(o->default_sink);
+    pa_xfree(o->default_source);
+
+    pa_xfree(o);
+}
 
-        pa_idxset_free(p->connections, NULL, NULL);
+int pa_simple_options_parse(pa_simple_options *o, pa_core *c, pa_modargs *ma) {
+    pa_bool_t enabled;
+
+    pa_assert(o);
+    pa_assert(PA_REFCNT_VALUE(o) >= 1);
+    pa_assert(ma);
+
+    o->sample_spec = c->default_sample_spec;
+    if (pa_modargs_get_sample_spec_and_channel_map(ma, &o->sample_spec, &o->channel_map, PA_CHANNEL_MAP_DEFAULT) < 0) {
+        pa_log("Failed to parse sample type specification.");
+        return -1;
     }
 
-    if (p->server)
-        pa_socket_server_unref(p->server);
+    pa_xfree(o->default_source);
+    o->default_source = pa_xstrdup(pa_modargs_get_value(ma, "source", NULL));
 
-    pa_xfree(p);
+    pa_xfree(o->default_sink);
+    o->default_sink = pa_xstrdup(pa_modargs_get_value(ma, "sink", NULL));
+
+    enabled = FALSE;
+    if (pa_modargs_get_value_boolean(ma, "record", &enabled) < 0) {
+        pa_log("record= expects a boolean argument.");
+        return -1;
+    }
+    o->record = enabled;
+
+    enabled = TRUE;
+    if (pa_modargs_get_value_boolean(ma, "playback", &enabled) < 0) {
+        pa_log("playback= expects a boolean argument.");
+        return -1;
+    }
+    o->playback = enabled;
+
+    if (!o->playback && !o->record) {
+        pa_log("neither playback nor recording enabled for protocol.");
+        return -1;
+    }
+
+    return 0;
 }
diff --git a/src/pulsecore/protocol-simple.h b/src/pulsecore/protocol-simple.h
index e1b3143..c10eabe 100644
--- a/src/pulsecore/protocol-simple.h
+++ b/src/pulsecore/protocol-simple.h
@@ -27,9 +27,31 @@
 #include <pulsecore/core.h>
 #include <pulsecore/modargs.h>
 
-typedef struct pa_protocol_simple pa_protocol_simple;
+typedef struct pa_simple_protocol pa_simple_protocol;
 
-pa_protocol_simple* pa_protocol_simple_new(pa_core *core, pa_socket_server *server, pa_module *m, pa_modargs *ma);
-void pa_protocol_simple_free(pa_protocol_simple *n);
+typedef struct pa_simple_options {
+    PA_REFCNT_DECLARE;
+
+    pa_module *module;
+
+    char *default_sink, *default_source;
+
+    pa_sample_spec sample_spec;
+    pa_channel_map channel_map;
+
+    pa_bool_t record:1;
+    pa_bool_t playback:1;
+} pa_simple_options;
+
+pa_simple_protocol* pa_simple_protocol_get(pa_core*core);
+pa_simple_protocol* pa_simple_protocol_ref(pa_simple_protocol *p);
+void pa_simple_protocol_unref(pa_simple_protocol *p);
+void pa_simple_protocol_connect(pa_simple_protocol *p, pa_iochannel *io, pa_simple_options *o);
+void pa_simple_protocol_disconnect(pa_simple_protocol *p, pa_module *m);
+
+pa_simple_options* pa_simple_options_new(void);
+pa_simple_options* pa_simple_options_ref(pa_simple_options *o);
+void pa_simple_options_unref(pa_simple_options *o);
+int pa_simple_options_parse(pa_simple_options *o, pa_core *c, pa_modargs *ma);
 
 #endif

commit 98fbd24d62bfe1fbbf8aaf7adb367e44da66fcd8
Author: Sjoerd Simons <sjoerd at luon.net>
Date:   Sun Aug 3 12:45:35 2008 +0100

    fix iteration over random devices
    
    Actually iterate over the various random devices. Fixes a infinite loop on
    startup when /dev/urandom isn't readable. Patch by Matt Kraai on Debian bug
    491270, closes #333
    
    Signed-off-by: Lennart Poettering <lennart at poettering.net>

diff --git a/src/pulsecore/random.c b/src/pulsecore/random.c
index 5deac37..da38106 100644
--- a/src/pulsecore/random.c
+++ b/src/pulsecore/random.c
@@ -77,6 +77,8 @@ static int random_proper(void *ret_data, size_t length) {
 
         if (ret == 0)
             break;
+
+        device++;
     }
 
     return ret;

-- 
hooks/post-receive
PulseAudio Sound Server



More information about the pulseaudio-commits mailing list