node: add port and node params

Add a new struct spa_param_info that lists the available params on
a node/port and if they are readable/writable/updated. We can use
this to replace and improve the PARAM_List and also to notify
property change and updates.

Update elements and code to deal with this new param stuff. Add
port and node info to most elements and signal changes.

Use async enum_params in -inspect and use the param info to know
which ones to enumerate.

Use the port info to know what parameters to update in the
remote-node.
This commit is contained in:
Wim Taymans 2019-02-27 16:43:01 +01:00
parent 3d25adc598
commit 499dd3ff22
52 changed files with 1979 additions and 1461 deletions

View file

@ -73,8 +73,6 @@ struct data {
struct pw_remote *remote;
struct spa_hook remote_listener;
struct spa_port_info port_info;
struct spa_node impl_node;
const struct spa_node_callbacks *callbacks;
void *callbacks_data;
@ -144,10 +142,19 @@ static int impl_set_callbacks(struct spa_node *node,
if (d->callbacks && d->callbacks->port_info) {
struct spa_port_info info;
struct spa_param_info params[5];
info = SPA_PORT_INFO_INIT();
info.change_mask = SPA_PORT_CHANGE_MASK_FLAGS;
info.flags = SPA_PORT_FLAG_CAN_USE_BUFFERS;
info.change_mask = SPA_PORT_CHANGE_MASK_PARAMS;
params[0] = SPA_PARAM_INFO(SPA_PARAM_EnumFormat, SPA_PARAM_INFO_READ);
params[1] = SPA_PARAM_INFO(SPA_PARAM_Meta, SPA_PARAM_INFO_READ);
params[2] = SPA_PARAM_INFO(SPA_PARAM_IO, SPA_PARAM_INFO_READ);
params[3] = SPA_PARAM_INFO(SPA_PARAM_Buffers, SPA_PARAM_INFO_READ);
params[4] = SPA_PARAM_INFO(SPA_PARAM_Format, SPA_PARAM_INFO_WRITE);
info.params = params;
info.n_params = 5;
d->callbacks->port_info(d->callbacks_data, SPA_DIRECTION_INPUT, 0, &info);
}
@ -201,22 +208,6 @@ static int impl_port_enum_params(struct spa_node *node, int seq,
spa_pod_builder_init(&b, buffer, sizeof(buffer));
switch (id) {
case SPA_PARAM_List:
{
uint32_t list[] = { SPA_PARAM_EnumFormat,
SPA_PARAM_Format,
SPA_PARAM_Buffers,
SPA_PARAM_Meta,
SPA_PARAM_IO };
if (result.index < SPA_N_ELEMENTS(list))
param = spa_pod_builder_add_object(&b,
SPA_TYPE_OBJECT_ParamList, id,
SPA_PARAM_LIST_id, SPA_POD_Id(list[result.index]));
else
return 0;
break;
}
case SPA_PARAM_EnumFormat:
{
SDL_RendererInfo info;

View file

@ -110,13 +110,23 @@ static int impl_set_callbacks(struct spa_node *node,
if (d->callbacks && d->callbacks->port_info) {
struct spa_port_info info;
struct spa_dict_item port_items[1];
struct spa_dict_item items[1];
struct spa_param_info params[5];
info = SPA_PORT_INFO_INIT();
info.change_mask = SPA_PORT_CHANGE_MASK_FLAGS | SPA_PORT_CHANGE_MASK_PROPS;
info.change_mask |= SPA_PORT_CHANGE_MASK_FLAGS;
info.flags = SPA_PORT_FLAG_CAN_USE_BUFFERS;
port_items[0] = SPA_DICT_ITEM_INIT("port.dsp", "32 bit float mono audio");
info.props = &SPA_DICT_INIT_ARRAY(port_items);
info.change_mask |= SPA_PORT_CHANGE_MASK_PROPS;
items[0] = SPA_DICT_ITEM_INIT("port.dsp", "32 bit float mono audio");
info.props = &SPA_DICT_INIT_ARRAY(items);
info.change_mask |= SPA_PORT_CHANGE_MASK_PARAMS;
params[0] = SPA_PARAM_INFO(SPA_PARAM_EnumFormat, SPA_PARAM_INFO_READ);
params[1] = SPA_PARAM_INFO(SPA_PARAM_Meta, SPA_PARAM_INFO_READ);
params[2] = SPA_PARAM_INFO(SPA_PARAM_IO, SPA_PARAM_INFO_READ);
params[3] = SPA_PARAM_INFO(SPA_PARAM_Buffers, SPA_PARAM_INFO_READ);
params[4] = SPA_PARAM_INFO(SPA_PARAM_Format, SPA_PARAM_INFO_WRITE);
info.params = params;
info.n_params = 5;
d->callbacks->port_info(d->callbacks_data, SPA_DIRECTION_OUTPUT, 0, &info);
}
@ -169,22 +179,6 @@ static int impl_port_enum_params(struct spa_node *node, int seq,
spa_pod_builder_init(&b, buffer, sizeof(buffer));
switch (id) {
case SPA_PARAM_List:
{
uint32_t list[] = { SPA_PARAM_EnumFormat,
SPA_PARAM_Format,
SPA_PARAM_Buffers,
SPA_PARAM_Meta,
SPA_PARAM_IO };
if (result.index < SPA_N_ELEMENTS(list))
param = spa_pod_builder_add_object(&b,
SPA_TYPE_OBJECT_ParamList, id,
SPA_PARAM_LIST_id, SPA_POD_Id(list[result.index]));
else
return 0;
break;
}
case SPA_PARAM_EnumFormat:
if (result.index != 0)
return 0;

View file

@ -75,10 +75,9 @@ struct port {
struct spa_io_buffers *io;
struct spa_io_range *range;
double *io_volume;
int32_t *io_mute;
struct spa_port_info info;
struct spa_param_info params[8];
int valid:1;
int have_format:1;
@ -96,6 +95,9 @@ struct impl {
struct spa_log *log;
struct spa_node_info info;
struct spa_param_info params[8];
const struct spa_node_callbacks *callbacks;
void *user_data;
@ -161,6 +163,14 @@ static int impl_node_send_command(struct spa_node *node, const struct spa_comman
return 0;
}
static void emit_node_info(struct impl *this)
{
if (this->callbacks && this->callbacks->info && this->info.change_mask) {
this->callbacks->info(this->user_data, &this->info);
this->info.change_mask = 0;
}
}
static void emit_port_info(struct impl *this, struct port *port)
{
if (this->callbacks && this->callbacks->port_info && port->info.change_mask) {
@ -184,6 +194,7 @@ impl_node_set_callbacks(struct spa_node *node,
this->callbacks = callbacks;
this->user_data = user_data;
emit_node_info(this);
emit_port_info(this, GET_OUT_PORT(this, 0));
for (i = 0; i < this->last_port; i++) {
if (this->in_ports[i].valid)
@ -209,16 +220,22 @@ static int impl_node_add_port(struct spa_node *node, enum spa_direction directio
port->id = port_id;
port_props_reset(&port->props);
port->io_volume = &port->props.volume;
port->io_mute = &port->props.mute;
spa_list_init(&port->queue);
port->info = SPA_PORT_INFO_INIT();
port->info.change_mask = SPA_PORT_CHANGE_MASK_FLAGS;
port->info.change_mask |= SPA_PORT_CHANGE_MASK_FLAGS;
port->info.flags = SPA_PORT_FLAG_CAN_USE_BUFFERS |
SPA_PORT_FLAG_REMOVABLE |
SPA_PORT_FLAG_OPTIONAL |
SPA_PORT_FLAG_IN_PLACE;
port->info.change_mask |= SPA_PORT_CHANGE_MASK_PARAMS;
port->params[0] = SPA_PARAM_INFO(SPA_PARAM_EnumFormat, SPA_PARAM_INFO_READ);
port->params[1] = SPA_PARAM_INFO(SPA_PARAM_Meta, SPA_PARAM_INFO_READ);
port->params[2] = SPA_PARAM_INFO(SPA_PARAM_IO, SPA_PARAM_INFO_READ);
port->params[3] = SPA_PARAM_INFO(SPA_PARAM_Format, SPA_PARAM_INFO_WRITE);
port->params[4] = SPA_PARAM_INFO(SPA_PARAM_Buffers, 0);
port->info.params = port->params;
port->info.n_params = 5;
this->port_count++;
if (this->last_port <= port_id)
@ -332,22 +349,6 @@ impl_node_port_enum_params(struct spa_node *node, int seq,
spa_pod_builder_init(&b, buffer, sizeof(buffer));
switch (id) {
case SPA_PARAM_List:
{
uint32_t list[] = { SPA_PARAM_EnumFormat,
SPA_PARAM_Format,
SPA_PARAM_Buffers,
SPA_PARAM_Meta,
SPA_PARAM_IO };
if (result.index < SPA_N_ELEMENTS(list))
param = spa_pod_builder_add_object(&b,
SPA_TYPE_OBJECT_ParamList, id,
SPA_PARAM_LIST_id, SPA_POD_Id(list[result.index]));
else
return 0;
break;
}
case SPA_PARAM_EnumFormat:
if ((res = port_enum_formats(node, direction, port_id, result.index, &param, &b)) <= 0)
return res;
@ -381,9 +382,6 @@ impl_node_port_enum_params(struct spa_node *node, int seq,
break;
case SPA_PARAM_Meta:
if (!port->have_format)
return -EIO;
switch (result.index) {
case 0:
param = spa_pod_builder_add_object(&b,
@ -523,6 +521,16 @@ static int port_set_format(struct spa_node *node,
this, direction, port_id);
}
}
if (port->have_format) {
port->info.change_mask |= SPA_PORT_CHANGE_MASK_PARAMS;
port->params[3] = SPA_PARAM_INFO(SPA_PARAM_Format, SPA_PARAM_INFO_READWRITE);
port->params[4] = SPA_PARAM_INFO(SPA_PARAM_Buffers, SPA_PARAM_INFO_READ);
} else {
port->info.change_mask |= SPA_PORT_CHANGE_MASK_PARAMS;
port->params[3] = SPA_PARAM_INFO(SPA_PARAM_Format, SPA_PARAM_INFO_WRITE);
port->params[4] = SPA_PARAM_INFO(SPA_PARAM_Buffers, 0);
}
emit_port_info(this, port);
return 0;
}
@ -892,14 +900,29 @@ impl_init(const struct spa_handle_factory *factory,
}
this->node = impl_node;
this->info = SPA_NODE_INFO_INIT();
this->info.max_input_ports = MAX_PORTS;
this->info.max_output_ports = 1;
this->info.change_mask |= SPA_NODE_CHANGE_MASK_FLAGS;
this->info.flags = SPA_NODE_FLAG_RT | SPA_NODE_FLAG_DYNAMIC_INPUT_PORTS;
port = GET_OUT_PORT(this, 0);
port->valid = true;
port->direction = SPA_DIRECTION_OUTPUT;
port->id = 0;
port->info = SPA_PORT_INFO_INIT();
port->info.change_mask = SPA_PORT_CHANGE_MASK_FLAGS;
port->info.change_mask |= SPA_PORT_CHANGE_MASK_FLAGS;
port->info.flags = SPA_PORT_FLAG_CAN_USE_BUFFERS |
SPA_PORT_FLAG_NO_REF;
SPA_PORT_FLAG_NO_REF;
port->info.change_mask |= SPA_PORT_CHANGE_MASK_PARAMS;
port->params[0] = SPA_PARAM_INFO(SPA_PARAM_EnumFormat, SPA_PARAM_INFO_READ);
port->params[1] = SPA_PARAM_INFO(SPA_PARAM_Meta, SPA_PARAM_INFO_READ);
port->params[2] = SPA_PARAM_INFO(SPA_PARAM_IO, SPA_PARAM_INFO_READ);
port->params[3] = SPA_PARAM_INFO(SPA_PARAM_Format, SPA_PARAM_INFO_WRITE);
port->params[4] = SPA_PARAM_INFO(SPA_PARAM_Buffers, 0);
port->info.params = port->params;
port->info.n_params = 5;
spa_list_init(&port->queue);
return 0;

View file

@ -379,7 +379,7 @@ static int impl_node_enum_params(struct spa_node *node, int seq,
result.index = result.next++;
if (result.index >= this->n_params)
return 0;
break;
param = this->params[result.index];
@ -390,10 +390,11 @@ static int impl_node_enum_params(struct spa_node *node, int seq,
if (spa_pod_filter(&b, &result.param, param, filter) != 0)
continue;
pw_log_debug("client-node %p: %d param %u", this, seq, result.index);
if ((res = this->callbacks->result(this->callbacks_data, seq, 0, &result)) != 0)
return res;
if (++count != num)
if (++count == num)
break;
}
return 0;
@ -668,7 +669,7 @@ impl_node_port_enum_params(struct spa_node *node, int seq,
result.index = result.next++;
if (result.index >= port->n_params)
return 0;
break;
param = port->params[result.index];
@ -683,7 +684,7 @@ impl_node_port_enum_params(struct spa_node *node, int seq,
if ((res = this->callbacks->result(this->callbacks_data, seq, 0, &result)) != 0)
return res;
if (++count != num)
if (++count == num)
break;
}
return 0;

View file

@ -137,20 +137,6 @@ static int impl_node_enum_params(struct spa_node *node, int seq,
spa_pod_builder_init(&b, buffer, sizeof(buffer));
switch (id) {
case SPA_PARAM_List:
{
uint32_t list[] = { SPA_PARAM_Props,
SPA_PARAM_EnumFormat,
SPA_PARAM_Format };
if (result.index < SPA_N_ELEMENTS(list))
param = spa_pod_builder_add_object(&b,
SPA_TYPE_OBJECT_ParamList, id,
SPA_PARAM_LIST_id, SPA_POD_Id(list[result.index]));
else
return 0;
break;
}
case SPA_PARAM_Props:
if (impl->adapter == impl->cnode)
return 0;
@ -326,6 +312,26 @@ static const struct spa_node_callbacks adapter_node_callbacks = {
.result = adapter_result,
};
static void emit_node_info(struct node *this)
{
if (this->callbacks && this->callbacks->info) {
struct spa_node_info info;
struct spa_param_info params[4];
info = SPA_NODE_INFO_INIT();
info.max_input_ports = 0;
info.max_output_ports = 0;
info.change_mask |= SPA_NODE_CHANGE_MASK_PARAMS;
params[0] = SPA_PARAM_INFO(SPA_PARAM_EnumFormat, SPA_PARAM_INFO_READ);
params[1] = SPA_PARAM_INFO(SPA_PARAM_Props, SPA_PARAM_INFO_READWRITE);
params[2] = SPA_PARAM_INFO(SPA_PARAM_Format, SPA_PARAM_INFO_READ);
params[3] = SPA_PARAM_INFO(SPA_PARAM_Profile, SPA_PARAM_INFO_WRITE);
info.params = params;
info.n_params = 4;
this->callbacks->info(this->callbacks_data, &info);
}
}
static int
impl_node_set_callbacks(struct spa_node *node,
const struct spa_node_callbacks *callbacks,
@ -342,6 +348,8 @@ impl_node_set_callbacks(struct spa_node *node,
this->callbacks = callbacks;
this->callbacks_data = data;
emit_node_info(this);
if (this->callbacks && impl->adapter && impl->adapter != impl->cnode)
spa_node_set_callbacks(impl->adapter, &adapter_node_callbacks, impl);

View file

@ -107,10 +107,18 @@ client_node_marshal_port_update(void *object,
SPA_POD_Pod(params[i]), NULL);
if (info) {
uint64_t change_mask = info->change_mask;
n_items = info->props ? info->props->n_items : 0;
change_mask &= SPA_PORT_CHANGE_MASK_FLAGS |
SPA_PORT_CHANGE_MASK_RATE |
SPA_PORT_CHANGE_MASK_PROPS |
SPA_PORT_CHANGE_MASK_PARAMS;
spa_pod_builder_push_struct(b, &f[1]);
spa_pod_builder_add(b,
SPA_POD_Long(change_mask),
SPA_POD_Int(info->flags),
SPA_POD_Int(info->rate),
SPA_POD_Int(n_items), NULL);
@ -119,7 +127,15 @@ client_node_marshal_port_update(void *object,
SPA_POD_String(info->props->items[i].key),
SPA_POD_String(info->props->items[i].value), NULL);
}
spa_pod_builder_add(b,
SPA_POD_Int(info->n_params), NULL);
for (i = 0; i < info->n_params; i++) {
spa_pod_builder_add(b,
SPA_POD_Id(info->params[i].id),
SPA_POD_Int(info->params[i].flags), NULL);
}
spa_pod_builder_pop(b, &f[1]);
} else {
spa_pod_builder_add(b,
SPA_POD_Pod(NULL), NULL);
@ -812,11 +828,17 @@ static int client_node_demarshal_port_update(void *object, void *data, size_t si
spa_pod_parser_pod(&p2, ipod);
if (spa_pod_parser_push_struct(&p2, &f2) < 0 ||
spa_pod_parser_get(&p2,
SPA_POD_Long(&info.change_mask),
SPA_POD_Int(&info.flags),
SPA_POD_Int(&info.rate),
SPA_POD_Int(&props.n_items), NULL) < 0)
return -EINVAL;
info.change_mask &= SPA_PORT_CHANGE_MASK_FLAGS |
SPA_PORT_CHANGE_MASK_RATE |
SPA_PORT_CHANGE_MASK_PROPS |
SPA_PORT_CHANGE_MASK_PARAMS;
if (props.n_items > 0) {
info.props = &props;
@ -828,6 +850,19 @@ static int client_node_demarshal_port_update(void *object, void *data, size_t si
return -EINVAL;
}
}
if (spa_pod_parser_get(&p2,
SPA_POD_Int(&info.n_params), NULL) < 0)
return -EINVAL;
if (info.n_params > 0) {
info.params = alloca(info.n_params * sizeof(struct spa_param_info));
for (i = 0; i < info.n_params; i++) {
if (spa_pod_parser_get(&p2,
SPA_POD_Id(&info.params[i].id),
SPA_POD_Int(&info.params[i].flags), NULL) < 0)
return -EINVAL;
}
}
}
pw_resource_do(resource, struct pw_client_node_proxy_methods, port_update, 0, direction,

View file

@ -406,27 +406,14 @@ static int add_port_update(struct pw_proxy *proxy, struct pw_port *port, uint32_
int res;
if (change_mask & PW_CLIENT_NODE_PORT_UPDATE_PARAMS) {
uint32_t idx1, idx2, id;
uint32_t i, idx2, id;
uint8_t buf[2048];
struct spa_pod_builder b = { 0 };
for (idx1 = 0;;) {
for (i = 0; i < port->info.n_params; i++) {
struct spa_pod *param;
spa_pod_builder_init(&b, buf, sizeof(buf));
if (spa_node_port_enum_params_sync(port->node->node,
port->direction, port->port_id,
SPA_PARAM_List, &idx1,
NULL, &param, &b,
port->node->pending) != 1)
break;
spa_pod_parse_object(param,
SPA_TYPE_OBJECT_ParamList, NULL,
SPA_PARAM_LIST_id, SPA_POD_Id(&id));
params = realloc(params, sizeof(struct spa_pod *) * (n_params + 1));
params[n_params++] = spa_pod_copy(param);
id = port->info.params[i].id;
for (idx2 = 0;;) {
spa_pod_builder_init(&b, buf, sizeof(buf));

View file

@ -113,7 +113,7 @@ static struct pw_port *get_port(struct pw_node *node, enum spa_direction directi
if (port_id == SPA_ID_INVALID)
return NULL;
p = pw_port_new(direction, port_id, 0, NULL, 0);
p = pw_port_new(direction, port_id, NULL, 0);
if (p == NULL)
return NULL;

View file

@ -119,6 +119,21 @@ static void push_dict(struct spa_pod_builder *b, const struct spa_dict *dict)
spa_pod_builder_pop(b, &f);
}
static void push_params(struct spa_pod_builder *b, uint32_t n_params,
const struct spa_param_info *params)
{
uint32_t i;
struct spa_pod_frame f;
spa_pod_builder_push_struct(b, &f);
spa_pod_builder_int(b, n_params);
for (i = 0; i < n_params; i++) {
spa_pod_builder_id(b, params[i].id);
spa_pod_builder_int(b, params[i].flags);
}
spa_pod_builder_pop(b, &f);
}
static int
core_method_marshal_create_object(void *object,
const char *factory_name,
@ -612,6 +627,7 @@ static int device_marshal_info(void *object, const struct pw_device_info *info)
SPA_POD_Long(info->change_mask),
NULL);
push_dict(b, info->props);
push_params(b, info->n_params, info->params);
spa_pod_builder_pop(b, &f);
return pw_protocol_native_end_resource(resource, b);
@ -647,6 +663,22 @@ static int device_demarshal_info(void *object, void *data, size_t size)
SPA_POD_String(&props.items[i].value), NULL) < 0)
return -EINVAL;
}
spa_pod_parser_pop(&prs, &f[1]);
if (spa_pod_parser_push_struct(&prs, &f[1]) < 0 ||
spa_pod_parser_get(&prs,
SPA_POD_Int(&info.n_params),
NULL) < 0)
return -EINVAL;
info.params = alloca(info.n_params * sizeof(struct spa_param_info));
for (i = 0; i < info.n_params; i++) {
if (spa_pod_parser_get(&prs,
SPA_POD_Id(&info.params[i].id),
SPA_POD_Int(&info.params[i].flags), NULL) < 0)
return -EINVAL;
}
return pw_proxy_notify(proxy, struct pw_device_proxy_events, info, 0, &info);
}
@ -838,6 +870,7 @@ static int node_marshal_info(void *object, const struct pw_node_info *info)
SPA_POD_String(info->error),
NULL);
push_dict(b, info->props);
push_params(b, info->n_params, info->params);
spa_pod_builder_pop(b, &f);
return pw_protocol_native_end_resource(resource, b);
@ -879,6 +912,22 @@ static int node_demarshal_info(void *object, void *data, size_t size)
SPA_POD_String(&props.items[i].value), NULL) < 0)
return -EINVAL;
}
spa_pod_parser_pop(&prs, &f[1]);
if (spa_pod_parser_push_struct(&prs, &f[1]) < 0 ||
spa_pod_parser_get(&prs,
SPA_POD_Int(&info.n_params),
NULL) < 0)
return -EINVAL;
info.params = alloca(info.n_params * sizeof(struct spa_param_info));
for (i = 0; i < info.n_params; i++) {
if (spa_pod_parser_get(&prs,
SPA_POD_Id(&info.params[i].id),
SPA_POD_Int(&info.params[i].flags), NULL) < 0)
return -EINVAL;
}
return pw_proxy_notify(proxy, struct pw_node_proxy_events, info, 0, &info);
}
@ -1032,6 +1081,7 @@ static int port_marshal_info(void *object, const struct pw_port_info *info)
SPA_POD_Long(info->change_mask),
NULL);
push_dict(b, info->props);
push_params(b, info->n_params, info->params);
spa_pod_builder_pop(b, &f);
return pw_protocol_native_end_resource(resource, b);
@ -1067,6 +1117,21 @@ static int port_demarshal_info(void *object, void *data, size_t size)
SPA_POD_String(&props.items[i].value), NULL) < 0)
return -EINVAL;
}
spa_pod_parser_pop(&prs, &f[1]);
if (spa_pod_parser_push_struct(&prs, &f[1]) < 0 ||
spa_pod_parser_get(&prs,
SPA_POD_Int(&info.n_params),
NULL) < 0)
return -EINVAL;
info.params = alloca(info.n_params * sizeof(struct spa_param_info));
for (i = 0; i < info.n_params; i++) {
if (spa_pod_parser_get(&prs,
SPA_POD_Id(&info.params[i].id),
SPA_POD_Int(&info.params[i].flags), NULL) < 0)
return -EINVAL;
}
return pw_proxy_notify(proxy, struct pw_port_proxy_events, info, 0, &info);
}

View file

@ -79,6 +79,7 @@ struct pw_device *pw_device_new(struct pw_core *core,
this->info.name = strdup(name);
this->info.props = &properties->dict;
this->info.params = this->params;
spa_hook_list_init(&this->listener_list);
spa_list_init(&this->node_list);
@ -242,7 +243,7 @@ global_bind(void *_data, struct pw_client *client, uint32_t permissions,
spa_list_append(&global->resource_list, &resource->link);
this->info.change_mask = ~0;
this->info.change_mask = PW_DEVICE_CHANGE_MASK_ALL;
pw_device_resource_info(resource, &this->info);
this->info.change_mask = 0;
@ -314,12 +315,49 @@ static const struct pw_node_events node_events = {
.destroy = node_destroy,
};
static void emit_info_changed(struct pw_device *device)
{
struct pw_resource *resource;
pw_device_emit_info_changed(device, &device->info);
if (device->global)
spa_list_for_each(resource, &device->global->resource_list, link)
pw_device_resource_info(resource, &device->info);
device->info.change_mask = 0;
}
static int update_properties(struct pw_device *device, const struct spa_dict *dict)
{
int changed;
changed = pw_properties_update(device->properties, dict);
pw_log_debug("device %p: updated %d properties", device, changed);
if (!changed)
return 0;
device->info.props = &device->properties->dict;
device->info.change_mask |= PW_DEVICE_CHANGE_MASK_PROPS;
return changed;
}
static int device_info(void *data, const struct spa_device_info *info)
{
struct pw_device *device = data;
if (info->change_mask & SPA_DEVICE_CHANGE_MASK_INFO)
pw_device_update_properties(device, info->info);
if (info->change_mask & SPA_DEVICE_CHANGE_MASK_PROPS) {
update_properties(device, info->props);
}
if (info->change_mask & SPA_DEVICE_CHANGE_MASK_PARAMS) {
device->info.change_mask |= PW_DEVICE_CHANGE_MASK_PARAMS;
device->info.n_params = SPA_MIN(info->n_params, SPA_N_ELEMENTS(device->params));
memcpy(device->info.params, info->params,
device->info.n_params * sizeof(struct spa_param_info));
}
emit_info_changed(device);
return 0;
}
@ -343,14 +381,14 @@ static void device_add(struct pw_device *device, uint32_t id,
support = pw_core_get_support(device->core, &n_support);
props = pw_properties_copy(device->properties);
if (info->info)
pw_properties_update(props, info->info);
if (info->props)
pw_properties_update(props, info->props);
node = pw_node_new(device->core,
device->info.name,
props,
sizeof(struct node_data) +
spa_handle_factory_get_size(info->factory, info->info));
spa_handle_factory_get_size(info->factory, info->props));
nd = pw_node_get_user_data(node);
nd->id = id;
@ -361,7 +399,7 @@ static void device_add(struct pw_device *device, uint32_t id,
if ((res = spa_handle_factory_init(info->factory,
nd->handle,
info->info,
info->props,
support,
n_support)) < 0) {
pw_log_error("can't make factory instance: %d", res);
@ -412,8 +450,8 @@ static int device_object_info(void *data, uint32_t id,
}
}
else if (nd != NULL) {
if (info->change_mask & SPA_DEVICE_OBJECT_CHANGE_MASK_INFO)
pw_node_update_properties(nd->node, info->info);
if (info->change_mask & SPA_DEVICE_OBJECT_CHANGE_MASK_PROPS)
pw_node_update_properties(nd->node, info->props);
}
else {
device_add(device, id, info);
@ -457,26 +495,8 @@ const struct pw_properties *pw_device_get_properties(struct pw_device *device)
SPA_EXPORT
int pw_device_update_properties(struct pw_device *device, const struct spa_dict *dict)
{
struct pw_resource *resource;
int changed;
changed = pw_properties_update(device->properties, dict);
pw_log_debug("device %p: updated %d properties", device, changed);
if (!changed)
return 0;
device->info.props = &device->properties->dict;
device->info.change_mask |= PW_DEVICE_CHANGE_MASK_PROPS;
pw_device_emit_info_changed(device, &device->info);
if (device->global)
spa_list_for_each(resource, &device->global->resource_list, link)
pw_device_resource_info(resource, &device->info);
device->info.change_mask = 0;
int changed = update_properties(device, dict);
emit_info_changed(device);
return changed;
}

View file

@ -179,7 +179,6 @@ SPA_EXPORT
struct pw_node_info *pw_node_info_update(struct pw_node_info *info,
const struct pw_node_info *update)
{
if (update == NULL)
return info;
@ -214,6 +213,17 @@ struct pw_node_info *pw_node_info_update(struct pw_node_info *info,
pw_spa_dict_destroy(info->props);
info->props = pw_spa_dict_copy(update->props);
}
if (update->change_mask & PW_NODE_CHANGE_MASK_PARAMS) {
info->n_params = update->n_params;
free((void *) info->params);
if (update->params) {
size_t size = info->n_params * sizeof(struct spa_param_info);
info->params = malloc(size);
memcpy(info->params, update->params, size);
}
else
info->params = NULL;
}
return info;
}
@ -225,6 +235,7 @@ void pw_node_info_free(struct pw_node_info *info)
free((void *) info->error);
if (info->props)
pw_spa_dict_destroy(info->props);
free((void *) info->params);
free(info);
}
@ -250,6 +261,17 @@ struct pw_port_info *pw_port_info_update(struct pw_port_info *info,
pw_spa_dict_destroy(info->props);
info->props = pw_spa_dict_copy(update->props);
}
if (update->change_mask & PW_PORT_CHANGE_MASK_PARAMS) {
info->n_params = update->n_params;
free((void *) info->params);
if (update->params) {
size_t size = info->n_params * sizeof(struct spa_param_info);
info->params = malloc(size);
memcpy(info->params, update->params, size);
}
else
info->params = NULL;
}
return info;
}
@ -259,6 +281,7 @@ void pw_port_info_free(struct pw_port_info *info)
if (info->props)
pw_spa_dict_destroy(info->props);
free((void *) info->params);
free(info);
}

View file

@ -128,11 +128,15 @@ void pw_module_info_free(struct pw_module_info *info);
/** The device information. Extra information can be added in later versions \memberof pw_introspect */
struct pw_device_info {
uint32_t id; /**< id of the global */
const char *name; /**< name the device */
uint32_t id; /**< id of the global */
const char *name; /**< name the device */
#define PW_DEVICE_CHANGE_MASK_PROPS (1 << 0)
uint64_t change_mask; /**< bitfield of changed fields since last call */
struct spa_dict *props; /**< extra properties */
#define PW_DEVICE_CHANGE_MASK_PARAMS (1 << 1)
#define PW_DEVICE_CHANGE_MASK_ALL ((1 << 2)-1)
uint64_t change_mask; /**< bitfield of changed fields since last call */
struct spa_dict *props; /**< extra properties */
struct spa_param_info *params; /**< parameters */
uint32_t n_params; /**< number of items in \a params */
};
/** Update and existing \ref pw_device_info with \a update \memberof pw_introspect */
@ -168,6 +172,8 @@ struct pw_node_info {
#define PW_NODE_CHANGE_MASK_OUTPUT_PORTS (1 << 2)
#define PW_NODE_CHANGE_MASK_STATE (1 << 3)
#define PW_NODE_CHANGE_MASK_PROPS (1 << 4)
#define PW_NODE_CHANGE_MASK_PARAMS (1 << 5)
#define PW_NODE_CHANGE_MASK_ALL ((1 << 6)-1)
uint64_t change_mask; /**< bitfield of changed fields since last call */
const char *name; /**< name the node, suitable for display */
uint32_t max_input_ports; /**< maximum number of inputs */
@ -177,6 +183,8 @@ struct pw_node_info {
enum pw_node_state state; /**< the current state of the node */
const char *error; /**< an error reason if \a state is error */
struct spa_dict *props; /**< the properties of the node */
struct spa_param_info *params; /**< parameters */
uint32_t n_params; /**< number of items in \a params */
};
struct pw_node_info *
@ -190,8 +198,12 @@ struct pw_port_info {
uint32_t id; /**< id of the global */
enum pw_direction direction; /**< port direction */
#define PW_PORT_CHANGE_MASK_PROPS (1 << 0)
#define PW_PORT_CHANGE_MASK_PARAMS (1 << 1)
#define PW_PORT_CHANGE_MASK_ALL ((1 << 2)-1)
uint64_t change_mask; /**< bitfield of changed fields since last call */
struct spa_dict *props; /**< the properties of the port */
struct spa_param_info *params; /**< parameters */
uint32_t n_params; /**< number of items in \a params */
};
struct pw_port_info *

View file

@ -166,10 +166,26 @@ static int start_node(struct pw_node *this)
return res;
}
static void emit_info_changed(struct pw_node *node)
{
struct pw_resource *resource;
if (node->info.change_mask == 0)
return;
pw_node_emit_info_changed(node, &node->info);
if (node->global)
spa_list_for_each(resource, &node->global->resource_list, link)
pw_node_resource_info(resource, &node->info);
node->info.change_mask = 0;
}
static void node_update_state(struct pw_node *node, enum pw_node_state state, char *error)
{
enum pw_node_state old;
struct pw_resource *resource;
old = node->info.state;
if (old == state)
@ -198,16 +214,9 @@ static void node_update_state(struct pw_node *node, enum pw_node_state state, ch
pw_node_emit_state_changed(node, old, state, error);
node->info.change_mask |= PW_NODE_CHANGE_MASK_STATE;
pw_node_emit_info_changed(node, &node->info);
if (node->global)
spa_list_for_each(resource, &node->global->resource_list, link)
pw_node_resource_info(resource, &node->info);
node->info.change_mask = 0;
emit_info_changed(node);
}
static int suspend_node(struct pw_node *this)
{
int res = 0;
@ -274,8 +283,10 @@ static int node_enum_params(void *object, int seq, uint32_t id,
filter, reply_param, data)) < 0) {
pw_log_error("resource %p: %d error %d (%s)", resource,
resource->id, res, spa_strerror(res));
pw_core_resource_error(client->core_resource,
resource->id, seq, res, spa_strerror(res));
pw_core_resource_errorf(client->core_resource,
resource->id, seq, res,
"enum params %s failed",
spa_debug_type_find_name(spa_type_param, id));
}
return 0;
}
@ -344,7 +355,7 @@ global_bind(void *_data, struct pw_client *client, uint32_t permissions,
spa_list_append(&global->resource_list, &resource->link);
this->info.change_mask = ~0;
this->info.change_mask = PW_NODE_CHANGE_MASK_ALL;
pw_node_resource_info(resource, &this->info);
this->info.change_mask = 0;
return 0;
@ -694,6 +705,7 @@ struct pw_node *pw_node_new(struct pw_core *core,
this->info.state = PW_NODE_STATE_CREATING;
this->info.props = &this->properties->dict;
this->info.params = this->params;
spa_list_init(&this->input_ports);
pw_map_init(&this->input_port_map, 64, 64);
@ -767,41 +779,48 @@ const struct pw_properties *pw_node_get_properties(struct pw_node *node)
return node->properties;
}
SPA_EXPORT
int pw_node_update_properties(struct pw_node *node, const struct spa_dict *dict)
static int update_properties(struct pw_node *node, const struct spa_dict *dict)
{
struct pw_resource *resource;
int changed;
changed = pw_properties_update(node->properties, dict);
pw_log_debug("node %p: updated %d properties", node, changed);
if (!changed)
return 0;
check_properties(node);
node->info.props = &node->properties->dict;
node->info.change_mask |= PW_NODE_CHANGE_MASK_PROPS;
pw_node_emit_info_changed(node, &node->info);
if (node->global)
spa_list_for_each(resource, &node->global->resource_list, link)
pw_node_resource_info(resource, &node->info);
node->info.change_mask = 0;
if (changed) {
check_properties(node);
node->info.props = &node->properties->dict;
node->info.change_mask |= PW_NODE_CHANGE_MASK_PROPS;
}
return changed;
}
SPA_EXPORT
int pw_node_update_properties(struct pw_node *node, const struct spa_dict *dict)
{
int changed = update_properties(node, dict);
emit_info_changed(node);
return changed;
}
static int node_info(void *data, const struct spa_node_info *info)
{
struct pw_node *node = data;
node->info.max_input_ports = info->max_input_ports;
node->info.max_output_ports = info->max_output_ports;
if (info->change_mask & SPA_NODE_CHANGE_MASK_PROPS)
pw_node_update_properties(node, info->props);
if (info->change_mask & SPA_NODE_CHANGE_MASK_PROPS) {
update_properties(node, info->props);
}
if (info->change_mask & SPA_NODE_CHANGE_MASK_PARAMS) {
node->info.change_mask |= PW_NODE_CHANGE_MASK_PARAMS;
node->info.n_params = SPA_MIN(info->n_params, SPA_N_ELEMENTS(node->params));
memcpy(node->info.params, info->params,
node->info.n_params * sizeof(struct spa_param_info));
}
emit_info_changed(node);
return 0;
}
@ -821,22 +840,16 @@ static int node_port_info(void *data, enum spa_direction direction, uint32_t por
pw_direction_as_string(direction), port_id);
}
} else if (port) {
if (info->change_mask & SPA_PORT_CHANGE_MASK_FLAGS)
port->spa_flags = info->flags;
if (info->change_mask & SPA_PORT_CHANGE_MASK_PROPS)
pw_port_update_properties(port, info->props);
pw_log_debug("node %p: %s port %d changed", node,
pw_direction_as_string(direction), port_id);
pw_port_update_info(port, info);
} else {
int res;
struct pw_properties *props;
pw_log_debug("node %p: %s port %d added", node,
pw_direction_as_string(direction), port_id);
props = info->props ?
pw_properties_new_dict(info->props) :
pw_properties_new(NULL, NULL);
if ((port = pw_port_new(direction, port_id, info->flags, props,
if ((port = pw_port_new(direction, port_id, info,
node->port_user_data_size))) {
if ((res = pw_port_add(port, node)) < 0) {
pw_log_error("node %p: can't add port %p: %d, %s",

View file

@ -79,6 +79,22 @@ void pw_port_mix_update_state(struct pw_port *port, struct pw_port_mix *mix, enu
}
}
static void emit_info_changed(struct pw_port *port)
{
struct pw_resource *resource;
if (port->info.change_mask == 0)
return;
pw_port_emit_info_changed(port, &port->info);
if (port->global)
spa_list_for_each(resource, &port->global->resource_list, link)
pw_port_resource_info(resource, &port->info);
port->info.change_mask = 0;
}
void pw_port_update_state(struct pw_port *port, enum pw_port_state state)
{
if (port->state != state) {
@ -243,15 +259,46 @@ int pw_port_release_mix(struct pw_port *port, struct pw_port_mix *mix)
return res;
}
static int update_properties(struct pw_port *port, const struct spa_dict *dict)
{
int changed;
changed = pw_properties_update(port->properties, dict);
pw_log_debug("port %p: updated %d properties", port, changed);
if (changed) {
port->info.props = &port->properties->dict;
port->info.change_mask |= PW_PORT_CHANGE_MASK_PROPS;
}
return changed;
}
static void update_info(struct pw_port *port, const struct spa_port_info *info)
{
if (info->change_mask & SPA_PORT_CHANGE_MASK_FLAGS) {
port->spa_flags = info->flags;
}
if (info->change_mask & SPA_PORT_CHANGE_MASK_PROPS) {
update_properties(port, info->props);
}
if (info->change_mask & SPA_PORT_CHANGE_MASK_PARAMS) {
port->info.change_mask |= PW_PORT_CHANGE_MASK_PARAMS;
port->info.n_params = SPA_MIN(info->n_params, SPA_N_ELEMENTS(port->params));
memcpy(port->info.params, info->params,
port->info.n_params * sizeof(struct spa_param_info));
}
}
SPA_EXPORT
struct pw_port *pw_port_new(enum pw_direction direction,
uint32_t port_id,
uint32_t spa_flags,
struct pw_properties *properties,
const struct spa_port_info *info,
size_t user_data_size)
{
struct impl *impl;
struct pw_port *this;
struct pw_properties *properties;
impl = calloc(1, sizeof(struct impl) + user_data_size);
if (impl == NULL)
@ -261,19 +308,22 @@ struct pw_port *pw_port_new(enum pw_direction direction,
pw_log_debug("port %p: new %s %d", this,
pw_direction_as_string(direction), port_id);
if (properties == NULL)
if (info && info->change_mask & SPA_PORT_CHANGE_MASK_PROPS && info->props)
properties = pw_properties_new_dict(info->props);
else
properties = pw_properties_new(NULL, NULL);
if (properties == NULL)
goto no_mem;
if (SPA_FLAG_CHECK(spa_flags, SPA_PORT_FLAG_PHYSICAL))
if (SPA_FLAG_CHECK(info->flags, SPA_PORT_FLAG_PHYSICAL))
pw_properties_set(properties, "port.physical", "1");
if (SPA_FLAG_CHECK(spa_flags, SPA_PORT_FLAG_TERMINAL))
if (SPA_FLAG_CHECK(info->flags, SPA_PORT_FLAG_TERMINAL))
pw_properties_set(properties, "port.terminal", "1");
this->direction = direction;
this->port_id = port_id;
this->spa_flags = spa_flags;
this->spa_flags = info->flags;
this->properties = properties;
this->state = PW_PORT_STATE_INIT;
this->rt.io = SPA_IO_BUFFERS_INIT;
@ -282,6 +332,8 @@ struct pw_port *pw_port_new(enum pw_direction direction,
this->user_data = SPA_MEMBER(impl, sizeof(struct impl), void);
this->info.direction = direction;
this->info.params = this->params;
this->info.change_mask = PW_PORT_CHANGE_MASK_PROPS;
this->info.props = &this->properties->dict;
spa_list_init(&this->links);
@ -308,6 +360,9 @@ struct pw_port *pw_port_new(enum pw_direction direction,
0);
this->rt.io.status = SPA_STATUS_NEED_BUFFER;
if (info)
update_info(this, info);
return this;
no_mem:
@ -354,29 +409,19 @@ const struct pw_properties *pw_port_get_properties(struct pw_port *port)
SPA_EXPORT
int pw_port_update_properties(struct pw_port *port, const struct spa_dict *dict)
{
struct pw_resource *resource;
int changed;
int changed = update_properties(port, dict);
changed = pw_properties_update(port->properties, dict);
pw_log_debug("port %p: updated %d properties", port, changed);
if (!changed)
return 0;
port->info.props = &port->properties->dict;
port->info.change_mask |= PW_PORT_CHANGE_MASK_PROPS;
pw_port_emit_info_changed(port, &port->info);
if (port->global)
spa_list_for_each(resource, &port->global->resource_list, link)
pw_port_resource_info(resource, &port->info);
port->info.change_mask = 0;
emit_info_changed(port);
return changed;
}
void pw_port_update_info(struct pw_port *port, const struct spa_port_info *info)
{
update_info(port, info);
emit_info_changed(port);
}
SPA_EXPORT
struct pw_node *pw_port_get_node(struct pw_port *port)
{
@ -431,11 +476,14 @@ static int check_param_io(void *data, int seq, uint32_t id,
uint32_t pid, psize;
if (spa_pod_parse_object(param,
SPA_TYPE_OBJECT_ParamIO, NULL,
SPA_PARAM_IO_id, SPA_POD_Id(&pid),
SPA_PARAM_IO_size, SPA_POD_Int(&psize)) < 0)
SPA_TYPE_OBJECT_ParamIO, NULL,
SPA_PARAM_IO_id, SPA_POD_Id(&pid),
SPA_PARAM_IO_size, SPA_POD_Int(&psize)) < 0)
return 0;
pw_log_debug("port %p: got control %s", port,
spa_debug_type_find_name(spa_type_io, pid));
switch (pid) {
case SPA_IO_Control:
case SPA_IO_Notify:
@ -518,7 +566,7 @@ global_bind(void *_data, struct pw_client *client, uint32_t permissions,
spa_list_append(&global->resource_list, &resource->link);
this->info.change_mask = ~0;
this->info.change_mask = PW_PORT_CHANGE_MASK_ALL;
pw_port_resource_info(resource, &this->info);
this->info.change_mask = 0;
return 0;

View file

@ -261,7 +261,8 @@ struct pw_device {
struct spa_hook global_listener;
struct pw_properties *properties; /**< properties of the device */
struct pw_device_info info; /**< introspectable device info */
struct pw_device_info info; /**< introspectable device info */
struct spa_param_info params[32];
struct spa_device *implementation; /**< implementation */
struct spa_hook_list listener_list;
@ -333,6 +334,7 @@ struct pw_node {
struct pw_properties *properties; /**< properties of the node */
struct pw_node_info info; /**< introspectable node info */
struct spa_param_info params[32];
int registered:1;
int enabled:1; /**< if the node is enabled */
@ -440,6 +442,7 @@ struct pw_port {
struct pw_properties *properties; /**< properties of the port */
struct pw_port_info info;
struct spa_param_info params[32];
struct allocation allocation;
@ -700,10 +703,11 @@ const struct pw_export_type *pw_core_find_export_type(struct pw_core *core, uint
struct pw_port *
pw_port_new(enum pw_direction direction,
uint32_t port_id,
uint32_t spa_flags,
struct pw_properties *properties,
const struct spa_port_info *info,
size_t user_data_size);
void pw_port_update_info(struct pw_port *port, const struct spa_port_info *info);
int pw_port_register(struct pw_port *port,
struct pw_client *owner,
struct pw_global *parent,

View file

@ -313,13 +313,40 @@ static int impl_send_command(struct spa_node *node, const struct spa_command *co
return 0;
}
static void emit_node_info(struct stream *d)
{
if (d->callbacks && d->callbacks->info) {
struct spa_node_info info;
info = SPA_NODE_INFO_INIT();
if (d->direction == SPA_DIRECTION_INPUT) {
info.max_input_ports = 1;
info.max_output_ports = 0;
} else {
info.max_input_ports = 0;
info.max_output_ports = 1;
}
info.change_mask |= SPA_NODE_CHANGE_MASK_FLAGS;
info.flags = SPA_NODE_FLAG_RT;
d->callbacks->info(d->callbacks_data, &info);
}
}
static void emit_port_info(struct stream *d)
{
if (d->callbacks && d->callbacks->port_info) {
struct spa_port_info info;
struct spa_param_info params[5];
info = SPA_PORT_INFO_INIT();
info.change_mask = SPA_PORT_CHANGE_MASK_FLAGS;
info.change_mask |= SPA_PORT_CHANGE_MASK_FLAGS;
info.flags = SPA_PORT_FLAG_CAN_USE_BUFFERS;
info.change_mask |= SPA_PORT_CHANGE_MASK_PARAMS;
params[0] = SPA_PARAM_INFO(SPA_PARAM_EnumFormat, SPA_PARAM_INFO_READ);
params[1] = SPA_PARAM_INFO(SPA_PARAM_Meta, SPA_PARAM_INFO_READ);
params[2] = SPA_PARAM_INFO(SPA_PARAM_IO, SPA_PARAM_INFO_READ);
params[3] = SPA_PARAM_INFO(SPA_PARAM_Format, SPA_PARAM_INFO_WRITE);
params[4] = SPA_PARAM_INFO(SPA_PARAM_Buffers, 0);
info.params = params;
info.n_params = 5;
d->callbacks->port_info(d->callbacks_data, d->direction, 0, &info);
}
}
@ -332,6 +359,7 @@ static int impl_set_callbacks(struct spa_node *node,
d->callbacks = callbacks;
d->callbacks_data = data;
emit_node_info(d);
emit_port_info(d);
return 0;
@ -382,8 +410,6 @@ static int impl_port_enum_params(struct spa_node *node, int seq,
const struct spa_pod *filter)
{
struct stream *d = SPA_CONTAINER_OF(node, struct stream, impl_node);
struct spa_pod *param;
uint32_t last_id = SPA_ID_INVALID;
uint32_t n_params = pw_array_get_len(&d->params, struct param);
struct spa_result_node_params result;
uint8_t buffer[1024];
@ -391,52 +417,34 @@ static int impl_port_enum_params(struct spa_node *node, int seq,
uint32_t count = 0;
int res;
spa_return_val_if_fail(num != 0, -EINVAL);
result.id = id;
result.next = start;
next:
result.index = result.next;
spa_pod_builder_init(&b, buffer, sizeof(buffer));
while (true) {
if (result.next < n_params) {
param = pw_array_get_unchecked(&d->params, result.next, struct param)->param;
}
else if (last_id != SPA_ID_INVALID)
struct spa_pod *param;
result.index = result.next++;
if (result.index >= n_params)
break;
else
return 0;
result.next++;
param = pw_array_get_unchecked(&d->params, result.index, struct param)->param;
if (id == SPA_PARAM_List) {
uint32_t new_id = ((struct spa_pod_object *) param)->body.id;
if (param == NULL || !spa_pod_is_object_id(param, id))
continue;
if (last_id == SPA_ID_INVALID){
result.param = spa_pod_builder_add_object(&b,
SPA_TYPE_OBJECT_ParamList, id,
SPA_PARAM_LIST_id, SPA_POD_Id(new_id));
last_id = new_id;
}
else if (last_id != new_id) {
result.next--;
break;
}
} else {
if (param == NULL || !spa_pod_is_object_id(param, id))
continue;
spa_pod_builder_init(&b, buffer, sizeof(buffer));
if (spa_pod_filter(&b, &result.param, param, filter) != 0)
continue;
if (spa_pod_filter(&b, &result.param, param, filter) == 0)
break;
}
if ((res = d->callbacks->result(d->callbacks_data, seq, 0, &result)) != 0)
return res;
if (++count == num)
break;
}
if ((res = d->callbacks->result(d->callbacks_data, seq, 0, &result)) != 0)
return res;
if (++count != num)
goto next;
return 0;
}

View file

@ -553,6 +553,7 @@ static void info_module(struct proxy_data *pd)
static void info_node(struct proxy_data *pd)
{
struct pw_node_info *info = pd->info;
uint32_t i;
info_global(pd);
fprintf(stdout, "%c\tname: \"%s\"\n", MARK_CHANGE(0), info->name);
@ -566,17 +567,26 @@ static void info_node(struct proxy_data *pd)
else
fprintf(stdout, "\n");
print_properties(info->props, MARK_CHANGE(4), true);
fprintf(stdout, "%c\tenum_params\n", MARK_CHANGE(5));
fprintf(stdout, "%c\tparams\n", MARK_CHANGE(5));
for (i = 0; i < info->n_params; i++) {
fprintf(stdout, "%c\t %d (%s)\n", MARK_CHANGE(5), info->params[i].id,
spa_debug_type_find_name(spa_type_param, info->params[i].id));
}
info->change_mask = 0;
}
static void info_port(struct proxy_data *pd)
{
struct pw_port_info *info = pd->info;
uint32_t i;
info_global(pd);
print_properties(info->props, MARK_CHANGE(0), true);
fprintf(stdout, "%c\tenum_params\n", MARK_CHANGE(1));
fprintf(stdout, "%c\tparams\n", MARK_CHANGE(1));
for (i = 0; i < info->n_params; i++) {
fprintf(stdout, "%c\t %d (%s)\n", MARK_CHANGE(1), info->params[i].id,
spa_debug_type_find_name(spa_type_param, info->params[i].id));
}
info->change_mask = 0;
}
@ -1182,16 +1192,14 @@ static bool do_node_params(struct data *data, const char *cmd, char *args, char
struct global *global;
n = pw_split_ip(args, WHITESPACE, 2, a);
if (n < 1) {
asprintf(error, "%s <object-id> [<param-id-name>]", cmd);
if (n < 2) {
asprintf(error, "%s <object-id> <param-id>", cmd);
return false;
}
if (n < 2)
param_id = SPA_PARAM_List;
else
param_id = atoi(a[1]);
id = atoi(a[0]);
param_id = atoi(a[1]);
global = pw_map_lookup(&rd->globals, id);
if (global == NULL) {
asprintf(error, "%s: unknown global %d", cmd, id);
@ -1221,16 +1229,14 @@ static bool do_port_params(struct data *data, const char *cmd, char *args, char
struct global *global;
n = pw_split_ip(args, WHITESPACE, 2, a);
if (n < 1) {
asprintf(error, "%s <object-id> [<param-id-name>]", cmd);
if (n < 2) {
asprintf(error, "%s <object-id> <param-id>", cmd);
return false;
}
if (n < 2)
param_id = SPA_PARAM_List;
else
param_id = atoi(a[1]);
id = atoi(a[0]);
param_id = atoi(a[1]);
global = pw_map_lookup(&rd->globals, id);
if (global == NULL) {
asprintf(error, "%s: unknown global %d", cmd, id);

View file

@ -39,6 +39,12 @@ struct proxy_data;
typedef void (*print_func_t) (struct proxy_data *data);
struct param {
struct spa_list link;
uint32_t id;
struct spa_pod *param;
};
struct data {
struct pw_main_loop *loop;
struct pw_core *core;
@ -71,15 +77,16 @@ struct proxy_data {
int pending_seq;
struct spa_list pending_link;
print_func_t print_func;
uint32_t n_params;
struct spa_pod **params;
struct spa_list param_list;
};
static void add_pending(struct proxy_data *pd)
{
struct data *d = pd->data;
spa_list_append(&d->pending_list, &pd->pending_link);
if (pd->pending_seq == 0) {
spa_list_append(&d->pending_list, &pd->pending_link);
}
pd->pending_seq = pw_core_proxy_sync(d->core_proxy, 0, pd->pending_seq);
}
@ -107,27 +114,52 @@ static int on_core_done(void *data, uint32_t id, int seq)
static void clear_params(struct proxy_data *data)
{
uint32_t i;
for (i = 0; i < data->n_params; i++)
free(data->params[i]);
free(data->params);
data->n_params = 0;
data->params = NULL;
struct param *p;
spa_list_consume(p, &data->param_list, link) {
spa_list_remove(&p->link);
free(p);
}
}
static int add_param(struct proxy_data *data, const struct spa_pod *param)
static void remove_params(struct proxy_data *data, uint32_t id)
{
uint32_t idx = data->n_params++;
struct param *p, *t;
spa_list_for_each_safe(p, t, &data->param_list, link) {
if (p->id == id) {
spa_list_remove(&p->link);
free(p);
}
}
}
data->params = realloc(data->params, sizeof(struct spa_pod *) * data->n_params);
if (data->params == NULL)
static int add_param(struct proxy_data *data, uint32_t id, const struct spa_pod *param)
{
struct param *p;
p = malloc(sizeof(struct param) + SPA_POD_SIZE(param));
if (p == NULL)
return -ENOMEM;
data->params[idx] = spa_pod_copy(param);
p->id = id;
p->param = SPA_MEMBER(p, sizeof(struct param), struct spa_pod);
memcpy(p->param, param, SPA_POD_SIZE(param));
spa_list_append(&data->param_list, &p->link);
return 0;
}
static void print_params(struct proxy_data *data, char mark)
{
struct param *p;
printf("%c\tparams:\n", mark);
spa_list_for_each(p, &data->param_list, link) {
if (spa_pod_is_object_type(p->param, SPA_TYPE_OBJECT_Format))
spa_debug_format(10, NULL, p->param);
else
spa_debug_pod(10, NULL, p->param);
}
}
static void print_properties(const struct spa_dict *props, char mark)
{
const struct spa_dict_item *item;
@ -226,16 +258,8 @@ static void print_node(struct proxy_data *data)
printf("\ttype: %s (version %d)\n",
spa_debug_type_find_name(pw_type_info(), data->type), data->version);
if (print_all) {
uint32_t i;
printf("%c\tname: \"%s\"\n", MARK_CHANGE(0), info->name);
printf("%c\tparams:\n", MARK_CHANGE(5));
for (i = 0; i < data->n_params; i++) {
if (spa_pod_is_object_type(data->params[i], SPA_TYPE_OBJECT_Format))
spa_debug_format(10, NULL, data->params[i]);
else
spa_debug_pod(10, NULL, data->params[i]);
}
print_params(data, MARK_CHANGE(5));
printf("%c\tinput ports: %u/%u\n", MARK_CHANGE(1),
info->n_input_ports, info->max_input_ports);
printf("%c\toutput ports: %u/%u\n", MARK_CHANGE(2),
@ -254,15 +278,23 @@ static void print_node(struct proxy_data *data)
static int node_event_info(void *object, const struct pw_node_info *info)
{
struct proxy_data *data = object;
bool is_new = data->info == NULL;
struct pw_node_info *old = data->info;
uint32_t i;
data->info = pw_node_info_update(data->info, info);
if (is_new) {
pw_node_proxy_enum_params((struct pw_node_proxy*)data->proxy,
0, SPA_PARAM_List, 0, 0, NULL);
if (info->change_mask & PW_NODE_CHANGE_MASK_PARAMS) {
for (i = 0; i < info->n_params; i++) {
if (old != NULL && info->params[i].flags == old->params[i].flags)
continue;
remove_params(data, info->params[i].id);
if (!SPA_FLAG_CHECK(info->params[i].flags, SPA_PARAM_INFO_READ))
continue;
pw_node_proxy_enum_params((struct pw_node_proxy*)data->proxy,
0, info->params[i].id, 0, 0, NULL);
}
add_pending(data);
}
data->info = pw_node_info_update(data->info, info);
if (data->pending_seq == 0)
data->print_func(data);
return 0;
@ -272,7 +304,7 @@ static int node_event_param(void *object, int seq, uint32_t id,
uint32_t index, uint32_t next, const struct spa_pod *param)
{
struct proxy_data *data = object;
return add_param(data, param);
return add_param(data, id, param);
}
static const struct pw_node_proxy_events node_events = {
@ -305,16 +337,9 @@ static void print_port(struct proxy_data *data)
printf("\ttype: %s (version %d)\n",
spa_debug_type_find_name(pw_type_info(), data->type), data->version);
if (print_all) {
uint32_t i;
printf(" \tdirection: \"%s\"\n", pw_direction_as_string(info->direction));
printf("%c\tparams:\n", MARK_CHANGE(2));
for (i = 0; i < data->n_params; i++) {
if (spa_pod_is_object_type(data->params[i], SPA_TYPE_OBJECT_Format))
spa_debug_format(12, NULL, data->params[i]);
else
spa_debug_pod(12, NULL, data->params[i]);
}
print_properties(info->props, MARK_CHANGE(1));
print_params(data, MARK_CHANGE(1));
print_properties(info->props, MARK_CHANGE(0));
}
}
@ -322,15 +347,23 @@ static int port_event_info(void *object, const struct pw_port_info *info)
{
struct proxy_data *data = object;
bool is_new = data->info == NULL;
struct pw_port_info *old = data->info;
uint32_t i;
data->info = pw_port_info_update(data->info, info);
if (is_new) {
pw_port_proxy_enum_params((struct pw_port_proxy*)data->proxy,
0, SPA_PARAM_EnumFormat, 0, 0, NULL);
if (info->change_mask & PW_PORT_CHANGE_MASK_PARAMS) {
for (i = 0; i < info->n_params; i++) {
if (old != NULL && info->params[i].flags == old->params[i].flags)
continue;
remove_params(data, info->params[i].id);
if (!SPA_FLAG_CHECK(info->params[i].flags, SPA_PARAM_INFO_READ))
continue;
pw_port_proxy_enum_params((struct pw_port_proxy*)data->proxy,
0, info->params[i].id, 0, 0, NULL);
}
add_pending(data);
}
data->info = pw_port_info_update(data->info, info);
if (data->pending_seq == 0)
data->print_func(data);
return 0;
@ -340,7 +373,7 @@ static int port_event_param(void *object, int seq, uint32_t id,
uint32_t index, uint32_t next, const struct spa_pod *param)
{
struct proxy_data *data = object;
return add_param(data, param);
return add_param(data, id, param);
}
static const struct pw_port_proxy_events port_events = {
@ -606,6 +639,7 @@ static int registry_event_global(void *data, uint32_t id, uint32_t parent_id,
pd->destroy = destroy;
pd->pending_seq = 0;
pd->print_func = print_func;
spa_list_init(&pd->param_list);
pw_proxy_add_proxy_listener(proxy, &pd->proxy_proxy_listener, events, pd);
pw_proxy_add_listener(proxy, &pd->proxy_listener, &proxy_events, pd);
return 0;