]> code.delx.au - pulseaudio/blobdiff - src/pulsecore/protocol-simple.c
sample-cache: use the sample name as unmodified fallback in the properties when playi...
[pulseaudio] / src / pulsecore / protocol-simple.c
index 020a281d16805d7c039b0a2b3c6e6f94fc9b6899..fb2e5648c48db71e3589c7f6e0d713c9a4235825 100644 (file)
@@ -5,7 +5,7 @@
 
   PulseAudio is free software; you can redistribute it and/or modify
   it under the terms of the GNU Lesser General Public License as published
 
   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,
+  by the Free Software Foundation; either version 2.1 of the License,
   or (at your option) any later version.
 
   PulseAudio is distributed in the hope that it will be useful, but
   or (at your option) any later version.
 
   PulseAudio is distributed in the hope that it will be useful, but
@@ -42,6 +42,7 @@
 #include <pulsecore/atomic.h>
 #include <pulsecore/thread-mq.h>
 #include <pulsecore/core-util.h>
 #include <pulsecore/atomic.h>
 #include <pulsecore/thread-mq.h>
 #include <pulsecore/core-util.h>
+#include <pulsecore/shared.h>
 
 #include "protocol-simple.h"
 
 
 #include "protocol-simple.h"
 
@@ -50,7 +51,8 @@
 
 typedef struct connection {
     pa_msgobject parent;
 
 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;
     pa_iochannel *io;
     pa_sink_input *sink_input;
     pa_source_output *source_output;
@@ -67,24 +69,14 @@ typedef struct connection {
     } playback;
 } connection;
 
     } playback;
 } connection;
 
-PA_DECLARE_CLASS(connection);
+PA_DEFINE_PRIVATE_CLASS(connection, pa_msgobject);
 #define CONNECTION(o) (connection_cast(o))
 #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_core *core;
-    pa_socket_server*server;
     pa_idxset *connections;
     pa_idxset *connections;
-
-    enum {
-        RECORD = 1,
-        PLAYBACK = 2,
-        DUPLEX = 3
-    } mode;
-
-    pa_sample_spec sample_spec;
-    char *source_name, *sink_name;
 };
 
 enum {
 };
 
 enum {
@@ -98,7 +90,6 @@ enum {
     CONNECTION_MESSAGE_UNLINK_CONNECTION    /* Please drop a aconnection now */
 };
 
     CONNECTION_MESSAGE_UNLINK_CONNECTION    /* Please drop a aconnection now */
 };
 
-
 #define PLAYBACK_BUFFER_SECONDS (.5)
 #define PLAYBACK_BUFFER_FRAGMENTS (10)
 #define RECORD_BUFFER_SECONDS (5)
 #define PLAYBACK_BUFFER_SECONDS (.5)
 #define PLAYBACK_BUFFER_FRAGMENTS (10)
 #define RECORD_BUFFER_SECONDS (5)
@@ -111,6 +102,11 @@ static void connection_unlink(connection *c) {
     if (!c->protocol)
         return;
 
     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);
     if (c->sink_input) {
         pa_sink_input_unlink(c->sink_input);
         pa_sink_input_unref(c->sink_input);
@@ -133,7 +129,7 @@ static void connection_unlink(connection *c) {
         c->io = NULL;
     }
 
         c->io = NULL;
     }
 
-    pa_assert_se(pa_idxset_remove_by_data(c->protocol->connections, c, NULL) == c);
+    pa_idxset_remove_by_data(c->protocol->connections, c, NULL);
     c->protocol = NULL;
     connection_unref(c);
 }
     c->protocol = NULL;
     connection_unref(c);
 }
