mirror of
https://gitlab.freedesktop.org/pipewire/pipewire.git
synced 2025-11-02 09:01:50 -05:00
Add more buffer types to add and remove memory shared memory between the server and client. We would like to send buffers only once and then simply reference them by index. Do format negotiation and stream start with a START message.
1029 lines
25 KiB
C
1029 lines
25 KiB
C
/* Pinos
|
|
* Copyright (C) 2015 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 <string.h>
|
|
|
|
#include <gio/gio.h>
|
|
|
|
#include "pinos/client/properties.h"
|
|
#include "pinos/client/context.h"
|
|
#include "pinos/client/buffer.h"
|
|
#include "pinos/client/private.h"
|
|
|
|
#if 0
|
|
#define PINOS_DEBUG_BUFFER(format,args...) g_debug(format,##args)
|
|
#else
|
|
#define PINOS_DEBUG_BUFFER(format,args...)
|
|
#endif
|
|
|
|
G_STATIC_ASSERT (sizeof (PinosStackBuffer) <= sizeof (PinosBuffer));
|
|
|
|
/**
|
|
* pinos_buffer_init_data:
|
|
* @buffer: a #PinosBuffer
|
|
* @data: data
|
|
* @size: size of @data
|
|
* @fds: file descriptors
|
|
* @n_fds: number of file descriptors
|
|
*
|
|
* Initialize @buffer with @data and @size and @fds and @n_fds.
|
|
* The memory pointer to by @data and @fds becomes property of @buffer
|
|
* and should not be freed or modified until all referenced to the buffer
|
|
* are gone pinos_buffer_unref().
|
|
*/
|
|
void
|
|
pinos_buffer_init_data (PinosBuffer *buffer,
|
|
gpointer data,
|
|
gsize size,
|
|
gint *fds,
|
|
gint n_fds)
|
|
{
|
|
PinosStackBuffer *sb = PSB (buffer);
|
|
|
|
PINOS_DEBUG_BUFFER ("buffer %p: init", buffer);
|
|
|
|
sb->magic = PSB_MAGIC;
|
|
sb->refcount = 1;
|
|
sb->data = data;
|
|
sb->size = size;
|
|
sb->max_size = size;
|
|
sb->free_data = NULL;
|
|
sb->fds = fds;
|
|
sb->n_fds = n_fds;
|
|
sb->max_fds = n_fds;
|
|
sb->free_fds = NULL;
|
|
}
|
|
|
|
PinosBuffer *
|
|
pinos_buffer_ref (PinosBuffer *buffer)
|
|
{
|
|
PinosStackBuffer *sb = PSB (buffer);
|
|
|
|
g_return_val_if_fail (is_valid_buffer (buffer), NULL);
|
|
|
|
PINOS_DEBUG_BUFFER ("buffer %p: ref %d -> %d", buffer, sb->refcount, sb->refcount+1);
|
|
|
|
sb->refcount++;
|
|
|
|
return buffer;
|
|
}
|
|
|
|
gboolean
|
|
pinos_buffer_unref (PinosBuffer *buffer)
|
|
{
|
|
PinosStackBuffer *sb = PSB (buffer);
|
|
gboolean res;
|
|
gint i;
|
|
|
|
g_return_val_if_fail (is_valid_buffer (buffer), FALSE);
|
|
|
|
PINOS_DEBUG_BUFFER ("buffer %p: unref %d -> %d", buffer, sb->refcount, sb->refcount-1);
|
|
|
|
sb->refcount--;
|
|
res = sb->refcount > 0;
|
|
if (!res) {
|
|
sb->magic = 0;
|
|
g_free (sb->free_data);
|
|
for (i = 0; i < sb->n_fds; i++) {
|
|
PINOS_DEBUG_BUFFER ("%p: close %d %d", buffer, i, sb->fds[i]);
|
|
close (sb->fds[i]);
|
|
}
|
|
g_free (sb->free_fds);
|
|
sb->n_fds = 0;
|
|
}
|
|
return res;
|
|
}
|
|
|
|
/**
|
|
* pinos_buffer_get_version
|
|
* @buffer: a #PinosBuffer
|
|
*
|
|
* Get the buffer version
|
|
*
|
|
* Returns: the buffer version.
|
|
*/
|
|
guint32
|
|
pinos_buffer_get_version (PinosBuffer *buffer)
|
|
{
|
|
PinosStackBuffer *sb = PSB (buffer);
|
|
PinosStackHeader *hdr;
|
|
|
|
g_return_val_if_fail (is_valid_buffer (buffer), -1);
|
|
|
|
hdr = sb->data;
|
|
|
|
return hdr->version;
|
|
}
|
|
|
|
/**
|
|
* pinos_buffer_get_flags
|
|
* @buffer: a #PinosBuffer
|
|
*
|
|
* Get the buffer flags
|
|
*
|
|
* Returns: the buffer flags.
|
|
*/
|
|
PinosBufferFlags
|
|
pinos_buffer_get_flags (PinosBuffer *buffer)
|
|
{
|
|
PinosStackBuffer *sb = PSB (buffer);
|
|
PinosStackHeader *hdr;
|
|
|
|
g_return_val_if_fail (is_valid_buffer (buffer), -1);
|
|
|
|
hdr = sb->data;
|
|
|
|
return hdr->flags;
|
|
}
|
|
|
|
/**
|
|
* pinos_buffer_get_fd:
|
|
* @buffer: a #PinosBuffer
|
|
* @index: an index
|
|
*
|
|
* Get the file descriptor at @index in @buffer.
|
|
*
|
|
* Returns: a file descriptor at @index in @buffer. The file descriptor
|
|
* is not duplicated in any way. -1 is returned on error.
|
|
*/
|
|
int
|
|
pinos_buffer_get_fd (PinosBuffer *buffer, gint index)
|
|
{
|
|
PinosStackBuffer *sb = PSB (buffer);
|
|
|
|
g_return_val_if_fail (is_valid_buffer (buffer), -1);
|
|
|
|
if (sb->fds == NULL || sb->n_fds < index)
|
|
return -1;
|
|
|
|
return sb->fds[index];
|
|
}
|
|
|
|
/**
|
|
* pinos_buffer_steal_data:
|
|
* @buffer: a #PinosBuffer
|
|
* @size: output size or %NULL to ignore
|
|
*
|
|
* Take the data from @buffer.
|
|
*
|
|
* Returns: the data of @buffer.
|
|
*/
|
|
gpointer
|
|
pinos_buffer_steal_data (PinosBuffer *buffer,
|
|
gsize *size)
|
|
{
|
|
PinosStackBuffer *sb = PSB (buffer);
|
|
gpointer data;
|
|
|
|
g_return_val_if_fail (is_valid_buffer (buffer), NULL);
|
|
g_return_val_if_fail (sb->refcount == 1, NULL);
|
|
|
|
data = sb->data;
|
|
if (size)
|
|
*size = sb->size;
|
|
|
|
if (sb->data != sb->free_data)
|
|
g_free (sb->free_data);
|
|
sb->data = NULL;
|
|
sb->free_data = NULL;
|
|
sb->size = 0;
|
|
sb->max_size = 0;
|
|
|
|
return data;
|
|
}
|
|
|
|
/**
|
|
* pinos_buffer_steal_fds:
|
|
* @buffer: a #PinosBuffer
|
|
* @n_fds: number of fds
|
|
*
|
|
* Take the fds from @buffer.
|
|
*
|
|
* Returns: the fds of @buffer.
|
|
*/
|
|
gint *
|
|
pinos_buffer_steal_fds (PinosBuffer *buffer,
|
|
gint *n_fds)
|
|
{
|
|
PinosStackBuffer *sb = PSB (buffer);
|
|
gint *fds;
|
|
|
|
g_return_val_if_fail (is_valid_buffer (buffer), NULL);
|
|
g_return_val_if_fail (sb->refcount == 1, NULL);
|
|
|
|
fds = sb->fds;
|
|
if (n_fds)
|
|
*n_fds = sb->n_fds;
|
|
|
|
if (sb->fds != sb->free_fds)
|
|
g_free (sb->free_fds);
|
|
sb->fds = NULL;
|
|
sb->free_fds = NULL;
|
|
sb->n_fds = 0;
|
|
sb->max_fds = 0;
|
|
|
|
return fds;
|
|
}
|
|
|
|
/**
|
|
* PinosBufferIter:
|
|
*
|
|
* #PinosBufferIter is an opaque data structure and can only be accessed
|
|
* using the following functions.
|
|
*/
|
|
struct stack_iter {
|
|
gsize magic;
|
|
guint32 version;
|
|
PinosStackBuffer *buffer;
|
|
gsize offset;
|
|
|
|
PinosPacketType type;
|
|
gsize size;
|
|
gpointer data;
|
|
|
|
guint item;
|
|
};
|
|
|
|
G_STATIC_ASSERT (sizeof (struct stack_iter) <= sizeof (PinosBufferIter));
|
|
|
|
#define PPSI(i) ((struct stack_iter *) (i))
|
|
#define PPSI_MAGIC ((gsize) 6739527471u)
|
|
#define is_valid_iter(i) (i != NULL && \
|
|
PPSI(i)->magic == PPSI_MAGIC)
|
|
|
|
/**
|
|
* pinos_buffer_iter_init:
|
|
* @iter: a #PinosBufferIter
|
|
* @buffer: a #PinosBuffer
|
|
*
|
|
* Initialize @iter to iterate the packets in @buffer.
|
|
*/
|
|
void
|
|
pinos_buffer_iter_init_full (PinosBufferIter *iter,
|
|
PinosBuffer *buffer,
|
|
guint32 version)
|
|
{
|
|
struct stack_iter *si = PPSI (iter);
|
|
|
|
g_return_if_fail (iter != NULL);
|
|
g_return_if_fail (is_valid_buffer (buffer));
|
|
|
|
si->magic = PPSI_MAGIC;
|
|
si->version = version;
|
|
si->buffer = PSB (buffer);
|
|
si->offset = 0;
|
|
si->type = PINOS_PACKET_TYPE_INVALID;
|
|
si->size = sizeof (PinosStackHeader);
|
|
si->data = NULL;
|
|
si->item = 0;
|
|
}
|
|
|
|
static gboolean
|
|
read_length (guint8 * data, guint size, gsize * length, gsize * skip)
|
|
{
|
|
gsize len, offset;
|
|
guint8 b;
|
|
|
|
/* start reading the length, we need this to skip to the data later */
|
|
len = offset = 0;
|
|
do {
|
|
if (offset >= size)
|
|
return FALSE;
|
|
b = data[offset++];
|
|
len = (len << 7) | (b & 0x7f);
|
|
} while (b & 0x80);
|
|
|
|
/* check remaining buffer size */
|
|
if (size - offset < len)
|
|
return FALSE;
|
|
|
|
*length = len;
|
|
*skip = offset;
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
/**
|
|
* pinos_buffer_iter_next:
|
|
* @iter: a #PinosBufferIter
|
|
*
|
|
* Move to the next packet in @iter.
|
|
*
|
|
* Returns: %TRUE if more packets are available.
|
|
*/
|
|
gboolean
|
|
pinos_buffer_iter_next (PinosBufferIter *iter)
|
|
{
|
|
struct stack_iter *si = PPSI (iter);
|
|
gsize len, size, skip;
|
|
guint8 *data;
|
|
|
|
g_return_val_if_fail (is_valid_iter (iter), FALSE);
|
|
|
|
/* move to next packet */
|
|
si->offset += si->size;
|
|
|
|
/* now read packet */
|
|
data = si->buffer->data;
|
|
size = si->buffer->size;
|
|
if (si->offset >= size)
|
|
return FALSE;
|
|
|
|
data += si->offset;
|
|
size -= si->offset;
|
|
|
|
if (size < 1)
|
|
return FALSE;
|
|
|
|
si->type = *data;
|
|
|
|
data++;
|
|
size--;
|
|
|
|
if (!read_length (data, size, &len, &skip))
|
|
return FALSE;
|
|
|
|
si->size = len;
|
|
si->data = data + skip;
|
|
si->offset += 1 + skip;
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
/**
|
|
* pinos_buffer_iter_done:
|
|
* @iter: a #PinosBufferIter
|
|
*
|
|
* End iterations on @iter.
|
|
*/
|
|
void
|
|
pinos_buffer_iter_end (PinosBufferIter *iter)
|
|
{
|
|
struct stack_iter *si = PPSI (iter);
|
|
|
|
g_return_if_fail (is_valid_iter (iter));
|
|
|
|
si->magic = 0;
|
|
}
|
|
|
|
PinosPacketType
|
|
pinos_buffer_iter_get_type (PinosBufferIter *iter)
|
|
{
|
|
struct stack_iter *si = PPSI (iter);
|
|
|
|
g_return_val_if_fail (is_valid_iter (iter), PINOS_PACKET_TYPE_INVALID);
|
|
|
|
return si->type;
|
|
}
|
|
|
|
gpointer
|
|
pinos_buffer_iter_get_data (PinosBufferIter *iter, gsize *size)
|
|
{
|
|
struct stack_iter *si = PPSI (iter);
|
|
|
|
g_return_val_if_fail (is_valid_iter (iter), NULL);
|
|
|
|
if (size)
|
|
*size = si->size;
|
|
|
|
return si->data;
|
|
}
|
|
|
|
|
|
/**
|
|
* PinosBufferBuilder:
|
|
* @buffer: owner #PinosBuffer
|
|
*/
|
|
struct stack_builder {
|
|
gsize magic;
|
|
|
|
PinosStackHeader *sh;
|
|
PinosStackBuffer buf;
|
|
|
|
PinosPacketType type;
|
|
gsize offset;
|
|
};
|
|
|
|
G_STATIC_ASSERT (sizeof (struct stack_builder) <= sizeof (PinosBufferBuilder));
|
|
|
|
#define PPSB(b) ((struct stack_builder *) (b))
|
|
#define PPSB_MAGIC ((gsize) 8103647428u)
|
|
#define is_valid_builder(b) (b != NULL && \
|
|
PPSB(b)->magic == PPSB_MAGIC)
|
|
|
|
|
|
/**
|
|
* pinos_buffer_builder_init_full:
|
|
* @builder: a #PinosBufferBuilder
|
|
* @version: a version
|
|
* @data: data to build into or %NULL to allocate
|
|
* @max_data: allocated size of @data
|
|
* @fds: memory for fds
|
|
* @max_fds: maximum number of fds in @fds
|
|
*
|
|
* Initialize a stack allocated @builder and set the @version.
|
|
*/
|
|
void
|
|
pinos_buffer_builder_init_full (PinosBufferBuilder *builder,
|
|
guint32 version,
|
|
gpointer data,
|
|
gsize max_data,
|
|
gint *fds,
|
|
gint max_fds)
|
|
{
|
|
struct stack_builder *sb = PPSB (builder);
|
|
PinosStackHeader *sh;
|
|
|
|
g_return_if_fail (builder != NULL);
|
|
|
|
sb->magic = PPSB_MAGIC;
|
|
|
|
if (max_data < sizeof (PinosStackHeader) || data == NULL) {
|
|
sb->buf.max_size = sizeof (PinosStackHeader) + 128;
|
|
sb->buf.data = g_malloc (sb->buf.max_size);
|
|
sb->buf.free_data = sb->buf.data;
|
|
g_warning ("builder %p: realloc buffer memory %"G_GSIZE_FORMAT" -> %"G_GSIZE_FORMAT,
|
|
builder, max_data, sb->buf.max_size);
|
|
} else {
|
|
sb->buf.max_size = max_data;
|
|
sb->buf.data = data;
|
|
sb->buf.free_data = NULL;
|
|
}
|
|
sb->buf.size = sizeof (PinosStackHeader);
|
|
|
|
sb->buf.fds = fds;
|
|
sb->buf.max_fds = max_fds;
|
|
sb->buf.n_fds = 0;
|
|
sb->buf.free_fds = NULL;
|
|
|
|
sh = sb->sh = sb->buf.data;
|
|
sh->version = version;
|
|
sh->flags = 0;
|
|
sh->length = 0;
|
|
|
|
sb->type = 0;
|
|
sb->offset = 0;
|
|
}
|
|
|
|
/**
|
|
* pinos_buffer_builder_set_flags:
|
|
* @builder: a #PinosBufferBuilder
|
|
* @flags: flags to set
|
|
*
|
|
* Set the flags on the buffer from @builder.
|
|
*/
|
|
void
|
|
pinos_buffer_builder_set_flags (PinosBufferBuilder *builder, PinosBufferFlags flags)
|
|
{
|
|
struct stack_builder *sb = PPSB (builder);
|
|
|
|
g_return_if_fail (is_valid_builder (builder));
|
|
|
|
sb->sh->flags = flags;
|
|
}
|
|
|
|
/**
|
|
* pinos_buffer_builder_clear:
|
|
* @builder: a #PinosBufferBuilder
|
|
*
|
|
* Clear the memory used by @builder. This can be used to abort building the
|
|
* buffer.
|
|
*
|
|
* @builder becomes invalid after this function and can be reused with
|
|
* pinos_buffer_builder_init()
|
|
*/
|
|
void
|
|
pinos_buffer_builder_clear (PinosBufferBuilder *builder)
|
|
{
|
|
struct stack_builder *sb = PPSB (builder);
|
|
|
|
g_return_if_fail (is_valid_builder (builder));
|
|
|
|
sb->magic = 0;
|
|
g_free (sb->buf.free_data);
|
|
g_free (sb->buf.free_fds);
|
|
}
|
|
|
|
/**
|
|
* pinos_buffer_builder_end:
|
|
* @builder: a #PinosBufferBuilder
|
|
* @buffer: a #PinosBuffer
|
|
*
|
|
* Ends the building process and fills @buffer with the constructed
|
|
* #PinosBuffer.
|
|
*
|
|
* @builder becomes invalid after this function and can be reused with
|
|
* pinos_buffer_builder_init()
|
|
*/
|
|
void
|
|
pinos_buffer_builder_end (PinosBufferBuilder *builder,
|
|
PinosBuffer *buffer)
|
|
{
|
|
struct stack_builder *sb = PPSB (builder);
|
|
PinosStackBuffer *sbuf = PSB (buffer);
|
|
|
|
g_return_if_fail (is_valid_builder (builder));
|
|
g_return_if_fail (buffer != NULL);
|
|
|
|
sb->magic = 0;
|
|
sb->sh->length = sb->buf.size - sizeof (PinosStackHeader);
|
|
|
|
sbuf->magic = PSB_MAGIC;
|
|
sbuf->refcount = 1;
|
|
sbuf->data = sb->buf.data;
|
|
sbuf->size = sb->buf.size;
|
|
sbuf->max_size = sb->buf.max_size;
|
|
sbuf->free_data = sb->buf.free_data;
|
|
|
|
sbuf->fds = sb->buf.fds;
|
|
sbuf->n_fds = sb->buf.n_fds;
|
|
sbuf->max_fds = sb->buf.max_fds;
|
|
sbuf->free_fds = sb->buf.free_fds;
|
|
|
|
PINOS_DEBUG_BUFFER ("builder %p: buffer %p init", builder, buffer);
|
|
}
|
|
|
|
/**
|
|
* pinos_buffer_builder_add_fd:
|
|
* @builder: a #PinosBufferBuilder
|
|
* @fd: a valid fd
|
|
*
|
|
* Add the file descriptor @fd to @builder.
|
|
*
|
|
* Returns: the index of the file descriptor in @builder.
|
|
*/
|
|
gint
|
|
pinos_buffer_builder_add_fd (PinosBufferBuilder *builder,
|
|
int fd)
|
|
{
|
|
struct stack_builder *sb = PPSB (builder);
|
|
gint index;
|
|
|
|
g_return_val_if_fail (is_valid_builder (builder), -1);
|
|
g_return_val_if_fail (fd > 0, -1);
|
|
|
|
if (sb->buf.n_fds >= sb->buf.max_fds) {
|
|
gint new_size = sb->buf.max_fds + 8;
|
|
g_warning ("builder %p: realloc buffer fds %d -> %d",
|
|
builder, sb->buf.max_fds, new_size);
|
|
sb->buf.max_fds = new_size;
|
|
sb->buf.free_fds = g_realloc (sb->buf.free_fds, new_size * sizeof (int));
|
|
sb->buf.fds = sb->buf.free_fds;
|
|
}
|
|
index = sb->buf.n_fds;
|
|
sb->buf.fds[index] = fd;
|
|
sb->buf.n_fds++;
|
|
|
|
return index;
|
|
}
|
|
|
|
static gpointer
|
|
builder_ensure_size (struct stack_builder *sb, gsize size)
|
|
{
|
|
if (sb->buf.size + size > sb->buf.max_size) {
|
|
gsize new_size = sb->buf.size + MAX (size, 1024);
|
|
g_warning ("builder %p: realloc buffer memory %"G_GSIZE_FORMAT" -> %"G_GSIZE_FORMAT,
|
|
sb, sb->buf.max_size, new_size);
|
|
sb->buf.max_size = new_size;
|
|
sb->buf.free_data = g_realloc (sb->buf.free_data, new_size);
|
|
sb->sh = sb->buf.data = sb->buf.free_data;
|
|
}
|
|
return (guint8 *) sb->buf.data + sb->buf.size;
|
|
}
|
|
|
|
static gpointer
|
|
builder_add_packet (struct stack_builder *sb, PinosPacketType type, gsize size)
|
|
{
|
|
guint8 *p;
|
|
guint plen;
|
|
|
|
plen = 1;
|
|
while (size >> (7 * plen))
|
|
plen++;
|
|
|
|
/* 1 for type, plen for size and size for payload */
|
|
p = builder_ensure_size (sb, 1 + plen + size);
|
|
|
|
sb->type = type;
|
|
sb->offset = sb->buf.size;
|
|
sb->buf.size += 1 + plen + size;
|
|
|
|
*p++ = type;
|
|
/* write length */
|
|
while (plen) {
|
|
plen--;
|
|
*p++ = ((plen > 0) ? 0x80 : 0) | ((size >> (7 * plen)) & 0x7f);
|
|
}
|
|
return p;
|
|
}
|
|
|
|
/**
|
|
* pinos_buffer_builder_add_empty:
|
|
* @builder: a #PinosBufferBuilder
|
|
* @type: a #PinosPacketType
|
|
*
|
|
* Add an empty packet of @type.
|
|
*
|
|
* Returns: %TRUE on success.
|
|
*/
|
|
gboolean
|
|
pinos_buffer_builder_add_empty (PinosBufferBuilder *builder,
|
|
PinosPacketType type)
|
|
{
|
|
struct stack_builder *sb = PPSB (builder);
|
|
|
|
g_return_val_if_fail (is_valid_builder (builder), FALSE);
|
|
|
|
builder_add_packet (sb, type, 0);
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
/**
|
|
* pinos_buffer_iter_parse_add_mem:
|
|
* @iter: a #PinosBufferIter
|
|
* @payload: a #PinosPacketAddMem
|
|
*
|
|
* Get the #PinosPacketAddMem. @iter must be positioned on a packet of
|
|
* type #PINOS_PACKET_TYPE_ADD_MEM
|
|
*
|
|
* Returns: %TRUE if @payload contains valid data.
|
|
*/
|
|
gboolean
|
|
pinos_buffer_iter_parse_add_mem (PinosBufferIter *iter,
|
|
PinosPacketAddMem *payload)
|
|
{
|
|
struct stack_iter *si = PPSI (iter);
|
|
|
|
g_return_val_if_fail (is_valid_iter (iter), FALSE);
|
|
g_return_val_if_fail (si->type == PINOS_PACKET_TYPE_ADD_MEM, FALSE);
|
|
|
|
if (si->size < sizeof (PinosPacketAddMem))
|
|
return FALSE;
|
|
|
|
memcpy (payload, si->data, sizeof (*payload));
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
/**
|
|
* pinos_buffer_builder_add_add_mem:
|
|
* @builder: a #PinosBufferBuilder
|
|
* @payload: a #PinosPacketAddMem
|
|
*
|
|
* Add a #PINOS_PACKET_TYPE_ADD_MEM to @builder with data from @payload.
|
|
*
|
|
* Returns: %TRUE on success.
|
|
*/
|
|
gboolean
|
|
pinos_buffer_builder_add_add_mem (PinosBufferBuilder *builder,
|
|
PinosPacketAddMem *payload)
|
|
{
|
|
struct stack_builder *sb = PPSB (builder);
|
|
PinosPacketAddMem *p;
|
|
|
|
g_return_val_if_fail (is_valid_builder (builder), FALSE);
|
|
|
|
p = builder_add_packet (sb, PINOS_PACKET_TYPE_ADD_MEM, sizeof (PinosPacketAddMem));
|
|
memcpy (p, payload, sizeof (*payload));
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
/**
|
|
* pinos_buffer_iter_parse_remove_mem:
|
|
* @iter: a #PinosBufferIter
|
|
* @payload: a #PinosPacketRemoveMem
|
|
*
|
|
* Get the #PinosPacketRemoveMem. @iter must be positioned on a packet of
|
|
* type #PINOS_PACKET_TYPE_REMOVE_MEM
|
|
*
|
|
* Returns: %TRUE if @payload contains valid data.
|
|
*/
|
|
gboolean
|
|
pinos_buffer_iter_parse_remove_mem (PinosBufferIter *iter,
|
|
PinosPacketRemoveMem *payload)
|
|
{
|
|
struct stack_iter *si = PPSI (iter);
|
|
|
|
g_return_val_if_fail (is_valid_iter (iter), FALSE);
|
|
g_return_val_if_fail (si->type == PINOS_PACKET_TYPE_REMOVE_MEM, FALSE);
|
|
|
|
if (si->size < sizeof (PinosPacketRemoveMem))
|
|
return FALSE;
|
|
|
|
memcpy (payload, si->data, sizeof (*payload));
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
/**
|
|
* pinos_buffer_builder_add_remove_mem:
|
|
* @builder: a #PinosBufferBuilder
|
|
* @payload: a #PinosPacketRemoveMem
|
|
*
|
|
* Add a #PINOS_PACKET_TYPE_REMOVE_MEM to @builder with data from @payload.
|
|
*
|
|
* Returns: %TRUE on success.
|
|
*/
|
|
gboolean
|
|
pinos_buffer_builder_add_remove_mem (PinosBufferBuilder *builder,
|
|
PinosPacketRemoveMem *payload)
|
|
{
|
|
struct stack_builder *sb = PPSB (builder);
|
|
PinosPacketRemoveMem *p;
|
|
|
|
g_return_val_if_fail (is_valid_builder (builder), FALSE);
|
|
|
|
p = builder_add_packet (sb, PINOS_PACKET_TYPE_REMOVE_MEM, sizeof (PinosPacketRemoveMem));
|
|
memcpy (p, payload, sizeof (*payload));
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
/* header packets */
|
|
/**
|
|
* pinos_buffer_iter_parse_header:
|
|
* @iter: a #PinosBufferIter
|
|
* @payload: a #PinosPacketHeader
|
|
*
|
|
* Get the #PinosPacketHeader. @iter must be positioned on a packet of
|
|
* type #PINOS_PACKET_TYPE_HEADER
|
|
*
|
|
* Returns: %TRUE if @payload contains valid data.
|
|
*/
|
|
gboolean
|
|
pinos_buffer_iter_parse_header (PinosBufferIter *iter,
|
|
PinosPacketHeader *payload)
|
|
{
|
|
struct stack_iter *si = PPSI (iter);
|
|
|
|
g_return_val_if_fail (is_valid_iter (iter), FALSE);
|
|
g_return_val_if_fail (si->type == PINOS_PACKET_TYPE_HEADER, FALSE);
|
|
|
|
if (si->size < sizeof (PinosPacketHeader))
|
|
return FALSE;
|
|
|
|
memcpy (payload, si->data, sizeof (*payload));
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
/**
|
|
* pinos_buffer_builder_add_header:
|
|
* @builder: a #PinosBufferBuilder
|
|
* @payload: a #PinosPacketHeader
|
|
*
|
|
* Add a #PINOS_PACKET_TYPE_HEADER to @builder with data from @payload.
|
|
*
|
|
* Returns: %TRUE on success.
|
|
*/
|
|
gboolean
|
|
pinos_buffer_builder_add_header (PinosBufferBuilder *builder,
|
|
PinosPacketHeader *payload)
|
|
{
|
|
struct stack_builder *sb = PPSB (builder);
|
|
PinosPacketHeader *p;
|
|
|
|
g_return_val_if_fail (is_valid_builder (builder), FALSE);
|
|
|
|
p = builder_add_packet (sb, PINOS_PACKET_TYPE_HEADER, sizeof (PinosPacketHeader));
|
|
memcpy (p, payload, sizeof (*payload));
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
/* process-mem packets */
|
|
/**
|
|
* pinos_buffer_iter_parse_process_mem:
|
|
* @iter: a #PinosBufferIter
|
|
* @payload: a #PinosPacketProcessMem
|
|
*
|
|
* Get the #PinosPacketProcessMem. @iter must be positioned on a packet of
|
|
* type #PINOS_PACKET_TYPE_PROCESS_MEM
|
|
*
|
|
* Returns: %TRUE if @payload contains valid data.
|
|
*/
|
|
gboolean
|
|
pinos_buffer_iter_parse_process_mem (PinosBufferIter *iter,
|
|
PinosPacketProcessMem *payload)
|
|
{
|
|
struct stack_iter *si = PPSI (iter);
|
|
|
|
g_return_val_if_fail (is_valid_iter (iter), FALSE);
|
|
g_return_val_if_fail (si->type == PINOS_PACKET_TYPE_PROCESS_MEM, FALSE);
|
|
|
|
if (si->size < sizeof (PinosPacketProcessMem))
|
|
return FALSE;
|
|
|
|
memcpy (payload, si->data, sizeof (*payload));
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
/**
|
|
* pinos_buffer_builder_add_process_mem:
|
|
* @builder: a #PinosBufferBuilder
|
|
* @payload: a #PinosPacketProcessMem
|
|
*
|
|
* Add a #PINOS_PACKET_TYPE_PROCESS_MEM to @builder with data from @payload.
|
|
*
|
|
* Returns: %TRUE on success.
|
|
*/
|
|
gboolean
|
|
pinos_buffer_builder_add_process_mem (PinosBufferBuilder *builder,
|
|
PinosPacketProcessMem *payload)
|
|
{
|
|
struct stack_builder *sb = PPSB (builder);
|
|
PinosPacketProcessMem *p;
|
|
|
|
g_return_val_if_fail (is_valid_builder (builder), FALSE);
|
|
g_return_val_if_fail (payload->size > 0, FALSE);
|
|
|
|
p = builder_add_packet (sb, PINOS_PACKET_TYPE_PROCESS_MEM, sizeof (PinosPacketProcessMem));
|
|
memcpy (p, payload, sizeof (*payload));
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
/**
|
|
* pinos_buffer_iter_parse_reuse_mem:
|
|
* @iter: a #PinosBufferIter
|
|
* @payload: a #PinosPacketReuseMem
|
|
*
|
|
* Parse a #PINOS_PACKET_TYPE_REUSE_MEM packet from @iter into @payload.
|
|
*
|
|
* Returns: %TRUE on success
|
|
*/
|
|
gboolean
|
|
pinos_buffer_iter_parse_reuse_mem (PinosBufferIter *iter,
|
|
PinosPacketReuseMem *payload)
|
|
{
|
|
struct stack_iter *si = PPSI (iter);
|
|
|
|
g_return_val_if_fail (is_valid_iter (iter), FALSE);
|
|
g_return_val_if_fail (si->type == PINOS_PACKET_TYPE_REUSE_MEM, FALSE);
|
|
|
|
if (si->size < sizeof (PinosPacketReuseMem))
|
|
return FALSE;
|
|
|
|
memcpy (payload, si->data, sizeof (*payload));
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
/**
|
|
* pinos_buffer_builder_add_reuse_mem:
|
|
* @builder: a #PinosBufferBuilder
|
|
* @payload: a #PinosPacketReuseMem
|
|
*
|
|
* Add a #PINOS_PACKET_TYPE_REUSE_MEM payload in @payload to @builder.
|
|
*
|
|
* Returns: %TRUE on success
|
|
*/
|
|
gboolean
|
|
pinos_buffer_builder_add_reuse_mem (PinosBufferBuilder *builder,
|
|
PinosPacketReuseMem *payload)
|
|
{
|
|
struct stack_builder *sb = PPSB (builder);
|
|
PinosPacketReuseMem *p;
|
|
|
|
g_return_val_if_fail (is_valid_builder (builder), FALSE);
|
|
|
|
p = builder_add_packet (sb,
|
|
PINOS_PACKET_TYPE_REUSE_MEM,
|
|
sizeof (PinosPacketReuseMem));
|
|
memcpy (p, payload, sizeof (*payload));
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
/**
|
|
* pinos_buffer_iter_parse_format_change:
|
|
* @iter: a #PinosBufferIter
|
|
* @payload: a #PinosPacketFormatChange
|
|
*
|
|
* Parse a #PINOS_PACKET_TYPE_FORMAT_CHANGE packet from @iter into @payload.
|
|
*
|
|
* Returns: %TRUE on success
|
|
*/
|
|
gboolean
|
|
pinos_buffer_iter_parse_format_change (PinosBufferIter *iter,
|
|
PinosPacketFormatChange *payload)
|
|
{
|
|
struct stack_iter *si = PPSI (iter);
|
|
char *p;
|
|
|
|
g_return_val_if_fail (is_valid_iter (iter), FALSE);
|
|
g_return_val_if_fail (si->type == PINOS_PACKET_TYPE_FORMAT_CHANGE, FALSE);
|
|
|
|
if (si->size < 2)
|
|
return FALSE;
|
|
|
|
p = si->data;
|
|
|
|
payload->id = *p++;
|
|
payload->format = p;
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
/**
|
|
* pinos_buffer_builder_add_format_change:
|
|
* @builder: a #PinosBufferBuilder
|
|
* @payload: a #PinosPacketFormatChange
|
|
*
|
|
* Add a #PINOS_PACKET_TYPE_FORMAT_CHANGE payload in @payload to @builder.
|
|
*
|
|
* Returns: %TRUE on success
|
|
*/
|
|
gboolean
|
|
pinos_buffer_builder_add_format_change (PinosBufferBuilder *builder,
|
|
PinosPacketFormatChange *payload)
|
|
{
|
|
struct stack_builder *sb = PPSB (builder);
|
|
gsize len;
|
|
char *p;
|
|
|
|
g_return_val_if_fail (is_valid_builder (builder), FALSE);
|
|
|
|
/* id + format len + zero byte */
|
|
len = 1 + strlen (payload->format) + 1;
|
|
p = builder_add_packet (sb,
|
|
PINOS_PACKET_TYPE_FORMAT_CHANGE,
|
|
len);
|
|
*p++ = payload->id;
|
|
strcpy (p, payload->format);
|
|
sb->sh->flags |= PINOS_BUFFER_FLAG_CONTROL;
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
/**
|
|
* pinos_buffer_iter_parse_refresh_request:
|
|
* @iter: a #PinosBufferIter
|
|
* @payload: a #PinosPacketRefreshRequest
|
|
*
|
|
* Parse a #PINOS_PACKET_TYPE_REFRESH_REQUEST packet from @iter into @payload.
|
|
*
|
|
* Returns: %TRUE on success.
|
|
*/
|
|
gboolean
|
|
pinos_buffer_iter_parse_refresh_request (PinosBufferIter *iter,
|
|
PinosPacketRefreshRequest *payload)
|
|
{
|
|
struct stack_iter *si = PPSI (iter);
|
|
|
|
g_return_val_if_fail (is_valid_iter (iter), FALSE);
|
|
g_return_val_if_fail (si->type == PINOS_PACKET_TYPE_REFRESH_REQUEST, FALSE);
|
|
|
|
if (si->size < sizeof (PinosPacketRefreshRequest))
|
|
return FALSE;
|
|
|
|
memcpy (payload, si->data, sizeof (*payload));
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
/**
|
|
* pinos_buffer_builder_add_refresh_request:
|
|
* @builder: a #PinosBufferBuilder
|
|
* @payload: a #PinosPacketRefreshRequest
|
|
*
|
|
* Add a #PINOS_PACKET_TYPE_REFRESH_REQUEST payload in @payload to @builder.
|
|
*
|
|
* Returns: %TRUE on success
|
|
*/
|
|
gboolean
|
|
pinos_buffer_builder_add_refresh_request (PinosBufferBuilder *builder,
|
|
PinosPacketRefreshRequest *payload)
|
|
{
|
|
struct stack_builder *sb = PPSB (builder);
|
|
PinosPacketRefreshRequest *p;
|
|
|
|
g_return_val_if_fail (is_valid_builder (builder), FALSE);
|
|
|
|
p = builder_add_packet (sb,
|
|
PINOS_PACKET_TYPE_REFRESH_REQUEST,
|
|
sizeof (PinosPacketRefreshRequest));
|
|
memcpy (p, payload, sizeof (*payload));
|
|
|
|
return TRUE;
|
|
}
|