mirror of
https://gitlab.freedesktop.org/pulseaudio/pulseaudio.git
synced 2025-10-28 05:40:21 -04:00
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:
parent
4931637f82
commit
1827991548
5 changed files with 136 additions and 2 deletions
20
PROTOCOL
20
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.
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -69,6 +69,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,
|
||||
|
|
@ -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_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);
|
||||
|
||||
|
|
@ -165,6 +169,9 @@ pa_context *pa_context_new_with_proplist(pa_mainloop_api *mainloop, const char *
|
|||
c->conf = pa_client_conf_new();
|
||||
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->conf->disable_shm)
|
||||
|
|
@ -206,6 +213,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;
|
||||
|
|
@ -331,6 +343,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;
|
||||
|
|
@ -343,6 +384,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) {
|
||||
|
|
@ -1362,6 +1409,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;
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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
|
||||
};
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue