• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /* Copyright (c) 2012 The Chromium OS Authors. All rights reserved.
2  * Use of this source code is governed by a BSD-style license that can be
3  * found in the LICENSE file.
4  */
5 
6 #include <inttypes.h>
7 #include <sys/param.h>
8 #include <syslog.h>
9 
10 #include "cras_util.h"
11 #include "cras_dsp_module.h"
12 #include "cras_dsp_pipeline.h"
13 #include "dsp_util.h"
14 
15 /* We have a static representation of the dsp graph in a "struct ini",
16  * and here we will construct a dynamic representation of it in a
17  * "struct pipeline". The difference between the static one and the
18  * dynamic one is that we will only include the subset of the dsp
19  * graph actually needed in the dynamic one (so those plugins that are
20  * disabled will not be included). Here are the mapping between the
21  * static representation and the dynamic representation:
22  *
23  *      static                      dynamic
24  *  -------------    --------------------------------------
25  *  struct ini       struct pipeline
26  *  struct plugin    struct instance
27  *  strict port      struct audio_port, struct control_port
28  *
29  * For example, if the ini file specifies these plugins and their
30  * connections:
31  *
32  * [A]
33  * output_0={audio}
34  * [B]
35  * input_0={audio}
36  * output_1={result}
37  * [C]
38  * input_0={result}
39  *
40  * That is, A connects to B, and B connects to C. If the plugin B is
41  * now disabled, in the pipeline we construct there will only be two
42  * instances (A and C) and the audio ports on these instances will
43  * connect to each other directly, bypassing B.
44  */
45 
46 /* This represents an audio port on an instance. */
47 struct audio_port {
48 	struct audio_port *peer; /* the audio port this port connects to */
49 	struct plugin *plugin; /* the plugin corresponds to the instance */
50 	int original_index; /* the port index in the plugin */
51 	int buf_index; /* the buffer index in the pipeline */
52 };
53 
54 /* This represents a control port on an instance. */
55 struct control_port {
56 	struct control_port *peer; /* the control port this port connects to */
57 	struct plugin *plugin; /* the plugin corresponds to the instance */
58 	int original_index; /* the port index in the plugin */
59 	float value; /* the value of the control port */
60 };
61 
62 DECLARE_ARRAY_TYPE(struct audio_port, audio_port_array);
63 DECLARE_ARRAY_TYPE(struct control_port, control_port_array);
64 
65 /* An instance is a dynamic representation of a plugin. We only create
66  * an instance when a plugin is needed (data actually flows through it
67  * and it is not disabled). An instance also contains a pointer to a
68  * struct dsp_module, which is the implementation of the plugin */
69 struct instance {
70 	/* The plugin this instance corresponds to */
71 	struct plugin *plugin;
72 
73 	/* These are the ports on this instance. The difference
74 	 * between this and the port array in a struct plugin is that
75 	 * the ports skip disabled plugins and connect to the upstream
76 	 * ports directly.
77 	 */
78 	audio_port_array input_audio_ports;
79 	audio_port_array output_audio_ports;
80 	control_port_array input_control_ports;
81 	control_port_array output_control_ports;
82 
83 	/* The implementation of the plugin */
84 	struct dsp_module *module;
85 
86 	/* Whether this module's instantiate() function has been called */
87 	int instantiated;
88 
89 	/* This caches the value returned from get_properties() of a module */
90 	int properties;
91 
92 	/* This is the total buffering delay from source to this instance. It is
93 	 * in number of frames. */
94 	int total_delay;
95 };
96 
97 DECLARE_ARRAY_TYPE(struct instance, instance_array)
98 
99 /* An pipeline is a dynamic representation of a dsp ini file. */
100 struct pipeline {
101 	/* The purpose of the pipeline. "playback" or "capture" */
102 	const char *purpose;
103 
104 	/* The ini file this pipeline comes from */
105 	struct ini *ini;
106 
107 	/* All needed instances for this pipeline. It is sorted in an
108 	 * order that if instance B depends on instance A, then A will
109 	 * appear in front of B. */
110 	instance_array instances;
111 
112 	/* The maximum number of audio buffers that will be used at
113 	 * the same time for this pipeline */
114 	int peak_buf;
115 
116 	/* The audio data buffers */
117 	float **buffers;
118 
119 	/* The instance where the audio data flow in */
120 	struct instance *source_instance;
121 
122 	/* The instance where the audio data flow out */
123 	struct instance *sink_instance;
124 
125 	/* The number of audio channels for this pipeline */
126 	int input_channels;
127 	int output_channels;
128 
129 	/* The audio sampling rate for this pipleine. It is zero if
130 	 * cras_dsp_pipeline_instantiate() has not been called. */
131 	int sample_rate;
132 
133 	/* The total time it takes to run the pipeline, in nanoseconds. */
134 	int64_t total_time;
135 
136 	/* The max/min time it takes to run the pipeline, in nanoseconds. */
137 	int64_t max_time;
138 	int64_t min_time;
139 
140 	/* The number of blocks the pipeline. */
141 	int64_t total_blocks;
142 
143 	/* The total number of sample frames the pipeline processed */
144 	int64_t total_samples;
145 };
146 
find_instance_by_plugin(const instance_array * instances,const struct plugin * plugin)147 static struct instance *find_instance_by_plugin(const instance_array *instances,
148 						const struct plugin *plugin)
149 {
150 	int i;
151 	struct instance *instance;
152 
153 	ARRAY_ELEMENT_FOREACH (instances, i, instance) {
154 		if (instance->plugin == plugin)
155 			return instance;
156 	}
157 
158 	return NULL;
159 }
160 
161 /* Finds out where the data sent to plugin:index come from. The issue
162  * we need to handle here is the previous plugin may be disabled, so
163  * we need to go upstream until we find the real origin */
find_origin_port(struct ini * ini,const instance_array * instances,const struct plugin * plugin,int index,const struct plugin ** origin,int * origin_index)164 static int find_origin_port(struct ini *ini, const instance_array *instances,
165 			    const struct plugin *plugin, int index,
166 			    const struct plugin **origin, int *origin_index)
167 {
168 	enum port_type type;
169 	struct port *port;
170 	int flow_id;
171 	struct flow *flow;
172 	int i, k;
173 	int found;
174 
175 	port = ARRAY_ELEMENT(&plugin->ports, index);
176 	type = port->type;
177 	flow_id = port->flow_id;
178 	if (flow_id == INVALID_FLOW_ID)
179 		return -1;
180 	flow = ARRAY_ELEMENT(&ini->flows, flow_id);
181 
182 	/* move to the previous plugin */
183 	plugin = flow->from;
184 	index = flow->from_port;
185 
186 	/* if the plugin is not disabled, it will be pointed by some instance */
187 	if (find_instance_by_plugin(instances, plugin)) {
188 		*origin = plugin;
189 		*origin_index = index;
190 		return 0;
191 	}
192 
193 	/* Now we know the previous plugin is disabled, we need to go
194 	 * upstream. We assume the k-th output port of the plugin
195 	 * corresponds to the k-th input port of the plugin (with the
196 	 * same type) */
197 
198 	k = 0;
199 	found = 0;
200 	ARRAY_ELEMENT_FOREACH (&plugin->ports, i, port) {
201 		if (index == i) {
202 			found = 1;
203 			break;
204 		}
205 		if (port->direction == PORT_OUTPUT && port->type == type)
206 			k++;
207 	}
208 	if (!found)
209 		return -1;
210 
211 	found = 0;
212 	ARRAY_ELEMENT_FOREACH (&plugin->ports, i, port) {
213 		if (port->direction == PORT_INPUT && port->type == type) {
214 			if (k-- == 0) {
215 				index = i;
216 				found = 1;
217 				break;
218 			}
219 		}
220 	}
221 	if (!found)
222 		return -1;
223 
224 	return find_origin_port(ini, instances, plugin, index, origin,
225 				origin_index);
226 }
227 
find_output_audio_port(instance_array * instances,const struct plugin * plugin,int index)228 static struct audio_port *find_output_audio_port(instance_array *instances,
229 						 const struct plugin *plugin,
230 						 int index)
231 {
232 	int i;
233 	struct instance *instance;
234 	struct audio_port *audio_port;
235 
236 	instance = find_instance_by_plugin(instances, plugin);
237 	if (!instance)
238 		return NULL;
239 
240 	ARRAY_ELEMENT_FOREACH (&instance->output_audio_ports, i, audio_port) {
241 		if (audio_port->original_index == index)
242 			return audio_port;
243 	}
244 
245 	return NULL;
246 }
247 
find_output_control_port(instance_array * instances,const struct plugin * plugin,int index)248 static struct control_port *find_output_control_port(instance_array *instances,
249 						     const struct plugin *plugin,
250 						     int index)
251 {
252 	int i;
253 	struct instance *instance;
254 	struct control_port *control_port;
255 
256 	instance = find_instance_by_plugin(instances, plugin);
257 	if (!instance)
258 		return NULL;
259 
260 	ARRAY_ELEMENT_FOREACH (&instance->output_control_ports, i,
261 			       control_port) {
262 		if (control_port->original_index == index)
263 			return control_port;
264 	}
265 
266 	return NULL;
267 }
268 
is_disabled(struct plugin * plugin,struct cras_expr_env * env)269 static char is_disabled(struct plugin *plugin, struct cras_expr_env *env)
270 {
271 	char disabled;
272 	return (plugin->disable_expr &&
273 		cras_expr_expression_eval_boolean(plugin->disable_expr, env,
274 						  &disabled) == 0 &&
275 		disabled == 1);
276 }
277 
topological_sort(struct pipeline * pipeline,struct cras_expr_env * env,struct plugin * plugin,char * visited)278 static int topological_sort(struct pipeline *pipeline,
279 			    struct cras_expr_env *env, struct plugin *plugin,
280 			    char *visited)
281 {
282 	struct port *port;
283 	struct flow *flow;
284 	int index;
285 	int i;
286 	int flow_id;
287 	struct instance *instance;
288 	struct ini *ini = pipeline->ini;
289 
290 	index = ARRAY_INDEX(&ini->plugins, plugin);
291 	if (visited[index])
292 		return 0;
293 	visited[index] = 1;
294 
295 	ARRAY_ELEMENT_FOREACH (&plugin->ports, i, port) {
296 		if (port->flow_id == INVALID_FLOW_ID)
297 			continue;
298 		flow_id = port->flow_id;
299 		flow = ARRAY_ELEMENT(&ini->flows, flow_id);
300 		if (!flow->from) {
301 			syslog(LOG_ERR, "no plugin flows to %s:%d",
302 			       plugin->title, i);
303 			return -1;
304 		}
305 		if (topological_sort(pipeline, env, flow->from, visited) < 0)
306 			return -1;
307 	}
308 
309 	/* if the plugin is disabled, we don't construct an instance for it */
310 	if (is_disabled(plugin, env))
311 		return 0;
312 
313 	instance = ARRAY_APPEND_ZERO(&pipeline->instances);
314 	instance->plugin = plugin;
315 
316 	/* constructs audio and control ports for the instance */
317 	ARRAY_ELEMENT_FOREACH (&plugin->ports, i, port) {
318 		int need_connect = (port->flow_id != INVALID_FLOW_ID &&
319 				    port->direction == PORT_INPUT);
320 		const struct plugin *origin = NULL;
321 		int origin_index = 0;
322 
323 		if (need_connect) {
324 			if (find_origin_port(ini, &pipeline->instances, plugin,
325 					     i, &origin, &origin_index) < 0)
326 				return -1;
327 		}
328 
329 		if (port->type == PORT_AUDIO) {
330 			audio_port_array *audio_port_array =
331 				(port->direction == PORT_INPUT) ?
332 					&instance->input_audio_ports :
333 					&instance->output_audio_ports;
334 			struct audio_port *audio_port =
335 				ARRAY_APPEND_ZERO(audio_port_array);
336 			audio_port->plugin = plugin;
337 			audio_port->original_index = i;
338 			if (need_connect) {
339 				struct audio_port *from;
340 				from = find_output_audio_port(
341 					&pipeline->instances, origin,
342 					origin_index);
343 				if (!from)
344 					return -1;
345 				from->peer = audio_port;
346 				audio_port->peer = from;
347 			}
348 		} else if (port->type == PORT_CONTROL) {
349 			control_port_array *control_port_array =
350 				(port->direction == PORT_INPUT) ?
351 					&instance->input_control_ports :
352 					&instance->output_control_ports;
353 			struct control_port *control_port =
354 				ARRAY_APPEND_ZERO(control_port_array);
355 			control_port->plugin = plugin;
356 			control_port->original_index = i;
357 			control_port->value = port->init_value;
358 			if (need_connect) {
359 				struct control_port *from;
360 				from = find_output_control_port(
361 					&pipeline->instances, origin,
362 					origin_index);
363 				if (!from)
364 					return -1;
365 				from->peer = control_port;
366 				control_port->peer = from;
367 			}
368 		}
369 	}
370 
371 	return 0;
372 }
373 
find_enabled_builtin_plugin(struct ini * ini,const char * label,const char * purpose,struct cras_expr_env * env)374 static struct plugin *find_enabled_builtin_plugin(struct ini *ini,
375 						  const char *label,
376 						  const char *purpose,
377 						  struct cras_expr_env *env)
378 {
379 	int i;
380 	struct plugin *plugin, *found = NULL;
381 
382 	ARRAY_ELEMENT_FOREACH (&ini->plugins, i, plugin) {
383 		if (strcmp(plugin->library, "builtin") != 0)
384 			continue;
385 		if (strcmp(plugin->label, label) != 0)
386 			continue;
387 		if (!plugin->purpose || strcmp(plugin->purpose, purpose) != 0)
388 			continue;
389 		if (is_disabled(plugin, env))
390 			continue;
391 		if (found) {
392 			syslog(LOG_ERR, "two %s plugins enabled: %s and %s",
393 			       label, found->title, plugin->title);
394 			return NULL;
395 		}
396 		found = plugin;
397 	}
398 
399 	return found;
400 }
401 
cras_dsp_pipeline_create(struct ini * ini,struct cras_expr_env * env,const char * purpose)402 struct pipeline *cras_dsp_pipeline_create(struct ini *ini,
403 					  struct cras_expr_env *env,
404 					  const char *purpose)
405 {
406 	struct pipeline *pipeline;
407 	int n;
408 	char *visited;
409 	int rc;
410 	struct plugin *source =
411 		find_enabled_builtin_plugin(ini, "source", purpose, env);
412 	struct plugin *sink =
413 		find_enabled_builtin_plugin(ini, "sink", purpose, env);
414 
415 	if (!source || !sink) {
416 		syslog(LOG_DEBUG,
417 		       "no enabled source or sink found %p/%p for %s", source,
418 		       sink, purpose);
419 		return NULL;
420 	}
421 
422 	pipeline = calloc(1, sizeof(struct pipeline));
423 	if (!pipeline) {
424 		syslog(LOG_ERR, "no memory for pipeline");
425 		return NULL;
426 	}
427 
428 	pipeline->ini = ini;
429 	pipeline->purpose = purpose;
430 	/* create instances for needed plugins, in the order of dependency */
431 	n = ARRAY_COUNT(&ini->plugins);
432 	visited = calloc(1, n);
433 	rc = topological_sort(pipeline, env, sink, visited);
434 	free(visited);
435 
436 	if (rc < 0) {
437 		syslog(LOG_ERR, "failed to construct pipeline");
438 		cras_dsp_pipeline_free(pipeline);
439 		return NULL;
440 	}
441 
442 	pipeline->source_instance =
443 		find_instance_by_plugin(&pipeline->instances, source);
444 	pipeline->sink_instance =
445 		find_instance_by_plugin(&pipeline->instances, sink);
446 
447 	if (!pipeline->source_instance || !pipeline->sink_instance) {
448 		syslog(LOG_ERR, "source(%p) or sink(%p) missing/disabled?",
449 		       source, sink);
450 		cras_dsp_pipeline_free(pipeline);
451 		return NULL;
452 	}
453 
454 	pipeline->input_channels =
455 		ARRAY_COUNT(&pipeline->source_instance->output_audio_ports);
456 	pipeline->output_channels =
457 		ARRAY_COUNT(&pipeline->sink_instance->input_audio_ports);
458 	if (pipeline->output_channels > pipeline->input_channels) {
459 		/* Can't increase channel count, no where to put them. */
460 		syslog(LOG_ERR, "DSP output more channels than input\n");
461 		cras_dsp_pipeline_free(pipeline);
462 		return NULL;
463 	}
464 
465 	return pipeline;
466 }
467 
load_module(struct plugin * plugin,struct instance * instance)468 static int load_module(struct plugin *plugin, struct instance *instance)
469 {
470 	struct dsp_module *module;
471 	module = cras_dsp_module_load_builtin(plugin);
472 	if (!module)
473 		module = cras_dsp_module_load_ladspa(plugin);
474 	if (!module)
475 		return -1;
476 	instance->module = module;
477 	instance->properties = module->get_properties(module);
478 	return 0;
479 }
480 
use_buffers(char * busy,audio_port_array * audio_ports)481 static void use_buffers(char *busy, audio_port_array *audio_ports)
482 {
483 	int i, k = 0;
484 	struct audio_port *audio_port;
485 
486 	ARRAY_ELEMENT_FOREACH (audio_ports, i, audio_port) {
487 		while (busy[k])
488 			k++;
489 		audio_port->buf_index = k;
490 		busy[k] = 1;
491 	}
492 }
493 
unuse_buffers(char * busy,audio_port_array * audio_ports)494 static void unuse_buffers(char *busy, audio_port_array *audio_ports)
495 {
496 	int i;
497 	struct audio_port *audio_port;
498 
499 	ARRAY_ELEMENT_FOREACH (audio_ports, i, audio_port) {
500 		busy[audio_port->buf_index] = 0;
501 	}
502 }
503 
504 /* assign which buffer each audio port on each instance should use */
allocate_buffers(struct pipeline * pipeline)505 static int allocate_buffers(struct pipeline *pipeline)
506 {
507 	int i;
508 	struct instance *instance;
509 	int need_buf = 0, peak_buf = 0;
510 	char *busy;
511 
512 	/* first figure out how many buffers do we need */
513 	ARRAY_ELEMENT_FOREACH (&pipeline->instances, i, instance) {
514 		int in = ARRAY_COUNT(&instance->input_audio_ports);
515 		int out = ARRAY_COUNT(&instance->output_audio_ports);
516 
517 		if (instance->properties & MODULE_INPLACE_BROKEN) {
518 			/* We cannot reuse input buffer as output
519 			 * buffer, so we need to use extra buffers */
520 			need_buf += out;
521 			peak_buf = MAX(peak_buf, need_buf);
522 			need_buf -= in;
523 		} else {
524 			need_buf += out - in;
525 			peak_buf = MAX(peak_buf, need_buf);
526 		}
527 	}
528 	/*
529 	 * cras_dsp_pipeline_create creates pipeline with source and sink and it
530 	 * makes sure all ports could be accessed from some sources, which means
531 	 * that there is at least one source with out > 0 and in == 0.
532 	 * This will give us peak_buf > 0 in the previous calculation.
533 	 */
534 	if (peak_buf <= 0) {
535 		syslog(LOG_ERR, "peak_buf = %d, which must be greater than 0.",
536 		       peak_buf);
537 		return -1;
538 	}
539 
540 	/* then allocate the buffers */
541 	pipeline->peak_buf = peak_buf;
542 	pipeline->buffers = (float **)calloc(peak_buf, sizeof(float *));
543 
544 	if (!pipeline->buffers) {
545 		syslog(LOG_ERR, "failed to allocate buffers");
546 		return -1;
547 	}
548 
549 	for (i = 0; i < peak_buf; i++) {
550 		size_t size = DSP_BUFFER_SIZE * sizeof(float);
551 		float *buf = calloc(1, size);
552 		if (!buf) {
553 			syslog(LOG_ERR, "failed to allocate buf");
554 			return -1;
555 		}
556 		pipeline->buffers[i] = buf;
557 	}
558 
559 	/* Now assign buffer index for each instance's input/output ports */
560 	busy = calloc(peak_buf, sizeof(*busy));
561 	ARRAY_ELEMENT_FOREACH (&pipeline->instances, i, instance) {
562 		int j;
563 		struct audio_port *audio_port;
564 
565 		/* Collect input buffers from upstream */
566 		ARRAY_ELEMENT_FOREACH (&instance->input_audio_ports, j,
567 				       audio_port) {
568 			audio_port->buf_index = audio_port->peer->buf_index;
569 		}
570 
571 		/* If the module has the MODULE_INPLACE_BROKEN flag,
572 		 * we cannot reuse input buffers as output buffers, so
573 		 * we need to use extra buffers. For example, in this graph
574 		 *
575 		 * [A]
576 		 * output_0={x}
577 		 * output_1={y}
578 		 * output_2={z}
579 		 * output_3={w}
580 		 * [B]
581 		 * input_0={x}
582 		 * input_1={y}
583 		 * input_2={z}
584 		 * input_3={w}
585 		 * output_4={u}
586 		 *
587 		 * Then peak_buf for this pipeline is 4. However if
588 		 * plugin B has the MODULE_INPLACE_BROKEN flag, then
589 		 * peak_buf is 5 because plugin B cannot output to the
590 		 * same buffer used for input.
591 		 *
592 		 * This means if we don't have the flag, we can free
593 		 * the input buffers then allocate the output buffers,
594 		 * but if we have the flag, we have to allocate the
595 		 * output buffers before freeing the input buffers.
596 		 */
597 		if (instance->properties & MODULE_INPLACE_BROKEN) {
598 			use_buffers(busy, &instance->output_audio_ports);
599 			unuse_buffers(busy, &instance->input_audio_ports);
600 		} else {
601 			unuse_buffers(busy, &instance->input_audio_ports);
602 			use_buffers(busy, &instance->output_audio_ports);
603 		}
604 	}
605 	free(busy);
606 
607 	return 0;
608 }
609 
cras_dsp_pipeline_load(struct pipeline * pipeline)610 int cras_dsp_pipeline_load(struct pipeline *pipeline)
611 {
612 	int i;
613 	struct instance *instance;
614 
615 	ARRAY_ELEMENT_FOREACH (&pipeline->instances, i, instance) {
616 		struct plugin *plugin = instance->plugin;
617 		if (load_module(plugin, instance) != 0)
618 			return -1;
619 	}
620 
621 	if (allocate_buffers(pipeline) != 0)
622 		return -1;
623 
624 	return 0;
625 }
626 
627 /* Calculates the total buffering delay of each instance from the source */
calculate_audio_delay(struct pipeline * pipeline)628 static void calculate_audio_delay(struct pipeline *pipeline)
629 {
630 	int i;
631 	struct instance *instance;
632 
633 	ARRAY_ELEMENT_FOREACH (&pipeline->instances, i, instance) {
634 		struct dsp_module *module = instance->module;
635 		audio_port_array *audio_in = &instance->input_audio_ports;
636 		struct audio_port *audio_port;
637 		int delay = 0;
638 		int j;
639 
640 		/* Finds the max delay of all modules that provide input to this
641 		 * instance. */
642 		ARRAY_ELEMENT_FOREACH (audio_in, j, audio_port) {
643 			struct instance *upstream = find_instance_by_plugin(
644 				&pipeline->instances, audio_port->peer->plugin);
645 			delay = MAX(upstream->total_delay, delay);
646 		}
647 
648 		instance->total_delay = delay + module->get_delay(module);
649 	}
650 }
651 
cras_dsp_pipeline_instantiate(struct pipeline * pipeline,int sample_rate)652 int cras_dsp_pipeline_instantiate(struct pipeline *pipeline, int sample_rate)
653 {
654 	int i;
655 	struct instance *instance;
656 
657 	ARRAY_ELEMENT_FOREACH (&pipeline->instances, i, instance) {
658 		struct dsp_module *module = instance->module;
659 		if (module->instantiate(module, sample_rate) != 0)
660 			return -1;
661 		instance->instantiated = 1;
662 		syslog(LOG_DEBUG, "instantiate %s", instance->plugin->label);
663 	}
664 	pipeline->sample_rate = sample_rate;
665 
666 	ARRAY_ELEMENT_FOREACH (&pipeline->instances, i, instance) {
667 		audio_port_array *audio_in = &instance->input_audio_ports;
668 		audio_port_array *audio_out = &instance->output_audio_ports;
669 		control_port_array *control_in = &instance->input_control_ports;
670 		control_port_array *control_out =
671 			&instance->output_control_ports;
672 		int j;
673 		struct audio_port *audio_port;
674 		struct control_port *control_port;
675 		struct dsp_module *module = instance->module;
676 
677 		/* connect audio ports */
678 		ARRAY_ELEMENT_FOREACH (audio_in, j, audio_port) {
679 			float *buf = pipeline->buffers[audio_port->buf_index];
680 			module->connect_port(module, audio_port->original_index,
681 					     buf);
682 			syslog(LOG_DEBUG, "connect audio buf %d to %s:%d (in)",
683 			       audio_port->buf_index, instance->plugin->title,
684 			       audio_port->original_index);
685 		}
686 		ARRAY_ELEMENT_FOREACH (audio_out, j, audio_port) {
687 			float *buf = pipeline->buffers[audio_port->buf_index];
688 			module->connect_port(module, audio_port->original_index,
689 					     buf);
690 			syslog(LOG_DEBUG, "connect audio buf %d to %s:%d (out)",
691 			       audio_port->buf_index, instance->plugin->title,
692 			       audio_port->original_index);
693 		}
694 
695 		/* connect control ports */
696 		ARRAY_ELEMENT_FOREACH (control_in, j, control_port) {
697 			/* Note for input control ports which has a
698 			 * peer, we use &control_port->peer->value, so
699 			 * we can get the peer port's output value
700 			 * directly */
701 			float *value = control_port->peer ?
702 					       &control_port->peer->value :
703 					       &control_port->value;
704 			module->connect_port(
705 				module, control_port->original_index, value);
706 			syslog(LOG_DEBUG,
707 			       "connect control (val=%g) to %s:%d (in)",
708 			       control_port->value, instance->plugin->title,
709 			       control_port->original_index);
710 		}
711 		ARRAY_ELEMENT_FOREACH (control_out, j, control_port) {
712 			module->connect_port(module,
713 					     control_port->original_index,
714 					     &control_port->value);
715 			syslog(LOG_DEBUG,
716 			       "connect control (val=%g) to %s:%d (out)",
717 			       control_port->value, instance->plugin->title,
718 			       control_port->original_index);
719 		}
720 	}
721 
722 	calculate_audio_delay(pipeline);
723 	return 0;
724 }
725 
cras_dsp_pipeline_deinstantiate(struct pipeline * pipeline)726 void cras_dsp_pipeline_deinstantiate(struct pipeline *pipeline)
727 {
728 	int i;
729 	struct instance *instance;
730 
731 	ARRAY_ELEMENT_FOREACH (&pipeline->instances, i, instance) {
732 		struct dsp_module *module = instance->module;
733 		if (instance->instantiated) {
734 			module->deinstantiate(module);
735 			instance->instantiated = 0;
736 		}
737 	}
738 	pipeline->sample_rate = 0;
739 }
740 
cras_dsp_pipeline_get_delay(struct pipeline * pipeline)741 int cras_dsp_pipeline_get_delay(struct pipeline *pipeline)
742 {
743 	return pipeline->sink_instance->total_delay;
744 }
745 
cras_dsp_pipeline_get_sample_rate(struct pipeline * pipeline)746 int cras_dsp_pipeline_get_sample_rate(struct pipeline *pipeline)
747 {
748 	return pipeline->sample_rate;
749 }
750 
cras_dsp_pipeline_get_num_input_channels(struct pipeline * pipeline)751 int cras_dsp_pipeline_get_num_input_channels(struct pipeline *pipeline)
752 {
753 	return pipeline->input_channels;
754 }
755 
cras_dsp_pipeline_get_num_output_channels(struct pipeline * pipeline)756 int cras_dsp_pipeline_get_num_output_channels(struct pipeline *pipeline)
757 {
758 	return pipeline->output_channels;
759 }
760 
cras_dsp_pipeline_get_peak_audio_buffers(struct pipeline * pipeline)761 int cras_dsp_pipeline_get_peak_audio_buffers(struct pipeline *pipeline)
762 {
763 	return pipeline->peak_buf;
764 }
765 
find_buffer(struct pipeline * pipeline,audio_port_array * audio_ports,int index)766 static float *find_buffer(struct pipeline *pipeline,
767 			  audio_port_array *audio_ports, int index)
768 {
769 	int i;
770 	struct audio_port *audio_port;
771 
772 	ARRAY_ELEMENT_FOREACH (audio_ports, i, audio_port) {
773 		if (audio_port->original_index == index)
774 			return pipeline->buffers[audio_port->buf_index];
775 	}
776 	return NULL;
777 }
778 
cras_dsp_pipeline_get_source_buffer(struct pipeline * pipeline,int index)779 float *cras_dsp_pipeline_get_source_buffer(struct pipeline *pipeline, int index)
780 {
781 	return find_buffer(pipeline,
782 			   &pipeline->source_instance->output_audio_ports,
783 			   index);
784 }
785 
cras_dsp_pipeline_get_sink_buffer(struct pipeline * pipeline,int index)786 float *cras_dsp_pipeline_get_sink_buffer(struct pipeline *pipeline, int index)
787 {
788 	return find_buffer(pipeline,
789 			   &pipeline->sink_instance->input_audio_ports, index);
790 }
791 
cras_dsp_pipeline_set_sink_ext_module(struct pipeline * pipeline,struct ext_dsp_module * ext_module)792 void cras_dsp_pipeline_set_sink_ext_module(struct pipeline *pipeline,
793 					   struct ext_dsp_module *ext_module)
794 {
795 	cras_dsp_module_set_sink_ext_module(pipeline->sink_instance->module,
796 					    ext_module);
797 }
798 
cras_dsp_pipeline_get_ini(struct pipeline * pipeline)799 struct ini *cras_dsp_pipeline_get_ini(struct pipeline *pipeline)
800 {
801 	return pipeline->ini;
802 }
803 
cras_dsp_pipeline_run(struct pipeline * pipeline,int sample_count)804 void cras_dsp_pipeline_run(struct pipeline *pipeline, int sample_count)
805 {
806 	int i;
807 	struct instance *instance;
808 
809 	ARRAY_ELEMENT_FOREACH (&pipeline->instances, i, instance) {
810 		struct dsp_module *module = instance->module;
811 		module->run(module, sample_count);
812 	}
813 }
814 
cras_dsp_pipeline_add_statistic(struct pipeline * pipeline,const struct timespec * time_delta,int samples)815 void cras_dsp_pipeline_add_statistic(struct pipeline *pipeline,
816 				     const struct timespec *time_delta,
817 				     int samples)
818 {
819 	int64_t t;
820 	if (samples <= 0)
821 		return;
822 
823 	t = time_delta->tv_sec * 1000000000LL + time_delta->tv_nsec;
824 
825 	if (pipeline->total_blocks == 0) {
826 		pipeline->max_time = t;
827 		pipeline->min_time = t;
828 	} else {
829 		pipeline->max_time = MAX(pipeline->max_time, t);
830 		pipeline->min_time = MIN(pipeline->min_time, t);
831 	}
832 
833 	pipeline->total_blocks++;
834 	pipeline->total_samples += samples;
835 	pipeline->total_time += t;
836 }
837 
cras_dsp_pipeline_apply(struct pipeline * pipeline,uint8_t * buf,snd_pcm_format_t format,unsigned int frames)838 int cras_dsp_pipeline_apply(struct pipeline *pipeline, uint8_t *buf,
839 			    snd_pcm_format_t format, unsigned int frames)
840 {
841 	size_t remaining;
842 	size_t chunk;
843 	size_t i;
844 	unsigned int input_channels = pipeline->input_channels;
845 	unsigned int output_channels = pipeline->output_channels;
846 	float *source[input_channels];
847 	float *sink[output_channels];
848 	struct timespec begin, end, delta;
849 	int rc;
850 
851 	if (!pipeline || frames == 0)
852 		return 0;
853 
854 	clock_gettime(CLOCK_THREAD_CPUTIME_ID, &begin);
855 
856 	/* get pointers to source and sink buffers */
857 	for (i = 0; i < input_channels; i++)
858 		source[i] = cras_dsp_pipeline_get_source_buffer(pipeline, i);
859 	for (i = 0; i < output_channels; i++)
860 		sink[i] = cras_dsp_pipeline_get_sink_buffer(pipeline, i);
861 
862 	remaining = frames;
863 
864 	/* process at most DSP_BUFFER_SIZE frames each loop */
865 	while (remaining > 0) {
866 		chunk = MIN(remaining, (size_t)DSP_BUFFER_SIZE);
867 
868 		/* deinterleave and convert to float */
869 		rc = dsp_util_deinterleave(buf, source, input_channels, format,
870 					   chunk);
871 		if (rc)
872 			return rc;
873 
874 		/* Run the pipeline */
875 		cras_dsp_pipeline_run(pipeline, chunk);
876 
877 		/* interleave and convert back to int16_t */
878 		rc = dsp_util_interleave(sink, buf, output_channels, format,
879 					 chunk);
880 		if (rc)
881 			return rc;
882 
883 		buf += chunk * output_channels * PCM_FORMAT_WIDTH(format) / 8;
884 		remaining -= chunk;
885 	}
886 
887 	clock_gettime(CLOCK_THREAD_CPUTIME_ID, &end);
888 	subtract_timespecs(&end, &begin, &delta);
889 	cras_dsp_pipeline_add_statistic(pipeline, &delta, frames);
890 	return 0;
891 }
892 
cras_dsp_pipeline_free(struct pipeline * pipeline)893 void cras_dsp_pipeline_free(struct pipeline *pipeline)
894 {
895 	int i;
896 	struct instance *instance;
897 
898 	ARRAY_ELEMENT_FOREACH (&pipeline->instances, i, instance) {
899 		struct dsp_module *module = instance->module;
900 		instance->plugin = NULL;
901 		ARRAY_FREE(&instance->input_audio_ports);
902 		ARRAY_FREE(&instance->input_control_ports);
903 		ARRAY_FREE(&instance->output_audio_ports);
904 		ARRAY_FREE(&instance->output_control_ports);
905 
906 		if (module) {
907 			if (instance->instantiated) {
908 				module->deinstantiate(module);
909 				instance->instantiated = 0;
910 			}
911 			module->free_module(module);
912 			instance->module = NULL;
913 		}
914 	}
915 
916 	pipeline->ini = NULL;
917 	ARRAY_FREE(&pipeline->instances);
918 
919 	for (i = 0; i < pipeline->peak_buf; i++)
920 		free(pipeline->buffers[i]);
921 	free(pipeline->buffers);
922 	free(pipeline);
923 }
924 
dump_audio_ports(struct dumper * d,const char * name,audio_port_array * audio_ports)925 static void dump_audio_ports(struct dumper *d, const char *name,
926 			     audio_port_array *audio_ports)
927 {
928 	int i;
929 	struct audio_port *audio_port;
930 	int n = ARRAY_COUNT(audio_ports);
931 
932 	if (n == 0)
933 		return;
934 	dumpf(d, "   %s (%d) =\n", name, n);
935 
936 	ARRAY_ELEMENT_FOREACH (audio_ports, i, audio_port) {
937 		dumpf(d, "   %p, peer %p, orig=%d, buf=%d\n", audio_port,
938 		      audio_port->peer, audio_port->original_index,
939 		      audio_port->buf_index);
940 	}
941 }
942 
dump_control_ports(struct dumper * d,const char * name,control_port_array * control_ports)943 static void dump_control_ports(struct dumper *d, const char *name,
944 			       control_port_array *control_ports)
945 {
946 	int i;
947 	struct control_port *control_port;
948 	int n = ARRAY_COUNT(control_ports);
949 
950 	if (n == 0)
951 		return;
952 	dumpf(d, "   %s (%d) =\n", name, ARRAY_COUNT(control_ports));
953 
954 	ARRAY_ELEMENT_FOREACH (control_ports, i, control_port) {
955 		dumpf(d, "   %p, peer %p, orig=%d, value=%g\n", control_port,
956 		      control_port->peer, control_port->original_index,
957 		      control_port->value);
958 	}
959 }
960 
cras_dsp_pipeline_dump(struct dumper * d,struct pipeline * pipeline)961 void cras_dsp_pipeline_dump(struct dumper *d, struct pipeline *pipeline)
962 {
963 	int i;
964 	struct instance *instance;
965 
966 	dumpf(d, "---- pipeline dump begin ----\n");
967 	dumpf(d, "pipeline (%s):\n", pipeline->purpose);
968 	dumpf(d, " input channels: %d\n", pipeline->input_channels);
969 	dumpf(d, " output channels: %d\n", pipeline->output_channels);
970 	dumpf(d, " sample_rate: %d\n", pipeline->sample_rate);
971 	dumpf(d, " processed samples: %" PRId64 "\n", pipeline->total_samples);
972 	dumpf(d, " processed blocks: %" PRId64 "\n", pipeline->total_blocks);
973 	dumpf(d, " total processing time: %" PRId64 "ns\n",
974 	      pipeline->total_time);
975 	if (pipeline->total_blocks) {
976 		dumpf(d, " average block size: %" PRId64 "\n",
977 		      pipeline->total_samples / pipeline->total_blocks);
978 		dumpf(d, " avg processing time per block: %" PRId64 "ns\n",
979 		      pipeline->total_time / pipeline->total_blocks);
980 	}
981 	dumpf(d, " min processing time per block: %" PRId64 "ns\n",
982 	      pipeline->min_time);
983 	dumpf(d, " max processing time per block: %" PRId64 "ns\n",
984 	      pipeline->max_time);
985 	if (pipeline->total_samples)
986 		dumpf(d, " cpu load: %g%%\n",
987 		      pipeline->total_time * 1e-9 / pipeline->total_samples *
988 			      pipeline->sample_rate * 100);
989 	dumpf(d, " instances (%d):\n", ARRAY_COUNT(&pipeline->instances));
990 	ARRAY_ELEMENT_FOREACH (&pipeline->instances, i, instance) {
991 		struct dsp_module *module = instance->module;
992 		dumpf(d, "  [%d]%s mod=%p, total delay=%d\n", i,
993 		      instance->plugin->title, module, instance->total_delay);
994 		if (module)
995 			module->dump(module, d);
996 		dump_audio_ports(d, "input_audio_ports",
997 				 &instance->input_audio_ports);
998 		dump_audio_ports(d, "output_audio_ports",
999 				 &instance->output_audio_ports);
1000 		dump_control_ports(d, "input_control_ports",
1001 				   &instance->input_control_ports);
1002 		dump_control_ports(d, "output_control_ports",
1003 				   &instance->output_control_ports);
1004 	}
1005 	dumpf(d, " peak_buf = %d\n", pipeline->peak_buf);
1006 	dumpf(d, "---- pipeline dump end ----\n");
1007 }
1008