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

@ -117,8 +117,7 @@ static int emit_node(struct impl *this, snd_pcm_info_t *pcminfo, uint32_t id)
else
info.factory = &spa_alsa_source_factory;
info.change_mask = SPA_DEVICE_OBJECT_CHANGE_MASK_INFO;
info.change_mask = SPA_DEVICE_OBJECT_CHANGE_MASK_PROPS;
snprintf(device_name, 128, "%s,%d", this->props.device, snd_pcm_info_get_device(pcminfo));
items[0] = SPA_DICT_ITEM_INIT("alsa.device", device_name);
items[1] = SPA_DICT_ITEM_INIT("alsa.pcm.id", snd_pcm_info_get_id(pcminfo));
@ -126,7 +125,7 @@ static int emit_node(struct impl *this, snd_pcm_info_t *pcminfo, uint32_t id)
items[3] = SPA_DICT_ITEM_INIT("alsa.pcm.subname", snd_pcm_info_get_subdevice_name(pcminfo));
items[4] = SPA_DICT_ITEM_INIT("alsa.pcm.class", get_class(pcminfo));
items[5] = SPA_DICT_ITEM_INIT("alsa.pcm.subclass", get_subclass(pcminfo));
info.info = &SPA_DICT_INIT_ARRAY(items);
info.props = &SPA_DICT_INIT_ARRAY(items);
this->callbacks->object_info(this->callbacks_data, id, &info);
@ -214,7 +213,7 @@ static int emit_info(struct impl *this)
snd_ctl_t *ctl_hndl;
snd_ctl_card_info_t *info;
struct spa_device_info dinfo;
uint32_t params[] = { SPA_PARAM_EnumProfile, SPA_PARAM_Profile };
struct spa_param_info params[2];
spa_log_info(this->log, "open card %s", this->props.device);
if ((err = snd_ctl_open(&ctl_hndl, this->props.device, 0)) < 0) {
@ -230,8 +229,8 @@ static int emit_info(struct impl *this)
}
dinfo = SPA_DEVICE_INFO_INIT();
dinfo.change_mask = SPA_DEVICE_CHANGE_MASK_INFO | SPA_DEVICE_CHANGE_MASK_PARAMS;
dinfo.change_mask = SPA_DEVICE_CHANGE_MASK_PROPS;
items[0] = SPA_DICT_ITEM_INIT("device.api", "alsa");
items[1] = SPA_DICT_ITEM_INIT("device.path", (char *)this->props.device);
items[2] = SPA_DICT_ITEM_INIT("device.nick", snd_ctl_card_info_get_id(info));
@ -242,7 +241,11 @@ static int emit_info(struct impl *this)
items[7] = SPA_DICT_ITEM_INIT("alsa.card.name", snd_ctl_card_info_get_name(info));
items[8] = SPA_DICT_ITEM_INIT("alsa.card.longname", snd_ctl_card_info_get_longname(info));
items[9] = SPA_DICT_ITEM_INIT("alsa.card.mixername", snd_ctl_card_info_get_mixername(info));
dinfo.info = &SPA_DICT_INIT(items, 10);
dinfo.props = &SPA_DICT_INIT(items, 10);
dinfo.change_mask |= SPA_DEVICE_CHANGE_MASK_PARAMS;
params[0] = SPA_PARAM_INFO(SPA_PARAM_EnumProfile, SPA_PARAM_INFO_READ);
params[1] = SPA_PARAM_INFO(SPA_PARAM_Profile, SPA_PARAM_INFO_READWRITE);
dinfo.n_params = SPA_N_ELEMENTS(params);
dinfo.params = params;
@ -303,19 +306,6 @@ static int impl_enum_params(struct spa_device *device, int seq,
spa_pod_builder_init(&b, buffer, sizeof(buffer));
switch (id) {
case SPA_PARAM_List:
{
uint32_t list[] = { SPA_PARAM_EnumProfile,
SPA_PARAM_Profile };
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_EnumProfile:
{
switch (result.index) {

View file

@ -27,6 +27,7 @@
#include <asoundlib.h>
#include <spa/node/node.h>
#include <spa/node/utils.h>
#include <spa/param/audio/format.h>
#include <spa/pod/filter.h>
#include <spa/debug/pod.h>
@ -74,19 +75,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_PropInfo,
SPA_PARAM_Props };
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_PropInfo:
{
struct props *p = &this->props;
@ -253,23 +241,19 @@ static const struct spa_dict_item node_info_items[] = {
static void emit_node_info(struct state *this)
{
if (this->callbacks && this->callbacks->info) {
struct spa_node_info info;
info = SPA_NODE_INFO_INIT();
info.max_input_ports = 1;
info.change_mask = SPA_NODE_CHANGE_MASK_PROPS;
info.props = &SPA_DICT_INIT_ARRAY(node_info_items);
this->callbacks->info(this->callbacks_data, &info);
if (this->callbacks && this->callbacks->info && this->info.change_mask) {
this->info.props = &SPA_DICT_INIT_ARRAY(node_info_items);
this->callbacks->info(this->callbacks_data, &this->info);
this->info.change_mask = 0;
}
}
static void emit_port_info(struct state *this)
{
if (this->callbacks && this->callbacks->port_info && this->info.change_mask) {
this->callbacks->port_info(this->callbacks_data, SPA_DIRECTION_INPUT, 0, &this->info);
this->info.change_mask = 0;
if (this->callbacks && this->callbacks->port_info && this->port_info.change_mask) {
this->callbacks->port_info(this->callbacks_data,
SPA_DIRECTION_INPUT, 0, &this->port_info);
this->port_info.change_mask = 0;
}
}
@ -335,22 +319,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:
return spa_alsa_enum_format(this, seq, start, num, filter);
@ -382,9 +350,6 @@ impl_node_port_enum_params(struct spa_node *node, int seq,
break;
case SPA_PARAM_Meta:
if (!this->have_format)
return -EIO;
switch (result.index) {
case 0:
param = spa_pod_builder_add_object(&b,
@ -456,6 +421,9 @@ static int port_set_format(struct spa_node *node,
int err;
if (format == NULL) {
if (!this->have_format)
return 0;
spa_log_debug(this->log, "clear format");
spa_alsa_pause(this);
clear_buffers(this);
@ -481,11 +449,17 @@ static int port_set_format(struct spa_node *node,
this->have_format = true;
}
this->port_info.change_mask |= SPA_PORT_CHANGE_MASK_RATE;
this->port_info.rate = this->rate;
this->port_info.change_mask |= SPA_PORT_CHANGE_MASK_PARAMS;
if (this->have_format) {
this->info.change_mask |= SPA_PORT_CHANGE_MASK_RATE;
this->info.rate = this->rate;
emit_port_info(this);
this->port_params[3] = SPA_PARAM_INFO(SPA_PARAM_Format, SPA_PARAM_INFO_READWRITE);
this->port_params[4] = SPA_PARAM_INFO(SPA_PARAM_Buffers, SPA_PARAM_INFO_READ);
} else {
this->port_params[3] = SPA_PARAM_INFO(SPA_PARAM_Format, SPA_PARAM_INFO_WRITE);
this->port_params[4] = SPA_PARAM_INFO(SPA_PARAM_Buffers, 0);
}
emit_port_info(this);
return 0;
}
@ -734,15 +708,34 @@ impl_init(const struct spa_handle_factory *factory,
this->node = impl_node;
this->stream = SND_PCM_STREAM_PLAYBACK;
this->info = SPA_NODE_INFO_INIT();
this->info.max_input_ports = 1;
this->info.change_mask = SPA_NODE_CHANGE_MASK_PROPS;
this->info.change_mask |= SPA_NODE_CHANGE_MASK_PARAMS;
this->params[0] = SPA_PARAM_INFO(SPA_PARAM_PropInfo, SPA_PARAM_INFO_READ);
this->params[1] = SPA_PARAM_INFO(SPA_PARAM_Props, SPA_PARAM_INFO_READWRITE);
this->info.params = this->params;
this->info.n_params = 2;
reset_props(&this->props);
this->info = SPA_PORT_INFO_INIT();
this->info.change_mask |= SPA_PORT_CHANGE_MASK_FLAGS;
this->info.flags = SPA_PORT_FLAG_CAN_USE_BUFFERS |
this->port_info = SPA_PORT_INFO_INIT();
this->port_info.change_mask |= SPA_PORT_CHANGE_MASK_FLAGS;
this->port_info.flags = SPA_PORT_FLAG_CAN_USE_BUFFERS |
SPA_PORT_FLAG_LIVE |
SPA_PORT_FLAG_PHYSICAL |
SPA_PORT_FLAG_TERMINAL;
this->port_info.change_mask |= SPA_PORT_CHANGE_MASK_PARAMS;
this->port_params[0] = SPA_PARAM_INFO(SPA_PARAM_EnumFormat, SPA_PARAM_INFO_READ);
this->port_params[1] = SPA_PARAM_INFO(SPA_PARAM_Meta, SPA_PARAM_INFO_READ);
this->port_params[2] = SPA_PARAM_INFO(SPA_PARAM_IO, SPA_PARAM_INFO_READ);
this->port_params[3] = SPA_PARAM_INFO(SPA_PARAM_Format, SPA_PARAM_INFO_WRITE);
this->port_params[4] = SPA_PARAM_INFO(SPA_PARAM_Buffers, 0);
this->port_info.params = this->port_params;
this->port_info.n_params = 5;
spa_list_init(&this->ready);
for (i = 0; info && i < info->n_items; i++) {

View file

@ -27,6 +27,7 @@
#include <asoundlib.h>
#include <spa/node/node.h>
#include <spa/node/utils.h>
#include <spa/utils/list.h>
#include <spa/param/audio/format.h>
#include <spa/pod/filter.h>
@ -76,19 +77,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_PropInfo,
SPA_PARAM_Props, };
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_PropInfo:
switch (result.index) {
case 0:
@ -253,23 +241,19 @@ static const struct spa_dict_item node_info_items[] = {
static void emit_node_info(struct state *this)
{
if (this->callbacks && this->callbacks->info) {
struct spa_node_info info;
info = SPA_NODE_INFO_INIT();
info.max_output_ports = 1;
info.change_mask = SPA_NODE_CHANGE_MASK_PROPS;
info.props = &SPA_DICT_INIT_ARRAY(node_info_items);
this->callbacks->info(this->callbacks_data, &info);
if (this->callbacks && this->callbacks->info && this->info.change_mask) {
this->info.props = &SPA_DICT_INIT_ARRAY(node_info_items);
this->callbacks->info(this->callbacks_data, &this->info);
this->info.change_mask = 0;
}
}
static void emit_port_info(struct state *this)
{
if (this->callbacks && this->callbacks->port_info && this->info.change_mask) {
this->callbacks->port_info(this->callbacks_data, SPA_DIRECTION_OUTPUT, 0, &this->info);
this->info.change_mask = 0;
if (this->callbacks && this->callbacks->port_info && this->port_info.change_mask) {
this->callbacks->port_info(this->callbacks_data,
SPA_DIRECTION_OUTPUT, 0, &this->port_info);
this->port_info.change_mask = 0;
}
}
@ -346,21 +330,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 };
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:
return spa_alsa_enum_format(this, seq, start, num, filter);
@ -392,9 +361,6 @@ impl_node_port_enum_params(struct spa_node *node, int seq,
break;
case SPA_PARAM_Meta:
if (!this->have_format)
return -EIO;
switch (result.index) {
case 0:
param = spa_pod_builder_add_object(&b,
@ -460,6 +426,9 @@ static int port_set_format(struct spa_node *node,
int err;
if (format == NULL) {
if (!this->have_format)
return 0;
spa_alsa_pause(this);
clear_buffers(this);
spa_alsa_close(this);
@ -484,11 +453,17 @@ static int port_set_format(struct spa_node *node,
this->have_format = true;
}
this->port_info.change_mask |= SPA_PORT_CHANGE_MASK_RATE;
this->port_info.rate = this->rate;
this->port_info.change_mask |= SPA_PORT_CHANGE_MASK_PARAMS;
if (this->have_format) {
this->info.rate = this->rate;
this->info.change_mask |= SPA_PORT_CHANGE_MASK_RATE;
emit_port_info(this);
this->port_params[3] = SPA_PARAM_INFO(SPA_PARAM_Format, SPA_PARAM_INFO_READWRITE);
this->port_params[4] = SPA_PARAM_INFO(SPA_PARAM_Buffers, SPA_PARAM_INFO_READ);
} else {
this->port_params[3] = SPA_PARAM_INFO(SPA_PARAM_Format, SPA_PARAM_INFO_WRITE);
this->port_params[4] = SPA_PARAM_INFO(SPA_PARAM_Buffers, 0);
}
emit_port_info(this);
return 0;
}
@ -499,15 +474,22 @@ impl_node_port_set_param(struct spa_node *node,
uint32_t id, uint32_t flags,
const struct spa_pod *param)
{
int res;
spa_return_val_if_fail(node != NULL, -EINVAL);
spa_return_val_if_fail(CHECK_PORT(node, direction, port_id), -EINVAL);
if (id == SPA_PARAM_Format) {
return port_set_format(node, direction, port_id, flags, param);
switch (id) {
case SPA_PARAM_Format:
res = port_set_format(node, direction, port_id, flags, param);
break;
default:
res = -ENOENT;
break;
}
else
return -ENOENT;
return res;
}
static int
@ -747,14 +729,30 @@ impl_init(const struct spa_handle_factory *factory,
this->node = impl_node;
this->stream = SND_PCM_STREAM_CAPTURE;
this->info.max_output_ports = 1;
this->info.change_mask = SPA_NODE_CHANGE_MASK_PROPS;
this->info.change_mask |= SPA_NODE_CHANGE_MASK_PARAMS;
this->params[0] = SPA_PARAM_INFO(SPA_PARAM_PropInfo, SPA_PARAM_INFO_READ);
this->params[1] = SPA_PARAM_INFO(SPA_PARAM_Props, SPA_PARAM_INFO_READWRITE);
this->info.params = this->params;
this->info.n_params = 2;
reset_props(&this->props);
this->info = SPA_PORT_INFO_INIT();
this->info.change_mask = SPA_PORT_CHANGE_MASK_FLAGS;
this->info.flags = SPA_PORT_FLAG_CAN_USE_BUFFERS |
this->port_info = SPA_PORT_INFO_INIT();
this->port_info.change_mask = SPA_PORT_CHANGE_MASK_FLAGS;
this->port_info.flags = SPA_PORT_FLAG_CAN_USE_BUFFERS |
SPA_PORT_FLAG_LIVE |
SPA_PORT_FLAG_PHYSICAL |
SPA_PORT_FLAG_TERMINAL;
this->port_info.change_mask |= SPA_PORT_CHANGE_MASK_PARAMS;
this->port_params[0] = SPA_PARAM_INFO(SPA_PARAM_EnumFormat, SPA_PARAM_INFO_READ);
this->port_params[1] = SPA_PARAM_INFO(SPA_PARAM_Meta, SPA_PARAM_INFO_READ);
this->port_params[2] = SPA_PARAM_INFO(SPA_PARAM_IO, SPA_PARAM_INFO_READ);
this->port_params[3] = SPA_PARAM_INFO(SPA_PARAM_Format, SPA_PARAM_INFO_WRITE);
this->port_params[4] = SPA_PARAM_INFO(SPA_PARAM_Buffers, 0);
this->port_info.params = this->port_params;
this->port_info.n_params = 5;
spa_list_init(&this->free);
spa_list_init(&this->ready);

View file

@ -58,10 +58,10 @@ struct props {
struct buffer {
uint32_t id;
#define BUFFER_FLAG_OUT (1<<0)
uint32_t flags;
struct spa_buffer *buf;
struct spa_meta_header *h;
#define BUFFER_FLAG_OUT (1<<0)
struct spa_list link;
};
@ -80,8 +80,6 @@ struct state {
struct spa_handle handle;
struct spa_node node;
uint32_t seq;
struct spa_log *log;
struct spa_loop *main_loop;
struct spa_loop *data_loop;
@ -92,6 +90,8 @@ struct state {
const struct spa_node_callbacks *callbacks;
void *callbacks_data;
struct spa_node_info info;
struct spa_param_info params[8];
struct props props;
bool opened;
@ -108,7 +108,8 @@ struct state {
int channels;
size_t frame_size;
struct spa_port_info info;
struct spa_port_info port_info;
struct spa_param_info port_params[8];
struct spa_io_buffers *io;
struct spa_io_range *range;
struct spa_io_clock *clock;