v4l2: use param_info to track param updates

This commit is contained in:
Wim Taymans 2022-11-05 14:01:27 +01:00
parent 11ab47e4c9
commit 59f9ed41fb

View file

@ -166,8 +166,8 @@ struct global {
int changed; int changed;
void *info; void *info;
struct spa_list pending_list;
struct spa_list param_list; struct spa_list param_list;
int param_seq[MAX_PARAMS];
union { union {
struct { struct {
@ -183,6 +183,7 @@ struct global {
struct param { struct param {
struct spa_list link; struct spa_list link;
uint32_t id; uint32_t id;
int32_t seq;
struct spa_pod *param; struct spa_pod *param;
}; };
@ -202,7 +203,7 @@ static uint32_t clear_params(struct spa_list *param_list, uint32_t id)
} }
static struct param *add_param(struct spa_list *params, static struct param *add_param(struct spa_list *params,
int seq, int *param_seq, uint32_t id, const struct spa_pod *param) int seq, uint32_t id, const struct spa_pod *param)
{ {
struct param *p; struct param *p;
@ -214,24 +215,12 @@ static struct param *add_param(struct spa_list *params,
id = SPA_POD_OBJECT_ID(param); id = SPA_POD_OBJECT_ID(param);
} }
if (id >= MAX_PARAMS) {
pw_log_error("too big param id %d", id);
errno = EINVAL;
return NULL;
}
if (seq != param_seq[id]) {
pw_log_debug("ignoring param %d, seq:%d != current_seq:%d",
id, seq, param_seq[id]);
errno = EBUSY;
return NULL;
}
p = malloc(sizeof(*p) + (param != NULL ? SPA_POD_SIZE(param) : 0)); p = malloc(sizeof(*p) + (param != NULL ? SPA_POD_SIZE(param) : 0));
if (p == NULL) if (p == NULL)
return NULL; return NULL;
p->id = id; p->id = id;
p->seq = seq;
if (param != NULL) { if (param != NULL) {
p->param = SPA_PTROFF(p, sizeof(*p), struct spa_pod); p->param = SPA_PTROFF(p, sizeof(*p), struct spa_pod);
memcpy(p->param, param, SPA_POD_SIZE(param)); memcpy(p->param, param, SPA_POD_SIZE(param));
@ -244,6 +233,39 @@ static struct param *add_param(struct spa_list *params,
return p; return p;
} }
static void update_params(struct file *file)
{
struct param *p, *t;
struct global *node;
struct pw_node_info *info;
uint32_t i;
if ((node = file->node) == NULL)
return;
if ((info = node->info) == NULL)
return;
for (i = 0; i < info->n_params; i++) {
spa_list_for_each_safe(p, t, &node->pending_list, link) {
if (p->id == info->params[i].id &&
p->seq != info->params[i].seq &&
p->param != NULL) {
spa_list_remove(&p->link);
free(p);
}
}
}
spa_list_consume(p, &node->pending_list, link) {
spa_list_remove(&p->link);
if (p->param == NULL) {
clear_params(&node->param_list, p->id);
free(p);
} else {
spa_list_append(&node->param_list, &p->link);
}
}
}
#define ATOMIC_DEC(s) __atomic_sub_fetch(&(s), 1, __ATOMIC_SEQ_CST) #define ATOMIC_DEC(s) __atomic_sub_fetch(&(s), 1, __ATOMIC_SEQ_CST)
#define ATOMIC_INC(s) __atomic_add_fetch(&(s), 1, __ATOMIC_SEQ_CST) #define ATOMIC_INC(s) __atomic_add_fetch(&(s), 1, __ATOMIC_SEQ_CST)
@ -510,8 +532,10 @@ static void on_sync_reply(void *data, uint32_t id, int seq)
return; return;
file->last_seq = seq; file->last_seq = seq;
if (file->pending_seq == seq) if (file->pending_seq == seq) {
update_params(file);
pw_thread_loop_signal(file->loop, false); pw_thread_loop_signal(file->loop, false);
}
} }
static void on_error(void *data, uint32_t id, int seq, int res, const char *message) static void on_error(void *data, uint32_t id, int seq, int res, const char *message)
@ -576,21 +600,14 @@ static void node_event_info(void *object, const struct pw_node_info *info)
continue; continue;
info->params[i].user = 0; info->params[i].user = 0;
if (id >= MAX_PARAMS) { add_param(&g->pending_list, info->params[i].seq, id, NULL);
pw_log_error("too big param id %d", id);
continue;
}
if (id != SPA_PARAM_EnumFormat)
continue;
if (!(info->params[i].flags & SPA_PARAM_INFO_READ)) if (!(info->params[i].flags & SPA_PARAM_INFO_READ))
continue; continue;
res = pw_node_enum_params((struct pw_node*)g->proxy, res = pw_node_enum_params((struct pw_node*)g->proxy,
++g->param_seq[id], id, 0, -1, NULL); ++info->params[i].seq, id, 0, -1, NULL);
if (SPA_RESULT_IS_ASYNC(res)) if (SPA_RESULT_IS_ASYNC(res))
g->param_seq[id] = res; info->params[i].seq = res;
} }
} }
do_resync(file); do_resync(file);
@ -602,8 +619,8 @@ static void node_event_param(void *object, int seq,
{ {
struct global *g = object; struct global *g = object;
pw_log_debug("update param %d %d %d %d", g->id, id, seq, g->param_seq[id]); pw_log_debug("update param %d %d %d", g->id, id, seq);
add_param(&g->param_list, seq, g->param_seq, id, param); add_param(&g->pending_list, seq, id, param);
} }
static const struct pw_node_events node_events = { static const struct pw_node_events node_events = {
@ -630,6 +647,10 @@ static void proxy_destroy(void *data)
struct global *g = data; struct global *g = data;
spa_list_remove(&g->link); spa_list_remove(&g->link);
g->proxy = NULL; g->proxy = NULL;
if (g->file)
g->file->node = NULL;
clear_params(&g->param_list, SPA_ID_INVALID);
clear_params(&g->pending_list, SPA_ID_INVALID);
} }
static const struct pw_proxy_events proxy_events = { static const struct pw_proxy_events proxy_events = {
@ -687,6 +708,7 @@ static void registry_event_global(void *data, uint32_t id,
g->permissions = permissions; g->permissions = permissions;
g->props = props ? pw_properties_new_dict(props) : NULL; g->props = props ? pw_properties_new_dict(props) : NULL;
g->proxy = proxy; g->proxy = proxy;
spa_list_init(&g->pending_list);
spa_list_init(&g->param_list); spa_list_init(&g->param_list);
spa_list_append(&file->globals, &g->link); spa_list_append(&file->globals, &g->link);