mirror of
				https://gitlab.freedesktop.org/pipewire/pipewire.git
				synced 2025-11-03 09:01:54 -05:00 
			
		
		
		
	module-echo-cancel: aec-plugin parameters
Make it possible for a aec-plugin to provide props/params through module-echo-cancel and make it possible for a aec-plugin to listen and react to these props/params getting updated. Add method enum_props() that is used under setup_streams() to get props from aec_plugin. Add get_params() and set_params() for updating and getting aec-plugin params under the input/output_param_changed calls and getting params under setup_streams().
This commit is contained in:
		
							parent
							
								
									2086fa5ad2
								
							
						
					
					
						commit
						b35983eb7e
					
				
					 2 changed files with 112 additions and 14 deletions
				
			
		| 
						 | 
					@ -23,6 +23,7 @@
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <spa/pod/builder.h>
 | 
				
			||||||
#include <spa/utils/dict.h>
 | 
					#include <spa/utils/dict.h>
 | 
				
			||||||
#include <spa/utils/hook.h>
 | 
					#include <spa/utils/hook.h>
 | 
				
			||||||
#include <spa/param/audio/raw.h>
 | 
					#include <spa/param/audio/raw.h>
 | 
				
			||||||
| 
						 | 
					@ -60,7 +61,7 @@ struct spa_audio_aec_events {
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct spa_audio_aec_methods {
 | 
					struct spa_audio_aec_methods {
 | 
				
			||||||
#define SPA_VERSION_AUDIO_AEC_METHODS	1
 | 
					#define SPA_VERSION_AUDIO_AEC_METHODS	2
 | 
				
			||||||
        uint32_t version;
 | 
					        uint32_t version;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	int (*add_listener) (void *object,
 | 
						int (*add_listener) (void *object,
 | 
				
			||||||
| 
						 | 
					@ -75,6 +76,11 @@ struct spa_audio_aec_methods {
 | 
				
			||||||
	int (*activate) (void *object);
 | 
						int (*activate) (void *object);
 | 
				
			||||||
	/* since 0.3.58, version 1:1 */
 | 
						/* since 0.3.58, version 1:1 */
 | 
				
			||||||
	int (*deactivate) (void *object);
 | 
						int (*deactivate) (void *object);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* version 1:2 */
 | 
				
			||||||
 | 
						int (*enum_props) (void* object, int index, struct spa_pod_builder* builder);
 | 
				
			||||||
 | 
						int (*get_params) (void* object, struct spa_pod_builder* builder);
 | 
				
			||||||
 | 
						int (*set_params) (void *object, const struct spa_pod *args);
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#define spa_audio_aec_method(o,method,version,...)			\
 | 
					#define spa_audio_aec_method(o,method,version,...)			\
 | 
				
			||||||
| 
						 | 
					@ -93,6 +99,9 @@ struct spa_audio_aec_methods {
 | 
				
			||||||
#define spa_audio_aec_set_props(o,...)		spa_audio_aec_method(o, set_props, 0, __VA_ARGS__)
 | 
					#define spa_audio_aec_set_props(o,...)		spa_audio_aec_method(o, set_props, 0, __VA_ARGS__)
 | 
				
			||||||
#define spa_audio_aec_activate(o)		spa_audio_aec_method(o, activate, 1)
 | 
					#define spa_audio_aec_activate(o)		spa_audio_aec_method(o, activate, 1)
 | 
				
			||||||
#define spa_audio_aec_deactivate(o)		spa_audio_aec_method(o, deactivate, 1)
 | 
					#define spa_audio_aec_deactivate(o)		spa_audio_aec_method(o, deactivate, 1)
 | 
				
			||||||
 | 
					#define spa_audio_aec_enum_props(o,...)		spa_audio_aec_method(o, enum_props, 2, __VA_ARGS__)
 | 
				
			||||||
 | 
					#define spa_audio_aec_get_params(o,...)		spa_audio_aec_method(o, get_params, 2, __VA_ARGS__)
 | 
				
			||||||
 | 
					#define spa_audio_aec_set_params(o,...)		spa_audio_aec_method(o, set_params, 2, __VA_ARGS__)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#ifdef __cplusplus
 | 
					#ifdef __cplusplus
 | 
				
			||||||
}  /* extern "C" */
 | 
					}  /* extern "C" */
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -43,6 +43,7 @@
 | 
				
			||||||
#include <spa/param/audio/raw.h>
 | 
					#include <spa/param/audio/raw.h>
 | 
				
			||||||
#include <spa/param/profiler.h>
 | 
					#include <spa/param/profiler.h>
 | 
				
			||||||
#include <spa/pod/builder.h>
 | 
					#include <spa/pod/builder.h>
 | 
				
			||||||
 | 
					#include <spa/pod/dynamic.h>
 | 
				
			||||||
#include <spa/support/plugin.h>
 | 
					#include <spa/support/plugin.h>
 | 
				
			||||||
#include <spa/utils/json.h>
 | 
					#include <spa/utils/json.h>
 | 
				
			||||||
#include <spa/utils/names.h>
 | 
					#include <spa/utils/names.h>
 | 
				
			||||||
| 
						 | 
					@ -504,14 +505,55 @@ static void input_param_latency_changed(struct impl *impl, const struct spa_pod
 | 
				
			||||||
	else
 | 
						else
 | 
				
			||||||
		pw_stream_update_params(impl->capture, params, 1);
 | 
							pw_stream_update_params(impl->capture, params, 1);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					static struct spa_pod* get_props_param(struct impl* impl, struct spa_pod_builder* b)
 | 
				
			||||||
static void input_param_changed(void *data, uint32_t id, const struct spa_pod *param)
 | 
					 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct impl *impl = data;
 | 
						if (spa_audio_aec_get_params(impl->aec, NULL) > 0) {
 | 
				
			||||||
 | 
							struct spa_pod_frame f[2];
 | 
				
			||||||
 | 
							spa_pod_builder_push_object(
 | 
				
			||||||
 | 
							    b, &f[0], SPA_TYPE_OBJECT_Props, SPA_PARAM_Props);
 | 
				
			||||||
 | 
							spa_pod_builder_prop(b, SPA_PROP_params, 0);
 | 
				
			||||||
 | 
							spa_pod_builder_push_struct(b, &f[1]);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							spa_audio_aec_get_params(impl->aec, b);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							spa_pod_builder_pop(b, &f[1]);
 | 
				
			||||||
 | 
							return spa_pod_builder_pop(b, &f[0]);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return NULL;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void input_param_changed(void *data, uint32_t id, const struct spa_pod* param)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct spa_pod_object* obj = (struct spa_pod_object*)param;
 | 
				
			||||||
 | 
						const struct spa_pod_prop* prop;
 | 
				
			||||||
 | 
						struct impl* impl = data;
 | 
				
			||||||
	switch (id) {
 | 
						switch (id) {
 | 
				
			||||||
	case SPA_PARAM_Latency:
 | 
						case SPA_PARAM_Latency:
 | 
				
			||||||
		input_param_latency_changed(impl, param);
 | 
							input_param_latency_changed(impl, param);
 | 
				
			||||||
		break;
 | 
							break;
 | 
				
			||||||
 | 
						case SPA_PARAM_Props:
 | 
				
			||||||
 | 
							if (param != NULL) {
 | 
				
			||||||
 | 
								uint8_t buffer[1024];
 | 
				
			||||||
 | 
								struct spa_pod_dynamic_builder b;
 | 
				
			||||||
 | 
								const struct spa_pod* params[1];
 | 
				
			||||||
 | 
								SPA_POD_OBJECT_FOREACH(obj, prop)
 | 
				
			||||||
 | 
								{
 | 
				
			||||||
 | 
									if (prop->key == SPA_PROP_params) {
 | 
				
			||||||
 | 
										spa_audio_aec_set_params(impl->aec, &prop->value);
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								spa_pod_dynamic_builder_init(&b, buffer, sizeof(buffer), 4096);
 | 
				
			||||||
 | 
								params[0] = get_props_param(impl, &b.b);
 | 
				
			||||||
 | 
								if (params[0]) {
 | 
				
			||||||
 | 
									pw_stream_update_params(impl->capture, params, 1);
 | 
				
			||||||
 | 
									pw_stream_update_params(impl->playback, params, 1);
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								spa_pod_dynamic_builder_clean(&b);
 | 
				
			||||||
 | 
							} else {
 | 
				
			||||||
 | 
								pw_log_warn("param is null");
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							break;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -582,11 +624,34 @@ static void output_param_latency_changed(struct impl *impl, const struct spa_pod
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void output_param_changed(void *data, uint32_t id, const struct spa_pod *param)
 | 
					static void output_param_changed(void *data, uint32_t id, const struct spa_pod *param)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
 | 
						struct spa_pod_object *obj = (struct spa_pod_object *) param;
 | 
				
			||||||
 | 
						const struct spa_pod_prop *prop;
 | 
				
			||||||
	struct impl *impl = data;
 | 
						struct impl *impl = data;
 | 
				
			||||||
	switch (id) {
 | 
						switch (id) {
 | 
				
			||||||
	case SPA_PARAM_Latency:
 | 
						case SPA_PARAM_Latency:
 | 
				
			||||||
		output_param_latency_changed(impl, param);
 | 
							output_param_latency_changed(impl, param);
 | 
				
			||||||
		break;
 | 
							break;
 | 
				
			||||||
 | 
						case SPA_PARAM_Props:
 | 
				
			||||||
 | 
							if (param != NULL) {
 | 
				
			||||||
 | 
								uint8_t buffer[1024];
 | 
				
			||||||
 | 
								struct spa_pod_dynamic_builder b;
 | 
				
			||||||
 | 
								const struct spa_pod* params[1];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								SPA_POD_OBJECT_FOREACH(obj, prop)
 | 
				
			||||||
 | 
								{
 | 
				
			||||||
 | 
									if (prop->key == SPA_PROP_params) {
 | 
				
			||||||
 | 
										spa_audio_aec_set_params(impl->aec, &prop->value);
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								spa_pod_dynamic_builder_init(&b, buffer, sizeof(buffer), 4096);
 | 
				
			||||||
 | 
								params[0] = get_props_param(impl, &b.b);
 | 
				
			||||||
 | 
								if (params[0] != NULL) {
 | 
				
			||||||
 | 
									pw_stream_update_params(impl->capture, params, 1);
 | 
				
			||||||
 | 
									pw_stream_update_params(impl->playback, params, 1);
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								spa_pod_dynamic_builder_clean(&b);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							break;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -685,9 +750,9 @@ static int setup_streams(struct impl *impl)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	int res;
 | 
						int res;
 | 
				
			||||||
	uint32_t n_params, i;
 | 
						uint32_t n_params, i;
 | 
				
			||||||
	const struct spa_pod *params[1];
 | 
						uint32_t offsets[512];
 | 
				
			||||||
	uint8_t buffer[1024];
 | 
						const struct spa_pod *params[512];
 | 
				
			||||||
	struct spa_pod_builder b;
 | 
						struct spa_pod_dynamic_builder b;
 | 
				
			||||||
	struct pw_properties *props;
 | 
						struct pw_properties *props;
 | 
				
			||||||
	const char *str;
 | 
						const char *str;
 | 
				
			||||||
	uint32_t index;
 | 
						uint32_t index;
 | 
				
			||||||
| 
						 | 
					@ -771,9 +836,23 @@ static int setup_streams(struct impl *impl)
 | 
				
			||||||
			&sink_events, impl);
 | 
								&sink_events, impl);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	n_params = 0;
 | 
						n_params = 0;
 | 
				
			||||||
	spa_pod_builder_init(&b, buffer, sizeof(buffer));
 | 
						spa_pod_dynamic_builder_init(&b, NULL, 0, 4096);
 | 
				
			||||||
	params[n_params++] = spa_format_audio_raw_build(&b, SPA_PARAM_EnumFormat,
 | 
					
 | 
				
			||||||
			&impl->info);
 | 
						offsets[n_params++] = b.b.state.offset;
 | 
				
			||||||
 | 
						spa_format_audio_raw_build(&b.b, SPA_PARAM_EnumFormat, &impl->info);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						int nbr_of_external_props = spa_audio_aec_enum_props(impl->aec, 0, NULL);
 | 
				
			||||||
 | 
						if (nbr_of_external_props > 0) {
 | 
				
			||||||
 | 
							for (int i = 0; i < nbr_of_external_props; i++) {
 | 
				
			||||||
 | 
								offsets[n_params++] = b.b.state.offset;
 | 
				
			||||||
 | 
								spa_audio_aec_enum_props(impl->aec, i, &b.b);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							get_props_param(impl, &b.b);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						for (i = 0; i < n_params; i++) {
 | 
				
			||||||
 | 
							params[i] = spa_pod_builder_deref(&b.b, offsets[i]);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if ((res = pw_stream_connect(impl->capture,
 | 
						if ((res = pw_stream_connect(impl->capture,
 | 
				
			||||||
			PW_DIRECTION_INPUT,
 | 
								PW_DIRECTION_INPUT,
 | 
				
			||||||
| 
						 | 
					@ -781,24 +860,30 @@ static int setup_streams(struct impl *impl)
 | 
				
			||||||
			PW_STREAM_FLAG_AUTOCONNECT |
 | 
								PW_STREAM_FLAG_AUTOCONNECT |
 | 
				
			||||||
			PW_STREAM_FLAG_MAP_BUFFERS |
 | 
								PW_STREAM_FLAG_MAP_BUFFERS |
 | 
				
			||||||
			PW_STREAM_FLAG_RT_PROCESS,
 | 
								PW_STREAM_FLAG_RT_PROCESS,
 | 
				
			||||||
			params, n_params)) < 0)
 | 
								params, n_params)) < 0) {
 | 
				
			||||||
 | 
							spa_pod_dynamic_builder_clean(&b);
 | 
				
			||||||
		return res;
 | 
							return res;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if ((res = pw_stream_connect(impl->source,
 | 
						if ((res = pw_stream_connect(impl->source,
 | 
				
			||||||
			PW_DIRECTION_OUTPUT,
 | 
								PW_DIRECTION_OUTPUT,
 | 
				
			||||||
			PW_ID_ANY,
 | 
								PW_ID_ANY,
 | 
				
			||||||
			PW_STREAM_FLAG_MAP_BUFFERS |
 | 
								PW_STREAM_FLAG_MAP_BUFFERS |
 | 
				
			||||||
			PW_STREAM_FLAG_RT_PROCESS,
 | 
								PW_STREAM_FLAG_RT_PROCESS,
 | 
				
			||||||
			params, n_params)) < 0)
 | 
								params, n_params)) < 0) {
 | 
				
			||||||
 | 
							spa_pod_dynamic_builder_clean(&b);
 | 
				
			||||||
		return res;
 | 
							return res;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if ((res = pw_stream_connect(impl->sink,
 | 
						if ((res = pw_stream_connect(impl->sink,
 | 
				
			||||||
			PW_DIRECTION_INPUT,
 | 
								PW_DIRECTION_INPUT,
 | 
				
			||||||
			PW_ID_ANY,
 | 
								PW_ID_ANY,
 | 
				
			||||||
			PW_STREAM_FLAG_MAP_BUFFERS |
 | 
								PW_STREAM_FLAG_MAP_BUFFERS |
 | 
				
			||||||
			PW_STREAM_FLAG_RT_PROCESS,
 | 
								PW_STREAM_FLAG_RT_PROCESS,
 | 
				
			||||||
			params, n_params)) < 0)
 | 
								params, n_params)) < 0) {
 | 
				
			||||||
 | 
							spa_pod_dynamic_builder_clean(&b);
 | 
				
			||||||
		return res;
 | 
							return res;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if ((res = pw_stream_connect(impl->playback,
 | 
						if ((res = pw_stream_connect(impl->playback,
 | 
				
			||||||
			PW_DIRECTION_OUTPUT,
 | 
								PW_DIRECTION_OUTPUT,
 | 
				
			||||||
| 
						 | 
					@ -806,8 +891,12 @@ static int setup_streams(struct impl *impl)
 | 
				
			||||||
			PW_STREAM_FLAG_AUTOCONNECT |
 | 
								PW_STREAM_FLAG_AUTOCONNECT |
 | 
				
			||||||
			PW_STREAM_FLAG_MAP_BUFFERS |
 | 
								PW_STREAM_FLAG_MAP_BUFFERS |
 | 
				
			||||||
			PW_STREAM_FLAG_RT_PROCESS,
 | 
								PW_STREAM_FLAG_RT_PROCESS,
 | 
				
			||||||
			params, n_params)) < 0)
 | 
								params, n_params)) < 0) {
 | 
				
			||||||
 | 
							spa_pod_dynamic_builder_clean(&b);
 | 
				
			||||||
		return res;
 | 
							return res;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						spa_pod_dynamic_builder_clean(&b);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	impl->rec_ringsize = sizeof(float) * impl->max_buffer_size * impl->info.rate / 1000;
 | 
						impl->rec_ringsize = sizeof(float) * impl->max_buffer_size * impl->info.rate / 1000;
 | 
				
			||||||
	impl->play_ringsize = sizeof(float) * ((impl->max_buffer_size * impl->info.rate / 1000) + impl->buffer_delay);
 | 
						impl->play_ringsize = sizeof(float) * ((impl->max_buffer_size * impl->info.rate / 1000) + impl->buffer_delay);
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue