impl-port: rework port properties

Don't update info.props all the time, just once when we create the
properties, the dict will not change after that.

Move the port property check code to a new function. Keep track if we
auto generated path, name or alias and if we explicitly update it or
not.

Listen for node property changes and update the port properties if
necessary. Some of the port properties or feature depend on the node
properties so we want to keep those in sync.
This commit is contained in:
Wim Taymans 2025-09-22 14:21:46 +02:00
parent ad33ff34f7
commit 3c921acb48
9 changed files with 173 additions and 173 deletions

View file

@ -216,7 +216,6 @@ static int update_properties(struct pw_impl_client *client, const struct spa_dic
}
changed += pw_properties_set(client->properties, dict->items[i].key, dict->items[i].value);
}
client->info.props = &client->properties->dict;
pw_log_debug("%p: updated %d properties", client, changed);
@ -481,6 +480,8 @@ struct pw_impl_client *pw_context_create_client(struct pw_impl_core *core,
pw_mempool_add_listener(this->pool, &impl->pool_listener, &pool_events, impl);
this->properties = properties;
this->info.props = &this->properties->dict;
this->permission_func = client_permission_func;
this->permission_data = impl;
@ -493,7 +494,6 @@ struct pw_impl_client *pw_context_create_client(struct pw_impl_core *core,
pw_context_add_listener(this->context, &impl->context_listener, &context_events, impl);
this->info.props = &this->properties->dict;
return this;
@ -559,7 +559,6 @@ int pw_impl_client_register(struct pw_impl_client *client,
pw_properties_setf(client->properties, PW_KEY_OBJECT_ID, "%d", client->info.id);
pw_properties_setf(client->properties, PW_KEY_OBJECT_SERIAL, "%"PRIu64,
pw_global_get_serial(client->global));
client->info.props = &client->properties->dict;
pw_global_add_listener(client->global, &client->global_listener, &global_events, client);
pw_global_update_keys(client->global, client->info.props, keys);

View file

@ -416,6 +416,7 @@ struct pw_impl_core *pw_context_create_core(struct pw_context *context,
this->info.version = pw_get_library_version();
this->info.cookie = pw_rand32();
this->info.name = name;
this->info.props = &this->properties->dict;
spa_hook_list_init(&this->listener_list);
if (user_data_size > 0)
@ -552,7 +553,6 @@ int pw_impl_core_update_properties(struct pw_impl_core *core, const struct spa_d
int changed;
changed = pw_properties_update(core->properties, dict);
core->info.props = &core->properties->dict;
pw_log_debug("%p: updated %d properties", core, changed);
@ -603,7 +603,6 @@ int pw_impl_core_register(struct pw_impl_core *core,
pw_properties_setf(core->properties, PW_KEY_OBJECT_ID, "%d", core->info.id);
pw_properties_setf(core->properties, PW_KEY_OBJECT_SERIAL, "%"PRIu64,
pw_global_get_serial(core->global));
core->info.props = &core->properties->dict;
pw_global_update_keys(core->global, core->info.props, keys);

View file

@ -143,7 +143,6 @@ static int execute_match(void *data, const char *location, const char *action,
struct pw_impl_device *this = match->device;
if (spa_streq(action, "update-props")) {
match->count += pw_properties_update_string(this->properties, val, len);
this->info.props = &this->properties->dict;
}
return 1;
}
@ -197,7 +196,6 @@ struct pw_impl_device *pw_context_create_device(struct pw_context *context,
this->context = context;
this->properties = properties;
this->info.props = &properties->dict;
this->info.params = this->params;
spa_hook_list_init(&this->listener_list);
@ -617,7 +615,6 @@ int pw_impl_device_register(struct pw_impl_device *device,
pw_properties_setf(device->properties, PW_KEY_OBJECT_ID, "%d", device->info.id);
pw_properties_setf(device->properties, PW_KEY_OBJECT_SERIAL, "%"PRIu64,
pw_global_get_serial(device->global));
device->info.props = &device->properties->dict;
pw_global_update_keys(device->global, device->info.props, global_keys);
@ -690,7 +687,6 @@ static int update_properties(struct pw_impl_device *device, const struct spa_dic
int changed;
changed = pw_properties_update_ignore(device->properties, dict, filter ? ignored : NULL);
device->info.props = &device->properties->dict;
pw_log_debug("%p: updated %d properties", device, changed);

View file

@ -139,7 +139,6 @@ int pw_impl_factory_update_properties(struct pw_impl_factory *factory, const str
int changed;
changed = pw_properties_update(factory->properties, dict);
factory->info.props = &factory->properties->dict;
pw_log_debug("%p: updated %d properties", factory, changed);
@ -192,7 +191,6 @@ int pw_impl_factory_register(struct pw_impl_factory *factory,
pw_properties_set(factory->properties, PW_KEY_FACTORY_NAME, factory->info.name);
pw_properties_setf(factory->properties, PW_KEY_FACTORY_TYPE_NAME, "%s", factory->info.type);
pw_properties_setf(factory->properties, PW_KEY_FACTORY_TYPE_VERSION, "%d", factory->info.version);
factory->info.props = &factory->properties->dict;
pw_global_update_keys(factory->global, factory->info.props, keys);

View file

@ -1493,6 +1493,7 @@ struct pw_impl_link *pw_context_create_link(struct pw_context *context,
this->context = context;
this->properties = properties;
this->info.props = &this->properties->dict;
this->info.state = PW_LINK_STATE_INIT;
this->output = output;
@ -1518,7 +1519,6 @@ struct pw_impl_link *pw_context_create_link(struct pw_context *context,
impl->format_filter = format_filter;
this->info.format = NULL;
this->info.props = &this->properties->dict;
this->rt.out_mix.peer_id = input->global->id;
this->rt.in_mix.peer_id = output->global->id;
@ -1682,7 +1682,6 @@ int pw_impl_link_register(struct pw_impl_link *link,
pw_properties_setf(link->properties, PW_KEY_LINK_OUTPUT_PORT, "%u", link->info.output_port_id);
pw_properties_setf(link->properties, PW_KEY_LINK_INPUT_NODE, "%u", link->info.input_node_id);
pw_properties_setf(link->properties, PW_KEY_LINK_INPUT_PORT, "%u", link->info.input_port_id);
link->info.props = &link->properties->dict;
pw_global_update_keys(link->global, link->info.props, keys);

View file

@ -206,6 +206,7 @@ pw_context_load_module(struct pw_context *context,
this = &impl->this;
this->context = context;
this->properties = properties;
this->info.props = &this->properties->dict;
properties = NULL;
spa_hook_list_init(&this->listener_list);
@ -234,7 +235,6 @@ pw_context_load_module(struct pw_context *context,
pw_properties_setf(this->properties, PW_KEY_OBJECT_ID, "%d", this->info.id);
pw_properties_setf(this->properties, PW_KEY_OBJECT_SERIAL, "%"PRIu64,
pw_global_get_serial(this->global));
this->info.props = &this->properties->dict;
pw_global_update_keys(this->global, &this->properties->dict, keys);
@ -354,7 +354,6 @@ int pw_impl_module_update_properties(struct pw_impl_module *module, const struct
int changed;
changed = pw_properties_update(module->properties, dict);
module->info.props = &module->properties->dict;
pw_log_debug("%p: updated %d properties", module, changed);

View file

@ -989,7 +989,6 @@ int pw_impl_node_register(struct pw_impl_node *this,
pw_properties_setf(this->properties, PW_KEY_OBJECT_ID, "%d", this->global->id);
pw_properties_setf(this->properties, PW_KEY_OBJECT_SERIAL, "%"PRIu64,
pw_global_get_serial(this->global));
this->info.props = &this->properties->dict;
pw_global_update_keys(this->global, &this->properties->dict, global_keys);
@ -1114,7 +1113,6 @@ static int execute_match(void *data, const char *location, const char *action,
struct pw_impl_node *this = match->node;
if (spa_streq(action, "update-props")) {
match->count += pw_properties_update_string(this->properties, val, len);
this->info.props = &this->properties->dict;
}
return 1;
}
@ -1785,7 +1783,6 @@ static int update_properties(struct pw_impl_node *node, const struct spa_dict *d
int changed;
changed = pw_properties_update_ignore(node->properties, dict, filter ? ignored : NULL);
node->info.props = &node->properties->dict;
pw_log_debug("%p: updated %d properties", node, changed);

View file

@ -39,6 +39,8 @@ struct impl {
struct spa_list param_list;
struct spa_list pending_list;
struct spa_hook node_listener;
unsigned int cache_params:1;
};
@ -452,6 +454,134 @@ int pw_impl_port_release_mix(struct pw_impl_port *port, struct pw_impl_port_mix
return res;
}
static int check_properties(struct pw_impl_port *port)
{
struct pw_impl_node *node = port->node;
bool is_control, is_network, is_monitor, is_device, is_duplex, is_virtual;
const char *media_class, *override_device_prefix, *channel_names;
const char *str, *prefix, *path, *desc, *nick, *name;
const struct pw_properties *nprops;
char position[256];
int changed = 0;
nprops = pw_impl_node_get_properties(node);
media_class = pw_properties_get(nprops, PW_KEY_MEDIA_CLASS);
is_network = pw_properties_get_bool(nprops, PW_KEY_NODE_NETWORK, false);
is_control = PW_IMPL_PORT_IS_CONTROL(port);
is_monitor = pw_properties_get_bool(port->properties, PW_KEY_PORT_MONITOR, false);
if (!is_monitor) {
if ((str = pw_properties_get(nprops, PW_KEY_NODE_TERMINAL)) != NULL)
changed += pw_properties_set(port->properties, PW_KEY_PORT_TERMINAL, str);
if ((str = pw_properties_get(nprops, PW_KEY_NODE_PHYSICAL)) != NULL)
changed += pw_properties_set(port->properties, PW_KEY_PORT_PHYSICAL, str);
}
port->ignore_latency = pw_properties_get_bool(port->properties, PW_KEY_PORT_IGNORE_LATENCY, false);
port->exclusive = pw_properties_get_bool(port->properties, PW_KEY_PORT_EXCLUSIVE, node->exclusive);
/* inherit passive state from parent node */
port->passive = pw_properties_get_bool(port->properties, PW_KEY_PORT_PASSIVE,
port->direction == PW_DIRECTION_INPUT ?
node->in_passive : node->out_passive);
if (media_class != NULL &&
(strstr(media_class, "Sink") != NULL ||
strstr(media_class, "Source") != NULL))
is_device = true;
else
is_device = false;
is_duplex = media_class != NULL && strstr(media_class, "Duplex") != NULL;
is_virtual = media_class != NULL && strstr(media_class, "Virtual") != NULL;
override_device_prefix = pw_properties_get(nprops, PW_KEY_NODE_DEVICE_PORT_NAME_PREFIX);
if (is_network) {
prefix = port->direction == PW_DIRECTION_INPUT ?
"send" : is_monitor ? "monitor" : "receive";
} else if (is_duplex) {
prefix = port->direction == PW_DIRECTION_INPUT ?
"playback" : "capture";
} else if (is_virtual) {
prefix = port->direction == PW_DIRECTION_INPUT ?
"input" : "capture";
} else if (is_device) {
if (override_device_prefix != NULL)
prefix = is_monitor ? "monitor" : override_device_prefix;
else
prefix = port->direction == PW_DIRECTION_INPUT ?
"playback" : is_monitor ? "monitor" : "capture";
} else {
prefix = port->direction == PW_DIRECTION_INPUT ?
"input" : is_monitor ? "monitor" : "output";
}
path = pw_properties_get(nprops, PW_KEY_OBJECT_PATH);
desc = pw_properties_get(nprops, PW_KEY_NODE_DESCRIPTION);
nick = pw_properties_get(nprops, PW_KEY_NODE_NICK);
name = pw_properties_get(nprops, PW_KEY_NODE_NAME);
if (pw_properties_get(port->properties, PW_KEY_OBJECT_PATH) == NULL ||
port->auto_path) {
if ((str = name) == NULL && (str = nick) == NULL && (str = desc) == NULL)
str = "node";
changed += pw_properties_setf(port->properties, PW_KEY_OBJECT_PATH, "%s:%s_%d",
path ? path : str, prefix, pw_impl_port_get_id(port));
port->auto_path = true;
}
str = pw_properties_get(port->properties, PW_KEY_AUDIO_CHANNEL);
if (str == NULL || spa_streq(str, "UNK"))
snprintf(position, sizeof(position), "%d", port->port_id + 1);
else if (str != NULL)
snprintf(position, sizeof(position), "%s", str);
channel_names = pw_properties_get(nprops, PW_KEY_NODE_CHANNELNAMES);
if (channel_names != NULL) {
struct spa_json it[1];
char v[256];
uint32_t i;
if (spa_json_begin_array_relax(&it[0], channel_names, strlen(channel_names)) > 0) {
for (i = 0; i < port->port_id + 1; i++)
if (spa_json_get_string(&it[0], v, sizeof(v)) <= 0)
break;
if (i == port->port_id + 1 && strlen(v) > 0)
snprintf(position, sizeof(position), "%s", v);
}
}
if (pw_properties_get(port->properties, PW_KEY_PORT_NAME) == NULL ||
port->auto_name) {
if (is_control)
changed += pw_properties_setf(port->properties, PW_KEY_PORT_NAME, "%s", prefix);
else if (prefix == NULL || strlen(prefix) == 0)
changed += pw_properties_setf(port->properties, PW_KEY_PORT_NAME, "%s", position);
else
changed += pw_properties_setf(port->properties, PW_KEY_PORT_NAME, "%s_%s", prefix, position);
port->auto_name = true;
}
if (pw_properties_get(port->properties, PW_KEY_PORT_ALIAS) == NULL ||
port->auto_alias) {
if ((str = nick) == NULL && (str = desc) == NULL && (str = name) == NULL)
str = "node";
if (is_control)
changed += pw_properties_setf(port->properties, PW_KEY_PORT_ALIAS, "%s:%s",
str, prefix);
else {
changed += pw_properties_setf(port->properties, PW_KEY_PORT_ALIAS, "%s:%s",
str, pw_properties_get(port->properties, PW_KEY_PORT_NAME));
}
port->auto_alias = true;
}
return changed;
}
static int update_properties(struct pw_impl_port *port, const struct spa_dict *dict, bool filter)
{
static const char * const ignored[] = {
@ -462,37 +592,21 @@ static int update_properties(struct pw_impl_port *port, const struct spa_dict *d
PW_KEY_PORT_ID,
NULL
};
int changed;
changed = pw_properties_update_ignore(port->properties, dict, filter ? ignored : NULL);
if (changed) {
const char *name, *alias;
name = spa_dict_lookup(dict, PW_KEY_PORT_NAME);
alias = spa_dict_lookup(dict, PW_KEY_PORT_ALIAS);
if (alias != NULL) {
/* alias was explicitly updated, don't generate one from
* the port.name */
port->alias_port_name = false;
}
else if (name != NULL && port->alias_port_name) {
const struct pw_properties *nprops = pw_impl_node_get_properties(port->node);
const char *node_desc = pw_properties_get(nprops, PW_KEY_NODE_DESCRIPTION);
const char *node_nick = pw_properties_get(nprops, PW_KEY_NODE_NICK);
const char *node_name = pw_properties_get(nprops, PW_KEY_NODE_NAME);
const char *str;
if ((str = node_nick) == NULL && (str = node_desc) == NULL && (str = node_name) == NULL)
str = "node";
pw_properties_setf(port->properties, PW_KEY_PORT_ALIAS, "%s:%s", str, name);
}
}
port->info.props = &port->properties->dict;
pw_log_debug("%p: updated %d properties", port, changed);
if (changed) {
pw_log_debug("%p: updated %d properties", port, changed);
/* check for explicit updates so we don't have to autogenerate */
if (spa_dict_lookup(dict, PW_KEY_OBJECT_PATH) != NULL)
port->auto_path = false;
if (spa_dict_lookup(dict, PW_KEY_PORT_NAME) != NULL)
port->auto_name = false;
if (spa_dict_lookup(dict, PW_KEY_PORT_ALIAS) != NULL)
port->auto_alias = false;
check_properties(port);
port->info.change_mask |= PW_PORT_CHANGE_MASK_PROPS;
}
return changed;
@ -1185,7 +1299,6 @@ int pw_impl_port_register(struct pw_impl_port *port,
pw_properties_setf(port->properties, PW_KEY_OBJECT_ID, "%d", port->info.id);
pw_properties_setf(port->properties, PW_KEY_OBJECT_SERIAL, "%"PRIu64,
pw_global_get_serial(port->global));
port->info.props = &port->properties->dict;
pw_global_update_keys(port->global, &port->properties->dict, global_keys);
@ -1194,18 +1307,32 @@ int pw_impl_port_register(struct pw_impl_port *port,
return pw_global_register(port->global);
}
static void node_info_changed(void *data, const struct pw_node_info *info)
{
struct pw_impl_port *port = data;
if (info->change_mask & PW_NODE_CHANGE_MASK_PROPS) {
if (check_properties(port) > 0) {
port->info.change_mask |= PW_PORT_CHANGE_MASK_PROPS;
emit_info_changed(port);
}
}
}
static const struct pw_impl_node_events node_events = {
PW_VERSION_IMPL_NODE_EVENTS,
.info_changed = node_info_changed,
};
SPA_EXPORT
int pw_impl_port_add(struct pw_impl_port *port, struct pw_impl_node *node)
{
struct impl *impl = SPA_CONTAINER_OF(port, struct impl, this);
uint32_t port_id = port->port_id;
struct spa_list *ports;
struct pw_map *portmap;
struct pw_impl_port *find;
bool is_control, is_network, is_monitor, is_device, is_duplex, is_virtual;
const char *media_class, *override_device_prefix, *channel_names;
const char *str, *dir, *prefix, *path, *desc, *nick, *name;
const struct pw_properties *nprops;
char position[256];
const char *dir;
bool is_control;
int res;
if (port->node != NULL)
@ -1227,146 +1354,28 @@ int pw_impl_port_add(struct pw_impl_port *port, struct pw_impl_node *node)
return res;
port->node = node;
pw_impl_node_add_listener(node, &impl->node_listener, &node_events, port);
pw_impl_node_emit_port_init(node, port);
check_params(port);
nprops = pw_impl_node_get_properties(node);
media_class = pw_properties_get(nprops, PW_KEY_MEDIA_CLASS);
is_network = pw_properties_get_bool(nprops, PW_KEY_NODE_NETWORK, false);
is_monitor = pw_properties_get_bool(port->properties, PW_KEY_PORT_MONITOR, false);
if (!is_monitor) {
if ((str = pw_properties_get(nprops, PW_KEY_NODE_TERMINAL)) != NULL)
pw_properties_set(port->properties, PW_KEY_PORT_TERMINAL, str);
if ((str = pw_properties_get(nprops, PW_KEY_NODE_PHYSICAL)) != NULL)
pw_properties_set(port->properties, PW_KEY_PORT_PHYSICAL, str);
}
port->ignore_latency = pw_properties_get_bool(port->properties, PW_KEY_PORT_IGNORE_LATENCY, false);
port->exclusive = pw_properties_get_bool(port->properties, PW_KEY_PORT_EXCLUSIVE, node->exclusive);
check_properties(port);
is_control = PW_IMPL_PORT_IS_CONTROL(port);
if (is_control) {
dir = port->direction == PW_DIRECTION_INPUT ? "control" : "notify";
pw_properties_set(port->properties, PW_KEY_PORT_CONTROL, "true");
}
else {
dir = port->direction == PW_DIRECTION_INPUT ? "in" : "out";
}
pw_properties_set(port->properties, PW_KEY_PORT_DIRECTION, dir);
/* inherit passive state from parent node */
if (port->direction == PW_DIRECTION_INPUT)
port->passive = node->in_passive;
else
port->passive = node->out_passive;
/* override with specific port property if available */
port->passive = pw_properties_get_bool(port->properties, PW_KEY_PORT_PASSIVE,
port->passive);
if (media_class != NULL &&
(strstr(media_class, "Sink") != NULL ||
strstr(media_class, "Source") != NULL))
is_device = true;
else
is_device = false;
is_duplex = media_class != NULL && strstr(media_class, "Duplex") != NULL;
is_virtual = media_class != NULL && strstr(media_class, "Virtual") != NULL;
override_device_prefix = pw_properties_get(nprops, PW_KEY_NODE_DEVICE_PORT_NAME_PREFIX);
if (is_network) {
prefix = port->direction == PW_DIRECTION_INPUT ?
"send" : is_monitor ? "monitor" : "receive";
} else if (is_duplex) {
prefix = port->direction == PW_DIRECTION_INPUT ?
"playback" : "capture";
} else if (is_virtual) {
prefix = port->direction == PW_DIRECTION_INPUT ?
"input" : "capture";
} else if (is_device) {
if (override_device_prefix != NULL)
prefix = is_monitor ? "monitor" : override_device_prefix;
else
prefix = port->direction == PW_DIRECTION_INPUT ?
"playback" : is_monitor ? "monitor" : "capture";
} else {
prefix = port->direction == PW_DIRECTION_INPUT ?
"input" : is_monitor ? "monitor" : "output";
}
path = pw_properties_get(nprops, PW_KEY_OBJECT_PATH);
desc = pw_properties_get(nprops, PW_KEY_NODE_DESCRIPTION);
nick = pw_properties_get(nprops, PW_KEY_NODE_NICK);
name = pw_properties_get(nprops, PW_KEY_NODE_NAME);
if (pw_properties_get(port->properties, PW_KEY_OBJECT_PATH) == NULL) {
if ((str = name) == NULL && (str = nick) == NULL && (str = desc) == NULL)
str = "node";
pw_properties_setf(port->properties, PW_KEY_OBJECT_PATH, "%s:%s_%d",
path ? path : str, prefix, pw_impl_port_get_id(port));
}
str = pw_properties_get(port->properties, PW_KEY_AUDIO_CHANNEL);
if (str == NULL || spa_streq(str, "UNK"))
snprintf(position, sizeof(position), "%d", port->port_id + 1);
else if (str != NULL)
snprintf(position, sizeof(position), "%s", str);
channel_names = pw_properties_get(nprops, PW_KEY_NODE_CHANNELNAMES);
if (channel_names != NULL) {
struct spa_json it[1];
char v[256];
uint32_t i;
if (spa_json_begin_array_relax(&it[0], channel_names, strlen(channel_names)) > 0) {
for (i = 0; i < port->port_id + 1; i++)
if (spa_json_get_string(&it[0], v, sizeof(v)) <= 0)
break;
if (i == port->port_id + 1 && strlen(v) > 0)
snprintf(position, sizeof(position), "%s", v);
}
}
if (pw_properties_get(port->properties, PW_KEY_PORT_NAME) == NULL) {
if (is_control)
pw_properties_setf(port->properties, PW_KEY_PORT_NAME, "%s", prefix);
else if (prefix == NULL || strlen(prefix) == 0)
pw_properties_setf(port->properties, PW_KEY_PORT_NAME, "%s", position);
else
pw_properties_setf(port->properties, PW_KEY_PORT_NAME, "%s_%s", prefix, position);
}
if (pw_properties_get(port->properties, PW_KEY_PORT_ALIAS) == NULL) {
if ((str = nick) == NULL && (str = desc) == NULL && (str = name) == NULL)
str = "node";
if (is_control)
pw_properties_setf(port->properties, PW_KEY_PORT_ALIAS, "%s:%s",
str, prefix);
else {
pw_properties_setf(port->properties, PW_KEY_PORT_ALIAS, "%s:%s",
str, pw_properties_get(port->properties, PW_KEY_PORT_NAME));
port->alias_port_name = true;
}
}
port->info.props = &port->properties->dict;
if (is_control) {
pw_log_debug("%p: setting node control", port);
pw_properties_set(port->properties, PW_KEY_PORT_CONTROL, "true");
} else {
dir = port->direction == PW_DIRECTION_INPUT ? "in" : "out";
pw_log_debug("%p: setting mixer position io", port);
spa_node_set_io(port->mix,
SPA_IO_Position,
node->rt.position,
sizeof(struct spa_io_position));
}
pw_properties_set(port->properties, PW_KEY_PORT_DIRECTION, dir);
pw_log_debug("%p: %d add to node %p", port, port_id, node);
@ -1419,6 +1428,7 @@ static int do_remove_port(struct spa_loop *loop,
static void pw_impl_port_remove(struct pw_impl_port *port)
{
struct impl *impl = SPA_CONTAINER_OF(port, struct impl, this);
struct pw_impl_node *node = port->node;
int res;
@ -1448,6 +1458,7 @@ static void pw_impl_port_remove(struct pw_impl_port *port)
spa_list_remove(&port->link);
pw_impl_node_emit_port_removed(node, port);
spa_hook_remove(&impl->node_listener);
port->node = NULL;
}

View file

@ -959,7 +959,9 @@ struct pw_impl_port {
} rt; /**< data only accessed from the data thread */
unsigned int destroying:1;
unsigned int passive:1;
unsigned int alias_port_name:1;
unsigned int auto_path:1; /* path was automatically generated */
unsigned int auto_name:1; /* name was automatically generated */
unsigned int auto_alias:1; /* alias was automatically generated */
int busy_count;
struct spa_latency_info latency[2]; /**< latencies */