node: make port for_each more powerful

Make an int return from pw_node_for_each_port() so that we can return
errors or early exit.
Add pw_port_for_each_param() to iterate params. And use this to collect
the formats.
This commit is contained in:
Wim Taymans 2017-11-29 16:58:17 +01:00
parent 425073afd8
commit 91a3670610
6 changed files with 81 additions and 47 deletions

View file

@ -234,10 +234,10 @@ static void node_port_removed(void *data, struct pw_port *port)
{ {
} }
static bool on_node_port_added(void *data, struct pw_port *port) static int on_node_port_added(void *data, struct pw_port *port)
{ {
node_port_added(data, port); node_port_added(data, port);
return true; return 0;
} }
static void on_node_created(struct pw_node *node, struct node_info *info) static void on_node_created(struct pw_node *node, struct node_info *info)

View file

@ -1067,16 +1067,16 @@ struct find_data {
struct pw_jack_port *result; struct pw_jack_port *result;
}; };
static bool find_port(void *data, struct pw_port *port) static int find_port(void *data, struct pw_port *port)
{ {
struct find_data *d = data; struct find_data *d = data;
struct port_data *pd = pw_port_get_user_data(port); struct port_data *pd = pw_port_get_user_data(port);
if (pd->port.port_id == d->port_id) { if (pd->port.port_id == d->port_id) {
d->result = &pd->port; d->result = &pd->port;
return false; return 1;
} }
return true; return 0;
} }
struct pw_jack_port * struct pw_jack_port *
@ -1085,7 +1085,7 @@ pw_jack_node_find_port(struct pw_jack_node *node,
jack_port_id_t port_id) jack_port_id_t port_id)
{ {
struct find_data data = { port_id, }; struct find_data data = { port_id, };
if (!pw_node_for_each_port(node->node, direction, find_port, &data)) if (pw_node_for_each_port(node->node, direction, find_port, &data) == 1)
return data.result; return data.result;
return NULL; return NULL;
} }

View file

@ -219,49 +219,43 @@ static int update_port_ids(struct pw_node *node)
return 0; return 0;
} }
static int collect_params(struct pw_port *port, uint32_t param_id, struct spa_pod ***result) struct param_array {
struct spa_pod **params;
uint32_t n_params;
};
static int add_param(void *data, struct spa_pod *param)
{ {
int res; struct param_array *arr = data;
uint8_t buffer[4096]; uint32_t idx = arr->n_params++;
struct spa_pod_builder b = { 0 };
uint32_t state = 0;
for (res = 0;; res++) { arr->params = realloc(arr->params, sizeof(struct spa_pod *) * arr->n_params);
struct spa_pod *fmt; arr->params[idx] = pw_spa_pod_copy(param);
return 0;
spa_pod_builder_init(&b, buffer, sizeof(buffer));
if (spa_node_port_enum_params(port->node->node,
port->direction, port->port_id,
param_id, &state,
NULL, &fmt, &b) <= 0)
break;
*result = realloc(*result, sizeof(struct spa_pod *) * (res + 1));
(*result)[res] = pw_spa_pod_copy(fmt);
}
return res;
} }
static void static void
update_info(struct pw_node *this) update_info(struct pw_node *this)
{ {
struct pw_type *t = &this->core->type; struct pw_type *t = &this->core->type;
struct param_array params;
struct pw_port *port;
this->info.input_params = NULL; params = (struct param_array) { NULL };
if (!spa_list_is_empty(&this->input_ports)) { if (!spa_list_is_empty(&this->input_ports)) {
struct pw_port *port = spa_list_first(&this->input_ports, struct pw_port, link); port = spa_list_first(&this->input_ports, struct pw_port, link);
this->info.n_input_params = collect_params(port, pw_port_for_each_param(port, t->param.idEnumFormat, NULL, add_param, &params);
t->param.idEnumFormat,
&this->info.input_params);
} }
this->info.input_params = params.params;
this->info.n_input_params = params.n_params;
this->info.output_params = NULL; params = (struct param_array) { NULL };
if (!spa_list_is_empty(&this->output_ports)) { if (!spa_list_is_empty(&this->output_ports)) {
struct pw_port *port = spa_list_first(&this->output_ports, struct pw_port, link); port = spa_list_first(&this->output_ports, struct pw_port, link);
this->info.n_output_params = collect_params(port, pw_port_for_each_param(port, t->param.idEnumFormat, NULL, add_param, &params);
t->param.idEnumFormat,
&this->info.output_params);
} }
this->info.output_params = params.params;
this->info.n_output_params = params.n_params;
} }
static void static void
@ -614,13 +608,14 @@ void pw_node_destroy(struct pw_node *node)
free(impl); free(impl);
} }
bool pw_node_for_each_port(struct pw_node *node, int pw_node_for_each_port(struct pw_node *node,
enum pw_direction direction, enum pw_direction direction,
bool (*callback) (void *data, struct pw_port *port), int (*callback) (void *data, struct pw_port *port),
void *data) void *data)
{ {
struct spa_list *ports; struct spa_list *ports;
struct pw_port *p, *t; struct pw_port *p, *t;
int res;
if (direction == PW_DIRECTION_INPUT) if (direction == PW_DIRECTION_INPUT)
ports = &node->input_ports; ports = &node->input_ports;
@ -628,9 +623,9 @@ bool pw_node_for_each_port(struct pw_node *node,
ports = &node->output_ports; ports = &node->output_ports;
spa_list_for_each_safe(p, t, ports, link) spa_list_for_each_safe(p, t, ports, link)
if (!callback(data, p)) if ((res = callback(data, p)) != 0)
return false; return res;
return true; return 0;
} }
struct pw_port * struct pw_port *

View file

@ -138,11 +138,14 @@ void pw_node_add_listener(struct pw_node *node,
const struct pw_node_events *events, const struct pw_node_events *events,
void *data); void *data);
/** iterate the ports in the given direction */ /** Iterate the ports in the given direction. The callback should return
bool pw_node_for_each_port(struct pw_node *node, * 0 to fetch the next item, any other value stops the iteration and returns
enum pw_direction direction, * the value. When all callbacks return 0, this function returns 0 when all
bool (*callback) (void *data, struct pw_port *port), * items are iterated. */
void *data); int pw_node_for_each_port(struct pw_node *node,
enum pw_direction direction,
int (*callback) (void *data, struct pw_port *port),
void *data);
/** Find the port with direction and port_id or NULL when not found */ /** Find the port with direction and port_id or NULL when not found */