@@ -158,11 +154,11 @@ static int do_read(connection *c) {
     ssize_t r;
     size_t l;
     void *p;
     ssize_t r;
     size_t l;
     void *p;
-    size_t space;
+    size_t space = 0;
 
     connection_assert_ref(c);
 
 
     connection_assert_ref(c);
 
-    if (!c->sink_input || (l = pa_atomic_load(&c->playback.missing)) <= 0)
+    if (!c->sink_input || (l = (size_t) pa_atomic_load(&c->playback.missing)) <= 0)
         return 0;
 
     if (c->playback.current_memblock) {
         return 0;
 
     if (c->playback.current_memblock) {
@@ -176,7 +172,7 @@ static int do_read(connection *c) {
     }
 
     if (!c->playback.current_memblock) {
     }
 
     if (!c->playback.current_memblock) {
-        pa_assert_se(c->playback.current_memblock = pa_memblock_new(c->protocol->core->mempool, 0));
+        pa_assert_se(c->playback.current_memblock = pa_memblock_new(c->protocol->core->mempool, (size_t) -1));
         c->playback.memblock_index = 0;
 
         space = pa_memblock_get_length(c->playback.current_memblock);
         c->playback.memblock_index = 0;
 
         space = pa_memblock_get_length(c->playback.current_memblock);
@@ -200,12 +196,12 @@ static int do_read(connection *c) {
 
     chunk.memblock = c->playback.current_memblock;
     chunk.index = c->playback.memblock_index;
 
     chunk.memblock = c->playback.current_memblock;
     chunk.index = c->playback.memblock_index;
-    chunk.length = r;
+    chunk.length = (size_t) r;
 
 
-    c->playback.memblock_index += r;
+    c->playback.memblock_index += (size_t) r;
 
     pa_asyncmsgq_post(c->sink_input->sink->asyncmsgq, PA_MSGOBJECT(c->sink_input), SINK_INPUT_MESSAGE_POST_DATA, NULL, 0, &chunk, NULL);
 
     pa_asyncmsgq_post(c->sink_input->sink->asyncmsgq, PA_MSGOBJECT(c->sink_input), SINK_INPUT_MESSAGE_POST_DATA, NULL, 0, &chunk, NULL);
-    pa_atomic_sub(&c->playback.missing, r);
+    pa_atomic_sub(&c->playback.missing, (int) r);
 
     return 0;
 }
 
     return 0;
 }
@@ -243,7 +239,7 @@ static int do_write(connection *c) {
         return -1;
     }
 
         return -1;
     }
 
-    pa_memblockq_drop(c->output_memblockq, r);
+    pa_memblockq_drop(c->output_memblockq, (size_t) r);
 
     return 0;
 }
 
     return 0;
 }
