Blob Blame History Raw
From a193bf7e1faa03d1907ebecac097f9ccc3420310 Mon Sep 17 00:00:00 2001
From: Pauli Virtanen <pav@iki.fi>
Date: Sun, 25 Apr 2021 19:11:43 +0300
Subject: [PATCH 4/6] media-session: keep track of seq in pw_*_enum_params

If multiple async enum param are running at the same time, take results
only from the latest one.
---
 src/examples/media-session/media-session.c | 55 +++++++++++++++++-----
 src/examples/media-session/media-session.h |  4 ++
 2 files changed, 46 insertions(+), 13 deletions(-)

diff --git a/src/examples/media-session/media-session.c b/src/examples/media-session/media-session.c
index 640c4caa..21fc8030 100644
--- a/src/examples/media-session/media-session.c
+++ b/src/examples/media-session/media-session.c
@@ -361,7 +361,7 @@ int sm_object_destroy(struct sm_object *obj)
 }
 
 static struct param *add_param(struct spa_list *param_list,
-		uint32_t id, const struct spa_pod *param)
+		int seq, int *param_seq, uint32_t id, const struct spa_pod *param)
 {
 	struct param *p;
 
@@ -372,6 +372,19 @@ static struct param *add_param(struct spa_list *param_list,
 	if (id == SPA_ID_INVALID)
 		id = SPA_POD_OBJECT_ID(param);
 
+	if (id >= SM_MAX_PARAMS) {
+		pw_log_error(NAME": too big param id %d", id);
+		errno = EINVAL;
+		return NULL;
+	}
+
+	if (seq != param_seq[id]) {
+		pw_log_debug(NAME": ignoring param %d, seq:%d != current_seq:%d",
+				id, seq, param_seq[id]);
+		errno = EBUSY;
+		return NULL;
+	}
+
 	p = malloc(sizeof(struct param) + SPA_POD_SIZE(param));
 	if (p == NULL)
 		return NULL;
@@ -490,13 +503,21 @@ static void device_event_info(void *object, const struct pw_device_info *info)
 			if (info->params[i].user == 0)
 				continue;
 
+			if (id >= SM_MAX_PARAMS) {
+				pw_log_error(NAME" %p: too big param id %d", impl, id);
+				continue;
+			}
+
 			device->n_params -= clear_params(&device->param_list, id);
 
 			if (info->params[i].flags & SPA_PARAM_INFO_READ) {
-				pw_log_debug(NAME" %p: device %d enum params %d", impl,
-						device->obj.id, id);
-				pw_device_enum_params((struct pw_device*)device->obj.proxy,
-						1, id, 0, UINT32_MAX, NULL);
+				int res;
+				res = pw_device_enum_params((struct pw_device*)device->obj.proxy,
+						++device->param_seq[id], id, 0, UINT32_MAX, NULL);
+				if (SPA_RESULT_IS_ASYNC(res))
+					device->param_seq[id] = res;
+				pw_log_debug(NAME" %p: device %d enum params %d seq:%d", impl,
+						device->obj.id, id, device->param_seq[id]);
 			}
 			info->params[i].user = 0;
 		}
@@ -512,8 +533,8 @@ static void device_event_param(void *object, int seq,
 	struct sm_device *device = object;
 	struct impl *impl = SPA_CONTAINER_OF(device->obj.session, struct impl, this);
 
-	pw_log_debug(NAME" %p: device %p param %d index:%d", impl, device, id, index);
-	if (add_param(&device->param_list, id, param) != NULL)
+	pw_log_debug(NAME" %p: device %p param %d index:%d seq:%d", impl, device, id, index, seq);
+	if (add_param(&device->param_list, seq, device->param_seq, id, param) != NULL)
 		device->n_params++;
 
 	device->obj.avail |= SM_DEVICE_CHANGE_MASK_PARAMS;
@@ -591,13 +612,21 @@ static void node_event_info(void *object, const struct pw_node_info *info)
 			if (info->params[i].user == 0)
 				continue;
 
+			if (id >= SM_MAX_PARAMS) {
+				pw_log_error(NAME" %p: too big param id %d", impl, id);
+				continue;
+			}
+
 			node->n_params -= clear_params(&node->param_list, id);
 
 			if (info->params[i].flags & SPA_PARAM_INFO_READ) {
-				pw_log_debug(NAME" %p: node %d enum params %d", impl,
-						node->obj.id, id);
-				pw_node_enum_params((struct pw_node*)node->obj.proxy,
-						1, id, 0, UINT32_MAX, NULL);
+				int res;
+				res = pw_node_enum_params((struct pw_node*)node->obj.proxy,
+						++node->param_seq[id], id, 0, UINT32_MAX, NULL);
+				if (SPA_RESULT_IS_ASYNC(res))
+					node->param_seq[id] = res;
+				pw_log_debug(NAME" %p: node %d enum params %d seq:%d", impl,
+						node->obj.id, id, node->param_seq[id]);
 			}
 			info->params[i].user = 0;
 		}
@@ -613,8 +642,8 @@ static void node_event_param(void *object, int seq,
 	struct sm_node *node = object;
 	struct impl *impl = SPA_CONTAINER_OF(node->obj.session, struct impl, this);
 
-	pw_log_debug(NAME" %p: node %p param %d index:%d", impl, node, id, index);
-	if (add_param(&node->param_list, id, param) != NULL)
+	pw_log_debug(NAME" %p: node %p param %d index:%d seq:%d", impl, node, id, index, seq);
+	if (add_param(&node->param_list, seq, node->param_seq, id, param) != NULL)
 		node->n_params++;
 
 	node->obj.avail |= SM_NODE_CHANGE_MASK_PARAMS;
diff --git a/src/examples/media-session/media-session.h b/src/examples/media-session/media-session.h
index edfb1331..7d036288 100644
--- a/src/examples/media-session/media-session.h
+++ b/src/examples/media-session/media-session.h
@@ -35,6 +35,8 @@ extern "C" {
 
 #define SM_TYPE_MEDIA_SESSION	PW_TYPE_INFO_OBJECT_BASE "SessionManager"
 
+#define SM_MAX_PARAMS 32
+
 struct sm_media_session;
 
 struct sm_object_events {
@@ -133,6 +135,7 @@ struct sm_device {
 #define SM_DEVICE_CHANGE_MASK_NODES	(SM_OBJECT_CHANGE_MASK_LAST<<2)
 	uint32_t n_params;
 	struct spa_list param_list;	/**< list of sm_param */
+	int param_seq[SM_MAX_PARAMS];
 	struct pw_device_info *info;
 	struct spa_list node_list;
 };
@@ -148,6 +151,7 @@ struct sm_node {
 #define SM_NODE_CHANGE_MASK_PORTS	(SM_OBJECT_CHANGE_MASK_LAST<<2)
 	uint32_t n_params;
 	struct spa_list param_list;	/**< list of sm_param */
+	int param_seq[SM_MAX_PARAMS];
 	struct pw_node_info *info;
 	struct spa_list port_list;
 
-- 
2.30.2