View file

@ -382,6 +382,33 @@ int pw_port_pause(struct pw_port *port)
return 0; return 0;
} }
int pw_port_for_each_param(struct pw_port *port,
uint32_t param_id,
const struct spa_pod *filter,
int (*callback) (void *data, struct spa_pod *param),
void *data)
{
int res;
uint8_t buffer[4096];
struct spa_pod_builder b = { 0 };
uint32_t state;
struct spa_pod *param;
for (state = 0;;) {
spa_pod_builder_init(&b, buffer, sizeof(buffer));
if ((res = spa_node_port_enum_params(port->node->node,
port->direction,
port->port_id,
param_id, &state,
filter, &param, &b)) <= 0)
break;
if ((res = callback(data, param)) != 0)
break;
}
return res;
}
int pw_port_set_param(struct pw_port *port, uint32_t id, uint32_t flags, int pw_port_set_param(struct pw_port *port, uint32_t id, uint32_t flags,
const struct spa_pod *param) const struct spa_pod *param)
{ {

View file

@ -429,6 +429,15 @@ bool pw_port_add(struct pw_port *port, struct pw_node *node);
/** Destroy a port \memberof pw_port */ /** Destroy a port \memberof pw_port */
void pw_port_destroy(struct pw_port *port); void pw_port_destroy(struct pw_port *port);
/** Iterate the params of the given port. The callback should return
* 1 to fetch the next item, 0 to stop iteration or <0 on error.
* The function returns 0 on success or the error returned by the callback. */
int pw_port_for_each_param(struct pw_port *port,
uint32_t param_id,
const struct spa_pod *filter,
int (*callback) (void *data, struct spa_pod *param),
void *data);
/** Set a param on a port \memberof pw_port */ /** Set a param on a port \memberof pw_port */
int pw_port_set_param(struct pw_port *port, uint32_t id, uint32_t flags, int pw_port_set_param(struct pw_port *port, uint32_t id, uint32_t flags,
const struct spa_pod *param); const struct spa_pod *param);