1 /* Simple Plugin API
2  *
3  * Copyright © 2019 Wim Taymans
4  *
5  * Permission is hereby granted, free of charge, to any person obtaining a
6  * copy of this software and associated documentation files (the "Software"),
7  * to deal in the Software without restriction, including without limitation
8  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
9  * and/or sell copies of the Software, and to permit persons to whom the
10  * Software is furnished to do so, subject to the following conditions:
11  *
12  * The above copyright notice and this permission notice (including the next
13  * paragraph) shall be included in all copies or substantial portions of the
14  * Software.
15  *
16  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
19  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
22  * DEALINGS IN THE SOFTWARE.
23  */
24 
25 #ifndef SPA_NODE_UTILS_H
26 #define SPA_NODE_UTILS_H
27 
28 #ifdef __cplusplus
29 extern "C" {
30 #endif
31 
32 #include <spa/pod/builder.h>
33 
34 #include <spa/node/node.h>
35 
36 struct spa_result_node_params_data {
37 	struct spa_pod_builder *builder;
38 	struct spa_result_node_params data;
39 };
40 
spa_result_func_node_params(void * data,int seq,int res,uint32_t type,const void * result)41 static inline void spa_result_func_node_params(void *data,
42 		int seq, int res, uint32_t type, const void *result)
43 {
44 	struct spa_result_node_params_data *d =
45 		(struct spa_result_node_params_data *) data;
46 	const struct spa_result_node_params *r =
47 		(const struct spa_result_node_params *) result;
48 	uint32_t offset = d->builder->state.offset;
49 	spa_pod_builder_raw_padded(d->builder, r->param, SPA_POD_SIZE(r->param));
50 	d->data.next = r->next;
51 	d->data.param = SPA_MEMBER(d->builder->data, offset, struct spa_pod);
52 }
53 
spa_node_enum_params_sync(struct spa_node * node,uint32_t id,uint32_t * index,const struct spa_pod * filter,struct spa_pod ** param,struct spa_pod_builder * builder)54 static inline int spa_node_enum_params_sync(struct spa_node *node,
55 			uint32_t id, uint32_t *index,
56 			const struct spa_pod *filter,
57 			struct spa_pod **param,
58 			struct spa_pod_builder *builder)
59 {
60 	struct spa_result_node_params_data data = { builder, };
61 	struct spa_hook listener = { 0 };
62 	static const struct spa_node_events node_events = {
63 		SPA_VERSION_NODE_EVENTS,
64 		.result = spa_result_func_node_params,
65 	};
66 	int res;
67 
68 	res = spa_node_add_listener(node, &listener, &node_events, &data);
69 	if (res >= 0) {
70 		res = spa_node_enum_params(node, 0, id, *index, 1, filter);
71 		spa_hook_remove(&listener);
72 	}
73 
74 	if (data.data.param == NULL) {
75 		if (res > 0)
76 			res = 0;
77 	} else {
78 		*index = data.data.next;
79 		*param = data.data.param;
80 		res = 1;
81 	}
82 	return res;
83 }
84 
spa_node_port_enum_params_sync(struct spa_node * node,enum spa_direction direction,uint32_t port_id,uint32_t id,uint32_t * index,const struct spa_pod * filter,struct spa_pod ** param,struct spa_pod_builder * builder)85 static inline int spa_node_port_enum_params_sync(struct spa_node *node,
86 			enum spa_direction direction, uint32_t port_id,
87 			uint32_t id, uint32_t *index,
88 			const struct spa_pod *filter,
89 			struct spa_pod **param,
90 			struct spa_pod_builder *builder)
91 {
92 	struct spa_result_node_params_data data = { builder, };
93 	struct spa_hook listener = { 0 };
94 	static const struct spa_node_events node_events = {
95 		SPA_VERSION_NODE_EVENTS,
96 		.result = spa_result_func_node_params,
97 	};
98 	int res;
99 
100 	res = spa_node_add_listener(node, &listener, &node_events, &data);
101 	if (res >= 0) {
102 		res = spa_node_port_enum_params(node, 0, direction, port_id,
103 				id, *index, 1, filter);
104 		spa_hook_remove(&listener);
105 	}
106 
107 	if (data.data.param == NULL) {
108 		if (res > 0)
109 			res = 0;
110 	} else {
111 		*index = data.data.next;
112 		*param = data.data.param;
113 		res = 1;
114 	}
115 	return res;
116 }
117 
118 #define spa_node_emit(hooks,method,version,...)					\
119 		spa_hook_list_call_simple(hooks, struct spa_node_events,	\
120 				method, version, ##__VA_ARGS__)
121 
122 #define spa_node_emit_info(hooks,...)		spa_node_emit(hooks,info, 0, __VA_ARGS__)
123 #define spa_node_emit_port_info(hooks,...)	spa_node_emit(hooks,port_info, 0, __VA_ARGS__)
124 #define spa_node_emit_result(hooks,...)		spa_node_emit(hooks,result, 0, __VA_ARGS__)
125 #define spa_node_emit_event(hooks,...)		spa_node_emit(hooks,event, 0, __VA_ARGS__)
126 
127 
128 #define spa_node_call(callbacks,method,version,...)			\
129 ({									\
130 	int _res = -ENOTSUP;							\
131 	spa_callbacks_call_res(callbacks, struct spa_node_callbacks,	\
132 			_res, method, version, ##__VA_ARGS__);		\
133 	_res;								\
134 })
135 
136 #define spa_node_call_ready(hook,...)		spa_node_call(hook, ready, 0, __VA_ARGS__)
137 #define spa_node_call_reuse_buffer(hook,...)	spa_node_call(hook, reuse_buffer, 0, __VA_ARGS__)
138 #define spa_node_call_xrun(hook,...)		spa_node_call(hook, xrun, 0, __VA_ARGS__)
139 
140 #ifdef __cplusplus
141 }  /* extern "C" */
142 #endif
143 
144 #endif /* SPA_NODE_UTILS_H */
145