mirror of
https://gitlab.freedesktop.org/pipewire/pipewire.git
synced 2025-11-26 07:00:13 -05:00
Rework transport protocol
Remove the old PinosBuffer object and replace it with SpaControl, this communication protocol is designed to make it possible to implement remote nodes and so it is moved to Spa. Move SpaBuffer into to API Work on easier API to make formats, implement enumeration and support for all formats in v4l2. Improve format output in -inspect
This commit is contained in:
parent
b795fb851f
commit
4cb90f3b86
37 changed files with 2658 additions and 1032 deletions
|
|
@ -40,8 +40,8 @@ AM_CFLAGS = $(GLIB_CFLAGS) $(GST_CFLAGS)
|
|||
AM_CXXFLAGS = $(AM_CFLAGS)
|
||||
SERVER_CFLAGS = -D__INCLUDED_FROM_PINOS
|
||||
|
||||
AM_LIBADD = $(GLIB_LIBS) $(INTLLIBS) $(GST_LIBS) #$(top_srcdir)/spa/build/lib/libspa-lib.so
|
||||
AM_LDADD = $(GLIB_LIBS) $(GST_LIBS) $(INTLLIBS) #$(top_srcdir)/spa/build/lib/libspa-lib.so
|
||||
AM_LIBADD = $(GLIB_LIBS) $(INTLLIBS) $(GST_LIBS) -L$(top_srcdir)/spa/build/lib/ -lspa-lib
|
||||
AM_LDADD = $(GLIB_LIBS) $(GST_LIBS) $(INTLLIBS) -L$(top_srcdir)/spa/build/lib/ -lspa-lib
|
||||
AM_LDFLAGS = $(NODELETE_LDFLAGS)
|
||||
|
||||
FOREIGN_CFLAGS = -w
|
||||
|
|
@ -161,9 +161,7 @@ pinos_monitor_LDFLAGS = $(AM_LDFLAGS) $(BINLDFLAGS)
|
|||
# Client library #
|
||||
###################################
|
||||
|
||||
pinosgstsource = gst/gstpinospay.h gst/gstpinospay.c \
|
||||
gst/gstpinosdepay.h gst/gstpinosdepay.c \
|
||||
gst/gsttmpfileallocator.h gst/gsttmpfileallocator.c
|
||||
pinosgstsource = gst/gsttmpfileallocator.h gst/gsttmpfileallocator.c
|
||||
|
||||
pinosinclude_HEADERS = \
|
||||
client/buffer.h \
|
||||
|
|
@ -227,8 +225,8 @@ libpinoscore_@PINOS_MAJORMINOR@_la_SOURCES = \
|
|||
|
||||
libpinoscore_@PINOS_MAJORMINOR@_la_CFLAGS = $(AM_CFLAGS) $(SERVER_CFLAGS)
|
||||
libpinoscore_@PINOS_MAJORMINOR@_la_LDFLAGS = $(AM_LDFLAGS) -avoid-version
|
||||
libpinoscore_@PINOS_MAJORMINOR@_la_LIBADD = $(AM_LIBADD) $(LIBLTDL) $(LTLIBICONV) \
|
||||
libpinos-@PINOS_MAJORMINOR@.la
|
||||
libpinoscore_@PINOS_MAJORMINOR@_la_LIBADD = $(LIBLTDL) $(LTLIBICONV) \
|
||||
libpinos-@PINOS_MAJORMINOR@.la $(AM_LIBADD)
|
||||
|
||||
###################################
|
||||
# GStreamer Plugin #
|
||||
|
|
@ -241,19 +239,19 @@ plugin_LTLIBRARIES = libgstpinos.la
|
|||
libgstpinos_la_SOURCES = \
|
||||
gst/gstburstcache.c \
|
||||
gst/gstpinos.c \
|
||||
gst/gstpinossocketsink.c \
|
||||
gst/gstpinosportsink.c \
|
||||
gst/gstpinosportsrc.c \
|
||||
gst/gstpinospay.c \
|
||||
gst/gstpinosdepay.c \
|
||||
gst/gstpinosdeviceprovider.c \
|
||||
gst/gstpinossrc.c \
|
||||
gst/gstpinossink.c
|
||||
#gst/gstpinosdepay.c
|
||||
#gst/gstpinosportsrc.c
|
||||
#gst/gstpinosportsink.c
|
||||
#gst/gstpinossocketsink.c
|
||||
#gst/gstpinospay.c
|
||||
|
||||
libgstpinos_la_CFLAGS = $(GST_PLUGINS_BASE_CFLAGS) $(GST_BASE_CFLAGS) $(GST_CFLAGS) $(GLIB_CFLAGS)
|
||||
libgstpinos_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS)
|
||||
libgstpinos_la_LDFLAGS = $(AM_LDFLAGS) $(GST_PLUGIN_LDFLAGS)
|
||||
libgstpinos_la_LIBADD = $(GST_BASE_LIBS) $(GST_LIBS) $(GLIB_LIBS) $(LIBM) -lgstvideo-1.0 \
|
||||
libpinos-@PINOS_MAJORMINOR@.la libpinoscore-@PINOS_MAJORMINOR@.la
|
||||
libpinos-@PINOS_MAJORMINOR@.la libpinoscore-@PINOS_MAJORMINOR@.la $(AM_LIBADD)
|
||||
libgstpinos_la_LIBTOOLFLAGS = $(GST_PLUGIN_LIBTOOLFLAGS)
|
||||
|
||||
noinst_HEADERS = gst/gstburstcache.h gst/gstpinossrc.h \
|
||||
|
|
|
|||
|
|
@ -21,6 +21,7 @@
|
|||
|
||||
#include <gio/gio.h>
|
||||
|
||||
#if 0
|
||||
#include "pinos/client/properties.h"
|
||||
#include "pinos/client/context.h"
|
||||
#include "pinos/client/buffer.h"
|
||||
|
|
@ -1032,3 +1033,4 @@ pinos_buffer_builder_add_refresh_request (PinosBufferBuilder *builder,
|
|||
|
||||
return TRUE;
|
||||
}
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -26,6 +26,7 @@
|
|||
G_BEGIN_DECLS
|
||||
|
||||
typedef struct _PinosBuffer PinosBuffer;
|
||||
#if 0
|
||||
typedef struct _PinosBufferIter PinosBufferIter;
|
||||
typedef struct _PinosBufferBuilder PinosBufferBuilder;
|
||||
|
||||
|
|
@ -329,4 +330,5 @@ gboolean pinos_buffer_builder_add_refresh_request (PinosBufferBuilder
|
|||
PinosPacketRefreshRequest *payload);
|
||||
|
||||
|
||||
#endif
|
||||
#endif /* __PINOS_BUFFER_H__ */
|
||||
|
|
|
|||
|
|
@ -26,6 +26,7 @@
|
|||
#include "pinos/client/pinos.h"
|
||||
#include "pinos/client/private.h"
|
||||
|
||||
#if 0
|
||||
gboolean
|
||||
pinos_io_read_buffer (int fd,
|
||||
PinosBuffer *buffer,
|
||||
|
|
@ -177,3 +178,4 @@ send_error:
|
|||
return FALSE;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -57,6 +57,7 @@ GDBusProxy * pinos_subscribe_get_proxy_finish (PinosSubscribe *subsc
|
|||
GError **error);
|
||||
|
||||
|
||||
#if 0
|
||||
typedef struct {
|
||||
guint32 version;
|
||||
guint32 flags;
|
||||
|
|
@ -92,3 +93,4 @@ gboolean pinos_io_read_buffer (int fd,
|
|||
gboolean pinos_io_write_buffer (int fd,
|
||||
PinosBuffer *buffer,
|
||||
GError **error);
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -31,10 +31,37 @@
|
|||
#include "pinos/client/enumtypes.h"
|
||||
|
||||
#include "pinos/client/private.h"
|
||||
#include "spa/include/spa/control.h"
|
||||
|
||||
#define MAX_BUFFER_SIZE 1024
|
||||
#define MAX_FDS 16
|
||||
|
||||
typedef struct {
|
||||
bool cleanup;
|
||||
uint32_t id;
|
||||
int fd;
|
||||
} MemId;
|
||||
|
||||
static void
|
||||
clear_mem_id (MemId *id)
|
||||
{
|
||||
close (id->fd);
|
||||
id->fd = -1;
|
||||
}
|
||||
|
||||
typedef struct {
|
||||
bool cleanup;
|
||||
uint32_t id;
|
||||
SpaBuffer *buf;
|
||||
} BufferId;
|
||||
|
||||
static void
|
||||
clear_buffer_id (BufferId *id)
|
||||
{
|
||||
spa_buffer_unref (id->buf);
|
||||
id->buf = NULL;
|
||||
}
|
||||
|
||||
struct _PinosStreamPrivate
|
||||
{
|
||||
PinosContext *context;
|
||||
|
|
@ -61,15 +88,18 @@ struct _PinosStreamPrivate
|
|||
GSource *socket_source;
|
||||
int fd;
|
||||
|
||||
PinosBuffer *buffer;
|
||||
PinosBuffer recv_buffer;
|
||||
SpaBuffer *buffer;
|
||||
|
||||
SpaControl *control;
|
||||
SpaControl recv_control;
|
||||
guint8 recv_data[MAX_BUFFER_SIZE];
|
||||
int recv_fds[MAX_FDS];
|
||||
|
||||
guint8 send_data[MAX_BUFFER_SIZE];
|
||||
int send_fds[MAX_FDS];
|
||||
|
||||
GHashTable *mem_ids;
|
||||
GArray *mem_ids;
|
||||
GArray *buffer_ids;
|
||||
};
|
||||
|
||||
#define PINOS_STREAM_GET_PRIVATE(obj) \
|
||||
|
|
@ -260,9 +290,6 @@ pinos_stream_finalize (GObject * object)
|
|||
g_bytes_unref (priv->format);
|
||||
|
||||
g_free (priv->path);
|
||||
if (priv->possible_formats)
|
||||
g_bytes_unref (priv->possible_formats);
|
||||
|
||||
g_clear_error (&priv->error);
|
||||
|
||||
if (priv->properties)
|
||||
|
|
@ -397,6 +424,10 @@ pinos_stream_init (PinosStream * stream)
|
|||
g_debug ("new stream %p", stream);
|
||||
|
||||
priv->state = PINOS_STREAM_STATE_UNCONNECTED;
|
||||
priv->mem_ids = g_array_sized_new (FALSE, FALSE, sizeof (MemId), 64);
|
||||
g_array_set_clear_func (priv->mem_ids, (GDestroyNotify) clear_mem_id);
|
||||
priv->buffer_ids = g_array_sized_new (FALSE, FALSE, sizeof (BufferId), 64);
|
||||
g_array_set_clear_func (priv->buffer_ids, (GDestroyNotify) clear_buffer_id);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -487,86 +518,224 @@ pinos_stream_get_error (PinosStream *stream)
|
|||
return stream->priv->error;
|
||||
}
|
||||
|
||||
static void
|
||||
send_need_input (PinosStream *stream, uint32_t port)
|
||||
{
|
||||
PinosStreamPrivate *priv = stream->priv;
|
||||
SpaControlBuilder builder;
|
||||
SpaControl control;
|
||||
guint8 buffer[64];
|
||||
SpaControlCmdNeedInput ni;
|
||||
|
||||
spa_control_builder_init_into (&builder, buffer, 64, NULL, 0);
|
||||
ni.port = port;
|
||||
spa_control_builder_add_cmd (&builder, SPA_CONTROL_CMD_NEED_INPUT, &ni);
|
||||
spa_control_builder_end (&builder, &control);
|
||||
|
||||
if (spa_control_write (&control, priv->fd) < 0)
|
||||
g_warning ("stream %p: error writing control", stream);
|
||||
}
|
||||
|
||||
static BufferId *
|
||||
find_buffer (PinosStream *stream, uint32_t id)
|
||||
{
|
||||
PinosStreamPrivate *priv = stream->priv;
|
||||
guint i;
|
||||
for (i = 0; i < priv->buffer_ids->len; i++) {
|
||||
BufferId *bid = &g_array_index (priv->buffer_ids, BufferId, i);
|
||||
if (bid->id == id)
|
||||
return bid;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static MemId *
|
||||
find_mem (PinosStream *stream, uint32_t id)
|
||||
{
|
||||
PinosStreamPrivate *priv = stream->priv;
|
||||
guint i;
|
||||
for (i = 0; i < priv->mem_ids->len; i++) {
|
||||
MemId *mid = &g_array_index (priv->mem_ids, MemId, i);
|
||||
if (mid->id == id)
|
||||
return mid;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
parse_buffer (PinosStream *stream,
|
||||
PinosBuffer *pbuf)
|
||||
parse_control (PinosStream *stream,
|
||||
SpaControl *ctrl)
|
||||
{
|
||||
PinosBufferIter it;
|
||||
SpaControlIter it;
|
||||
PinosStreamPrivate *priv = stream->priv;
|
||||
|
||||
pinos_buffer_iter_init (&it, pbuf);
|
||||
while (pinos_buffer_iter_next (&it)) {
|
||||
PinosPacketType type = pinos_buffer_iter_get_type (&it);
|
||||
spa_control_iter_init (&it, ctrl);
|
||||
while (spa_control_iter_next (&it) == SPA_RESULT_OK) {
|
||||
SpaControlCmd cmd = spa_control_iter_get_cmd (&it);
|
||||
|
||||
switch (type) {
|
||||
case PINOS_PACKET_TYPE_ADD_MEM:
|
||||
{
|
||||
PinosPacketAddMem p;
|
||||
int fd;
|
||||
|
||||
if (!pinos_buffer_iter_parse_add_mem (&it, &p))
|
||||
break;
|
||||
|
||||
fd = pinos_buffer_get_fd (pbuf, p.fd_index);
|
||||
if (fd == -1)
|
||||
break;
|
||||
|
||||
// g_hash_table_insert (priv->mem_ids, GINT_TO_POINTER (p.id), NULL);
|
||||
switch (cmd) {
|
||||
case SPA_CONTROL_CMD_NODE_UPDATE:
|
||||
case SPA_CONTROL_CMD_PORT_UPDATE:
|
||||
case SPA_CONTROL_CMD_PORT_REMOVED:
|
||||
case SPA_CONTROL_CMD_START_CONFIGURE:
|
||||
case SPA_CONTROL_CMD_PORT_STATUS_CHANGE:
|
||||
case SPA_CONTROL_CMD_START_ALLOC:
|
||||
case SPA_CONTROL_CMD_NEED_INPUT:
|
||||
case SPA_CONTROL_CMD_HAVE_OUTPUT:
|
||||
g_warning ("got unexpected control %d", cmd);
|
||||
break;
|
||||
}
|
||||
case PINOS_PACKET_TYPE_REMOVE_MEM:
|
||||
{
|
||||
PinosPacketRemoveMem p;
|
||||
|
||||
if (!pinos_buffer_iter_parse_remove_mem (&it, &p))
|
||||
break;
|
||||
|
||||
// g_hash_table_remove (priv->mem_ids, GINT_TO_POINTER (p.id));
|
||||
case SPA_CONTROL_CMD_ADD_PORT:
|
||||
case SPA_CONTROL_CMD_REMOVE_PORT:
|
||||
g_warning ("add/remove port not supported");
|
||||
break;
|
||||
}
|
||||
case PINOS_PACKET_TYPE_FORMAT_CHANGE:
|
||||
{
|
||||
PinosPacketFormatChange p;
|
||||
|
||||
if (!pinos_buffer_iter_parse_format_change (&it, &p))
|
||||
case SPA_CONTROL_CMD_SET_FORMAT:
|
||||
{
|
||||
SpaControlCmdSetFormat p;
|
||||
|
||||
if (spa_control_iter_parse_cmd (&it, &p) < 0)
|
||||
break;
|
||||
|
||||
if (priv->format)
|
||||
g_bytes_unref (priv->format);
|
||||
priv->format = g_bytes_new (p.format, strlen (p.format) + 1);
|
||||
priv->format = g_bytes_new (p.str, strlen (p.str) + 1);
|
||||
g_object_notify (G_OBJECT (stream), "format");
|
||||
break;
|
||||
}
|
||||
case PINOS_PACKET_TYPE_STREAMING:
|
||||
case SPA_CONTROL_CMD_SET_PROPERTY:
|
||||
g_warning ("set property not implemented");
|
||||
break;
|
||||
|
||||
case SPA_CONTROL_CMD_END_CONFIGURE:
|
||||
{
|
||||
SpaControlBuilder builder;
|
||||
SpaControl control;
|
||||
guint8 buffer[1024];
|
||||
|
||||
/* FIXME send update port status */
|
||||
/* send start-alloc */
|
||||
spa_control_builder_init_into (&builder, buffer, 1024, NULL, 0);
|
||||
spa_control_builder_add_cmd (&builder, SPA_CONTROL_CMD_START_ALLOC, NULL);
|
||||
spa_control_builder_end (&builder, &control);
|
||||
|
||||
if (spa_control_write (&control, priv->fd) < 0)
|
||||
g_warning ("stream %p: error writing control", stream);
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case SPA_CONTROL_CMD_PAUSE:
|
||||
break;
|
||||
case SPA_CONTROL_CMD_START:
|
||||
{
|
||||
if (priv->direction == PINOS_DIRECTION_INPUT)
|
||||
send_need_input (stream, 0);
|
||||
|
||||
stream_set_state (stream, PINOS_STREAM_STATE_STREAMING, NULL);
|
||||
break;
|
||||
}
|
||||
case PINOS_PACKET_TYPE_STOPPED:
|
||||
case SPA_CONTROL_CMD_STOP:
|
||||
{
|
||||
unhandle_socket (stream);
|
||||
|
||||
g_clear_pointer (&priv->format, g_bytes_unref);
|
||||
g_object_notify (G_OBJECT (stream), "format");
|
||||
|
||||
stream_set_state (stream, PINOS_STREAM_STATE_READY, NULL);
|
||||
break;
|
||||
}
|
||||
case PINOS_PACKET_TYPE_HEADER:
|
||||
|
||||
case SPA_CONTROL_CMD_ADD_MEM:
|
||||
{
|
||||
SpaControlCmdAddMem p;
|
||||
MemId mid;
|
||||
int fd;
|
||||
|
||||
if (spa_control_iter_parse_cmd (&it, &p) < 0)
|
||||
break;
|
||||
|
||||
fd = spa_control_get_fd (ctrl, p.fd_index, false);
|
||||
if (fd == -1)
|
||||
break;
|
||||
|
||||
mid.cleanup = false;
|
||||
mid.id = p.id;
|
||||
mid.fd = fd;
|
||||
g_array_append_val (priv->mem_ids, mid);
|
||||
break;
|
||||
}
|
||||
case PINOS_PACKET_TYPE_PROCESS_MEM:
|
||||
case SPA_CONTROL_CMD_REMOVE_MEM:
|
||||
{
|
||||
SpaControlCmdRemoveMem p;
|
||||
MemId *mid;
|
||||
|
||||
if (spa_control_iter_parse_cmd (&it, &p) < 0)
|
||||
break;
|
||||
|
||||
if ((mid = find_mem (stream, p.id)))
|
||||
mid->cleanup = true;
|
||||
break;
|
||||
}
|
||||
default:
|
||||
g_warning ("unhandled packet %d", type);
|
||||
case SPA_CONTROL_CMD_ADD_BUFFER:
|
||||
{
|
||||
SpaControlCmdAddBuffer p;
|
||||
BufferId bid;
|
||||
|
||||
if (spa_control_iter_parse_cmd (&it, &p) < 0)
|
||||
break;
|
||||
|
||||
bid.cleanup = false;
|
||||
bid.id = p.buffer->id;
|
||||
bid.buf = p.buffer;
|
||||
g_array_append_val (priv->buffer_ids, bid);
|
||||
break;
|
||||
}
|
||||
case SPA_CONTROL_CMD_REMOVE_BUFFER:
|
||||
{
|
||||
SpaControlCmdRemoveBuffer p;
|
||||
BufferId *bid;
|
||||
|
||||
if (spa_control_iter_parse_cmd (&it, &p) < 0)
|
||||
break;
|
||||
|
||||
if ((bid = find_buffer (stream, p.id)))
|
||||
bid->cleanup = true;
|
||||
break;
|
||||
}
|
||||
case SPA_CONTROL_CMD_PROCESS_BUFFER:
|
||||
{
|
||||
SpaControlCmdProcessBuffer p;
|
||||
unsigned int i;
|
||||
BufferId *bid;
|
||||
|
||||
if (spa_control_iter_parse_cmd (&it, &p) < 0)
|
||||
break;
|
||||
|
||||
if ((bid = find_buffer (stream, p.id))) {
|
||||
SpaBuffer *b = bid->buf;
|
||||
|
||||
for (i = 0; i < b->n_datas; i++) {
|
||||
SpaData *d = &b->datas[i];
|
||||
|
||||
if (d->type == SPA_DATA_TYPE_MEMID) {
|
||||
int id = *((int*)(d->ptr));
|
||||
MemId *mid;
|
||||
|
||||
if ((mid = find_mem (stream, id))) {
|
||||
d->type = SPA_DATA_TYPE_FD;
|
||||
*((int *)(d->ptr)) = mid->fd;
|
||||
}
|
||||
}
|
||||
}
|
||||
priv->buffer = b;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case SPA_CONTROL_CMD_REUSE_BUFFER:
|
||||
break;
|
||||
|
||||
case SPA_CONTROL_CMD_INVALID:
|
||||
g_warning ("unhandled command %d", cmd);
|
||||
break;
|
||||
}
|
||||
}
|
||||
pinos_buffer_iter_end (&it);
|
||||
spa_control_iter_end (&it);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
|
@ -582,28 +751,41 @@ on_socket_condition (GSocket *socket,
|
|||
switch (condition) {
|
||||
case G_IO_IN:
|
||||
{
|
||||
PinosBuffer *buffer = &priv->recv_buffer;
|
||||
GError *error = NULL;
|
||||
SpaControl *control = &priv->recv_control;
|
||||
guint i;
|
||||
|
||||
if (!pinos_io_read_buffer (priv->fd,
|
||||
buffer,
|
||||
priv->recv_data,
|
||||
MAX_BUFFER_SIZE,
|
||||
priv->recv_fds,
|
||||
MAX_FDS,
|
||||
&error)) {
|
||||
g_warning ("stream %p: failed to read buffer: %s", stream, error->message);
|
||||
g_clear_error (&error);
|
||||
if (spa_control_read (control,
|
||||
priv->fd,
|
||||
priv->recv_data,
|
||||
MAX_BUFFER_SIZE,
|
||||
priv->recv_fds,
|
||||
MAX_FDS) < 0) {
|
||||
g_warning ("stream %p: failed to read buffer", stream);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
parse_buffer (stream, buffer);
|
||||
parse_control (stream, control);
|
||||
|
||||
priv->buffer = buffer;
|
||||
g_signal_emit (stream, signals[SIGNAL_NEW_BUFFER], 0, NULL);
|
||||
priv->buffer = NULL;
|
||||
|
||||
g_assert (pinos_buffer_unref (buffer) == FALSE);
|
||||
if (priv->buffer) {
|
||||
g_signal_emit (stream, signals[SIGNAL_NEW_BUFFER], 0, NULL);
|
||||
priv->buffer = NULL;
|
||||
send_need_input (stream, 0);
|
||||
}
|
||||
for (i = 0; i < priv->mem_ids->len; i++) {
|
||||
MemId *mid = &g_array_index (priv->mem_ids, MemId, i);
|
||||
if (mid->cleanup) {
|
||||
g_array_remove_index_fast (priv->mem_ids, i);
|
||||
i--;
|
||||
}
|
||||
}
|
||||
for (i = 0; i < priv->buffer_ids->len; i++) {
|
||||
BufferId *bid = &g_array_index (priv->buffer_ids, BufferId, i);
|
||||
if (bid->cleanup) {
|
||||
g_array_remove_index_fast (priv->buffer_ids, i);
|
||||
i--;
|
||||
}
|
||||
}
|
||||
spa_control_clear (control);
|
||||
break;
|
||||
}
|
||||
|
||||
|
|
@ -851,29 +1033,39 @@ pinos_stream_connect (PinosStream *stream,
|
|||
return TRUE;
|
||||
}
|
||||
|
||||
static void
|
||||
control_builder_init (PinosStream *stream, SpaControlBuilder *builder)
|
||||
{
|
||||
PinosStreamPrivate *priv = stream->priv;
|
||||
|
||||
spa_control_builder_init_into (builder,
|
||||
priv->send_data,
|
||||
MAX_BUFFER_SIZE,
|
||||
priv->send_fds,
|
||||
MAX_FDS);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
do_start (PinosStream *stream)
|
||||
{
|
||||
PinosStreamPrivate *priv = stream->priv;
|
||||
PinosBufferBuilder builder;
|
||||
PinosPacketFormatChange fc;
|
||||
PinosBuffer pbuf;
|
||||
GError *error = NULL;
|
||||
SpaControlBuilder builder;
|
||||
SpaControlCmdPortUpdate pu;
|
||||
SpaControl control;
|
||||
|
||||
handle_socket (stream, priv->fd);
|
||||
|
||||
pinos_stream_buffer_builder_init (stream, &builder);
|
||||
fc.port = 0;
|
||||
fc.id = 0;
|
||||
fc.format = priv->format ? g_bytes_get_data (priv->format, NULL) : "ANY";
|
||||
pinos_buffer_builder_add_format_change (&builder, &fc);
|
||||
pinos_buffer_builder_add_empty (&builder, PINOS_PACKET_TYPE_START);
|
||||
pinos_buffer_builder_end (&builder, &pbuf);
|
||||
control_builder_init (stream, &builder);
|
||||
pu.port = 0;
|
||||
pu.change_mask = 0;
|
||||
|
||||
spa_control_builder_add_cmd (&builder, SPA_CONTROL_CMD_PORT_UPDATE, &pu);
|
||||
spa_control_builder_add_cmd (&builder, SPA_CONTROL_CMD_START_CONFIGURE, NULL);
|
||||
spa_control_builder_end (&builder, &control);
|
||||
|
||||
if (spa_control_write (&control, priv->fd) < 0)
|
||||
g_warning ("stream %p: failed to write control", stream);
|
||||
|
||||
if (!pinos_io_write_buffer (priv->fd, &pbuf, &error)) {
|
||||
g_warning ("stream %p: failed to read buffer: %s", stream, error->message);
|
||||
g_clear_error (&error);
|
||||
}
|
||||
g_object_unref (stream);
|
||||
|
||||
return FALSE;
|
||||
|
|
@ -923,10 +1115,10 @@ pinos_stream_start (PinosStream *stream,
|
|||
static gboolean
|
||||
do_stop (PinosStream *stream)
|
||||
{
|
||||
PinosBufferBuilder builder;
|
||||
SpaControlBuilder builder;
|
||||
|
||||
pinos_stream_buffer_builder_init (stream, &builder);
|
||||
pinos_buffer_builder_add_empty (&builder, PINOS_PACKET_TYPE_STOP);
|
||||
control_builder_init (stream, &builder);
|
||||
spa_control_builder_add_cmd (&builder, SPA_CONTROL_CMD_STOP, NULL);
|
||||
g_object_unref (stream);
|
||||
|
||||
return FALSE;
|
||||
|
|
@ -1048,9 +1240,9 @@ pinos_stream_disconnect (PinosStream *stream)
|
|||
* Get the current buffer from @stream. This function should be called from
|
||||
* the new-buffer signal callback.
|
||||
*
|
||||
* Returns: a #PinosBuffer or %NULL when there is no buffer.
|
||||
* Returns: a #SpaBuffer or %NULL when there is no buffer.
|
||||
*/
|
||||
PinosBuffer *
|
||||
SpaBuffer *
|
||||
pinos_stream_peek_buffer (PinosStream *stream)
|
||||
{
|
||||
PinosStreamPrivate *priv;
|
||||
|
|
@ -1058,37 +1250,13 @@ pinos_stream_peek_buffer (PinosStream *stream)
|
|||
g_return_val_if_fail (PINOS_IS_STREAM (stream), NULL);
|
||||
priv = stream->priv;
|
||||
|
||||
return priv->buffer;
|
||||
}
|
||||
|
||||
/**
|
||||
* pinos_stream_buffer_builder_init:
|
||||
* @stream: a #PinosStream
|
||||
* @builder: a #PinosBufferBuilder
|
||||
*
|
||||
* Get a #PinosBufferBuilder for @stream.
|
||||
*
|
||||
* Returns: a #PinosBuffer or %NULL when there is no buffer.
|
||||
*/
|
||||
void
|
||||
pinos_stream_buffer_builder_init (PinosStream *stream, PinosBufferBuilder *builder)
|
||||
{
|
||||
PinosStreamPrivate *priv;
|
||||
|
||||
g_return_if_fail (PINOS_IS_STREAM (stream));
|
||||
priv = stream->priv;
|
||||
|
||||
pinos_buffer_builder_init_into (builder,
|
||||
priv->send_data,
|
||||
MAX_BUFFER_SIZE,
|
||||
priv->send_fds,
|
||||
MAX_FDS);
|
||||
return spa_buffer_ref (priv->buffer);
|
||||
}
|
||||
|
||||
/**
|
||||
* pinos_stream_send_buffer:
|
||||
* @stream: a #PinosStream
|
||||
* @buffer: a #PinosBuffer
|
||||
* @buffer: a #SpaBuffer
|
||||
*
|
||||
* Send a buffer to @stream.
|
||||
*
|
||||
|
|
@ -1102,20 +1270,17 @@ pinos_stream_buffer_builder_init (PinosStream *stream, PinosBufferBuilder *buil
|
|||
*/
|
||||
gboolean
|
||||
pinos_stream_send_buffer (PinosStream *stream,
|
||||
PinosBuffer *buffer)
|
||||
SpaBuffer *buffer)
|
||||
{
|
||||
PinosStreamPrivate *priv;
|
||||
GError *error = NULL;
|
||||
|
||||
g_return_val_if_fail (PINOS_IS_STREAM (stream), FALSE);
|
||||
g_return_val_if_fail (buffer != NULL, FALSE);
|
||||
|
||||
priv = stream->priv;
|
||||
|
||||
if (!pinos_io_write_buffer (priv->fd, buffer, &error)) {
|
||||
#if 0
|
||||
if (!spa_control_write (priv->fd, buffer, &error)) {
|
||||
g_warning ("stream %p: failed to write buffer: %s", stream, error->message);
|
||||
g_clear_error (&error);
|
||||
return FALSE;
|
||||
}
|
||||
#endif
|
||||
return TRUE;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -24,6 +24,7 @@
|
|||
|
||||
#include <pinos/client/buffer.h>
|
||||
#include <pinos/client/context.h>
|
||||
#include <spa/include/spa/buffer.h>
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
|
|
@ -105,12 +106,9 @@ gboolean pinos_stream_start (PinosStream *stream,
|
|||
PinosStreamMode mode);
|
||||
gboolean pinos_stream_stop (PinosStream *stream);
|
||||
|
||||
PinosBuffer * pinos_stream_peek_buffer (PinosStream *stream);
|
||||
void pinos_stream_buffer_builder_init (PinosStream *stream,
|
||||
PinosBufferBuilder *builder);
|
||||
SpaBuffer * pinos_stream_peek_buffer (PinosStream *stream);
|
||||
gboolean pinos_stream_send_buffer (PinosStream *stream,
|
||||
PinosBuffer *buffer);
|
||||
|
||||
SpaBuffer *buffer);
|
||||
G_END_DECLS
|
||||
|
||||
#endif /* __PINOS_STREAM_H__ */
|
||||
|
|
|
|||
|
|
@ -32,7 +32,7 @@
|
|||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#include "gstpinossocketsink.h"
|
||||
//#include "gstpinossocketsink.h"
|
||||
#include "gstpinosportsink.h"
|
||||
#include "gstpinosportsrc.h"
|
||||
#include "gstpinossrc.h"
|
||||
|
|
@ -46,20 +46,20 @@ GST_DEBUG_CATEGORY (pinos_debug);
|
|||
static gboolean
|
||||
plugin_init (GstPlugin * plugin)
|
||||
{
|
||||
gst_element_register (plugin, "pinospay", GST_RANK_NONE,
|
||||
GST_TYPE_PINOS_PAY);
|
||||
gst_element_register (plugin, "pinosdepay", GST_RANK_NONE,
|
||||
GST_TYPE_PINOS_DEPAY);
|
||||
// gst_element_register (plugin, "pinospay", GST_RANK_NONE,
|
||||
// GST_TYPE_PINOS_PAY);
|
||||
// gst_element_register (plugin, "pinosdepay", GST_RANK_NONE,
|
||||
// GST_TYPE_PINOS_DEPAY);
|
||||
gst_element_register (plugin, "pinossrc", GST_RANK_PRIMARY + 1,
|
||||
GST_TYPE_PINOS_SRC);
|
||||
gst_element_register (plugin, "pinossink", GST_RANK_NONE,
|
||||
GST_TYPE_PINOS_SINK);
|
||||
gst_element_register (plugin, "pinossocketsink", GST_RANK_NONE,
|
||||
GST_TYPE_PINOS_SOCKET_SINK);
|
||||
gst_element_register (plugin, "pinosportsink", GST_RANK_NONE,
|
||||
GST_TYPE_PINOS_PORT_SINK);
|
||||
gst_element_register (plugin, "pinosportsrc", GST_RANK_NONE,
|
||||
GST_TYPE_PINOS_PORT_SRC);
|
||||
// gst_element_register (plugin, "pinossocketsink", GST_RANK_NONE,
|
||||
// GST_TYPE_PINOS_SOCKET_SINK);
|
||||
// gst_element_register (plugin, "pinosportsink", GST_RANK_NONE,
|
||||
// GST_TYPE_PINOS_PORT_SINK);
|
||||
// gst_element_register (plugin, "pinosportsrc", GST_RANK_NONE,
|
||||
// GST_TYPE_PINOS_PORT_SRC);
|
||||
|
||||
if (!gst_device_provider_register (plugin, "pinosdeviceprovider",
|
||||
GST_RANK_PRIMARY + 1, GST_TYPE_PINOS_DEVICE_PROVIDER))
|
||||
|
|
|
|||
|
|
@ -43,6 +43,8 @@
|
|||
#include <gst/allocators/gstfdmemory.h>
|
||||
#include <gst/video/video.h>
|
||||
|
||||
#include <spa/include/spa/buffer.h>
|
||||
|
||||
#include "gsttmpfileallocator.h"
|
||||
|
||||
|
||||
|
|
@ -329,8 +331,7 @@ on_new_buffer (GObject *gobject,
|
|||
gpointer user_data)
|
||||
{
|
||||
GstPinosSink *pinossink = user_data;
|
||||
PinosBuffer *pbuf;
|
||||
PinosBufferIter it;
|
||||
SpaBuffer *b;
|
||||
|
||||
GST_LOG_OBJECT (pinossink, "got new buffer");
|
||||
if (pinossink->stream == NULL) {
|
||||
|
|
@ -338,11 +339,12 @@ on_new_buffer (GObject *gobject,
|
|||
return;
|
||||
}
|
||||
|
||||
if (!(pbuf = pinos_stream_peek_buffer (pinossink->stream))) {
|
||||
if (!(b = pinos_stream_peek_buffer (pinossink->stream))) {
|
||||
g_warning ("failed to capture buffer");
|
||||
return;
|
||||
}
|
||||
|
||||
#if 0
|
||||
pinos_buffer_iter_init (&it, pbuf);
|
||||
while (pinos_buffer_iter_next (&it)) {
|
||||
switch (pinos_buffer_iter_get_type (&it)) {
|
||||
|
|
@ -375,6 +377,7 @@ on_new_buffer (GObject *gobject,
|
|||
}
|
||||
}
|
||||
pinos_buffer_iter_end (&it);
|
||||
#endif
|
||||
}
|
||||
|
||||
static void
|
||||
|
|
@ -483,18 +486,32 @@ start_error:
|
|||
}
|
||||
}
|
||||
|
||||
typedef struct {
|
||||
SpaBuffer buffer;
|
||||
SpaMeta metas[1];
|
||||
SpaMetaHeader header;
|
||||
SpaData datas[1];
|
||||
GstMemory *mem;
|
||||
GstPinosSink *pinossink;
|
||||
int fd;
|
||||
} SinkBuffer;
|
||||
|
||||
static void
|
||||
sink_buffer_free (void *user_data)
|
||||
{
|
||||
SinkBuffer *b = user_data;
|
||||
gst_memory_unref (b->mem);
|
||||
gst_object_unref (b->pinossink);
|
||||
g_slice_free (SinkBuffer, user_data);
|
||||
}
|
||||
|
||||
static GstFlowReturn
|
||||
gst_pinos_sink_render (GstBaseSink * bsink, GstBuffer * buffer)
|
||||
{
|
||||
GstPinosSink *pinossink;
|
||||
PinosBuffer pbuf;
|
||||
PinosBufferBuilder builder;
|
||||
SinkBuffer *b;
|
||||
GstMemory *mem = NULL;
|
||||
GstClockTime pts, dts, base;
|
||||
PinosPacketHeader hdr;
|
||||
PinosPacketAddMem am;
|
||||
PinosPacketProcessMem p;
|
||||
PinosPacketRemoveMem rm;
|
||||
gsize size;
|
||||
gboolean tmpfile, res;
|
||||
|
||||
|
|
@ -505,6 +522,18 @@ gst_pinos_sink_render (GstBaseSink * bsink, GstBuffer * buffer)
|
|||
|
||||
base = GST_ELEMENT_CAST (bsink)->base_time;
|
||||
|
||||
size = gst_buffer_get_size (buffer);
|
||||
|
||||
b = g_slice_new (SinkBuffer);
|
||||
b->buffer.refcount = 0;
|
||||
b->buffer.notify = sink_buffer_free;
|
||||
b->buffer.id = pinos_fd_manager_get_id (pinossink->fdmanager);
|
||||
b->buffer.size = size;
|
||||
b->buffer.n_metas = 1;
|
||||
b->buffer.metas = b->metas;
|
||||
b->buffer.n_datas = 1;
|
||||
b->buffer.datas = b->datas;
|
||||
|
||||
pts = GST_BUFFER_PTS (buffer);
|
||||
dts = GST_BUFFER_DTS (buffer);
|
||||
if (!GST_CLOCK_TIME_IS_VALID (pts))
|
||||
|
|
@ -512,12 +541,13 @@ gst_pinos_sink_render (GstBaseSink * bsink, GstBuffer * buffer)
|
|||
else if (!GST_CLOCK_TIME_IS_VALID (dts))
|
||||
dts = pts;
|
||||
|
||||
hdr.flags = 0;
|
||||
hdr.seq = GST_BUFFER_OFFSET (buffer);
|
||||
hdr.pts = GST_CLOCK_TIME_IS_VALID (pts) ? pts + base : base;
|
||||
hdr.dts_offset = GST_CLOCK_TIME_IS_VALID (dts) && GST_CLOCK_TIME_IS_VALID (pts) ? pts - dts : 0;
|
||||
|
||||
size = gst_buffer_get_size (buffer);
|
||||
b->header.flags = 0;
|
||||
b->header.seq = GST_BUFFER_OFFSET (buffer);
|
||||
b->header.pts = GST_CLOCK_TIME_IS_VALID (pts) ? pts + base : base;
|
||||
b->header.dts_offset = GST_CLOCK_TIME_IS_VALID (dts) && GST_CLOCK_TIME_IS_VALID (pts) ? pts - dts : 0;
|
||||
b->metas[0].type = SPA_META_TYPE_HEADER;
|
||||
b->metas[0].data = &b->header;
|
||||
b->metas[0].size = sizeof (b->header);
|
||||
|
||||
if (gst_buffer_n_memory (buffer) == 1
|
||||
&& gst_is_fd_memory (gst_buffer_peek_memory (buffer, 0))) {
|
||||
|
|
@ -541,35 +571,22 @@ gst_pinos_sink_render (GstBaseSink * bsink, GstBuffer * buffer)
|
|||
if (pinos_stream_get_state (pinossink->stream) != PINOS_STREAM_STATE_STREAMING)
|
||||
goto streaming_error;
|
||||
|
||||
pinos_stream_buffer_builder_init (pinossink->stream, &builder);
|
||||
pinos_buffer_builder_add_header (&builder, &hdr);
|
||||
b->mem = mem;
|
||||
b->fd = gst_fd_memory_get_fd (mem);
|
||||
b->datas[0].type = SPA_DATA_TYPE_FD;
|
||||
b->datas[0].ptr = &b->fd;
|
||||
b->datas[0].ptr_type = mem->allocator->mem_type;
|
||||
b->datas[0].offset = mem->offset;
|
||||
b->datas[0].size = mem->size;
|
||||
b->datas[0].stride = 0;
|
||||
|
||||
am.id = pinos_fd_manager_get_id (pinossink->fdmanager);
|
||||
am.fd_index = pinos_buffer_builder_add_fd (&builder, gst_fd_memory_get_fd (mem));
|
||||
am.offset = 0;
|
||||
am.size = mem->size + mem->offset;
|
||||
p.port = 0;
|
||||
p.id = am.id;
|
||||
p.offset = mem->offset;
|
||||
p.size = mem->size;
|
||||
rm.id = am.id;
|
||||
pinos_buffer_builder_add_add_mem (&builder, &am);
|
||||
pinos_buffer_builder_add_process_mem (&builder, &p);
|
||||
pinos_buffer_builder_add_remove_mem (&builder, &rm);
|
||||
pinos_buffer_builder_end (&builder, &pbuf);
|
||||
if (!(res = pinos_stream_send_buffer (pinossink->stream, &b->buffer)))
|
||||
g_warning ("can't send buffer");
|
||||
|
||||
GST_LOG ("sending fd mem %d %d", am.id, am.fd_index);
|
||||
|
||||
res = pinos_stream_send_buffer (pinossink->stream, &pbuf);
|
||||
pinos_buffer_steal_fds (&pbuf, NULL);
|
||||
pinos_buffer_unref (&pbuf);
|
||||
pinos_main_loop_unlock (pinossink->loop);
|
||||
|
||||
if (res && !tmpfile) {
|
||||
/* keep the memory around until we get the reuse mem message */
|
||||
g_hash_table_insert (pinossink->mem_ids, GINT_TO_POINTER (p.id), mem);
|
||||
} else
|
||||
gst_memory_unref (mem);
|
||||
/* keep the memory around until we get the reuse mem message */
|
||||
g_hash_table_insert (pinossink->mem_ids, GINT_TO_POINTER (b->buffer.id), b);
|
||||
|
||||
return GST_FLOW_OK;
|
||||
|
||||
|
|
|
|||
|
|
@ -44,6 +44,8 @@
|
|||
#include <gst/allocators/gstfdmemory.h>
|
||||
#include <gst/video/video.h>
|
||||
|
||||
#include <spa/include/spa/buffer.h>
|
||||
|
||||
|
||||
static GQuark process_mem_data_quark;
|
||||
|
||||
|
|
@ -322,35 +324,16 @@ gst_pinos_src_src_fixate (GstBaseSrc * bsrc, GstCaps * caps)
|
|||
|
||||
typedef struct {
|
||||
GstPinosSrc *src;
|
||||
PinosPacketProcessMem p;
|
||||
SpaBuffer *buffer;
|
||||
} ProcessMemData;
|
||||
|
||||
static void
|
||||
process_mem_data_destroy (gpointer user_data)
|
||||
{
|
||||
ProcessMemData *data = user_data;
|
||||
GstPinosSrc *pinossrc = data->src;
|
||||
PinosBufferBuilder b;
|
||||
PinosPacketReuseMem r;
|
||||
PinosBuffer pbuf;
|
||||
|
||||
r.id = data->p.id;
|
||||
|
||||
GST_DEBUG_OBJECT (pinossrc, "destroy %d", r.id);
|
||||
|
||||
GST_OBJECT_LOCK (pinossrc);
|
||||
if (pinossrc->stream_state == PINOS_STREAM_STATE_STREAMING) {
|
||||
pinos_stream_buffer_builder_init (pinossrc->stream, &b);
|
||||
pinos_buffer_builder_add_reuse_mem (&b, &r);
|
||||
pinos_buffer_builder_end (&b, &pbuf);
|
||||
|
||||
GST_DEBUG_OBJECT (pinossrc, "send release-fd for %d", r.id);
|
||||
pinos_stream_send_buffer (pinossrc->stream, &pbuf);
|
||||
pinos_buffer_unref (&pbuf);
|
||||
}
|
||||
GST_OBJECT_UNLOCK (pinossrc);
|
||||
|
||||
gst_object_unref (pinossrc);
|
||||
spa_buffer_unref (data->buffer);
|
||||
gst_object_unref (data->src);
|
||||
g_slice_free (ProcessMemData, data);
|
||||
}
|
||||
|
||||
|
|
@ -359,113 +342,74 @@ on_new_buffer (GObject *gobject,
|
|||
gpointer user_data)
|
||||
{
|
||||
GstPinosSrc *pinossrc = user_data;
|
||||
PinosBuffer *pbuf;
|
||||
PinosBufferIter it;
|
||||
GstBuffer *buf = NULL;
|
||||
SpaBuffer *b;
|
||||
GstBuffer *buf;
|
||||
unsigned int i;
|
||||
ProcessMemData data;
|
||||
|
||||
GST_LOG_OBJECT (pinossrc, "got new buffer");
|
||||
if (!(pbuf = pinos_stream_peek_buffer (pinossrc->stream))) {
|
||||
if (!(b = pinos_stream_peek_buffer (pinossrc->stream))) {
|
||||
g_warning ("failed to capture buffer");
|
||||
return;
|
||||
}
|
||||
|
||||
pinos_buffer_iter_init (&it, pbuf);
|
||||
while (pinos_buffer_iter_next (&it)) {
|
||||
switch (pinos_buffer_iter_get_type (&it)) {
|
||||
case PINOS_PACKET_TYPE_HEADER:
|
||||
buf = gst_buffer_new ();
|
||||
|
||||
data.src = gst_object_ref (pinossrc);
|
||||
data.buffer = b;
|
||||
gst_mini_object_set_qdata (GST_MINI_OBJECT_CAST (buf),
|
||||
process_mem_data_quark,
|
||||
g_slice_dup (ProcessMemData, &data),
|
||||
process_mem_data_destroy);
|
||||
|
||||
for (i = 0; i < b->n_metas; i++) {
|
||||
SpaMeta *m = &b->metas[i];
|
||||
|
||||
switch (m->type) {
|
||||
case SPA_META_TYPE_HEADER:
|
||||
{
|
||||
PinosPacketHeader hdr;
|
||||
SpaMetaHeader *h = m->data;
|
||||
|
||||
if (!pinos_buffer_iter_parse_header (&it, &hdr))
|
||||
goto parse_failed;
|
||||
GST_INFO ("pts %" G_GUINT64_FORMAT ", dts_offset %"G_GUINT64_FORMAT, h->pts, h->dts_offset);
|
||||
|
||||
if (buf == NULL)
|
||||
buf = gst_buffer_new ();
|
||||
|
||||
GST_INFO ("pts %" G_GUINT64_FORMAT ", dts_offset %"G_GUINT64_FORMAT, hdr.pts, hdr.dts_offset);
|
||||
|
||||
if (GST_CLOCK_TIME_IS_VALID (hdr.pts)) {
|
||||
GST_BUFFER_PTS (buf) = hdr.pts;
|
||||
if (GST_BUFFER_PTS (buf) + hdr.dts_offset > 0)
|
||||
GST_BUFFER_DTS (buf) = GST_BUFFER_PTS (buf) + hdr.dts_offset;
|
||||
if (GST_CLOCK_TIME_IS_VALID (h->pts)) {
|
||||
GST_BUFFER_PTS (buf) = h->pts;
|
||||
if (GST_BUFFER_PTS (buf) + h->dts_offset > 0)
|
||||
GST_BUFFER_DTS (buf) = GST_BUFFER_PTS (buf) + h->dts_offset;
|
||||
}
|
||||
GST_BUFFER_OFFSET (buf) = hdr.seq;
|
||||
break;
|
||||
}
|
||||
case PINOS_PACKET_TYPE_ADD_MEM:
|
||||
{
|
||||
GstMemory *fdmem = NULL;
|
||||
PinosPacketAddMem p;
|
||||
int fd;
|
||||
|
||||
if (!pinos_buffer_iter_parse_add_mem (&it, &p))
|
||||
goto parse_failed;
|
||||
|
||||
fd = pinos_buffer_get_fd (pbuf, p.fd_index);
|
||||
if (fd == -1)
|
||||
goto parse_failed;
|
||||
|
||||
fdmem = gst_fd_allocator_alloc (pinossrc->fd_allocator, dup (fd),
|
||||
p.offset + p.size, GST_FD_MEMORY_FLAG_NONE);
|
||||
gst_memory_resize (fdmem, p.offset, p.size);
|
||||
|
||||
g_hash_table_insert (pinossrc->mem_ids, GINT_TO_POINTER (p.id), fdmem);
|
||||
break;
|
||||
}
|
||||
case PINOS_PACKET_TYPE_REMOVE_MEM:
|
||||
{
|
||||
PinosPacketRemoveMem p;
|
||||
|
||||
if (!pinos_buffer_iter_parse_remove_mem (&it, &p))
|
||||
goto parse_failed;
|
||||
|
||||
g_hash_table_remove (pinossrc->mem_ids, GINT_TO_POINTER (p.id));
|
||||
break;
|
||||
}
|
||||
case PINOS_PACKET_TYPE_PROCESS_MEM:
|
||||
{
|
||||
GstMemory *fdmem = NULL;
|
||||
ProcessMemData data;
|
||||
|
||||
if (!pinos_buffer_iter_parse_process_mem (&it, &data.p))
|
||||
goto parse_failed;
|
||||
|
||||
GST_DEBUG ("got mem id %d", data.p.id);
|
||||
if (!(fdmem = g_hash_table_lookup (pinossrc->mem_ids, GINT_TO_POINTER (data.p.id))))
|
||||
goto parse_failed;
|
||||
|
||||
if (buf == NULL)
|
||||
buf = gst_buffer_new ();
|
||||
|
||||
fdmem = gst_memory_share (fdmem, data.p.offset, data.p.size);
|
||||
gst_buffer_append_memory (buf, fdmem);
|
||||
|
||||
data.src = gst_object_ref (pinossrc);
|
||||
gst_mini_object_set_qdata (GST_MINI_OBJECT_CAST (fdmem),
|
||||
process_mem_data_quark,
|
||||
g_slice_dup (ProcessMemData, &data),
|
||||
process_mem_data_destroy);
|
||||
break;
|
||||
}
|
||||
case PINOS_PACKET_TYPE_FORMAT_CHANGE:
|
||||
{
|
||||
PinosPacketFormatChange change;
|
||||
GstCaps *caps;
|
||||
|
||||
if (!pinos_buffer_iter_parse_format_change (&it, &change))
|
||||
goto parse_failed;
|
||||
GST_DEBUG ("got format change %d %s", change.id, change.format);
|
||||
|
||||
caps = gst_caps_from_string (change.format);
|
||||
gst_base_src_set_caps (GST_BASE_SRC (pinossrc), caps);
|
||||
gst_caps_unref (caps);
|
||||
GST_BUFFER_OFFSET (buf) = h->seq;
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
for (i = 0; i < b->n_datas; i++) {
|
||||
SpaData *d = &b->datas[i];
|
||||
|
||||
switch (d->type) {
|
||||
case SPA_DATA_TYPE_MEMPTR:
|
||||
{
|
||||
gst_buffer_append_memory (buf,
|
||||
gst_memory_new_wrapped (0, d->ptr, d->offset + d->size, d->offset,
|
||||
d->size, NULL, NULL));
|
||||
break;
|
||||
}
|
||||
case SPA_DATA_TYPE_FD:
|
||||
{
|
||||
GstMemory *fdmem = NULL;
|
||||
int fd = *((int *) d->ptr);
|
||||
|
||||
fdmem = gst_fd_allocator_alloc (pinossrc->fd_allocator, dup (fd),
|
||||
d->offset + d->size, GST_FD_MEMORY_FLAG_NONE);
|
||||
gst_memory_resize (fdmem, d->offset, d->size);
|
||||
gst_buffer_append_memory (buf, fdmem);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
pinos_buffer_iter_end (&it);
|
||||
|
||||
if (buf) {
|
||||
g_queue_push_tail (&pinossrc->queue, buf);
|
||||
|
|
@ -473,17 +417,6 @@ on_new_buffer (GObject *gobject,
|
|||
pinos_main_loop_signal (pinossrc->loop, FALSE);
|
||||
}
|
||||
return;
|
||||
|
||||
/* ERRORS */
|
||||
parse_failed:
|
||||
{
|
||||
pinos_buffer_iter_end (&it);
|
||||
pinos_buffer_unref (pbuf);
|
||||
gst_buffer_unref (buf);
|
||||
GST_ELEMENT_ERROR (pinossrc, RESOURCE, FAILED, ("buffer parse failure"), (NULL));
|
||||
pinos_main_loop_signal (pinossrc->loop, FALSE);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
|
|
@ -740,6 +673,22 @@ connect_error:
|
|||
}
|
||||
}
|
||||
|
||||
static void
|
||||
on_format_notify (GObject *gobject,
|
||||
GParamSpec *pspec,
|
||||
gpointer user_data)
|
||||
{
|
||||
GstPinosSrc *pinossrc = user_data;
|
||||
GBytes *format;
|
||||
GstCaps *caps;
|
||||
|
||||
g_object_get (gobject, "format", &format, NULL);
|
||||
|
||||
caps = gst_caps_from_string (g_bytes_get_data (format, NULL));
|
||||
gst_base_src_set_caps (GST_BASE_SRC (pinossrc), caps);
|
||||
gst_caps_unref (caps);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
gst_pinos_src_unlock (GstBaseSrc * basesrc)
|
||||
{
|
||||
|
|
@ -771,9 +720,6 @@ static gboolean
|
|||
gst_pinos_src_event (GstBaseSrc * src, GstEvent * event)
|
||||
{
|
||||
gboolean res = FALSE;
|
||||
GstPinosSrc *pinossrc;
|
||||
|
||||
pinossrc = GST_PINOS_SRC (src);
|
||||
|
||||
switch (GST_EVENT_TYPE (event)) {
|
||||
case GST_EVENT_CUSTOM_UPSTREAM:
|
||||
|
|
@ -781,13 +727,11 @@ gst_pinos_src_event (GstBaseSrc * src, GstEvent * event)
|
|||
GstClockTime running_time;
|
||||
gboolean all_headers;
|
||||
guint count;
|
||||
PinosPacketRefreshRequest refresh;
|
||||
PinosBufferBuilder b;
|
||||
PinosBuffer pbuf;
|
||||
|
||||
gst_video_event_parse_upstream_force_key_unit (event,
|
||||
&running_time, &all_headers, &count);
|
||||
|
||||
#if 0
|
||||
pinos_buffer_builder_init (&b);
|
||||
|
||||
refresh.last_id = 0;
|
||||
|
|
@ -805,6 +749,7 @@ gst_pinos_src_event (GstBaseSrc * src, GstEvent * event)
|
|||
GST_OBJECT_UNLOCK (pinossrc);
|
||||
|
||||
pinos_buffer_unref (&pbuf);
|
||||
#endif
|
||||
res = TRUE;
|
||||
} else {
|
||||
res = GST_BASE_SRC_CLASS (parent_class)->event (src, event);
|
||||
|
|
@ -1010,6 +955,7 @@ gst_pinos_src_open (GstPinosSrc * pinossrc)
|
|||
|
||||
pinossrc->stream = pinos_stream_new (pinossrc->ctx, pinossrc->client_name, props);
|
||||
g_signal_connect (pinossrc->stream, "notify::state", (GCallback) on_stream_notify, pinossrc);
|
||||
g_signal_connect (pinossrc->stream, "notify::format", (GCallback) on_format_notify, pinossrc);
|
||||
g_signal_connect (pinossrc->stream, "new-buffer", (GCallback) on_new_buffer, pinossrc);
|
||||
pinos_main_loop_unlock (pinossrc->loop);
|
||||
|
||||
|
|
|
|||
|
|
@ -434,110 +434,40 @@ free_mem_block (MemBlock *b)
|
|||
|
||||
static gboolean
|
||||
on_received_buffer (PinosPort *port,
|
||||
PinosBuffer *buffer,
|
||||
SpaBuffer *buffer,
|
||||
GError **error,
|
||||
gpointer user_data)
|
||||
{
|
||||
PinosSpaAlsaSink *this = user_data;
|
||||
PinosSpaAlsaSinkPrivate *priv = this->priv;
|
||||
PinosBuffer *pbuf = buffer;
|
||||
PinosBufferIter it;
|
||||
unsigned int i;
|
||||
|
||||
pinos_buffer_iter_init (&it, pbuf);
|
||||
while (pinos_buffer_iter_next (&it)) {
|
||||
switch (pinos_buffer_iter_get_type (&it)) {
|
||||
case PINOS_PACKET_TYPE_HEADER:
|
||||
{
|
||||
PinosPacketHeader hdr;
|
||||
for (i = 0; i < buffer->n_datas; i++) {
|
||||
SpaData *d = &buffer->datas[i];
|
||||
PinosRingbufferArea areas[2];
|
||||
uint8_t *data;
|
||||
size_t size, towrite, total;
|
||||
|
||||
if (!pinos_buffer_iter_parse_header (&it, &hdr))
|
||||
break;
|
||||
if (d->type != SPA_DATA_TYPE_MEMPTR)
|
||||
continue;
|
||||
|
||||
break;
|
||||
}
|
||||
case PINOS_PACKET_TYPE_ADD_MEM:
|
||||
{
|
||||
PinosPacketAddMem p;
|
||||
MemBlock *b;
|
||||
int fd;
|
||||
size = d->size;
|
||||
data = (guint8*)d->ptr + d->offset;
|
||||
|
||||
if (!pinos_buffer_iter_parse_add_mem (&it, &p))
|
||||
break;
|
||||
pinos_ringbuffer_get_write_areas (priv->ringbuffer, areas);
|
||||
|
||||
fd = pinos_buffer_get_fd (pbuf, p.fd_index);
|
||||
if (fd == -1)
|
||||
break;
|
||||
total = MIN (size, areas[0].len + areas[1].len);
|
||||
g_debug ("total write %zd %zd", total, areas[0].len + areas[1].len);
|
||||
towrite = MIN (size, areas[0].len);
|
||||
memcpy (areas[0].data, data, towrite);
|
||||
size -= towrite;
|
||||
data += towrite;
|
||||
towrite = MIN (size, areas[1].len);
|
||||
memcpy (areas[1].data, data, towrite);
|
||||
|
||||
b = g_slice_new0 (MemBlock);
|
||||
b->id = p.id;
|
||||
b->type = p.type;
|
||||
b->fd = fd;
|
||||
b->data = mmap (NULL, p.size, PROT_READ, MAP_PRIVATE, fd, p.offset);
|
||||
b->offset = p.offset;
|
||||
b->size = p.size;
|
||||
|
||||
g_hash_table_insert (priv->mem_ids, GINT_TO_POINTER (p.id), b);
|
||||
break;
|
||||
}
|
||||
|
||||
case PINOS_PACKET_TYPE_REMOVE_MEM:
|
||||
{
|
||||
PinosPacketRemoveMem p;
|
||||
|
||||
if (!pinos_buffer_iter_parse_remove_mem (&it, &p))
|
||||
break;
|
||||
|
||||
g_hash_table_remove (priv->mem_ids, GINT_TO_POINTER (p.id));
|
||||
break;
|
||||
}
|
||||
|
||||
case PINOS_PACKET_TYPE_PROCESS_MEM:
|
||||
{
|
||||
PinosPacketProcessMem p;
|
||||
MemBlock *b;
|
||||
PinosRingbufferArea areas[2];
|
||||
uint8_t *data;
|
||||
size_t size, towrite, total;
|
||||
|
||||
if (!pinos_buffer_iter_parse_process_mem (&it, &p))
|
||||
break;
|
||||
|
||||
if (!(b = g_hash_table_lookup (priv->mem_ids, GINT_TO_POINTER (p.id))))
|
||||
break;
|
||||
|
||||
size = p.size;
|
||||
data = (guint8*)b->data + p.offset;
|
||||
|
||||
pinos_ringbuffer_get_write_areas (priv->ringbuffer, areas);
|
||||
|
||||
total = MIN (size, areas[0].len + areas[1].len);
|
||||
g_debug ("total write %zd %zd", total, areas[0].len + areas[1].len);
|
||||
towrite = MIN (size, areas[0].len);
|
||||
memcpy (areas[0].data, data, towrite);
|
||||
size -= towrite;
|
||||
data += towrite;
|
||||
towrite = MIN (size, areas[1].len);
|
||||
memcpy (areas[1].data, data, towrite);
|
||||
|
||||
pinos_ringbuffer_write_advance (priv->ringbuffer, total);
|
||||
|
||||
break;
|
||||
}
|
||||
case PINOS_PACKET_TYPE_FORMAT_CHANGE:
|
||||
{
|
||||
PinosPacketFormatChange change;
|
||||
|
||||
if (!pinos_buffer_iter_parse_format_change (&it, &change))
|
||||
break;
|
||||
g_debug ("got format change %d %s", change.id, change.format);
|
||||
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
pinos_ringbuffer_write_advance (priv->ringbuffer, total);
|
||||
}
|
||||
pinos_buffer_iter_end (&it);
|
||||
spa_buffer_unref (buffer);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
|
@ -550,12 +480,11 @@ on_format_change (GObject *obj,
|
|||
SinkPortData *data = user_data;
|
||||
PinosNode *node = PINOS_NODE (data->sink);
|
||||
PinosSpaAlsaSink *sink = PINOS_SPA_ALSA_SINK (node);
|
||||
PinosSpaAlsaSinkPrivate *priv = sink->priv;
|
||||
GBytes *formats;
|
||||
|
||||
g_object_get (obj, "format", &formats, NULL);
|
||||
if (formats) {
|
||||
g_debug ("port %p: format change %s", obj, g_bytes_get_data (formats, NULL));
|
||||
g_debug ("port %p: format change %s", obj, (gchar*) g_bytes_get_data (formats, NULL));
|
||||
negotiate_formats (sink);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -58,10 +58,9 @@ struct _PinosSpaV4l2SourcePrivate
|
|||
gboolean running;
|
||||
pthread_t thread;
|
||||
|
||||
const void *format;
|
||||
GBytes *format;
|
||||
|
||||
GList *ports;
|
||||
PinosFdManager *fdmanager;
|
||||
};
|
||||
|
||||
enum {
|
||||
|
|
@ -113,50 +112,6 @@ make_node (SpaHandle **handle, const SpaNode **node, const char *lib, const char
|
|||
return SPA_RESULT_ERROR;
|
||||
}
|
||||
|
||||
static void
|
||||
send_format (PinosSpaV4l2Source *source, SourcePortData *data)
|
||||
{
|
||||
PinosSpaV4l2SourcePrivate *priv = source->priv;
|
||||
GError *error = NULL;
|
||||
PinosBufferBuilder builder;
|
||||
PinosBuffer pbuf;
|
||||
PinosPacketFormatChange fc;
|
||||
guint8 buf[1024];
|
||||
|
||||
pinos_buffer_builder_init_into (&builder, buf, 1024, NULL, 0);
|
||||
fc.id = 0;
|
||||
fc.format = priv->format;
|
||||
pinos_buffer_builder_add_format_change (&builder, &fc);
|
||||
pinos_buffer_builder_end (&builder, &pbuf);
|
||||
|
||||
if (!pinos_port_send_buffer (PINOS_PORT (data->port), &pbuf, &error)) {
|
||||
g_debug ("format update failed: %s", error->message);
|
||||
g_clear_error (&error);
|
||||
}
|
||||
pinos_buffer_unref (&pbuf);
|
||||
|
||||
data->have_format = TRUE;
|
||||
}
|
||||
|
||||
static int
|
||||
tmpfile_create (PinosSpaV4l2Source * source, void *data, gsize size)
|
||||
{
|
||||
char filename[] = "/dev/shm/tmpfilepay.XXXXXX";
|
||||
int fd;
|
||||
|
||||
fd = mkostemp (filename, O_CLOEXEC);
|
||||
if (fd == -1) {
|
||||
g_debug ("Failed to create temporary file: %s", strerror (errno));
|
||||
return -1;
|
||||
}
|
||||
unlink (filename);
|
||||
|
||||
if (write (fd, data, size) != (gssize) size)
|
||||
g_debug ("Failed to write data: %s", strerror (errno));
|
||||
|
||||
return fd;
|
||||
}
|
||||
|
||||
static void
|
||||
on_source_event (SpaHandle *handle, SpaEvent *event, void *user_data)
|
||||
{
|
||||
|
|
@ -169,66 +124,27 @@ on_source_event (SpaHandle *handle, SpaEvent *event, void *user_data)
|
|||
SpaOutputInfo info[1] = { 0, };
|
||||
SpaResult res;
|
||||
SpaBuffer *b;
|
||||
PinosBuffer pbuf;
|
||||
PinosBufferBuilder builder;
|
||||
PinosPacketHeader hdr;
|
||||
PinosPacketAddMem am;
|
||||
PinosPacketProcessMem p;
|
||||
PinosPacketRemoveMem rm;
|
||||
GList *walk;
|
||||
gint fd;
|
||||
guint8 buf[1024];
|
||||
gint fdbuf[8];
|
||||
gboolean do_close = FALSE;
|
||||
|
||||
if ((res = priv->source_node->port_pull_output (priv->source, 1, info)) < 0)
|
||||
g_debug ("spa-v4l2-source %p: got pull error %d", source, res);
|
||||
|
||||
b = info[0].buffer;
|
||||
|
||||
hdr.flags = 0;
|
||||
hdr.seq = 0;
|
||||
hdr.pts = -1;
|
||||
hdr.dts_offset = 0;
|
||||
|
||||
pinos_buffer_builder_init_into (&builder, buf, 1024, fdbuf, 8);
|
||||
pinos_buffer_builder_add_header (&builder, &hdr);
|
||||
|
||||
if (b->datas[0].type == SPA_DATA_TYPE_FD) {
|
||||
fd = *((int *)b->datas[0].ptr);
|
||||
} else {
|
||||
fd = tmpfile_create (source, b->datas[0].ptr, b->size);
|
||||
do_close = TRUE;
|
||||
}
|
||||
am.fd_index = pinos_buffer_builder_add_fd (&builder, fd);
|
||||
am.id = pinos_fd_manager_get_id (priv->fdmanager);
|
||||
am.offset = 0;
|
||||
am.size = b->datas[0].size + b->datas[0].offset;
|
||||
p.id = am.id;
|
||||
p.offset = b->datas[0].offset;
|
||||
p.size = b->datas[0].size;
|
||||
rm.id = am.id;
|
||||
pinos_buffer_builder_add_add_mem (&builder, &am);
|
||||
pinos_buffer_builder_add_process_mem (&builder, &p);
|
||||
pinos_buffer_builder_add_remove_mem (&builder, &rm);
|
||||
pinos_buffer_builder_end (&builder, &pbuf);
|
||||
|
||||
for (walk = priv->ports; walk; walk = g_list_next (walk)) {
|
||||
SourcePortData *data = walk->data;
|
||||
GError *error = NULL;
|
||||
|
||||
if (!data->have_format)
|
||||
send_format (source, data);
|
||||
if (!data->have_format) {
|
||||
g_object_set (data->port, "format", priv->format, NULL);
|
||||
data->have_format = TRUE;
|
||||
}
|
||||
|
||||
if (!pinos_port_send_buffer (PINOS_PORT (data->port), &pbuf, &error)) {
|
||||
if (!pinos_port_send_buffer (data->port, b, &error)) {
|
||||
g_debug ("send failed: %s", error->message);
|
||||
g_clear_error (&error);
|
||||
}
|
||||
}
|
||||
if (!do_close)
|
||||
pinos_buffer_steal_fds (&pbuf, NULL);
|
||||
pinos_buffer_unref (&pbuf);
|
||||
|
||||
spa_buffer_unref (b);
|
||||
break;
|
||||
}
|
||||
|
|
@ -270,7 +186,7 @@ create_pipeline (PinosSpaV4l2Source *this)
|
|||
g_debug ("got get_props error %d", res);
|
||||
|
||||
value.type = SPA_PROP_TYPE_STRING;
|
||||
value.value = "/dev/video0";
|
||||
value.value = "/dev/video1";
|
||||
value.size = strlen (value.value)+1;
|
||||
props->set_prop (props, spa_props_index_for_name (props, "device"), &value);
|
||||
|
||||
|
|
@ -290,6 +206,7 @@ negotiate_formats (PinosSpaV4l2Source *this)
|
|||
void *state = NULL;
|
||||
SpaFraction frac;
|
||||
SpaRectangle rect;
|
||||
const gchar *str;
|
||||
|
||||
if ((res = priv->source_node->port_enum_formats (priv->source, 0, &format, NULL, &state)) < 0)
|
||||
return res;
|
||||
|
|
@ -323,11 +240,12 @@ negotiate_formats (PinosSpaV4l2Source *this)
|
|||
if ((res = priv->source_node->port_set_format (priv->source, 0, 0, format)) < 0)
|
||||
return res;
|
||||
|
||||
priv->format = "video/x-raw,"
|
||||
" format=(string)YUY2,"
|
||||
" width=(int)320,"
|
||||
" height=(int)240,"
|
||||
" framerate=(fraction)30/1";
|
||||
str = "video/x-raw,"
|
||||
" format=(string)YUY2,"
|
||||
" width=(int)320,"
|
||||
" height=(int)240,"
|
||||
" framerate=(fraction)30/1";
|
||||
priv->format = g_bytes_new_static (str, strlen (str)+1);
|
||||
|
||||
return SPA_RESULT_OK;
|
||||
}
|
||||
|
|
@ -487,26 +405,6 @@ on_deactivate (PinosPort *port, gpointer user_data)
|
|||
pinos_node_report_idle (PINOS_NODE (source));
|
||||
}
|
||||
|
||||
static gboolean
|
||||
on_received_buffer (PinosPort *port,
|
||||
PinosBuffer *pbuf,
|
||||
GError **error,
|
||||
gpointer user_data)
|
||||
{
|
||||
PinosBufferIter it;
|
||||
|
||||
pinos_buffer_iter_init (&it, pbuf);
|
||||
while (pinos_buffer_iter_next (&it)) {
|
||||
switch (pinos_buffer_iter_get_type (&it)) {
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
pinos_buffer_iter_end (&it);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static void
|
||||
free_source_port_data (SourcePortData *data)
|
||||
{
|
||||
|
|
@ -575,8 +473,6 @@ add_port (PinosNode *node,
|
|||
data->port = PINOS_NODE_CLASS (pinos_spa_v4l2_source_parent_class)
|
||||
->add_port (node, direction, id, error);
|
||||
|
||||
pinos_port_set_received_buffer_cb (data->port, on_received_buffer, source, NULL);
|
||||
|
||||
g_debug ("connecting signals");
|
||||
g_signal_connect (data->port, "activate", (GCallback) on_activate, data);
|
||||
g_signal_connect (data->port, "deactivate", (GCallback) on_deactivate, data);
|
||||
|
|
@ -607,10 +503,7 @@ pinos_spa_v4l2_source_class_init (PinosSpaV4l2SourceClass * klass)
|
|||
static void
|
||||
pinos_spa_v4l2_source_init (PinosSpaV4l2Source * source)
|
||||
{
|
||||
PinosSpaV4l2SourcePrivate *priv = source->priv = PINOS_SPA_V4L2_SOURCE_GET_PRIVATE (source);
|
||||
|
||||
priv->fdmanager = pinos_fd_manager_get (PINOS_FD_MANAGER_DEFAULT);
|
||||
|
||||
source->priv = PINOS_SPA_V4L2_SOURCE_GET_PRIVATE (source);
|
||||
}
|
||||
|
||||
PinosNode *
|
||||
|
|
|
|||
|
|
@ -17,10 +17,15 @@
|
|||
* Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#define _GNU_SOURCE
|
||||
|
||||
#include <string.h>
|
||||
#include <sys/socket.h>
|
||||
#include <errno.h>
|
||||
#include <sys/mman.h>
|
||||
#include <unistd.h>
|
||||
#include <fcntl.h>
|
||||
|
||||
|
||||
#include <gio/gunixfdlist.h>
|
||||
|
||||
|
|
@ -34,26 +39,19 @@
|
|||
|
||||
#include "pinos/dbus/org-pinos.h"
|
||||
|
||||
#include "spa/include/spa/control.h"
|
||||
|
||||
|
||||
#define MAX_BUFFER_SIZE 1024
|
||||
#define MAX_FDS 16
|
||||
|
||||
typedef struct {
|
||||
guint32 id;
|
||||
guint32 type;
|
||||
int fd;
|
||||
guint64 offset;
|
||||
guint64 size;
|
||||
void *data;
|
||||
} MemBlock;
|
||||
|
||||
struct _PinosClientNodePrivate
|
||||
{
|
||||
int fd;
|
||||
GSource *socket_source;
|
||||
GSocket *sockets[2];
|
||||
|
||||
PinosBuffer recv_buffer;
|
||||
SpaControl recv_control;
|
||||
|
||||
guint8 recv_data[MAX_BUFFER_SIZE];
|
||||
int recv_fds[MAX_FDS];
|
||||
|
|
@ -112,178 +110,118 @@ pinos_client_node_set_property (GObject *_object,
|
|||
}
|
||||
}
|
||||
|
||||
static void
|
||||
free_mem_block (MemBlock *b)
|
||||
{
|
||||
munmap (b->data, b->size);
|
||||
g_slice_free (MemBlock, b);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
parse_buffer (PinosClientNode *cnode,
|
||||
PinosBuffer *pbuf)
|
||||
parse_control (PinosClientNode *cnode,
|
||||
SpaControl *ctrl)
|
||||
{
|
||||
PinosNode *node = PINOS_NODE (cnode);
|
||||
PinosBufferIter it;
|
||||
PinosClientNodePrivate *priv = cnode->priv;
|
||||
PinosPort *port;
|
||||
SpaControlIter it;
|
||||
|
||||
pinos_buffer_iter_init (&it, pbuf);
|
||||
while (pinos_buffer_iter_next (&it)) {
|
||||
PinosPacketType type = pinos_buffer_iter_get_type (&it);
|
||||
spa_control_iter_init (&it, ctrl);
|
||||
while (spa_control_iter_next (&it) == SPA_RESULT_OK) {
|
||||
SpaControlCmd cmd = spa_control_iter_get_cmd (&it);
|
||||
|
||||
switch (type) {
|
||||
case PINOS_PACKET_TYPE_FORMAT_CHANGE:
|
||||
switch (cmd) {
|
||||
case SPA_CONTROL_CMD_ADD_PORT:
|
||||
case SPA_CONTROL_CMD_REMOVE_PORT:
|
||||
case SPA_CONTROL_CMD_SET_FORMAT:
|
||||
case SPA_CONTROL_CMD_SET_PROPERTY:
|
||||
case SPA_CONTROL_CMD_END_CONFIGURE:
|
||||
case SPA_CONTROL_CMD_PAUSE:
|
||||
case SPA_CONTROL_CMD_START:
|
||||
case SPA_CONTROL_CMD_STOP:
|
||||
g_warning ("client-node %p: got unexpected control %d", node, cmd);
|
||||
break;
|
||||
|
||||
case SPA_CONTROL_CMD_NODE_UPDATE:
|
||||
case SPA_CONTROL_CMD_PORT_UPDATE:
|
||||
case SPA_CONTROL_CMD_PORT_REMOVED:
|
||||
g_warning ("client-node %p: command not implemented %d", node, cmd);
|
||||
break;
|
||||
|
||||
case SPA_CONTROL_CMD_START_CONFIGURE:
|
||||
{
|
||||
PinosPacketFormatChange p;
|
||||
GBytes *format;
|
||||
SpaControlBuilder builder;
|
||||
SpaControl control;
|
||||
guint8 buffer[1024];
|
||||
|
||||
if (!pinos_buffer_iter_parse_format_change (&it, &p))
|
||||
break;
|
||||
/* set port format */
|
||||
|
||||
g_debug ("format change port %d", p.port);
|
||||
/* send end-configure */
|
||||
spa_control_builder_init_into (&builder, buffer, 1024, NULL, 0);
|
||||
spa_control_builder_add_cmd (&builder, SPA_CONTROL_CMD_END_CONFIGURE, NULL);
|
||||
spa_control_builder_end (&builder, &control);
|
||||
|
||||
if (!(port = pinos_node_find_port (node, p.port)))
|
||||
break;
|
||||
if (spa_control_write (&control, priv->fd) < 0)
|
||||
g_warning ("client-node %p: error writing control", node);
|
||||
|
||||
format = g_bytes_new_static (p.format, strlen (p.format) + 1);
|
||||
|
||||
g_object_set (port, "possible-formats", format, NULL);
|
||||
g_object_set (port, "format", format, NULL);
|
||||
g_debug ("client-node %p: format change %s", node, p.format);
|
||||
break;
|
||||
}
|
||||
case PINOS_PACKET_TYPE_START:
|
||||
case SPA_CONTROL_CMD_PORT_STATUS_CHANGE:
|
||||
{
|
||||
GBytes *format;
|
||||
PinosBufferBuilder builder;
|
||||
PinosBuffer obuf;
|
||||
g_warning ("client-node %p: command not implemented %d", node, cmd);
|
||||
break;
|
||||
}
|
||||
case SPA_CONTROL_CMD_START_ALLOC:
|
||||
{
|
||||
SpaControlBuilder builder;
|
||||
SpaControl control;
|
||||
guint8 buffer[1024];
|
||||
GError *error = NULL;
|
||||
GList *ports, *walk;
|
||||
|
||||
pinos_buffer_builder_init_into (&builder, buffer, 1024, NULL, 0);
|
||||
/* FIXME read port memory requirements */
|
||||
/* FIXME add_mem */
|
||||
|
||||
/* send start */
|
||||
spa_control_builder_init_into (&builder, buffer, 1024, NULL, 0);
|
||||
spa_control_builder_add_cmd (&builder, SPA_CONTROL_CMD_START, NULL);
|
||||
spa_control_builder_end (&builder, &control);
|
||||
|
||||
if (spa_control_write (&control, priv->fd) < 0)
|
||||
g_warning ("client-node %p: error writing control", node);
|
||||
|
||||
ports = pinos_node_get_ports (node);
|
||||
for (walk = ports; walk; walk = g_list_next (walk)) {
|
||||
PinosPacketFormatChange fc;
|
||||
|
||||
port = walk->data;
|
||||
PinosPort *port = walk->data;
|
||||
|
||||
pinos_port_activate (port);
|
||||
|
||||
g_object_get (port, "format", &format, "id", &fc.port, NULL);
|
||||
if (format == NULL)
|
||||
break;
|
||||
|
||||
fc.id = 0;
|
||||
fc.format = g_bytes_get_data (format, NULL);
|
||||
|
||||
g_debug ("client-node %p: port %u we are now streaming in format \"%s\"",
|
||||
node, fc.port, fc.format);
|
||||
|
||||
pinos_buffer_builder_add_format_change (&builder, &fc);
|
||||
}
|
||||
pinos_buffer_builder_add_empty (&builder, PINOS_PACKET_TYPE_STREAMING);
|
||||
pinos_buffer_builder_end (&builder, &obuf);
|
||||
|
||||
if (!pinos_io_write_buffer (priv->fd, &obuf, &error)) {
|
||||
g_warning ("client-node %p: error writing buffer: %s", node, error->message);
|
||||
g_clear_error (&error);
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
case PINOS_PACKET_TYPE_STOP:
|
||||
{
|
||||
PinosBufferBuilder builder;
|
||||
PinosBuffer obuf;
|
||||
guint8 buffer[1024];
|
||||
GError *error = NULL;
|
||||
GList *ports, *walk;
|
||||
|
||||
pinos_buffer_builder_init_into (&builder, buffer, 1024, NULL, 0);
|
||||
|
||||
ports = pinos_node_get_ports (node);
|
||||
for (walk = ports; walk; walk = g_list_next (walk)) {
|
||||
port = walk->data;
|
||||
pinos_port_deactivate (port);
|
||||
}
|
||||
pinos_buffer_builder_add_empty (&builder, PINOS_PACKET_TYPE_STOPPED);
|
||||
pinos_buffer_builder_end (&builder, &obuf);
|
||||
|
||||
if (!pinos_io_write_buffer (priv->fd, &obuf, &error)) {
|
||||
g_warning ("client-node %p: error writing buffer: %s", node, error->message);
|
||||
g_clear_error (&error);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case PINOS_PACKET_TYPE_ADD_MEM:
|
||||
{
|
||||
PinosPacketAddMem p;
|
||||
MemBlock *b;
|
||||
int fd;
|
||||
|
||||
if (!pinos_buffer_iter_parse_add_mem (&it, &p))
|
||||
break;
|
||||
|
||||
fd = pinos_buffer_get_fd (pbuf, p.fd_index);
|
||||
if (fd == -1)
|
||||
break;
|
||||
|
||||
b = g_slice_new0 (MemBlock);
|
||||
b->id = p.id;
|
||||
b->type = p.type;
|
||||
b->fd = fd;
|
||||
b->data = mmap (NULL, p.size, PROT_READ, MAP_PRIVATE, fd, p.offset);
|
||||
b->offset = p.offset;
|
||||
b->size = p.size;
|
||||
|
||||
g_hash_table_insert (priv->mem_ids, GINT_TO_POINTER (p.id), b);
|
||||
break;
|
||||
}
|
||||
|
||||
case PINOS_PACKET_TYPE_REMOVE_MEM:
|
||||
{
|
||||
PinosPacketRemoveMem p;
|
||||
|
||||
if (!pinos_buffer_iter_parse_remove_mem (&it, &p))
|
||||
break;
|
||||
|
||||
g_hash_table_remove (priv->mem_ids, GINT_TO_POINTER (p.id));
|
||||
break;
|
||||
}
|
||||
case PINOS_PACKET_TYPE_PROCESS_MEM:
|
||||
{
|
||||
PinosPacketProcessMem p;
|
||||
GError *error = NULL;
|
||||
|
||||
if (!pinos_buffer_iter_parse_process_mem (&it, &p))
|
||||
break;
|
||||
|
||||
if (!(port = pinos_node_find_port (node, p.port)))
|
||||
break;
|
||||
|
||||
if (!pinos_port_send_buffer (port, pbuf, &error)) {
|
||||
g_warning ("client-node %p: port %p failed to receive buffer: %s", node, port, error->message);
|
||||
g_clear_error (&error);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case PINOS_PACKET_TYPE_HEADER:
|
||||
case SPA_CONTROL_CMD_NEED_INPUT:
|
||||
{
|
||||
break;
|
||||
}
|
||||
case PINOS_PACKET_TYPE_REUSE_MEM:
|
||||
case SPA_CONTROL_CMD_HAVE_OUTPUT:
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
case SPA_CONTROL_CMD_ADD_MEM:
|
||||
break;
|
||||
case SPA_CONTROL_CMD_REMOVE_MEM:
|
||||
break;
|
||||
case SPA_CONTROL_CMD_ADD_BUFFER:
|
||||
break;
|
||||
case SPA_CONTROL_CMD_REMOVE_BUFFER:
|
||||
break;
|
||||
|
||||
case SPA_CONTROL_CMD_PROCESS_BUFFER:
|
||||
{
|
||||
break;
|
||||
}
|
||||
case SPA_CONTROL_CMD_REUSE_BUFFER:
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
g_warning ("unhandled packet %d", type);
|
||||
g_warning ("client-node %p: command unhandled %d", node, cmd);
|
||||
break;
|
||||
}
|
||||
}
|
||||
pinos_buffer_iter_end (&it);
|
||||
spa_control_iter_end (&it);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
|
@ -299,22 +237,19 @@ on_socket_condition (GSocket *socket,
|
|||
switch (condition) {
|
||||
case G_IO_IN:
|
||||
{
|
||||
PinosBuffer *buffer = &priv->recv_buffer;
|
||||
GError *error = NULL;
|
||||
SpaControl *control = &priv->recv_control;
|
||||
|
||||
if (!pinos_io_read_buffer (priv->fd,
|
||||
buffer,
|
||||
priv->recv_data,
|
||||
MAX_BUFFER_SIZE,
|
||||
priv->recv_fds,
|
||||
MAX_FDS,
|
||||
&error)) {
|
||||
g_warning ("client-node %p: failed to read buffer: %s", node, error->message);
|
||||
g_clear_error (&error);
|
||||
if (spa_control_read (control,
|
||||
priv->fd,
|
||||
priv->recv_data,
|
||||
MAX_BUFFER_SIZE,
|
||||
priv->recv_fds,
|
||||
MAX_FDS) < 0) {
|
||||
g_warning ("client-node %p: failed to read buffer", node);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
parse_buffer (node, buffer);
|
||||
parse_control (node, control);
|
||||
|
||||
#if 0
|
||||
if (!pinos_port_receive_buffer (priv->port, buffer, &error)) {
|
||||
|
|
@ -322,7 +257,7 @@ on_socket_condition (GSocket *socket,
|
|||
g_clear_error (&error);
|
||||
}
|
||||
#endif
|
||||
g_assert (pinos_buffer_unref (buffer) == FALSE);
|
||||
spa_control_clear (control);
|
||||
break;
|
||||
}
|
||||
|
||||
|
|
@ -416,16 +351,153 @@ create_failed:
|
|||
}
|
||||
}
|
||||
|
||||
static gboolean
|
||||
on_received_buffer (PinosPort *port, PinosBuffer *buffer, GError **error, gpointer user_data)
|
||||
static void
|
||||
on_format_change (GObject *obj,
|
||||
GParamSpec *pspec,
|
||||
gpointer user_data)
|
||||
{
|
||||
PinosClientNode *node = user_data;
|
||||
PinosClientNodePrivate *priv = node->priv;
|
||||
GBytes *format;
|
||||
SpaControl control;
|
||||
SpaControlBuilder builder;
|
||||
SpaControlCmdSetFormat sf;
|
||||
guint8 buf[1024];
|
||||
|
||||
if (!pinos_io_write_buffer (priv->fd, buffer, error)) {
|
||||
g_warning ("client-node %p: error writing buffer: %s", node, (*error)->message);
|
||||
return FALSE;
|
||||
g_object_get (obj, "format", &format, NULL);
|
||||
if (format == NULL)
|
||||
return ;
|
||||
|
||||
g_debug ("port %p: format change %s", obj, (gchar*)g_bytes_get_data (format, NULL));
|
||||
|
||||
spa_control_builder_init_into (&builder, buf, 1024, NULL, 0);
|
||||
sf.port = 0;
|
||||
sf.format = NULL;
|
||||
sf.str = g_bytes_get_data (format, NULL);
|
||||
spa_control_builder_add_cmd (&builder, SPA_CONTROL_CMD_SET_FORMAT, &sf);
|
||||
spa_control_builder_end (&builder, &control);
|
||||
|
||||
if (spa_control_write (&control, priv->fd))
|
||||
g_warning ("client-node %p: error writing control", node);
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
tmpfile_create (void *data, gsize size)
|
||||
{
|
||||
char filename[] = "/dev/shm/tmpfilepay.XXXXXX";
|
||||
int fd;
|
||||
|
||||
fd = mkostemp (filename, O_CLOEXEC);
|
||||
if (fd == -1) {
|
||||
g_debug ("Failed to create temporary file: %s", strerror (errno));
|
||||
return -1;
|
||||
}
|
||||
unlink (filename);
|
||||
|
||||
if (write (fd, data, size) != (gssize) size)
|
||||
g_debug ("Failed to write data: %s", strerror (errno));
|
||||
|
||||
return fd;
|
||||
}
|
||||
|
||||
typedef struct {
|
||||
SpaBuffer buffer;
|
||||
SpaData datas[16];
|
||||
int idx[16];
|
||||
SpaBuffer *orig;
|
||||
} MyBuffer;
|
||||
|
||||
static gboolean
|
||||
on_received_buffer (PinosPort *port, SpaBuffer *buffer, GError **error, gpointer user_data)
|
||||
{
|
||||
PinosClientNode *node = user_data;
|
||||
PinosClientNodePrivate *priv = node->priv;
|
||||
SpaControl control;
|
||||
SpaControlBuilder builder;
|
||||
guint8 buf[1024];
|
||||
int fds[16];
|
||||
SpaControlCmdAddBuffer ab;
|
||||
SpaControlCmdProcessBuffer pb;
|
||||
SpaControlCmdRemoveBuffer rb;
|
||||
bool tmpfile = false;
|
||||
|
||||
if (pinos_port_get_direction (port) == PINOS_DIRECTION_OUTPUT) {
|
||||
/* FIXME, does not happen */
|
||||
spa_control_builder_init_into (&builder, buf, 1024, NULL, 0);
|
||||
spa_control_builder_add_cmd (&builder, SPA_CONTROL_CMD_HAVE_OUTPUT, NULL);
|
||||
spa_control_builder_end (&builder, &control);
|
||||
|
||||
if (spa_control_write (&control, priv->fd)) {
|
||||
g_warning ("client-node %p: error writing control", node);
|
||||
return FALSE;
|
||||
}
|
||||
} else {
|
||||
unsigned int i;
|
||||
MyBuffer b;
|
||||
|
||||
spa_control_builder_init_into (&builder, buf, 1024, fds, 16);
|
||||
|
||||
b.buffer.refcount = 1;
|
||||
b.buffer.notify = NULL;
|
||||
b.buffer.id = buffer->id;
|
||||
b.buffer.size = buffer->size;
|
||||
b.buffer.n_metas = buffer->n_metas;
|
||||
b.buffer.metas = buffer->metas;
|
||||
b.buffer.n_datas = buffer->n_datas;
|
||||
b.buffer.datas = b.datas;
|
||||
|
||||
for (i = 0; i < buffer->n_datas; i++) {
|
||||
SpaData *d = &buffer->datas[i];
|
||||
int fd;
|
||||
SpaControlCmdAddMem am;
|
||||
|
||||
if (d->type == SPA_DATA_TYPE_FD) {
|
||||
fd = *((int *)d->ptr);
|
||||
} else {
|
||||
fd = tmpfile_create (d->ptr, d->size + d->offset);
|
||||
tmpfile = true;
|
||||
}
|
||||
am.port = 0;
|
||||
am.id = i;
|
||||
am.type = 0;
|
||||
am.fd_index = spa_control_builder_add_fd (&builder, fd, tmpfile ? true : false);
|
||||
am.offset = 0;
|
||||
am.size = d->offset + d->size;
|
||||
spa_control_builder_add_cmd (&builder, SPA_CONTROL_CMD_ADD_MEM, &am);
|
||||
|
||||
b.idx[i] = i;
|
||||
b.datas[i].type = SPA_DATA_TYPE_MEMID;
|
||||
b.datas[i].ptr_type = NULL;
|
||||
b.datas[i].ptr = &b.idx[i];
|
||||
b.datas[i].offset = d->offset;
|
||||
b.datas[i].size = d->size;
|
||||
b.datas[i].stride = d->stride;
|
||||
}
|
||||
ab.port = 0;
|
||||
ab.buffer = &b.buffer;
|
||||
spa_control_builder_add_cmd (&builder, SPA_CONTROL_CMD_ADD_BUFFER, &ab);
|
||||
pb.port = 0;
|
||||
pb.id = b.buffer.id;
|
||||
spa_control_builder_add_cmd (&builder, SPA_CONTROL_CMD_PROCESS_BUFFER, &pb);
|
||||
rb.port = 0;
|
||||
rb.id = b.buffer.id;
|
||||
spa_control_builder_add_cmd (&builder, SPA_CONTROL_CMD_REMOVE_BUFFER, &rb);
|
||||
|
||||
for (i = 0; i < buffer->n_datas; i++) {
|
||||
SpaControlCmdRemoveMem rm;
|
||||
rm.port = 0;
|
||||
rm.id = i;
|
||||
spa_control_builder_add_cmd (&builder, SPA_CONTROL_CMD_REMOVE_MEM, &rm);
|
||||
}
|
||||
spa_control_builder_end (&builder, &control);
|
||||
|
||||
if (spa_control_write (&control, priv->fd))
|
||||
g_warning ("client-node %p: error writing control", node);
|
||||
|
||||
spa_control_clear (&control);
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
|
@ -441,6 +513,8 @@ add_port (PinosNode *node,
|
|||
|
||||
if (port) {
|
||||
pinos_port_set_received_buffer_cb (port, on_received_buffer, node, NULL);
|
||||
|
||||
g_signal_connect (port, "notify::format", (GCallback) on_format_change, node);
|
||||
}
|
||||
return port;
|
||||
}
|
||||
|
|
@ -506,8 +580,7 @@ pinos_client_node_class_init (PinosClientNodeClass * klass)
|
|||
static void
|
||||
pinos_client_node_init (PinosClientNode * node)
|
||||
{
|
||||
PinosClientNodePrivate *priv = node->priv = PINOS_CLIENT_NODE_GET_PRIVATE (node);
|
||||
node->priv = PINOS_CLIENT_NODE_GET_PRIVATE (node);
|
||||
|
||||
g_debug ("client-node %p: new", node);
|
||||
priv->mem_ids = g_hash_table_new_full (g_direct_hash, g_direct_equal, NULL, (GDestroyNotify) free_mem_block);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -22,6 +22,8 @@
|
|||
|
||||
#include <glib-object.h>
|
||||
|
||||
#include <pinos/server/node.h>
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
#define PINOS_TYPE_CLIENT_NODE (pinos_client_node_get_type ())
|
||||
|
|
|
|||
|
|
@ -250,7 +250,7 @@ handle_create_client_node (PinosDaemon1 *interface,
|
|||
continue;
|
||||
}
|
||||
|
||||
pinos_client_add_object (client, G_OBJECT (target));
|
||||
// pinos_client_add_object (client, G_OBJECT (target));
|
||||
|
||||
link = pinos_link_new (daemon, port, target, NULL);
|
||||
pinos_client_add_object (client, G_OBJECT (link));
|
||||
|
|
|
|||
|
|
@ -69,7 +69,7 @@ enum
|
|||
static guint signals[LAST_SIGNAL] = { 0 };
|
||||
|
||||
static gboolean
|
||||
on_output_send (PinosPort *port, PinosBuffer *buffer, GError **error, gpointer user_data)
|
||||
on_output_send (PinosPort *port, SpaBuffer *buffer, GError **error, gpointer user_data)
|
||||
{
|
||||
PinosLink *link = user_data;
|
||||
PinosLinkPrivate *priv = link->priv;
|
||||
|
|
@ -78,7 +78,7 @@ on_output_send (PinosPort *port, PinosBuffer *buffer, GError **error, gpointer u
|
|||
}
|
||||
|
||||
static gboolean
|
||||
on_input_send (PinosPort *port, PinosBuffer *buffer, GError **error, gpointer user_data)
|
||||
on_input_send (PinosPort *port, SpaBuffer *buffer, GError **error, gpointer user_data)
|
||||
{
|
||||
PinosLink *link = user_data;
|
||||
PinosLinkPrivate *priv = link->priv;
|
||||
|
|
@ -245,7 +245,7 @@ on_format_change (GObject *obj,
|
|||
GBytes *formats;
|
||||
|
||||
g_object_get (priv->output, "format", &formats, NULL);
|
||||
g_debug ("port %p: format change %s", priv->output, g_bytes_get_data (formats, NULL));
|
||||
g_debug ("port %p: format change %s", priv->output, (gchar*)g_bytes_get_data (formats, NULL));
|
||||
g_object_set (priv->input, "format", formats, NULL);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -597,34 +597,6 @@ pinos_port_filter_formats (PinosPort *port,
|
|||
return pinos_format_filter (priv->possible_formats, filter, error);
|
||||
}
|
||||
|
||||
static void
|
||||
parse_control_buffer (PinosPort *port, PinosBuffer *buffer)
|
||||
{
|
||||
PinosPortPrivate *priv = port->priv;
|
||||
PinosBufferIter it;
|
||||
|
||||
pinos_buffer_iter_init (&it, buffer);
|
||||
while (pinos_buffer_iter_next (&it)) {
|
||||
switch (pinos_buffer_iter_get_type (&it)) {
|
||||
case PINOS_PACKET_TYPE_FORMAT_CHANGE:
|
||||
{
|
||||
PinosPacketFormatChange change;
|
||||
|
||||
if (!pinos_buffer_iter_parse_format_change (&it, &change))
|
||||
continue;
|
||||
|
||||
if (priv->format)
|
||||
g_bytes_unref (priv->format);
|
||||
priv->format = g_bytes_new (change.format, strlen (change.format) + 1);
|
||||
g_object_notify (G_OBJECT (port), "format");
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
pinos_port_activate (PinosPort *port)
|
||||
{
|
||||
|
|
@ -668,15 +640,13 @@ pinos_port_deactivate (PinosPort *port)
|
|||
*/
|
||||
gboolean
|
||||
pinos_port_receive_buffer (PinosPort *port,
|
||||
PinosBuffer *buffer,
|
||||
SpaBuffer *buffer,
|
||||
GError **error)
|
||||
{
|
||||
gboolean res = TRUE;
|
||||
PinosPortPrivate *priv = port->priv;
|
||||
|
||||
PINOS_DEBUG_TRANSPORT ("port %p: receive buffer %p", port, buffer);
|
||||
if (pinos_buffer_get_flags (buffer) & PINOS_BUFFER_FLAG_CONTROL)
|
||||
parse_control_buffer (port, buffer);
|
||||
|
||||
if (priv->received_buffer_cb)
|
||||
res = priv->received_buffer_cb (port, buffer, error, priv->received_buffer_data);
|
||||
|
|
@ -687,7 +657,7 @@ pinos_port_receive_buffer (PinosPort *port,
|
|||
/**
|
||||
* pinos_port_send_buffer:
|
||||
* @port: a #PinosPort
|
||||
* @buffer: a #PinosBuffer
|
||||
* @buffer: a #SpaBuffer
|
||||
* @error: a #GError or %NULL
|
||||
*
|
||||
* Send @buffer out on @port.
|
||||
|
|
@ -696,7 +666,7 @@ pinos_port_receive_buffer (PinosPort *port,
|
|||
*/
|
||||
gboolean
|
||||
pinos_port_send_buffer (PinosPort *port,
|
||||
PinosBuffer *buffer,
|
||||
SpaBuffer *buffer,
|
||||
GError **error)
|
||||
{
|
||||
gboolean res = TRUE;
|
||||
|
|
@ -706,8 +676,6 @@ pinos_port_send_buffer (PinosPort *port,
|
|||
g_return_val_if_fail (PINOS_IS_PORT (port), FALSE);
|
||||
|
||||
PINOS_DEBUG_TRANSPORT ("port %p: send buffer %p", port, buffer);
|
||||
if (pinos_buffer_get_flags (buffer) & PINOS_BUFFER_FLAG_CONTROL)
|
||||
parse_control_buffer (port, buffer);
|
||||
|
||||
priv = port->priv;
|
||||
|
||||
|
|
|
|||
|
|
@ -31,6 +31,7 @@ typedef struct _PinosPortPrivate PinosPortPrivate;
|
|||
#include <pinos/client/introspect.h>
|
||||
#include <pinos/client/buffer.h>
|
||||
#include <pinos/server/daemon.h>
|
||||
#include <spa/include/spa/buffer.h>
|
||||
|
||||
#define PINOS_TYPE_PORT (pinos_port_get_type ())
|
||||
#define PINOS_IS_PORT(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), PINOS_TYPE_PORT))
|
||||
|
|
@ -65,7 +66,7 @@ struct _PinosPortClass {
|
|||
GTask *task);
|
||||
};
|
||||
|
||||
typedef gboolean (*PinosBufferCallback) (PinosPort *port, PinosBuffer *buffer, GError **error, gpointer user_data);
|
||||
typedef gboolean (*PinosBufferCallback) (PinosPort *port, SpaBuffer *buffer, GError **error, gpointer user_data);
|
||||
|
||||
/* normal GObject stuff */
|
||||
GType pinos_port_get_type (void);
|
||||
|
|
@ -99,10 +100,10 @@ void pinos_port_activate (PinosPort *port);
|
|||
void pinos_port_deactivate (PinosPort *port);
|
||||
|
||||
gboolean pinos_port_send_buffer (PinosPort *port,
|
||||
PinosBuffer *buffer,
|
||||
SpaBuffer *buffer,
|
||||
GError **error);
|
||||
gboolean pinos_port_receive_buffer (PinosPort *port,
|
||||
PinosBuffer *buffer,
|
||||
SpaBuffer *buffer,
|
||||
GError **error);
|
||||
|
||||
G_END_DECLS
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue