mirror of
				https://gitlab.freedesktop.org/pipewire/pipewire.git
				synced 2025-11-03 09:01:54 -05:00 
			
		
		
		
	impl-port: implement port_enum_param on mixers
Implement the IO areas the default mixers support and proxy all other queries to the peer port with the new node event.
This commit is contained in:
		
							parent
							
								
									67aafec8ab
								
							
						
					
					
						commit
						271f2d855d
					
				
					 2 changed files with 142 additions and 11 deletions
				
			
		| 
						 | 
					@ -70,6 +70,7 @@ struct port {
 | 
				
			||||||
	uint32_t id;
 | 
						uint32_t id;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	struct spa_node mix_node;
 | 
						struct spa_node mix_node;
 | 
				
			||||||
 | 
						struct spa_hook_list mix_hooks;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	struct spa_port_info info;
 | 
						struct spa_port_info info;
 | 
				
			||||||
	struct pw_properties *properties;
 | 
						struct pw_properties *properties;
 | 
				
			||||||
| 
						 | 
					@ -583,12 +584,11 @@ impl_node_remove_port(void *object, enum spa_direction direction, uint32_t port_
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static int
 | 
					static int
 | 
				
			||||||
impl_node_port_enum_params(void *object, int seq,
 | 
					node_port_enum_params(struct impl *impl, int seq,
 | 
				
			||||||
			   enum spa_direction direction, uint32_t port_id,
 | 
								   enum spa_direction direction, uint32_t port_id,
 | 
				
			||||||
			   uint32_t id, uint32_t start, uint32_t num,
 | 
								   uint32_t id, uint32_t start, uint32_t num,
 | 
				
			||||||
			   const struct spa_pod *filter)
 | 
								   const struct spa_pod *filter, struct spa_hook_list *hooks)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct impl *impl = object;
 | 
					 | 
				
			||||||
	struct port *port;
 | 
						struct port *port;
 | 
				
			||||||
	uint8_t buffer[1024];
 | 
						uint8_t buffer[1024];
 | 
				
			||||||
	struct spa_pod_dynamic_builder b;
 | 
						struct spa_pod_dynamic_builder b;
 | 
				
			||||||
| 
						 | 
					@ -628,7 +628,7 @@ impl_node_port_enum_params(void *object, int seq,
 | 
				
			||||||
		spa_pod_dynamic_builder_init(&b, buffer, sizeof(buffer), 4096);
 | 
							spa_pod_dynamic_builder_init(&b, buffer, sizeof(buffer), 4096);
 | 
				
			||||||
		if (spa_pod_filter(&b.b, &result.param, param, filter) == 0) {
 | 
							if (spa_pod_filter(&b.b, &result.param, param, filter) == 0) {
 | 
				
			||||||
			pw_log_debug("%p: %d param %u", impl, seq, result.index);
 | 
								pw_log_debug("%p: %d param %u", impl, seq, result.index);
 | 
				
			||||||
			spa_node_emit_result(&impl->hooks, seq, 0, SPA_RESULT_TYPE_NODE_PARAMS, &result);
 | 
								spa_node_emit_result(hooks, seq, 0, SPA_RESULT_TYPE_NODE_PARAMS, &result);
 | 
				
			||||||
			count++;
 | 
								count++;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		spa_pod_dynamic_builder_clean(&b);
 | 
							spa_pod_dynamic_builder_clean(&b);
 | 
				
			||||||
| 
						 | 
					@ -639,6 +639,17 @@ impl_node_port_enum_params(void *object, int seq,
 | 
				
			||||||
	return found ? 0 : -ENOENT;
 | 
						return found ? 0 : -ENOENT;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static int
 | 
				
			||||||
 | 
					impl_node_port_enum_params(void *object, int seq,
 | 
				
			||||||
 | 
								   enum spa_direction direction, uint32_t port_id,
 | 
				
			||||||
 | 
								   uint32_t id, uint32_t start, uint32_t num,
 | 
				
			||||||
 | 
								   const struct spa_pod *filter)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct impl *impl = object;
 | 
				
			||||||
 | 
						return node_port_enum_params(impl, seq, direction, port_id, id,
 | 
				
			||||||
 | 
								start, num, filter, &impl->hooks);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static int clear_buffers_cb(void *item, void *data)
 | 
					static int clear_buffers_cb(void *item, void *data)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	if (item)
 | 
						if (item)
 | 
				
			||||||
| 
						 | 
					@ -1518,19 +1529,28 @@ static const struct pw_impl_port_implementation port_impl = {
 | 
				
			||||||
	.release_mix = port_release_mix,
 | 
						.release_mix = port_release_mix,
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static int
 | 
				
			||||||
 | 
					impl_mix_add_listener(void *object, struct spa_hook *listener,
 | 
				
			||||||
 | 
							const struct spa_node_events *events, void *data)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct port *port = object;
 | 
				
			||||||
 | 
						spa_hook_list_append(&port->mix_hooks, listener, events, data);
 | 
				
			||||||
 | 
						return 0;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static int
 | 
					static int
 | 
				
			||||||
impl_mix_port_enum_params(void *object, int seq,
 | 
					impl_mix_port_enum_params(void *object, int seq,
 | 
				
			||||||
			   enum spa_direction direction, uint32_t port_id,
 | 
							enum spa_direction direction, uint32_t port_id,
 | 
				
			||||||
			   uint32_t id, uint32_t start, uint32_t num,
 | 
							uint32_t id, uint32_t start, uint32_t num,
 | 
				
			||||||
			   const struct spa_pod *filter)
 | 
							const struct spa_pod *filter)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct port *port = object;
 | 
						struct port *port = object;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (port->direction != direction)
 | 
						if (port->direction != direction)
 | 
				
			||||||
		return -ENOTSUP;
 | 
							return -ENOTSUP;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return impl_node_port_enum_params(port->impl, seq, direction, port->id,
 | 
						return node_port_enum_params(port->impl, seq, direction, port->id,
 | 
				
			||||||
			id, start, num, filter);
 | 
								id, start, num, filter, &port->mix_hooks);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static int
 | 
					static int
 | 
				
			||||||
| 
						 | 
					@ -1611,6 +1631,7 @@ static int impl_mix_process(void *object)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static const struct spa_node_methods impl_port_mix = {
 | 
					static const struct spa_node_methods impl_port_mix = {
 | 
				
			||||||
	SPA_VERSION_NODE_METHODS,
 | 
						SPA_VERSION_NODE_METHODS,
 | 
				
			||||||
 | 
						.add_listener = impl_mix_add_listener,
 | 
				
			||||||
	.port_enum_params = impl_mix_port_enum_params,
 | 
						.port_enum_params = impl_mix_port_enum_params,
 | 
				
			||||||
	.port_set_param = impl_mix_port_set_param,
 | 
						.port_set_param = impl_mix_port_set_param,
 | 
				
			||||||
	.add_port = impl_mix_add_port,
 | 
						.add_port = impl_mix_add_port,
 | 
				
			||||||
| 
						 | 
					@ -1635,6 +1656,7 @@ static void node_port_init(void *data, struct pw_impl_port *port)
 | 
				
			||||||
	p->id = port->port_id;
 | 
						p->id = port->port_id;
 | 
				
			||||||
	p->impl = impl;
 | 
						p->impl = impl;
 | 
				
			||||||
	pw_map_init(&p->mix, 2, 2);
 | 
						pw_map_init(&p->mix, 2, 2);
 | 
				
			||||||
 | 
						spa_hook_list_init(&p->mix_hooks);
 | 
				
			||||||
	p->mix_node.iface = SPA_INTERFACE_INIT(
 | 
						p->mix_node.iface = SPA_INTERFACE_INIT(
 | 
				
			||||||
			SPA_TYPE_INTERFACE_Node,
 | 
								SPA_TYPE_INTERFACE_Node,
 | 
				
			||||||
			SPA_VERSION_NODE,
 | 
								SPA_VERSION_NODE,
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -29,6 +29,9 @@ PW_LOG_TOPIC_EXTERN(log_port);
 | 
				
			||||||
struct impl {
 | 
					struct impl {
 | 
				
			||||||
	struct pw_impl_port this;
 | 
						struct pw_impl_port this;
 | 
				
			||||||
	struct spa_node mix_node;	/**< mix node implementation */
 | 
						struct spa_node mix_node;	/**< mix node implementation */
 | 
				
			||||||
 | 
						struct spa_hook_list mix_hooks;
 | 
				
			||||||
 | 
						struct spa_hook mix_listener;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	struct spa_list mix_list;
 | 
						struct spa_list mix_list;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	struct spa_list param_list;
 | 
						struct spa_list param_list;
 | 
				
			||||||
| 
						 | 
					@ -115,6 +118,78 @@ void pw_impl_port_update_state(struct pw_impl_port *port, enum pw_impl_port_stat
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static int mix_add_listener(void *object, struct spa_hook *listener,
 | 
				
			||||||
 | 
							const struct spa_node_events *events, void *data)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct impl *impl = object;
 | 
				
			||||||
 | 
						spa_hook_list_append(&impl->mix_hooks, listener, events, data);
 | 
				
			||||||
 | 
						return 0;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void mix_result(void *data, int seq, int res, uint32_t type, const void *result)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct impl *impl = data;
 | 
				
			||||||
 | 
						spa_node_emit_result(&impl->mix_hooks, seq, res, type, result);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static const struct spa_node_events mix_node_events = {
 | 
				
			||||||
 | 
						SPA_VERSION_NODE_EVENTS,
 | 
				
			||||||
 | 
						.result = mix_result,
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static int mix_port_enum_params(void *object, int seq,
 | 
				
			||||||
 | 
							enum spa_direction direction, uint32_t port_id,
 | 
				
			||||||
 | 
							uint32_t id, uint32_t start, uint32_t max,
 | 
				
			||||||
 | 
							const struct spa_pod *filter)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct impl *impl = object;
 | 
				
			||||||
 | 
						struct spa_pod *param;
 | 
				
			||||||
 | 
						struct spa_result_node_params result;
 | 
				
			||||||
 | 
						struct spa_pod_builder b = { 0 };
 | 
				
			||||||
 | 
						uint8_t buffer[1024];
 | 
				
			||||||
 | 
						uint32_t count = 0;
 | 
				
			||||||
 | 
						int res;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						pw_log_trace("%p: %d", impl, id);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						result.id = id;
 | 
				
			||||||
 | 
						result.next = start;
 | 
				
			||||||
 | 
					next:
 | 
				
			||||||
 | 
						result.index = result.next++;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						spa_pod_builder_init(&b, buffer, sizeof(buffer));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						switch (id) {
 | 
				
			||||||
 | 
						case SPA_PARAM_IO:
 | 
				
			||||||
 | 
							switch (result.index) {
 | 
				
			||||||
 | 
							case 0:
 | 
				
			||||||
 | 
								param = spa_pod_builder_add_object(&b,
 | 
				
			||||||
 | 
									SPA_TYPE_OBJECT_ParamIO, id,
 | 
				
			||||||
 | 
									SPA_PARAM_IO_id,   SPA_POD_Id(SPA_IO_Buffers),
 | 
				
			||||||
 | 
									SPA_PARAM_IO_size, SPA_POD_Int(sizeof(struct spa_io_buffers)));
 | 
				
			||||||
 | 
								break;
 | 
				
			||||||
 | 
							default:
 | 
				
			||||||
 | 
								return 0;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							break;
 | 
				
			||||||
 | 
						default:
 | 
				
			||||||
 | 
							res = -ENOTSUP;
 | 
				
			||||||
 | 
							spa_node_emit_peer_enum_params(&impl->mix_hooks, seq, direction, port_id,
 | 
				
			||||||
 | 
									id, start, max, filter, &mix_node_events, impl, &res);
 | 
				
			||||||
 | 
							return res;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (spa_pod_filter(&b, &result.param, param, filter) < 0)
 | 
				
			||||||
 | 
							goto next;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						spa_node_emit_result(&impl->mix_hooks, seq, 0, SPA_RESULT_TYPE_NODE_PARAMS, &result);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (++count != max)
 | 
				
			||||||
 | 
							goto next;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return 0;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static struct pw_impl_port_mix *find_mix(struct pw_impl_port *port,
 | 
					static struct pw_impl_port_mix *find_mix(struct pw_impl_port *port,
 | 
				
			||||||
		enum spa_direction direction, uint32_t port_id)
 | 
							enum spa_direction direction, uint32_t port_id)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
| 
						 | 
					@ -211,9 +286,11 @@ static int tee_reuse_buffer(void *object, uint32_t port_id, uint32_t buffer_id)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static const struct spa_node_methods schedule_tee_node = {
 | 
					static const struct spa_node_methods schedule_tee_node = {
 | 
				
			||||||
	SPA_VERSION_NODE_METHODS,
 | 
						SPA_VERSION_NODE_METHODS,
 | 
				
			||||||
	.process = tee_process,
 | 
						.add_listener = mix_add_listener,
 | 
				
			||||||
 | 
						.port_enum_params = mix_port_enum_params,
 | 
				
			||||||
	.port_set_io = port_set_io,
 | 
						.port_set_io = port_set_io,
 | 
				
			||||||
	.port_reuse_buffer = tee_reuse_buffer,
 | 
						.port_reuse_buffer = tee_reuse_buffer,
 | 
				
			||||||
 | 
						.process = tee_process,
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static int schedule_mix_input(void *object)
 | 
					static int schedule_mix_input(void *object)
 | 
				
			||||||
| 
						 | 
					@ -251,9 +328,11 @@ static int schedule_mix_reuse_buffer(void *object, uint32_t port_id, uint32_t bu
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static const struct spa_node_methods schedule_mix_node = {
 | 
					static const struct spa_node_methods schedule_mix_node = {
 | 
				
			||||||
	SPA_VERSION_NODE_METHODS,
 | 
						SPA_VERSION_NODE_METHODS,
 | 
				
			||||||
	.process = schedule_mix_input,
 | 
						.add_listener = mix_add_listener,
 | 
				
			||||||
 | 
						.port_enum_params = mix_port_enum_params,
 | 
				
			||||||
	.port_set_io = port_set_io,
 | 
						.port_set_io = port_set_io,
 | 
				
			||||||
	.port_reuse_buffer = schedule_mix_reuse_buffer,
 | 
						.port_reuse_buffer = schedule_mix_reuse_buffer,
 | 
				
			||||||
 | 
						.process = schedule_mix_input,
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
SPA_EXPORT
 | 
					SPA_EXPORT
 | 
				
			||||||
| 
						 | 
					@ -686,6 +765,7 @@ struct pw_impl_port *pw_context_create_port(
 | 
				
			||||||
			SPA_TYPE_INTERFACE_Node,
 | 
								SPA_TYPE_INTERFACE_Node,
 | 
				
			||||||
			SPA_VERSION_NODE,
 | 
								SPA_VERSION_NODE,
 | 
				
			||||||
			mix_methods, impl);
 | 
								mix_methods, impl);
 | 
				
			||||||
 | 
						spa_hook_list_init(&impl->mix_hooks);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	pw_impl_port_set_mix(this, NULL, 0);
 | 
						pw_impl_port_set_mix(this, NULL, 0);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -706,6 +786,30 @@ error_no_mem:
 | 
				
			||||||
	return NULL;
 | 
						return NULL;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void mix_peer_enum_params(void *data, int seq,
 | 
				
			||||||
 | 
							enum spa_direction direction, uint32_t port_id,
 | 
				
			||||||
 | 
							uint32_t id, uint32_t start, uint32_t max,
 | 
				
			||||||
 | 
							const struct spa_pod *filter,
 | 
				
			||||||
 | 
							const struct spa_node_events *events, void *events_data,
 | 
				
			||||||
 | 
							int *res)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct impl *impl = data;
 | 
				
			||||||
 | 
						struct pw_impl_port *port = &impl->this;
 | 
				
			||||||
 | 
						struct spa_hook listener;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						spa_zero(listener);
 | 
				
			||||||
 | 
						spa_node_add_listener(port->node->node, &listener, events, events_data);
 | 
				
			||||||
 | 
						*res = spa_node_port_enum_params(port->node->node, seq,
 | 
				
			||||||
 | 
								port->direction, port->port_id,
 | 
				
			||||||
 | 
								id, start, max, filter);
 | 
				
			||||||
 | 
						spa_hook_remove(&listener);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static const struct spa_node_events mix_peer_node_events = {
 | 
				
			||||||
 | 
						SPA_VERSION_NODE_EVENTS,
 | 
				
			||||||
 | 
						.peer_enum_params = mix_peer_enum_params,
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
SPA_EXPORT
 | 
					SPA_EXPORT
 | 
				
			||||||
int pw_impl_port_set_mix(struct pw_impl_port *port, struct spa_node *node, uint32_t flags)
 | 
					int pw_impl_port_set_mix(struct pw_impl_port *port, struct spa_node *node, uint32_t flags)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
| 
						 | 
					@ -727,6 +831,9 @@ int pw_impl_port_set_mix(struct pw_impl_port *port, struct spa_node *node, uint3
 | 
				
			||||||
			     pw_direction_reverse(port->direction), 0,
 | 
								     pw_direction_reverse(port->direction), 0,
 | 
				
			||||||
			     SPA_IO_Buffers, NULL, 0);
 | 
								     SPA_IO_Buffers, NULL, 0);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
						if (port->mix)
 | 
				
			||||||
 | 
							spa_hook_remove(&impl->mix_listener);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (port->mix_handle != NULL) {
 | 
						if (port->mix_handle != NULL) {
 | 
				
			||||||
		pw_unload_spa_handle(port->mix_handle);
 | 
							pw_unload_spa_handle(port->mix_handle);
 | 
				
			||||||
		port->mix_handle = NULL;
 | 
							port->mix_handle = NULL;
 | 
				
			||||||
| 
						 | 
					@ -734,6 +841,8 @@ int pw_impl_port_set_mix(struct pw_impl_port *port, struct spa_node *node, uint3
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	port->mix_flags = flags;
 | 
						port->mix_flags = flags;
 | 
				
			||||||
	port->mix = node;
 | 
						port->mix = node;
 | 
				
			||||||
 | 
						if (port->mix)
 | 
				
			||||||
 | 
							spa_node_add_listener(port->mix, &impl->mix_listener, &mix_peer_node_events, impl);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (port->mix && !port->destroying) {
 | 
						if (port->mix && !port->destroying) {
 | 
				
			||||||
		spa_list_for_each(mix, &port->mix_list, link)
 | 
							spa_list_for_each(mix, &port->mix_list, link)
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue