Protocol, client: Add commands to enable srbchannel

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@canonical.com>
This commit is contained in:
David Henningsson 2014-04-25 17:23:21 +02:00
parent 4931637f82
commit 1827991548
5 changed files with 136 additions and 2 deletions

View file

@ -351,6 +351,26 @@ New field in all commands that send/receive profile introspection data
The field is added once for every profile. 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 #### If you just changed the protocol, read this
## module-tunnel depends on the sink/source/sink-input/source-input protocol ## module-tunnel depends on the sink/source/sink-input/source-input protocol
## internals, so if you changed these, you might have broken module-tunnel. ## internals, so if you changed these, you might have broken module-tunnel.

View file

@ -41,7 +41,7 @@ AC_SUBST(PA_MINOR, pa_minor)
AC_SUBST(PA_MAJORMINOR, pa_major.pa_minor) AC_SUBST(PA_MAJORMINOR, pa_major.pa_minor)
AC_SUBST(PA_API_VERSION, 12) 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 # The stable ABI for client applications, for the version info x:y:z
# always will hold y=z # always will hold y=z

View file

@ -69,6 +69,8 @@
#include "context.h" #include "context.h"
void pa_command_extension(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata); 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] = { static const pa_pdispatch_cb_t command_table[PA_COMMAND_MAX] = {
[PA_COMMAND_REQUEST] = pa_command_request, [PA_COMMAND_REQUEST] = pa_command_request,
@ -87,7 +89,9 @@ static const pa_pdispatch_cb_t command_table[PA_COMMAND_MAX] = {
[PA_COMMAND_RECORD_STREAM_EVENT] = pa_command_stream_event, [PA_COMMAND_RECORD_STREAM_EVENT] = pa_command_stream_event,
[PA_COMMAND_CLIENT_EVENT] = pa_command_client_event, [PA_COMMAND_CLIENT_EVENT] = pa_command_client_event,
[PA_COMMAND_PLAYBACK_BUFFER_ATTR_CHANGED] = pa_command_stream_buffer_attr, [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); static void context_free(pa_context *c);
@ -165,6 +169,9 @@ pa_context *pa_context_new_with_proplist(pa_mainloop_api *mainloop, const char *
c->conf = pa_client_conf_new(); c->conf = pa_client_conf_new();
pa_client_conf_load(c->conf, true, true); pa_client_conf_load(c->conf, true, true);
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->mempool = pa_mempool_new(!c->conf->disable_shm, c->conf->shm_size))) {
if (!c->conf->disable_shm) if (!c->conf->disable_shm)
@ -206,6 +213,11 @@ static void context_unlink(pa_context *c) {
c->pstream = NULL; c->pstream = NULL;
} }
if (c->srb_template.memblock) {
pa_memblock_unref(c->srb_template.memblock);
c->srb_template.memblock = NULL;
}
if (c->client) { if (c->client) {
pa_socket_client_unref(c->client); pa_socket_client_unref(c->client);
c->client = NULL; c->client = NULL;
@ -331,6 +343,35 @@ static void pstream_packet_callback(pa_pstream *p, pa_packet *packet, const pa_a
pa_context_unref(c); 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) { 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_context *c = userdata;
pa_stream *s; pa_stream *s;
@ -343,6 +384,12 @@ static void pstream_memblock_callback(pa_pstream *p, uint32_t channel, int64_t o
pa_context_ref(c); 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 ((s = pa_hashmap_get(c->record_streams, PA_UINT32_TO_PTR(channel)))) {
if (chunk->memblock) { if (chunk->memblock) {
@ -1362,6 +1409,65 @@ finish:
pa_context_unref(c); 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) { void pa_command_client_event(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
pa_context *c = userdata; pa_context *c = userdata;
pa_proplist *pl = NULL; pa_proplist *pl = NULL;

View file

@ -66,6 +66,9 @@ struct pa_context {
pa_pstream *pstream; pa_pstream *pstream;
pa_pdispatch *pdispatch; pa_pdispatch *pdispatch;
pa_srbchannel_template srb_template;
uint32_t srb_setup_tag;
pa_hashmap *record_streams, *playback_streams; pa_hashmap *record_streams, *playback_streams;
PA_LLIST_HEAD(pa_stream, streams); PA_LLIST_HEAD(pa_stream, streams);
PA_LLIST_HEAD(pa_operation, operations); PA_LLIST_HEAD(pa_operation, operations);

View file

@ -176,6 +176,11 @@ enum {
/* Supported since protocol v27 (3.0) */ /* Supported since protocol v27 (3.0) */
PA_COMMAND_SET_PORT_LATENCY_OFFSET, 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 PA_COMMAND_MAX
}; };