mirror of
https://gitlab.freedesktop.org/pipewire/pipewire.git
synced 2025-10-31 22:25:38 -04:00
Remove the node state. The state of the node is based on the state of the ports, which can be derived directly from calling the port methods. Track this state in the Port instead. Add a mixer module that puts a mixer in from of audio sinks. This allows multiple clients to play on one sink (still has some bugs). do some fixes in the mixer and the scheduler to make this work.
1116 lines
32 KiB
C
1116 lines
32 KiB
C
/* Pinos
|
|
* Copyright (C) 2017 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 <errno.h>
|
|
|
|
#include "spa/pod-iter.h"
|
|
#include "pinos/client/pinos.h"
|
|
|
|
#include "pinos/client/protocol-native.h"
|
|
#include "pinos/client/interfaces.h"
|
|
#include "pinos/client/connection.h"
|
|
|
|
typedef struct {
|
|
SpaPODBuilder b;
|
|
PinosConnection *connection;
|
|
} Builder;
|
|
|
|
typedef bool (*PinosDemarshalFunc) (void *object, void *data, size_t size);
|
|
|
|
static uint32_t
|
|
write_pod (SpaPODBuilder *b, uint32_t ref, const void *data, uint32_t size)
|
|
{
|
|
if (ref == -1)
|
|
ref = b->offset;
|
|
|
|
if (b->size <= b->offset) {
|
|
b->size = SPA_ROUND_UP_N (b->offset + size, 4096);
|
|
b->data = pinos_connection_begin_write (((Builder*)b)->connection, b->size);
|
|
}
|
|
memcpy (b->data + ref, data, size);
|
|
return ref;
|
|
}
|
|
|
|
static void
|
|
core_update_map (PinosContext *context)
|
|
{
|
|
uint32_t diff, base, i;
|
|
const char **types;
|
|
|
|
base = context->n_types;
|
|
diff = spa_type_map_get_size (context->type.map) - base;
|
|
if (diff == 0)
|
|
return;
|
|
|
|
types = alloca (diff * sizeof (char *));
|
|
for (i = 0; i < diff; i++, base++)
|
|
types[i] = spa_type_map_get_type (context->type.map, base);
|
|
|
|
pinos_core_do_update_types (context->core_proxy,
|
|
context->n_types,
|
|
diff,
|
|
types);
|
|
context->n_types += diff;
|
|
}
|
|
|
|
static void
|
|
core_marshal_client_update (void *object,
|
|
const SpaDict *props)
|
|
{
|
|
PinosProxy *proxy = object;
|
|
PinosConnection *connection = proxy->context->protocol_private;
|
|
Builder b = { { NULL, 0, 0, NULL, write_pod }, connection };
|
|
SpaPODFrame f;
|
|
int i, n_items;
|
|
|
|
core_update_map (proxy->context);
|
|
|
|
n_items = props ? props->n_items : 0;
|
|
|
|
spa_pod_builder_add (&b.b,
|
|
SPA_POD_TYPE_STRUCT, &f,
|
|
SPA_POD_TYPE_INT, n_items, 0);
|
|
|
|
for (i = 0; i < n_items; i++) {
|
|
spa_pod_builder_add (&b.b,
|
|
SPA_POD_TYPE_STRING, props->items[i].key,
|
|
SPA_POD_TYPE_STRING, props->items[i].value,
|
|
0);
|
|
}
|
|
spa_pod_builder_add (&b.b, -SPA_POD_TYPE_STRUCT, &f, 0);
|
|
|
|
pinos_connection_end_write (connection, proxy->id, 0, b.b.offset);
|
|
}
|
|
|
|
static void
|
|
core_marshal_sync (void *object,
|
|
uint32_t seq)
|
|
{
|
|
PinosProxy *proxy = object;
|
|
PinosConnection *connection = proxy->context->protocol_private;
|
|
Builder b = { { NULL, 0, 0, NULL, write_pod }, connection };
|
|
SpaPODFrame f;
|
|
|
|
core_update_map (proxy->context);
|
|
|
|
spa_pod_builder_struct (&b.b, &f,
|
|
SPA_POD_TYPE_INT, seq);
|
|
|
|
pinos_connection_end_write (connection, proxy->id, 1, b.b.offset);
|
|
}
|
|
|
|
static void
|
|
core_marshal_get_registry (void *object,
|
|
uint32_t new_id)
|
|
{
|
|
PinosProxy *proxy = object;
|
|
PinosConnection *connection = proxy->context->protocol_private;
|
|
Builder b = { { NULL, 0, 0, NULL, write_pod }, connection };
|
|
SpaPODFrame f;
|
|
|
|
core_update_map (proxy->context);
|
|
|
|
spa_pod_builder_struct (&b.b, &f,
|
|
SPA_POD_TYPE_INT, new_id);
|
|
|
|
pinos_connection_end_write (connection, proxy->id, 2, b.b.offset);
|
|
}
|
|
|
|
static void
|
|
core_marshal_create_node (void *object,
|
|
const char *factory_name,
|
|
const char *name,
|
|
const SpaDict *props,
|
|
uint32_t new_id)
|
|
{
|
|
PinosProxy *proxy = object;
|
|
PinosConnection *connection = proxy->context->protocol_private;
|
|
Builder b = { { NULL, 0, 0, NULL, write_pod }, connection };
|
|
SpaPODFrame f;
|
|
uint32_t i, n_items;
|
|
|
|
core_update_map (proxy->context);
|
|
|
|
n_items = props ? props->n_items : 0;
|
|
|
|
spa_pod_builder_add (&b.b,
|
|
SPA_POD_TYPE_STRUCT, &f,
|
|
SPA_POD_TYPE_STRING, factory_name,
|
|
SPA_POD_TYPE_STRING, name,
|
|
SPA_POD_TYPE_INT, n_items, 0);
|
|
|
|
for (i = 0; i < n_items; i++) {
|
|
spa_pod_builder_add (&b.b,
|
|
SPA_POD_TYPE_STRING, props->items[i].key,
|
|
SPA_POD_TYPE_STRING, props->items[i].value,
|
|
0);
|
|
}
|
|
spa_pod_builder_add (&b.b,
|
|
SPA_POD_TYPE_INT, new_id,
|
|
-SPA_POD_TYPE_STRUCT, &f, 0);
|
|
|
|
pinos_connection_end_write (connection, proxy->id, 3, b.b.offset);
|
|
}
|
|
|
|
static void
|
|
core_marshal_create_client_node (void *object,
|
|
const char *name,
|
|
const SpaDict *props,
|
|
uint32_t new_id)
|
|
{
|
|
PinosProxy *proxy = object;
|
|
PinosConnection *connection = proxy->context->protocol_private;
|
|
Builder b = { { NULL, 0, 0, NULL, write_pod }, connection };
|
|
SpaPODFrame f;
|
|
uint32_t i, n_items;
|
|
|
|
core_update_map (proxy->context);
|
|
|
|
n_items = props ? props->n_items : 0;
|
|
|
|
spa_pod_builder_add (&b.b,
|
|
SPA_POD_TYPE_STRUCT, &f,
|
|
SPA_POD_TYPE_STRING, name,
|
|
SPA_POD_TYPE_INT, n_items, 0);
|
|
|
|
for (i = 0; i < n_items; i++) {
|
|
spa_pod_builder_add (&b.b,
|
|
SPA_POD_TYPE_STRING, props->items[i].key,
|
|
SPA_POD_TYPE_STRING, props->items[i].value,
|
|
0);
|
|
}
|
|
spa_pod_builder_add (&b.b,
|
|
SPA_POD_TYPE_INT, new_id,
|
|
-SPA_POD_TYPE_STRUCT, &f, 0);
|
|
|
|
pinos_connection_end_write (connection, proxy->id, 4, b.b.offset);
|
|
}
|
|
|
|
static void
|
|
core_marshal_update_types (void *object,
|
|
uint32_t first_id,
|
|
uint32_t n_types,
|
|
const char **types)
|
|
{
|
|
PinosProxy *proxy = object;
|
|
PinosConnection *connection = proxy->context->protocol_private;
|
|
Builder b = { { NULL, 0, 0, NULL, write_pod }, connection };
|
|
SpaPODFrame f;
|
|
uint32_t i;
|
|
|
|
spa_pod_builder_add (&b.b,
|
|
SPA_POD_TYPE_STRUCT, &f,
|
|
SPA_POD_TYPE_INT, first_id,
|
|
SPA_POD_TYPE_INT, n_types, 0);
|
|
|
|
for (i = 0; i < n_types; i++) {
|
|
spa_pod_builder_add (&b.b,
|
|
SPA_POD_TYPE_STRING, types[i], 0);
|
|
}
|
|
spa_pod_builder_add (&b.b,
|
|
-SPA_POD_TYPE_STRUCT, &f, 0);
|
|
|
|
pinos_connection_end_write (connection, proxy->id, 5, b.b.offset);
|
|
}
|
|
|
|
static bool
|
|
core_demarshal_info (void *object,
|
|
void *data,
|
|
size_t size)
|
|
{
|
|
PinosProxy *proxy = object;
|
|
SpaDict props;
|
|
PinosCoreInfo info;
|
|
SpaPODIter it;
|
|
int i;
|
|
|
|
if (!spa_pod_iter_struct (&it, data, size) ||
|
|
!spa_pod_iter_get (&it,
|
|
SPA_POD_TYPE_INT, &info.id,
|
|
SPA_POD_TYPE_LONG, &info.change_mask,
|
|
SPA_POD_TYPE_STRING, &info.user_name,
|
|
SPA_POD_TYPE_STRING, &info.host_name,
|
|
SPA_POD_TYPE_STRING, &info.version,
|
|
SPA_POD_TYPE_STRING, &info.name,
|
|
SPA_POD_TYPE_INT, &info.cookie,
|
|
SPA_POD_TYPE_INT, &props.n_items,
|
|
0))
|
|
return false;
|
|
|
|
info.props = &props;
|
|
props.items = alloca (props.n_items * sizeof (SpaDictItem));
|
|
for (i = 0; i < props.n_items; i++) {
|
|
if (!spa_pod_iter_get (&it,
|
|
SPA_POD_TYPE_STRING, &props.items[i].key,
|
|
SPA_POD_TYPE_STRING, &props.items[i].value,
|
|
0))
|
|
return false;
|
|
}
|
|
((PinosCoreEvents*)proxy->implementation)->info (proxy, &info);
|
|
return true;
|
|
}
|
|
|
|
static bool
|
|
core_demarshal_done (void *object,
|
|
void *data,
|
|
size_t size)
|
|
{
|
|
PinosProxy *proxy = object;
|
|
SpaPODIter it;
|
|
uint32_t seq;
|
|
|
|
if (!spa_pod_iter_struct (&it, data, size) ||
|
|
!spa_pod_iter_get (&it,
|
|
SPA_POD_TYPE_INT, &seq,
|
|
0))
|
|
return false;
|
|
|
|
((PinosCoreEvents*)proxy->implementation)->done (proxy, seq);
|
|
return true;
|
|
}
|
|
|
|
static bool
|
|
core_demarshal_error (void *object,
|
|
void *data,
|
|
size_t size)
|
|
{
|
|
PinosProxy *proxy = object;
|
|
SpaPODIter it;
|
|
uint32_t id, res;
|
|
const char *error;
|
|
|
|
if (!spa_pod_iter_struct (&it, data, size) ||
|
|
!spa_pod_iter_get (&it,
|
|
SPA_POD_TYPE_INT, &id,
|
|
SPA_POD_TYPE_INT, &res,
|
|
SPA_POD_TYPE_STRING, &error,
|
|
0))
|
|
return false;
|
|
|
|
((PinosCoreEvents*)proxy->implementation)->error (proxy, id, res, error);
|
|
return true;
|
|
}
|
|
|
|
static bool
|
|
core_demarshal_remove_id (void *object,
|
|
void *data,
|
|
size_t size)
|
|
{
|
|
PinosProxy *proxy = object;
|
|
SpaPODIter it;
|
|
uint32_t id;
|
|
|
|
if (!spa_pod_iter_struct (&it, data, size) ||
|
|
!spa_pod_iter_get (&it,
|
|
SPA_POD_TYPE_INT, &id,
|
|
0))
|
|
return false;
|
|
|
|
((PinosCoreEvents*)proxy->implementation)->remove_id (proxy, id);
|
|
return true;
|
|
}
|
|
|
|
static bool
|
|
core_demarshal_update_types (void *object,
|
|
void *data,
|
|
size_t size)
|
|
{
|
|
PinosProxy *proxy = object;
|
|
SpaPODIter it;
|
|
uint32_t first_id, n_types;
|
|
const char **types;
|
|
int i;
|
|
|
|
if (!spa_pod_iter_struct (&it, data, size) ||
|
|
!spa_pod_iter_get (&it,
|
|
SPA_POD_TYPE_INT, &first_id,
|
|
SPA_POD_TYPE_INT, &n_types,
|
|
0))
|
|
return false;
|
|
|
|
types = alloca (n_types * sizeof (char *));
|
|
for (i = 0; i < n_types; i++) {
|
|
if (!spa_pod_iter_get (&it, SPA_POD_TYPE_STRING, &types[i], 0))
|
|
return false;
|
|
}
|
|
((PinosCoreEvents*)proxy->implementation)->update_types (proxy, first_id, n_types, types);
|
|
return true;
|
|
}
|
|
|
|
static bool
|
|
module_demarshal_info (void *object,
|
|
void *data,
|
|
size_t size)
|
|
{
|
|
PinosProxy *proxy = object;
|
|
SpaPODIter it;
|
|
SpaDict props;
|
|
PinosModuleInfo info;
|
|
int i;
|
|
|
|
if (!spa_pod_iter_struct (&it, data, size) ||
|
|
!spa_pod_iter_get (&it,
|
|
SPA_POD_TYPE_INT, &info.id,
|
|
SPA_POD_TYPE_LONG, &info.change_mask,
|
|
SPA_POD_TYPE_STRING, &info.name,
|
|
SPA_POD_TYPE_STRING, &info.filename,
|
|
SPA_POD_TYPE_STRING, &info.args,
|
|
SPA_POD_TYPE_INT, &props.n_items,
|
|
0))
|
|
return false;
|
|
|
|
info.props = &props;
|
|
props.items = alloca (props.n_items * sizeof (SpaDictItem));
|
|
for (i = 0; i < props.n_items; i++) {
|
|
if (!spa_pod_iter_get (&it,
|
|
SPA_POD_TYPE_STRING, &props.items[i].key,
|
|
SPA_POD_TYPE_STRING, &props.items[i].value,
|
|
0))
|
|
return false;
|
|
}
|
|
((PinosModuleEvents*)proxy->implementation)->info (proxy, &info);
|
|
return true;
|
|
}
|
|
|
|
static bool
|
|
node_demarshal_info (void *object,
|
|
void *data,
|
|
size_t size)
|
|
{
|
|
PinosProxy *proxy = object;
|
|
SpaPODIter it;
|
|
SpaDict props;
|
|
PinosNodeInfo info;
|
|
int i;
|
|
|
|
if (!spa_pod_iter_struct (&it, data, size) ||
|
|
!spa_pod_iter_get (&it,
|
|
SPA_POD_TYPE_INT, &info.id,
|
|
SPA_POD_TYPE_LONG, &info.change_mask,
|
|
SPA_POD_TYPE_STRING, &info.name,
|
|
SPA_POD_TYPE_INT, &info.max_inputs,
|
|
SPA_POD_TYPE_INT, &info.n_inputs,
|
|
SPA_POD_TYPE_INT, &info.n_input_formats,
|
|
0))
|
|
return false;
|
|
|
|
info.input_formats = alloca (info.n_input_formats * sizeof (SpaFormat*));
|
|
for (i = 0; i < info.n_input_formats; i++)
|
|
if (!spa_pod_iter_get (&it, SPA_POD_TYPE_OBJECT, &info.input_formats[i], 0))
|
|
return false;
|
|
|
|
if (!spa_pod_iter_get (&it,
|
|
SPA_POD_TYPE_INT, &info.max_outputs,
|
|
SPA_POD_TYPE_INT, &info.n_outputs,
|
|
SPA_POD_TYPE_INT, &info.n_output_formats,
|
|
0))
|
|
return false;
|
|
|
|
info.output_formats = alloca (info.n_output_formats * sizeof (SpaFormat*));
|
|
for (i = 0; i < info.n_output_formats; i++)
|
|
if (!spa_pod_iter_get (&it, SPA_POD_TYPE_OBJECT, &info.output_formats[i], 0))
|
|
return false;
|
|
|
|
if (!spa_pod_iter_get (&it,
|
|
SPA_POD_TYPE_INT, &info.state,
|
|
SPA_POD_TYPE_STRING, &info.error,
|
|
SPA_POD_TYPE_INT, &props.n_items,
|
|
0))
|
|
return false;
|
|
|
|
info.props = &props;
|
|
props.items = alloca (props.n_items * sizeof (SpaDictItem));
|
|
for (i = 0; i < props.n_items; i++) {
|
|
if (!spa_pod_iter_get (&it,
|
|
SPA_POD_TYPE_STRING, &props.items[i].key,
|
|
SPA_POD_TYPE_STRING, &props.items[i].value,
|
|
0))
|
|
return false;
|
|
}
|
|
((PinosNodeEvents*)proxy->implementation)->info (proxy, &info);
|
|
return true;
|
|
}
|
|
|
|
static void
|
|
client_node_marshal_update (void *object,
|
|
uint32_t change_mask,
|
|
uint32_t max_input_ports,
|
|
uint32_t max_output_ports,
|
|
const SpaProps *props)
|
|
{
|
|
PinosProxy *proxy = object;
|
|
PinosConnection *connection = proxy->context->protocol_private;
|
|
Builder b = { { NULL, 0, 0, NULL, write_pod }, connection };
|
|
SpaPODFrame f;
|
|
|
|
core_update_map (proxy->context);
|
|
|
|
spa_pod_builder_struct (&b.b, &f,
|
|
SPA_POD_TYPE_INT, change_mask,
|
|
SPA_POD_TYPE_INT, max_input_ports,
|
|
SPA_POD_TYPE_INT, max_output_ports,
|
|
SPA_POD_TYPE_POD, props);
|
|
|
|
pinos_connection_end_write (connection, proxy->id, 0, b.b.offset);
|
|
}
|
|
|
|
static void
|
|
client_node_marshal_port_update (void *object,
|
|
SpaDirection direction,
|
|
uint32_t port_id,
|
|
uint32_t change_mask,
|
|
uint32_t n_possible_formats,
|
|
const SpaFormat **possible_formats,
|
|
const SpaFormat *format,
|
|
const SpaProps *props,
|
|
const SpaPortInfo *info)
|
|
{
|
|
PinosProxy *proxy = object;
|
|
PinosConnection *connection = proxy->context->protocol_private;
|
|
Builder b = { { NULL, 0, 0, NULL, write_pod }, connection };
|
|
SpaPODFrame f[2];
|
|
int i, n_items;
|
|
|
|
core_update_map (proxy->context);
|
|
|
|
spa_pod_builder_add (&b.b,
|
|
SPA_POD_TYPE_STRUCT, &f[0],
|
|
SPA_POD_TYPE_INT, direction,
|
|
SPA_POD_TYPE_INT, port_id,
|
|
SPA_POD_TYPE_INT, change_mask,
|
|
SPA_POD_TYPE_INT, n_possible_formats,
|
|
0);
|
|
|
|
for (i = 0; i < n_possible_formats; i++)
|
|
spa_pod_builder_add (&b.b, SPA_POD_TYPE_POD, possible_formats[i], 0);
|
|
|
|
spa_pod_builder_add (&b.b,
|
|
SPA_POD_TYPE_POD, format,
|
|
SPA_POD_TYPE_POD, props,
|
|
0);
|
|
|
|
if (info) {
|
|
spa_pod_builder_add (&b.b,
|
|
SPA_POD_TYPE_STRUCT, &f[1],
|
|
SPA_POD_TYPE_INT, info->flags,
|
|
SPA_POD_TYPE_LONG, info->maxbuffering,
|
|
SPA_POD_TYPE_LONG, info->latency,
|
|
SPA_POD_TYPE_INT, info->n_params,
|
|
0);
|
|
|
|
for (i = 0; i < info->n_params; i++) {
|
|
SpaAllocParam *p = info->params[i];
|
|
spa_pod_builder_add (&b.b, SPA_POD_TYPE_POD, p, 0);
|
|
}
|
|
n_items = info->extra ? info->extra->n_items : 0;
|
|
spa_pod_builder_add (&b.b, SPA_POD_TYPE_INT, n_items, 0);
|
|
for (i = 0; i < n_items; i++) {
|
|
spa_pod_builder_add (&b.b,
|
|
SPA_POD_TYPE_STRING, info->extra->items[i].key,
|
|
SPA_POD_TYPE_STRING, info->extra->items[i].value,
|
|
0);
|
|
}
|
|
spa_pod_builder_add (&b.b, -SPA_POD_TYPE_STRUCT, &f[1], 0);
|
|
} else {
|
|
spa_pod_builder_add (&b.b, SPA_POD_TYPE_POD, NULL, 0);
|
|
}
|
|
spa_pod_builder_add (&b.b, -SPA_POD_TYPE_STRUCT, &f[0], 0);
|
|
|
|
pinos_connection_end_write (connection, proxy->id, 1, b.b.offset);
|
|
}
|
|
|
|
static void
|
|
client_node_marshal_event (void *object,
|
|
SpaEvent *event)
|
|
{
|
|
PinosProxy *proxy = object;
|
|
PinosConnection *connection = proxy->context->protocol_private;
|
|
Builder b = { { NULL, 0, 0, NULL, write_pod }, connection };
|
|
SpaPODFrame f;
|
|
|
|
core_update_map (proxy->context);
|
|
|
|
spa_pod_builder_struct (&b.b, &f,
|
|
SPA_POD_TYPE_POD, event);
|
|
|
|
pinos_connection_end_write (connection, proxy->id, 2, b.b.offset);
|
|
}
|
|
|
|
static void
|
|
client_node_marshal_destroy (void *object)
|
|
{
|
|
PinosProxy *proxy = object;
|
|
PinosConnection *connection = proxy->context->protocol_private;
|
|
Builder b = { { NULL, 0, 0, NULL, write_pod }, connection };
|
|
SpaPODFrame f;
|
|
|
|
core_update_map (proxy->context);
|
|
|
|
spa_pod_builder_struct (&b.b, &f, 0);
|
|
|
|
pinos_connection_end_write (connection, proxy->id, 3, b.b.offset);
|
|
}
|
|
|
|
static bool
|
|
client_node_demarshal_done (void *object,
|
|
void *data,
|
|
size_t size)
|
|
{
|
|
PinosProxy *proxy = object;
|
|
SpaPODIter it;
|
|
PinosConnection *connection = proxy->context->protocol_private;
|
|
int32_t idx;
|
|
int fd;
|
|
|
|
if (!spa_pod_iter_struct (&it, data, size) ||
|
|
!spa_pod_iter_get (&it,
|
|
SPA_POD_TYPE_INT, &idx,
|
|
0))
|
|
return false;
|
|
|
|
fd = pinos_connection_get_fd (connection, idx);
|
|
((PinosClientNodeEvents*)proxy->implementation)->done (proxy, fd);
|
|
return true;
|
|
}
|
|
|
|
static bool
|
|
client_node_demarshal_event (void *object,
|
|
void *data,
|
|
size_t size)
|
|
{
|
|
PinosProxy *proxy = object;
|
|
SpaPODIter it;
|
|
const SpaEvent *event;
|
|
|
|
if (!spa_pod_iter_struct (&it, data, size) ||
|
|
!spa_pod_iter_get (&it,
|
|
SPA_POD_TYPE_OBJECT, &event,
|
|
0))
|
|
return false;
|
|
|
|
((PinosClientNodeEvents*)proxy->implementation)->event (proxy, event);
|
|
return true;
|
|
}
|
|
|
|
static bool
|
|
client_node_demarshal_add_port (void *object,
|
|
void *data,
|
|
size_t size)
|
|
{
|
|
PinosProxy *proxy = object;
|
|
SpaPODIter it;
|
|
int32_t seq, direction, port_id;
|
|
|
|
if (!spa_pod_iter_struct (&it, data, size) ||
|
|
!spa_pod_iter_get (&it,
|
|
SPA_POD_TYPE_INT, &seq,
|
|
SPA_POD_TYPE_INT, &direction,
|
|
SPA_POD_TYPE_INT, &port_id,
|
|
0))
|
|
return false;
|
|
|
|
((PinosClientNodeEvents*)proxy->implementation)->add_port (proxy, seq, direction, port_id);
|
|
return true;
|
|
}
|
|
|
|
static bool
|
|
client_node_demarshal_remove_port (void *object,
|
|
void *data,
|
|
size_t size)
|
|
{
|
|
PinosProxy *proxy = object;
|
|
SpaPODIter it;
|
|
int32_t seq, direction, port_id;
|
|
|
|
if (!spa_pod_iter_struct (&it, data, size) ||
|
|
!spa_pod_iter_get (&it,
|
|
SPA_POD_TYPE_INT, &seq,
|
|
SPA_POD_TYPE_INT, &direction,
|
|
SPA_POD_TYPE_INT, &port_id,
|
|
0))
|
|
return false;
|
|
|
|
((PinosClientNodeEvents*)proxy->implementation)->remove_port (proxy, seq, direction, port_id);
|
|
return true;
|
|
}
|
|
|
|
static bool
|
|
client_node_demarshal_set_format (void *object,
|
|
void *data,
|
|
size_t size)
|
|
{
|
|
PinosProxy *proxy = object;
|
|
SpaPODIter it;
|
|
uint32_t seq, direction, port_id, flags;
|
|
const SpaFormat *format = NULL;
|
|
|
|
if (!spa_pod_iter_struct (&it, data, size) ||
|
|
!spa_pod_iter_get (&it,
|
|
SPA_POD_TYPE_INT, &seq,
|
|
SPA_POD_TYPE_INT, &direction,
|
|
SPA_POD_TYPE_INT, &port_id,
|
|
SPA_POD_TYPE_INT, &flags,
|
|
-SPA_POD_TYPE_OBJECT, &format,
|
|
0))
|
|
return false;
|
|
|
|
((PinosClientNodeEvents*)proxy->implementation)->set_format (proxy, seq, direction, port_id,
|
|
flags, format);
|
|
return true;
|
|
}
|
|
|
|
static bool
|
|
client_node_demarshal_set_property (void *object,
|
|
void *data,
|
|
size_t size)
|
|
{
|
|
PinosProxy *proxy = object;
|
|
SpaPODIter it;
|
|
uint32_t seq, id;
|
|
const void *value;
|
|
uint32_t s;
|
|
|
|
if (!spa_pod_iter_struct (&it, data, size) ||
|
|
!spa_pod_iter_get (&it,
|
|
SPA_POD_TYPE_INT, &seq,
|
|
SPA_POD_TYPE_INT, &id,
|
|
SPA_POD_TYPE_BYTES, &value, &s,
|
|
0))
|
|
return false;
|
|
|
|
((PinosClientNodeEvents*)proxy->implementation)->set_property (proxy, seq, id, s, value);
|
|
return true;
|
|
}
|
|
|
|
static bool
|
|
client_node_demarshal_add_mem (void *object,
|
|
void *data,
|
|
size_t size)
|
|
{
|
|
PinosProxy *proxy = object;
|
|
SpaPODIter it;
|
|
PinosConnection *connection = proxy->context->protocol_private;
|
|
uint32_t direction, port_id, mem_id, type, memfd_idx, flags, offset, sz;
|
|
int memfd;
|
|
|
|
if (!spa_pod_iter_struct (&it, data, size) ||
|
|
!spa_pod_iter_get (&it,
|
|
SPA_POD_TYPE_INT, &direction,
|
|
SPA_POD_TYPE_INT, &port_id,
|
|
SPA_POD_TYPE_INT, &mem_id,
|
|
SPA_POD_TYPE_INT, &type,
|
|
SPA_POD_TYPE_INT, &memfd_idx,
|
|
SPA_POD_TYPE_INT, &flags,
|
|
SPA_POD_TYPE_INT, &offset,
|
|
SPA_POD_TYPE_INT, &sz,
|
|
0))
|
|
return false;
|
|
|
|
memfd = pinos_connection_get_fd (connection, memfd_idx);
|
|
|
|
((PinosClientNodeEvents*)proxy->implementation)->add_mem (proxy,
|
|
direction,
|
|
port_id,
|
|
mem_id,
|
|
type,
|
|
memfd,
|
|
flags,
|
|
offset,
|
|
sz);
|
|
return true;
|
|
}
|
|
|
|
static bool
|
|
client_node_demarshal_use_buffers (void *object,
|
|
void *data,
|
|
size_t size)
|
|
{
|
|
PinosProxy *proxy = object;
|
|
SpaPODIter it;
|
|
uint32_t seq, direction, port_id, n_buffers, data_id;
|
|
PinosClientNodeBuffer *buffers;
|
|
int i, j;
|
|
|
|
if (!spa_pod_iter_struct (&it, data, size) ||
|
|
!spa_pod_iter_get (&it,
|
|
SPA_POD_TYPE_INT, &seq,
|
|
SPA_POD_TYPE_INT, &direction,
|
|
SPA_POD_TYPE_INT, &port_id,
|
|
SPA_POD_TYPE_INT, &n_buffers,
|
|
0))
|
|
return false;
|
|
|
|
buffers = alloca (sizeof (PinosClientNodeBuffer) * n_buffers);
|
|
for (i = 0; i < n_buffers; i++) {
|
|
SpaBuffer *buf = buffers[i].buffer = alloca (sizeof (SpaBuffer));
|
|
|
|
if (!spa_pod_iter_get (&it,
|
|
SPA_POD_TYPE_INT, &buffers[i].mem_id,
|
|
SPA_POD_TYPE_INT, &buffers[i].offset,
|
|
SPA_POD_TYPE_INT, &buffers[i].size,
|
|
SPA_POD_TYPE_INT, &buf->id,
|
|
SPA_POD_TYPE_INT, &buf->n_metas, 0))
|
|
return false;
|
|
|
|
buf->metas = alloca (sizeof (SpaMeta) * buf->n_metas);
|
|
for (j = 0; j < buf->n_metas; j++) {
|
|
SpaMeta *m = &buf->metas[j];
|
|
|
|
if (!spa_pod_iter_get (&it,
|
|
SPA_POD_TYPE_INT, &m->type,
|
|
SPA_POD_TYPE_INT, &m->size, 0))
|
|
return false;
|
|
}
|
|
if (!spa_pod_iter_get (&it, SPA_POD_TYPE_INT, &buf->n_datas, 0))
|
|
return false;
|
|
|
|
buf->datas = alloca (sizeof (SpaData) * buf->n_datas);
|
|
for (j = 0; j < buf->n_datas; j++) {
|
|
SpaData *d = &buf->datas[j];
|
|
|
|
if (!spa_pod_iter_get (&it,
|
|
SPA_POD_TYPE_INT, &d->type,
|
|
SPA_POD_TYPE_INT, &data_id,
|
|
SPA_POD_TYPE_INT, &d->flags,
|
|
SPA_POD_TYPE_INT, &d->mapoffset,
|
|
SPA_POD_TYPE_INT, &d->maxsize,
|
|
0))
|
|
return false;
|
|
|
|
d->data = SPA_UINT32_TO_PTR (data_id);
|
|
}
|
|
}
|
|
((PinosClientNodeEvents*)proxy->implementation)->use_buffers (proxy,
|
|
seq,
|
|
direction,
|
|
port_id,
|
|
n_buffers,
|
|
buffers);
|
|
return true;
|
|
}
|
|
|
|
static bool
|
|
client_node_demarshal_node_command (void *object,
|
|
void *data,
|
|
size_t size)
|
|
{
|
|
PinosProxy *proxy = object;
|
|
SpaPODIter it;
|
|
const SpaCommand *command;
|
|
uint32_t seq;
|
|
|
|
if (!spa_pod_iter_struct (&it, data, size) ||
|
|
!spa_pod_iter_get (&it,
|
|
SPA_POD_TYPE_INT, &seq,
|
|
SPA_POD_TYPE_OBJECT, &command,
|
|
0))
|
|
return false;
|
|
|
|
((PinosClientNodeEvents*)proxy->implementation)->node_command (proxy, seq, command);
|
|
return true;
|
|
}
|
|
|
|
static bool
|
|
client_node_demarshal_port_command (void *object,
|
|
void *data,
|
|
size_t size)
|
|
{
|
|
PinosProxy *proxy = object;
|
|
SpaPODIter it;
|
|
const SpaCommand *command;
|
|
uint32_t port_id;
|
|
|
|
if (!spa_pod_iter_struct (&it, data, size) ||
|
|
!spa_pod_iter_get (&it,
|
|
SPA_POD_TYPE_INT, &port_id,
|
|
SPA_POD_TYPE_OBJECT, &command,
|
|
0))
|
|
return false;
|
|
|
|
((PinosClientNodeEvents*)proxy->implementation)->port_command (proxy, port_id, command);
|
|
return true;
|
|
}
|
|
|
|
static bool
|
|
client_node_demarshal_transport (void *object,
|
|
void *data,
|
|
size_t size)
|
|
{
|
|
PinosProxy *proxy = object;
|
|
SpaPODIter it;
|
|
PinosConnection *connection = proxy->context->protocol_private;
|
|
uint32_t memfd_idx, offset, sz;
|
|
int memfd;
|
|
|
|
if (!spa_pod_iter_struct (&it, data, size) ||
|
|
!spa_pod_iter_get (&it,
|
|
SPA_POD_TYPE_INT, &memfd_idx,
|
|
SPA_POD_TYPE_INT, &offset,
|
|
SPA_POD_TYPE_INT, &sz,
|
|
0))
|
|
return false;
|
|
|
|
memfd = pinos_connection_get_fd (connection, memfd_idx);
|
|
((PinosClientNodeEvents*)proxy->implementation)->transport (proxy, memfd, offset, sz);
|
|
return true;
|
|
}
|
|
|
|
static bool
|
|
client_demarshal_info (void *object,
|
|
void *data,
|
|
size_t size)
|
|
{
|
|
PinosProxy *proxy = object;
|
|
SpaPODIter it;
|
|
SpaDict props;
|
|
PinosClientInfo info;
|
|
uint32_t i;
|
|
|
|
if (!spa_pod_iter_struct (&it, data, size) ||
|
|
!spa_pod_iter_get (&it,
|
|
SPA_POD_TYPE_INT, &info.id,
|
|
SPA_POD_TYPE_LONG, &info.change_mask,
|
|
SPA_POD_TYPE_INT, &props.n_items,
|
|
0))
|
|
return false;
|
|
|
|
info.props = &props;
|
|
props.items = alloca (props.n_items * sizeof (SpaDictItem));
|
|
for (i = 0; i < props.n_items; i++) {
|
|
if (!spa_pod_iter_get (&it,
|
|
SPA_POD_TYPE_STRING, &props.items[i].key,
|
|
SPA_POD_TYPE_STRING, &props.items[i].value,
|
|
0))
|
|
return false;
|
|
}
|
|
((PinosClientEvents*)proxy->implementation)->info (proxy, &info);
|
|
return true;
|
|
}
|
|
|
|
static bool
|
|
link_demarshal_info (void *object,
|
|
void *data,
|
|
size_t size)
|
|
{
|
|
PinosProxy *proxy = object;
|
|
SpaPODIter it;
|
|
PinosLinkInfo info;
|
|
|
|
if (!spa_pod_iter_struct (&it, data, size) ||
|
|
!spa_pod_iter_get (&it,
|
|
SPA_POD_TYPE_INT, &info.id,
|
|
SPA_POD_TYPE_LONG, &info.change_mask,
|
|
SPA_POD_TYPE_INT, &info.output_node_id,
|
|
SPA_POD_TYPE_INT, &info.output_port_id,
|
|
SPA_POD_TYPE_INT, &info.input_node_id,
|
|
SPA_POD_TYPE_INT, &info.input_port_id,
|
|
0))
|
|
return false;
|
|
|
|
((PinosLinkEvents*)proxy->implementation)->info (proxy, &info);
|
|
return true;
|
|
}
|
|
|
|
static bool
|
|
registry_demarshal_global (void *object,
|
|
void *data,
|
|
size_t size)
|
|
{
|
|
PinosProxy *proxy = object;
|
|
SpaPODIter it;
|
|
uint32_t id;
|
|
const char *type;
|
|
|
|
if (!spa_pod_iter_struct (&it, data, size) ||
|
|
!spa_pod_iter_get (&it,
|
|
SPA_POD_TYPE_INT, &id,
|
|
SPA_POD_TYPE_STRING, &type,
|
|
0))
|
|
return false;
|
|
|
|
((PinosRegistryEvents*)proxy->implementation)->global (proxy, id, type);
|
|
return true;
|
|
}
|
|
|
|
static bool
|
|
registry_demarshal_global_remove (void *object,
|
|
void *data,
|
|
size_t size)
|
|
{
|
|
PinosProxy *proxy = object;
|
|
SpaPODIter it;
|
|
uint32_t id;
|
|
|
|
if (!spa_pod_iter_struct (&it, data, size) ||
|
|
!spa_pod_iter_get (&it,
|
|
SPA_POD_TYPE_INT, &id,
|
|
0))
|
|
return false;
|
|
|
|
((PinosRegistryEvents*)proxy->implementation)->global_remove (proxy, id);
|
|
return true;
|
|
}
|
|
|
|
static void
|
|
registry_marshal_bind (void *object,
|
|
uint32_t id,
|
|
uint32_t new_id)
|
|
{
|
|
PinosProxy *proxy = object;
|
|
PinosConnection *connection = proxy->context->protocol_private;
|
|
Builder b = { { NULL, 0, 0, NULL, write_pod }, connection };
|
|
SpaPODFrame f;
|
|
|
|
core_update_map (proxy->context);
|
|
|
|
spa_pod_builder_struct (&b.b, &f,
|
|
SPA_POD_TYPE_INT, id,
|
|
SPA_POD_TYPE_INT, new_id);
|
|
|
|
pinos_connection_end_write (connection, proxy->id, 0, b.b.offset);
|
|
}
|
|
|
|
static const PinosCoreMethods pinos_protocol_native_client_core_methods = {
|
|
&core_marshal_client_update,
|
|
&core_marshal_sync,
|
|
&core_marshal_get_registry,
|
|
&core_marshal_create_node,
|
|
&core_marshal_create_client_node,
|
|
&core_marshal_update_types,
|
|
};
|
|
|
|
static const PinosDemarshalFunc pinos_protocol_native_client_core_demarshal[] = {
|
|
&core_demarshal_info,
|
|
&core_demarshal_done,
|
|
&core_demarshal_error,
|
|
&core_demarshal_remove_id,
|
|
&core_demarshal_update_types,
|
|
};
|
|
|
|
static const PinosInterface pinos_protocol_native_client_core_interface = {
|
|
6, &pinos_protocol_native_client_core_methods,
|
|
5, pinos_protocol_native_client_core_demarshal
|
|
};
|
|
|
|
static const PinosRegistryMethods pinos_protocol_native_client_registry_methods = {
|
|
®istry_marshal_bind
|
|
};
|
|
|
|
static const PinosDemarshalFunc pinos_protocol_native_client_registry_demarshal[] = {
|
|
®istry_demarshal_global,
|
|
®istry_demarshal_global_remove,
|
|
};
|
|
|
|
static const PinosInterface pinos_protocol_native_client_registry_interface = {
|
|
1, &pinos_protocol_native_client_registry_methods,
|
|
2, pinos_protocol_native_client_registry_demarshal,
|
|
};
|
|
|
|
static const PinosClientNodeMethods pinos_protocol_native_client_client_node_methods = {
|
|
&client_node_marshal_update,
|
|
&client_node_marshal_port_update,
|
|
&client_node_marshal_event,
|
|
&client_node_marshal_destroy
|
|
};
|
|
|
|
static const PinosDemarshalFunc pinos_protocol_native_client_client_node_demarshal[] = {
|
|
&client_node_demarshal_done,
|
|
&client_node_demarshal_event,
|
|
&client_node_demarshal_add_port,
|
|
&client_node_demarshal_remove_port,
|
|
&client_node_demarshal_set_format,
|
|
&client_node_demarshal_set_property,
|
|
&client_node_demarshal_add_mem,
|
|
&client_node_demarshal_use_buffers,
|
|
&client_node_demarshal_node_command,
|
|
&client_node_demarshal_port_command,
|
|
&client_node_demarshal_transport
|
|
};
|
|
|
|
static const PinosInterface pinos_protocol_native_client_client_node_interface = {
|
|
4, &pinos_protocol_native_client_client_node_methods,
|
|
11, pinos_protocol_native_client_client_node_demarshal,
|
|
};
|
|
|
|
static const PinosDemarshalFunc pinos_protocol_native_client_module_demarshal[] = {
|
|
&module_demarshal_info,
|
|
};
|
|
|
|
static const PinosInterface pinos_protocol_native_client_module_interface = {
|
|
0, NULL,
|
|
1, pinos_protocol_native_client_module_demarshal,
|
|
};
|
|
|
|
static const PinosDemarshalFunc pinos_protocol_native_client_node_demarshal[] = {
|
|
&node_demarshal_info,
|
|
};
|
|
|
|
static const PinosInterface pinos_protocol_native_client_node_interface = {
|
|
0, NULL,
|
|
1, pinos_protocol_native_client_node_demarshal,
|
|
};
|
|
|
|
static const PinosDemarshalFunc pinos_protocol_native_client_client_demarshal[] = {
|
|
&client_demarshal_info,
|
|
};
|
|
|
|
static const PinosInterface pinos_protocol_native_client_client_interface = {
|
|
0, NULL,
|
|
1, pinos_protocol_native_client_client_demarshal,
|
|
};
|
|
|
|
static const PinosDemarshalFunc pinos_protocol_native_client_link_demarshal[] = {
|
|
&link_demarshal_info,
|
|
};
|
|
|
|
static const PinosInterface pinos_protocol_native_client_link_interface = {
|
|
0, NULL,
|
|
1, pinos_protocol_native_client_link_demarshal,
|
|
};
|
|
|
|
bool
|
|
pinos_protocol_native_client_setup (PinosProxy *proxy)
|
|
{
|
|
const PinosInterface *iface;
|
|
|
|
if (proxy->type == proxy->context->type.core) {
|
|
iface = &pinos_protocol_native_client_core_interface;
|
|
}
|
|
else if (proxy->type == proxy->context->type.registry) {
|
|
iface = &pinos_protocol_native_client_registry_interface;
|
|
}
|
|
else if (proxy->type == proxy->context->type.module) {
|
|
iface = &pinos_protocol_native_client_module_interface;
|
|
}
|
|
else if (proxy->type == proxy->context->type.node) {
|
|
iface = &pinos_protocol_native_client_node_interface;
|
|
}
|
|
else if (proxy->type == proxy->context->type.client_node) {
|
|
iface = &pinos_protocol_native_client_client_node_interface;
|
|
}
|
|
else if (proxy->type == proxy->context->type.client) {
|
|
iface = &pinos_protocol_native_client_client_interface;
|
|
}
|
|
else if (proxy->type == proxy->context->type.link) {
|
|
iface = &pinos_protocol_native_client_link_interface;
|
|
} else
|
|
return false;
|
|
proxy->iface = iface;
|
|
return true;
|
|
}
|