Rework transport protocol

Use a more simple tranport protocol for the realtime data. Use a piece
of shared memory and a socket where we use a 1byte read/write to trigger
remote actions. Also use a ringbuffer for events.
This commit is contained in:
Wim Taymans 2016-11-07 10:24:13 +01:00
parent 7e46f9e3ad
commit b774b99db5
22 changed files with 797 additions and 364 deletions

251
pinos/client/transport.c Normal file
View file

@ -0,0 +1,251 @@
/* Simple Plugin API
* Copyright (C) 2016 Wim Taymans <wim.taymans@gmail.com>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library 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
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
* Boston, MA 02110-1301, USA.
*/
#include <unistd.h>
#include <sys/mman.h>
#include <pinos/client/transport.h>
#define INPUT_BUFFER_SIZE (1<<12)
#define OUTPUT_BUFFER_SIZE (1<<12)
#define CMD_NONE 0
#define CMD_PROCESS_DATA (1<<0)
#define CMD_PROCESS_EVENTS (1<<1)
#define CMD_PROCESS_SYNC (1<<2)
typedef struct {
PinosTransport trans;
PinosMemblock mem;
size_t offset;
SpaRingbufferArea areas[2];
SpaNodeEvent current;
} PinosTransportImpl;
static size_t
transport_area_get_size (PinosTransportArea *area)
{
size_t size;
size = sizeof (PinosTransportArea);
size += area->max_input_info * sizeof (SpaPortInputInfo);
size += area->max_output_info * sizeof (SpaPortOutputInfo);
size += sizeof (SpaRingbuffer);
size += INPUT_BUFFER_SIZE;
size += sizeof (SpaRingbuffer);
size += OUTPUT_BUFFER_SIZE;
return size;
}
static void
transport_setup_area (void *p, PinosTransport *trans)
{
PinosTransportArea *a;
trans->area = a = p;
p = SPA_MEMBER (p, sizeof (PinosTransportArea), SpaPortInputInfo);
trans->input_info = p;
p = SPA_MEMBER (p, a->max_input_info * sizeof (SpaPortInputInfo), void);
trans->output_info = p;
p = SPA_MEMBER (p, a->max_output_info * sizeof (SpaPortOutputInfo), void);
trans->input_buffer = p;
spa_ringbuffer_init (trans->input_buffer, INPUT_BUFFER_SIZE);
p = SPA_MEMBER (p, sizeof (SpaRingbuffer), void);
trans->input_data = p;
p = SPA_MEMBER (p, INPUT_BUFFER_SIZE, void);
trans->output_buffer = p;
spa_ringbuffer_init (trans->output_buffer, OUTPUT_BUFFER_SIZE);
p = SPA_MEMBER (p, sizeof (SpaRingbuffer), void);
trans->output_data = p;
p = SPA_MEMBER (p, OUTPUT_BUFFER_SIZE, void);
}
PinosTransport *
pinos_transport_new (unsigned int max_input_info,
unsigned int max_output_info,
int fd)
{
PinosTransportImpl *impl;
PinosTransport *trans;
PinosTransportArea area;
area.max_input_info = max_input_info;
area.n_input_info = 0;
area.max_output_info = max_output_info;
area.n_output_info = 0;
impl = calloc (1, sizeof (PinosTransportImpl));
impl->offset = 0;
trans = &impl->trans;
trans->fd = fd;
pinos_memblock_alloc (PINOS_MEMBLOCK_FLAG_WITH_FD |
PINOS_MEMBLOCK_FLAG_MAP_READWRITE |
PINOS_MEMBLOCK_FLAG_SEAL,
transport_area_get_size (&area),
&impl->mem);
memcpy (impl->mem.ptr, &area, sizeof (PinosTransportArea));
transport_setup_area (impl->mem.ptr, trans);
return trans;
}
PinosTransport *
pinos_transport_new_from_info (PinosTransportInfo *info)
{
PinosTransportImpl *impl;
PinosTransport *trans;
void *tmp;
if (info == NULL)
return NULL;
impl = calloc (1, sizeof (PinosTransportImpl));
trans = &impl->trans;
trans->fd = info->fd;
impl->mem.flags = PINOS_MEMBLOCK_FLAG_MAP_READWRITE |
PINOS_MEMBLOCK_FLAG_WITH_FD;
impl->mem.fd = info->memfd;
impl->mem.size = info->size;
impl->mem.ptr = mmap (NULL, info->size, PROT_READ | PROT_WRITE, MAP_SHARED, info->memfd, info->offset);
impl->offset = info->offset;
transport_setup_area (impl->mem.ptr, trans);
tmp = trans->output_buffer;
trans->output_buffer = trans->input_buffer;
trans->input_buffer = tmp;
tmp = trans->output_data;
trans->output_data = trans->input_data;
trans->input_data = tmp;
return trans;
}
void
pinos_transport_free (PinosTransport *trans)
{
PinosTransportImpl *impl = (PinosTransportImpl *) trans;
if (impl == NULL)
return;
pinos_memblock_free (&impl->mem);
if (trans->fd != -1)
close (trans->fd);
free (impl);
}
SpaResult
pinos_transport_get_info (PinosTransport *trans,
PinosTransportInfo *info)
{
PinosTransportImpl *impl = (PinosTransportImpl *) trans;
if (impl == NULL)
return SPA_RESULT_INVALID_ARGUMENTS;
info->memfd = impl->mem.fd;
info->offset = impl->offset;
info->size = impl->mem.size;
info->fd = trans->fd;
return SPA_RESULT_OK;
}
SpaResult
pinos_transport_add_event (PinosTransport *trans,
SpaNodeEvent *event)
{
PinosTransportImpl *impl = (PinosTransportImpl *) trans;
SpaRingbufferArea areas[2];
size_t avail;
if (impl == NULL || event == NULL)
return SPA_RESULT_INVALID_ARGUMENTS;
avail = spa_ringbuffer_get_write_areas (trans->output_buffer, areas);
if (avail < event->size)
return SPA_RESULT_ERROR;
spa_ringbuffer_write_data (trans->output_buffer,
trans->output_data,
areas,
event,
event->size);
spa_ringbuffer_write_advance (trans->output_buffer, event->size);
return SPA_RESULT_OK;
}
SpaResult
pinos_transport_next_event (PinosTransport *trans,
SpaNodeEvent *event)
{
PinosTransportImpl *impl = (PinosTransportImpl *) trans;
size_t avail;
if (impl == NULL || event == NULL)
return SPA_RESULT_INVALID_ARGUMENTS;
avail = spa_ringbuffer_get_read_areas (trans->input_buffer, impl->areas);
if (avail < sizeof (SpaNodeEvent))
return SPA_RESULT_ENUM_END;
spa_ringbuffer_read_data (trans->input_buffer,
trans->input_data,
impl->areas,
&impl->current,
sizeof (SpaNodeEvent));
*event = impl->current;
return SPA_RESULT_OK;
}
SpaResult
pinos_transport_parse_event (PinosTransport *trans,
void *event)
{
PinosTransportImpl *impl = (PinosTransportImpl *) trans;
if (impl == NULL || event == NULL)
return SPA_RESULT_INVALID_ARGUMENTS;
spa_ringbuffer_read_data (trans->input_buffer,
trans->input_data,
impl->areas,
event,
impl->current.size);
spa_ringbuffer_read_advance (trans->input_buffer, impl->current.size);
return SPA_RESULT_OK;
}