[pulseaudio-discuss] [PATCH 10/12] Protocol, client: Add commands to enable srbchannel

David Henningsson david.henningsson at canonical.com
Fri May 30 04:59:29 PDT 2014


This increments protocol version to v30 and adds two new commands
to enable and disable an shm ringbuffer, as well as client side
implementation.

Signed-off-by: David Henningsson <david.henningsson at canonical.com>
---
 PROTOCOL                      |  20 ++++++++
 configure.ac                  |   2 +-
 src/pulse/context.c           | 108 +++++++++++++++++++++++++++++++++++++++++-
 src/pulse/internal.h          |   3 ++
 src/pulsecore/native-common.h |   5 ++
 5 files changed, 136 insertions(+), 2 deletions(-)

diff --git a/PROTOCOL b/PROTOCOL
index 850b953..3c08fea 100644
--- a/PROTOCOL
+++ b/PROTOCOL
@@ -351,6 +351,26 @@ New field in all commands that send/receive profile introspection data
 
 The field is added once for every profile.
 
+## v30, implemented by >= 6.0
+#
+A new protocol mechanism supported: Two ringbuffers in shared memory.
+Pulseaudio fdsem (wrappers around event file descriptors) are used for
+signalling new data.
+The protocol has a new SHM flag telling whether a SHM memblock is writable
+by both sides.
+
+PA_COMMAND_ENABLE_SRBCHANNEL
+First sent from server to client, tells the client to start listening on
+the additional SHM ringbuffer channel.
+This command also has ancillary data (two eventfds attached to it).
+Must be directly followed by a memblock which is the ringbuffer memory.
+When memblock is received by the client, it acks by sending
+PA_COMMAND_ENABLE_SRBCHANNEL back (without ancillary or memblock data).
+
+PA_COMMAND_DISABLE_SRBCHANNEL
+Tells the client to stop listening on the additional SHM ringbuffer channel.
+Acked by client by sending PA_COMMAND_DISABLE_SRBCHANNEL back.
+
 #### If you just changed the protocol, read this
 ## module-tunnel depends on the sink/source/sink-input/source-input protocol
 ## internals, so if you changed these, you might have broken module-tunnel.
diff --git a/configure.ac b/configure.ac
index 76490f4..b87dbdd 100644
--- a/configure.ac
+++ b/configure.ac
@@ -41,7 +41,7 @@ AC_SUBST(PA_MINOR, pa_minor)
 AC_SUBST(PA_MAJORMINOR, pa_major.pa_minor)
 
 AC_SUBST(PA_API_VERSION, 12)
-AC_SUBST(PA_PROTOCOL_VERSION, 29)
+AC_SUBST(PA_PROTOCOL_VERSION, 30)
 
 # The stable ABI for client applications, for the version info x:y:z
 # always will hold y=z
diff --git a/src/pulse/context.c b/src/pulse/context.c
index f3adf4c..047aa1a 100644
--- a/src/pulse/context.c
+++ b/src/pulse/context.c
@@ -72,6 +72,8 @@
 #include "context.h"
 
 void pa_command_extension(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata);
+static void pa_command_enable_srbchannel(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata);
+static void pa_command_disable_srbchannel(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata);
 
 static const pa_pdispatch_cb_t command_table[PA_COMMAND_MAX] = {
     [PA_COMMAND_REQUEST] = pa_command_request,
@@ -90,7 +92,9 @@ static const pa_pdispatch_cb_t command_table[PA_COMMAND_MAX] = {
     [PA_COMMAND_RECORD_STREAM_EVENT] = pa_command_stream_event,
     [PA_COMMAND_CLIENT_EVENT] = pa_command_client_event,
     [PA_COMMAND_PLAYBACK_BUFFER_ATTR_CHANGED] = pa_command_stream_buffer_attr,
-    [PA_COMMAND_RECORD_BUFFER_ATTR_CHANGED] = pa_command_stream_buffer_attr
+    [PA_COMMAND_RECORD_BUFFER_ATTR_CHANGED] = pa_command_stream_buffer_attr,
+    [PA_COMMAND_ENABLE_SRBCHANNEL] = pa_command_enable_srbchannel,
+    [PA_COMMAND_DISABLE_SRBCHANNEL] = pa_command_disable_srbchannel,
 };
 static void context_free(pa_context *c);
 
@@ -172,6 +176,9 @@ pa_context *pa_context_new_with_proplist(pa_mainloop_api *mainloop, const char *
 #endif
     pa_client_conf_env(c->conf);
 
+    c->srb_template.readfd = -1;
+    c->srb_template.writefd = -1;
+
     if (!(c->mempool = pa_mempool_new(!c->conf->disable_shm, c->conf->shm_size))) {
 
         if (!c->conf->disable_shm)
@@ -213,6 +220,11 @@ static void context_unlink(pa_context *c) {
         c->pstream = NULL;
     }
 
+    if (c->srb_template.memblock) {
+        pa_memblock_unref(c->srb_template.memblock);
+        c->srb_template.memblock = NULL;
+    }
+
     if (c->client) {
         pa_socket_client_unref(c->client);
         c->client = NULL;
@@ -338,6 +350,35 @@ static void pstream_packet_callback(pa_pstream *p, pa_packet *packet, const pa_a
     pa_context_unref(c);
 }
 
+static void handle_srbchannel_memblock(pa_context *c, pa_memblock *memblock) {
+    pa_srbchannel *sr;
+    pa_tagstruct *t;
+
+    pa_assert(c);
+
+    /* Memblock sanity check */
+    if (!memblock)
+        pa_context_fail(c, PA_ERR_PROTOCOL);
+    else if (pa_memblock_is_read_only(memblock))
+        pa_context_fail(c, PA_ERR_PROTOCOL);
+    else if (pa_memblock_is_ours(memblock))
+        pa_context_fail(c, PA_ERR_PROTOCOL);
+
+    /* Create the srbchannel */
+    c->srb_template.memblock = memblock;
+    pa_memblock_ref(memblock);
+    sr = pa_srbchannel_new_from_template(c->mainloop, &c->srb_template);
+
+    /* Ack the enable command */
+    t = pa_tagstruct_new(NULL, 0);
+    pa_tagstruct_putu32(t, PA_COMMAND_ENABLE_SRBCHANNEL);
+    pa_tagstruct_putu32(t, c->srb_setup_tag);
+    pa_pstream_send_tagstruct(c->pstream, t);
+
+    /* ...and switch over */
+    pa_pstream_set_srbchannel(c->pstream, sr);
+}
+
 static void pstream_memblock_callback(pa_pstream *p, uint32_t channel, int64_t offset, pa_seek_mode_t seek, const pa_memchunk *chunk, void *userdata) {
     pa_context *c = userdata;
     pa_stream *s;
@@ -350,6 +391,12 @@ static void pstream_memblock_callback(pa_pstream *p, uint32_t channel, int64_t o
 
     pa_context_ref(c);
 
+    if (c->srb_template.readfd != -1 && c->srb_template.memblock == NULL) {
+        handle_srbchannel_memblock(c, chunk->memblock);
+        pa_context_unref(c);
+        return;
+    }
+
     if ((s = pa_hashmap_get(c->record_streams, PA_UINT32_TO_PTR(channel)))) {
 
         if (chunk->memblock) {
@@ -1369,6 +1416,65 @@ finish:
     pa_context_unref(c);
 }
 
+static void pa_command_enable_srbchannel(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
+    pa_context *c = userdata;
+    const int *fds;
+    int nfd;
+
+    pa_assert(pd);
+    pa_assert(command == PA_COMMAND_ENABLE_SRBCHANNEL);
+    pa_assert(t);
+    pa_assert(c);
+    pa_assert(PA_REFCNT_VALUE(c) >= 1);
+
+    /* Currently only one srb channel is supported, might change in future versions */
+    if (c->srb_template.readfd != -1) {
+        pa_context_fail(c, PA_ERR_PROTOCOL);
+        return;
+    }
+
+    fds = pa_pdispatch_fds(pd, &nfd);
+    if (nfd != 2 || !fds || fds[0] == -1 || fds[1] == -1) {
+        pa_context_fail(c, PA_ERR_PROTOCOL);
+        return;
+    }
+
+    pa_context_ref(c);
+
+    c->srb_template.readfd = fds[0];
+    c->srb_template.writefd = fds[1];
+    c->srb_setup_tag = tag;
+
+    pa_context_unref(c);
+}
+
+static void pa_command_disable_srbchannel(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
+    pa_context *c = userdata;
+    pa_tagstruct *t2;
+
+    pa_assert(pd);
+    pa_assert(command == PA_COMMAND_DISABLE_SRBCHANNEL);
+    pa_assert(t);
+    pa_assert(c);
+    pa_assert(PA_REFCNT_VALUE(c) >= 1);
+
+    pa_pstream_set_srbchannel(c->pstream, NULL);
+
+    c->srb_template.readfd = -1;
+    c->srb_template.writefd = -1;
+    if (c->srb_template.memblock) {
+        pa_memblock_unref(c->srb_template.memblock);
+        c->srb_template.memblock = NULL;
+    }
+
+    /* Send disable command back again */
+    t2 = pa_tagstruct_new(NULL, 0);
+    pa_tagstruct_putu32(t2, PA_COMMAND_DISABLE_SRBCHANNEL);
+    pa_tagstruct_putu32(t2, tag);
+    pa_pstream_send_tagstruct(c->pstream, t2);
+}
+
+
 void pa_command_client_event(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
     pa_context *c = userdata;
     pa_proplist *pl = NULL;
diff --git a/src/pulse/internal.h b/src/pulse/internal.h
index c5084d5..fc2b702 100644
--- a/src/pulse/internal.h
+++ b/src/pulse/internal.h
@@ -66,6 +66,9 @@ struct pa_context {
     pa_pstream *pstream;
     pa_pdispatch *pdispatch;
 
+    pa_srbchannel_template srb_template;
+    uint32_t srb_setup_tag;
+
     pa_hashmap *record_streams, *playback_streams;
     PA_LLIST_HEAD(pa_stream, streams);
     PA_LLIST_HEAD(pa_operation, operations);
diff --git a/src/pulsecore/native-common.h b/src/pulsecore/native-common.h
index dad82e0..ee4fd50 100644
--- a/src/pulsecore/native-common.h
+++ b/src/pulsecore/native-common.h
@@ -176,6 +176,11 @@ enum {
     /* Supported since protocol v27 (3.0) */
     PA_COMMAND_SET_PORT_LATENCY_OFFSET,
 
+    /* Supported since protocol v30 (6.0) */
+    /* BOTH DIRECTIONS */
+    PA_COMMAND_ENABLE_SRBCHANNEL,
+    PA_COMMAND_DISABLE_SRBCHANNEL,
+
     PA_COMMAND_MAX
 };
 
-- 
1.9.1



More information about the pulseaudio-discuss mailing list