@@ -286,6 +282,9 @@ static int connection_process_msg(pa_msgobject *o, int code, void*userdata, int6
     connection *c = CONNECTION(o);
     connection_assert_ref(c);
 
     connection *c = CONNECTION(o);
     connection_assert_ref(c);
 
+    if (!c->protocol)
+        return -1;
+
     switch (code) {
         case CONNECTION_MESSAGE_REQUEST_DATA:
             do_work(c);
     switch (code) {
         case CONNECTION_MESSAGE_REQUEST_DATA:
             do_work(c);
@@ -326,7 +325,7 @@ static int sink_input_process_msg(pa_msgobject *o, int code, void *userdata, int
 
             if (pa_memblockq_is_readable(c->input_memblockq) && c->playback.underrun) {
                 pa_log_debug("Requesting rewind due to end of underrun.");
 
             if (pa_memblockq_is_readable(c->input_memblockq) && c->playback.underrun) {
                 pa_log_debug("Requesting rewind due to end of underrun.");
-                pa_sink_input_request_rewind(c->sink_input, 0, FALSE, TRUE);
+                pa_sink_input_request_rewind(c->sink_input, 0, FALSE, TRUE, FALSE);
             }
 
 /*             pa_log("got data, %u", pa_memblockq_get_length(c->input_memblockq)); */
             }
 
 /*             pa_log("got data, %u", pa_memblockq_get_length(c->input_memblockq)); */
@@ -380,7 +379,7 @@ static int sink_input_pop_cb(pa_sink_input *i, size_t length, pa_memchunk *chunk
         m = pa_memblockq_pop_missing(c->input_memblockq);
 
         if (m > 0)
         m = pa_memblockq_pop_missing(c->input_memblockq);
 
         if (m > 0)
-            if (pa_atomic_add(&c->playback.missing, m) <= 0)
+            if (pa_atomic_add(&c->playback.missing, (int) m) <= 0)
                 pa_asyncmsgq_post(pa_thread_mq_get()->outq, PA_MSGOBJECT(c), CONNECTION_MESSAGE_REQUEST_DATA, NULL, 0, NULL, NULL);
 
         return 0;
                 pa_asyncmsgq_post(pa_thread_mq_get()->outq, PA_MSGOBJECT(c), CONNECTION_MESSAGE_REQUEST_DATA, NULL, 0, NULL, NULL);
 
         return 0;
@@ -477,14 +476,14 @@ static void io_callback(pa_iochannel*io, void *userdata) {
 
 /*** socket_server callbacks ***/
 
 
 /*** 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;
     connection *c = NULL;
-    char cname[256], pname[128];
+    char pname[128];
+    pa_client_new_data client_data;
 
 
-    pa_assert(s);
-    pa_assert(io);
     pa_assert(p);
     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);
 
     if (pa_idxset_size(p->connections)+1 > MAX_CONNECTIONS) {
         pa_log("Warning! Too many connections (%u), dropping incoming connection.", MAX_CONNECTIONS);
@@ -496,43 +495,54 @@ static void on_connection(pa_socket_server*s, pa_iochannel *io, void *userdata)
     c->parent.parent.free = connection_free;
     c->parent.process_msg = connection_process_msg;
     c->io = io;
     c->parent.parent.free = connection_free;
     c->parent.process_msg = connection_process_msg;
     c->io = io;
+    pa_iochannel_set_callback(c->io, io_callback, c);
+
     c->sink_input = NULL;
     c->source_output = NULL;
     c->input_memblockq = c->output_memblockq = NULL;
     c->protocol = p;
     c->sink_input = NULL;
     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;
     c->playback.underrun = TRUE;
     pa_atomic_store(&c->playback.missing, 0);
 
     c->playback.current_memblock = NULL;
     c->playback.memblock_index = 0;
     c->dead = FALSE;
     c->playback.underrun = TRUE;
     pa_atomic_store(&c->playback.missing, 0);
 
+    pa_client_new_data_init(&client_data);
+    client_data.module = o->module;
+    client_data.driver = __FILE__;
     pa_iochannel_socket_peer_to_string(io, pname, sizeof(pname));
     pa_iochannel_socket_peer_to_string(io, pname, sizeof(pname));
-    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;
+    pa_proplist_setf(client_data.proplist, PA_PROP_APPLICATION_NAME, "Simple client (%s)", pname);
+    pa_proplist_sets(client_data.proplist, "simple-protocol.peer", pname);
+    c->client = pa_client_new(p->core, &client_data);
+    pa_client_new_data_done(&client_data);
+
+    if (!c->client)
+        goto fail;
+
     c->client->kill = client_kill_cb;
     c->client->userdata = c;
 
     c->client->kill = client_kill_cb;
     c->client->userdata = c;
 
-    if (p->mode & PLAYBACK) {
+    if (o->playback) {
         pa_sink_input_new_data data;
         pa_sink_input_new_data data;
+        pa_memchunk silence;
         size_t l;
         pa_sink *sink;
 
         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))) {
             pa_log("Failed to get sink.");
             goto fail;
         }
 
         pa_sink_input_new_data_init(&data);
         data.driver = __FILE__;
             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);
         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(&c->sink_input, p->core, &data);
         pa_sink_input_new_data_done(&data);
 
         if (!c->sink_input) {
         pa_sink_input_new_data_done(&data);
 
         if (!c->sink_input) {
@@ -549,42 +559,45 @@ 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);
 
 
         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) ((double) pa_bytes_per_second(&o->sample_spec)*PLAYBACK_BUFFER_SECONDS);
+        pa_sink_input_get_silence(c->sink_input, &silence);
         c->input_memblockq = pa_memblockq_new(
                 0,
                 l,
                 l,
         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,
                 (size_t) -1,
                 l/PLAYBACK_BUFFER_FRAGMENTS,
                 0,
-                NULL);
+                &silence);
+        pa_memblock_unref(silence.memblock);
+
         pa_iochannel_socket_set_rcvbuf(io, l);
 
         pa_iochannel_socket_set_rcvbuf(io, l);
 
-        pa_atomic_store(&c->playback.missing, pa_memblockq_missing(c->input_memblockq));
+        pa_atomic_store(&c->playback.missing, (int) pa_memblockq_missing(c->input_memblockq));
 
         pa_sink_input_put(c->sink_input);
     }
 
 
         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;
 
         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))) {
             pa_log("Failed to get source.");
             goto fail;
         }
 
         pa_source_output_new_data_init(&data);
         data.driver = __FILE__;
             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);
         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(&c->source_output, p->core, &data);
         pa_source_output_new_data_done(&data);
 
         if (!c->source_output) {
         pa_source_output_new_data_done(&data);
 
         if (!c->source_output) {
@@ -598,12 +611,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);
 
 
         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,
         c->output_memblockq = pa_memblockq_new(
                 0,
                 l,
                 0,
-                pa_frame_size(&p->sample_spec),
+                pa_frame_size(&o->sample_spec),
                 1,
                 0,
                 0,
                 1,
                 0,
                 0,
@@ -613,84 +626,148 @@ static void on_connection(pa_socket_server*s, pa_iochannel *io, void *userdata)
         pa_source_output_put(c->source_output);
     }
 
         pa_source_output_put(c->source_output);
     }
 
-    pa_iochannel_set_callback(c->io, io_callback, c);
     pa_idxset_put(p->connections, c, NULL);
 
     return;
 
 fail:
     pa_idxset_put(p->connections, c, NULL);
 
     return;
 
 fail:
-    if (c)
-        connection_unlink(c);
+    connection_unlink(c);
 }
 
 }
 
-pa_protocol_simple* pa_protocol_simple_new(pa_core *core, pa_socket_server *server, pa_module *m, pa_modargs *ma) {
-    pa_protocol_simple* p = NULL;
-    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(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->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);
+
+    return p;
+}
 
 
-    p->source_name = pa_xstrdup(pa_modargs_get_value(ma, "source", NULL));
-    p->sink_name = pa_xstrdup(pa_modargs_get_value(ma, "sink", NULL));
+pa_simple_protocol* pa_simple_protocol_get(pa_core *c) {
+    pa_simple_protocol *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;
+    if ((p = pa_shared_get(c, "simple-protocol")))
+        return pa_simple_protocol_ref(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;
+    return simple_protocol_new(c);
+}
 
 
-    if ((p->mode & (RECORD|PLAYBACK)) == 0) {
-        pa_log("neither playback nor recording enabled for protocol.");
-        goto fail;
-    }
+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;
 
     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;
+
+    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;
 
 
-    return NULL;
+    o = pa_xnew0(pa_simple_options, 1);
+    PA_REFCNT_INIT(o);
+
+    o->record = FALSE;
+    o->playback = TRUE;
+
+    return o;
 }
 
 }
 
+pa_simple_options* pa_simple_options_ref(pa_simple_options *o) {
+    pa_assert(o);
+    pa_assert(PA_REFCNT_VALUE(o) >= 1);
 
 
-void pa_protocol_simple_free(pa_protocol_simple *p) {
-    connection *c;
-    pa_assert(p);
+    PA_REFCNT_INC(o);
 
 
-    if (p->connections) {
-        while((c = pa_idxset_first(p->connections, NULL)))
-            connection_unlink(c);
+    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);
+}
+
+int pa_simple_options_parse(pa_simple_options *o, pa_core *c, pa_modargs *ma) {
+    pa_bool_t enabled;
 
 
-        pa_idxset_free(p->connections, NULL, NULL);
+    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 = o->record;
+    if (pa_modargs_get_value_boolean(ma, "record", &enabled) < 0) {
+        pa_log("record= expects a boolean argument.");
+        return -1;
+    }
+    o->record = enabled;
+
+    enabled = o->playback;
+    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;
 }
 }