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. */
47struct 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. */
55struct 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
62DECLARE_ARRAY_TYPE(struct audio_port, audio_port_array);
63DECLARE_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 */
69struct 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
97DECLARE_ARRAY_TYPE(struct instance, instance_array)
98
99/* An pipeline is a dynamic representation of a dsp ini file. */
100struct 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
147static struct instance *find_instance_by_plugin(instance_array *instances,
148						struct plugin *plugin)
149{
150	int i;
151	struct instance *instance;
152
153	FOR_ARRAY_ELEMENT(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 */
164static int find_origin_port(struct ini *ini, instance_array *instances,
165			    struct plugin *plugin, int index,
166			    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	FOR_ARRAY_ELEMENT(&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	FOR_ARRAY_ELEMENT(&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
228static struct audio_port *find_output_audio_port(instance_array *instances,
229						 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	FOR_ARRAY_ELEMENT(&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
248static struct control_port *find_output_control_port(instance_array *instances,
249						     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	FOR_ARRAY_ELEMENT(&instance->output_control_ports, i, control_port) {
261		if (control_port->original_index == index)
262			return control_port;
263	}
264
265	return NULL;
266}
267
268static char is_disabled(struct plugin *plugin, struct cras_expr_env *env)
269{
270	char disabled;
271	return (plugin->disable_expr &&
272		cras_expr_expression_eval_boolean(
273			plugin->disable_expr, env, &disabled) == 0 &&
274		disabled == 1);
275}
276
277static int topological_sort(struct pipeline *pipeline,
278			    struct cras_expr_env *env,
279			    struct plugin *plugin, char* visited)
280{
281	struct port *port;
282	struct flow *flow;
283	int index;
284	int i;
285	int flow_id;
286	struct instance *instance;
287	struct ini *ini = pipeline->ini;
288
289	index = ARRAY_INDEX(&ini->plugins, plugin);
290	if (visited[index])
291		return 0;
292	visited[index] = 1;
293
294	FOR_ARRAY_ELEMENT(&plugin->ports, i, port) {
295		if (port->flow_id == INVALID_FLOW_ID)
296			continue;
297		flow_id = port->flow_id;
298		flow = ARRAY_ELEMENT(&ini->flows, flow_id);
299		if (!flow->from) {
300			syslog(LOG_ERR, "no plugin flows to %s:%d",
301			       plugin->title, i);
302			return -1;
303		}
304		if (topological_sort(pipeline, env, flow->from, visited) < 0)
305			return -1;
306	}
307
308	/* if the plugin is disabled, we don't construct an instance for it */
309	if (is_disabled(plugin, env))
310		return 0;
311
312	instance = ARRAY_APPEND_ZERO(&pipeline->instances);
313	instance->plugin = plugin;
314
315	/* constructs audio and control ports for the instance */
316	FOR_ARRAY_ELEMENT(&plugin->ports, i, port) {
317		int need_connect = (port->flow_id != INVALID_FLOW_ID &&
318				    port->direction == PORT_INPUT);
319                struct plugin *origin = NULL;
320		int origin_index = 0;
321
322		if (need_connect) {
323			if (find_origin_port(ini, &pipeline->instances, plugin,
324					     i, &origin, &origin_index) < 0)
325				return -1;
326		}
327
328		if (port->type == PORT_AUDIO) {
329			audio_port_array *audio_port_array =
330				(port->direction == PORT_INPUT) ?
331				&instance->input_audio_ports :
332				&instance->output_audio_ports;
333			struct audio_port *audio_port =
334				ARRAY_APPEND_ZERO(audio_port_array);
335			audio_port->plugin = plugin;
336			audio_port->original_index = i;
337			if (need_connect) {
338				struct audio_port *from;
339				from = find_output_audio_port(
340					&pipeline->instances, origin,
341					origin_index);
342				if (!from)
343					return -1;
344				from->peer = audio_port;
345				audio_port->peer = from;
346			}
347		} else if (port->type == PORT_CONTROL) {
348			control_port_array *control_port_array =
349				(port->direction == PORT_INPUT) ?
350				&instance->input_control_ports :
351				&instance->output_control_ports;
352			struct control_port *control_port =
353				ARRAY_APPEND_ZERO(control_port_array);
354			control_port->plugin = plugin;
355			control_port->original_index = i;
356			control_port->value = port->init_value;
357			if (need_connect) {
358				struct control_port *from;
359				from = find_output_control_port(
360					&pipeline->instances, origin,
361					origin_index);
362				if (!from)
363					return -1;
364				from->peer = control_port;
365				control_port->peer = from;
366			}
367		}
368	}
369
370	return 0;
371}
372
373static struct plugin *find_enabled_builtin_plugin(struct ini *ini,
374						  const char *label,
375						  const char *purpose,
376						  struct cras_expr_env *env)
377{
378	int i;
379	struct plugin *plugin, *found = NULL;
380
381	FOR_ARRAY_ELEMENT(&ini->plugins, i, plugin) {
382		if (strcmp(plugin->library, "builtin") != 0)
383			continue;
384		if (strcmp(plugin->label, label) != 0)
385			continue;
386		if (!plugin->purpose || strcmp(plugin->purpose, purpose) != 0)
387			continue;
388		if (is_disabled(plugin, env))
389			continue;
390		if (found) {
391			syslog(LOG_ERR, "two %s plugins enabled: %s and %s",
392			       label, found->title, plugin->title);
393			return NULL;
394		}
395		found = plugin;
396	}
397
398	return found;
399}
400
401struct pipeline *cras_dsp_pipeline_create(struct ini *ini,
402					  struct cras_expr_env *env,
403					  const char *purpose)
404{
405	struct pipeline *pipeline;
406	int n;
407	char *visited;
408	int rc;
409	struct plugin *source = find_enabled_builtin_plugin(
410		ini, "source", purpose, env);
411	struct plugin *sink = find_enabled_builtin_plugin(
412		ini, "sink", purpose, env);
413
414	if (!source || !sink) {
415		syslog(LOG_INFO,
416		       "no enabled source or sink found %p/%p for %s",
417		       source, sink, purpose);
418		return NULL;
419	}
420
421	pipeline = calloc(1, sizeof(struct pipeline));
422	if (!pipeline) {
423		syslog(LOG_ERR, "no memory for pipeline");
424		return NULL;
425	}
426
427	pipeline->ini = ini;
428	pipeline->purpose = purpose;
429	/* create instances for needed plugins, in the order of dependency */
430	n = ARRAY_COUNT(&ini->plugins);
431	visited = calloc(1, n);
432	rc = topological_sort(pipeline, env, sink, visited);
433	free(visited);
434
435	if (rc < 0) {
436		syslog(LOG_ERR, "failed to construct pipeline");
437		return NULL;
438	}
439
440	pipeline->source_instance = find_instance_by_plugin(
441		&pipeline->instances, source);
442	pipeline->sink_instance = find_instance_by_plugin(
443		&pipeline->instances, sink);
444
445	if (!pipeline->source_instance || !pipeline->sink_instance) {
446		syslog(LOG_ERR, "source(%p) or sink(%p) missing/disabled?",
447		       source, sink);
448		cras_dsp_pipeline_free(pipeline);
449		return NULL;
450	}
451
452	pipeline->input_channels = ARRAY_COUNT(
453		&pipeline->source_instance->output_audio_ports);
454	pipeline->output_channels = ARRAY_COUNT(
455		&pipeline->sink_instance->input_audio_ports);
456	if (pipeline->output_channels > pipeline->input_channels) {
457		/* Can't increase channel count, no where to put them. */
458		syslog(LOG_ERR, "DSP output more channels than input\n");
459		cras_dsp_pipeline_free(pipeline);
460		return NULL;
461	}
462
463	return pipeline;
464}
465
466static int load_module(struct plugin *plugin, struct instance *instance)
467{
468	struct dsp_module *module;
469	module = cras_dsp_module_load_builtin(plugin);
470	if (!module)
471		return -1;
472	instance->module = module;
473	instance->properties = module->get_properties(module);
474	return 0;
475}
476
477static void use_buffers(char *busy, audio_port_array *audio_ports)
478{
479	int i, k = 0;
480	struct audio_port *audio_port;
481
482	FOR_ARRAY_ELEMENT(audio_ports, i, audio_port) {
483		while (busy[k])
484			k++;
485		audio_port->buf_index = k;
486		busy[k] = 1;
487	}
488}
489
490static void unuse_buffers(char *busy, audio_port_array *audio_ports)
491{
492	int i;
493	struct audio_port *audio_port;
494
495	FOR_ARRAY_ELEMENT(audio_ports, i, audio_port) {
496		busy[audio_port->buf_index] = 0;
497	}
498}
499
500/* assign which buffer each audio port on each instance should use */
501static int allocate_buffers(struct pipeline *pipeline)
502{
503	int i;
504	struct instance *instance;
505	int need_buf = 0, peak_buf = 0;
506	char *busy;
507
508	/* first figure out how many buffers do we need */
509	FOR_ARRAY_ELEMENT(&pipeline->instances, i, instance) {
510		int in = ARRAY_COUNT(&instance->input_audio_ports);
511		int out = ARRAY_COUNT(&instance->output_audio_ports);
512
513		if (instance->properties & MODULE_INPLACE_BROKEN) {
514			/* We cannot reuse input buffer as output
515			 * buffer, so we need to use extra buffers */
516			need_buf += out;
517			peak_buf = MAX(peak_buf, need_buf);
518			need_buf -= in;
519		} else {
520			need_buf += out - in;
521			peak_buf = MAX(peak_buf, need_buf);
522		}
523	}
524
525	/* then allocate the buffers */
526	pipeline->peak_buf = peak_buf;
527	pipeline->buffers = (float **)calloc(peak_buf, sizeof(float *));
528
529	if (!pipeline->buffers) {
530		syslog(LOG_ERR, "failed to allocate buffers");
531		return -1;
532	}
533
534	for (i = 0; i < peak_buf; i++) {
535		size_t size = DSP_BUFFER_SIZE * sizeof(float);
536		float *buf = calloc(1, size);
537		if (!buf) {
538			syslog(LOG_ERR, "failed to allocate buf");
539			return -1;
540		}
541		pipeline->buffers[i] = buf;
542	}
543
544	/* Now assign buffer index for each instance's input/output ports */
545	busy = calloc(peak_buf, sizeof(*busy));
546	FOR_ARRAY_ELEMENT(&pipeline->instances, i, instance) {
547		int j;
548		struct audio_port *audio_port;
549
550		/* Collect input buffers from upstream */
551		FOR_ARRAY_ELEMENT(&instance->input_audio_ports, j, audio_port) {
552			audio_port->buf_index = audio_port->peer->buf_index;
553		}
554
555		/* If the module has the MODULE_INPLACE_BROKEN flag,
556		 * we cannot reuse input buffers as output buffers, so
557		 * we need to use extra buffers. For example, in this graph
558		 *
559		 * [A]
560		 * output_0={x}
561		 * output_1={y}
562		 * output_2={z}
563		 * output_3={w}
564		 * [B]
565		 * input_0={x}
566		 * input_1={y}
567		 * input_2={z}
568		 * input_3={w}
569		 * output_4={u}
570		 *
571		 * Then peak_buf for this pipeline is 4. However if
572		 * plugin B has the MODULE_INPLACE_BROKEN flag, then
573		 * peak_buf is 5 because plugin B cannot output to the
574		 * same buffer used for input.
575		 *
576		 * This means if we don't have the flag, we can free
577		 * the input buffers then allocate the output buffers,
578		 * but if we have the flag, we have to allocate the
579		 * output buffers before freeing the input buffers.
580		 */
581		if (instance->properties & MODULE_INPLACE_BROKEN) {
582			use_buffers(busy, &instance->output_audio_ports);
583			unuse_buffers(busy, &instance->input_audio_ports);
584		} else {
585			unuse_buffers(busy, &instance->input_audio_ports);
586			use_buffers(busy, &instance->output_audio_ports);
587		}
588	}
589	free(busy);
590
591	return 0;
592}
593
594int cras_dsp_pipeline_load(struct pipeline *pipeline)
595{
596	int i;
597	struct instance *instance;
598
599	FOR_ARRAY_ELEMENT(&pipeline->instances, i, instance) {
600		struct plugin *plugin = instance->plugin;
601		if (load_module(plugin, instance) != 0)
602			return -1;
603	}
604
605	if (allocate_buffers(pipeline) != 0)
606		return -1;
607
608	return 0;
609}
610
611/* Calculates the total buffering delay of each instance from the source */
612static void calculate_audio_delay(struct pipeline *pipeline)
613{
614	int i;
615	struct instance *instance;
616
617	FOR_ARRAY_ELEMENT(&pipeline->instances, i, instance) {
618		struct dsp_module *module = instance->module;
619		audio_port_array *audio_in = &instance->input_audio_ports;
620		struct audio_port *audio_port;
621		int delay = 0;
622		int j;
623
624		/* Finds the max delay of all modules that provide input to this
625		 * instance. */
626		FOR_ARRAY_ELEMENT(audio_in, j, audio_port) {
627			struct instance *upstream = find_instance_by_plugin(
628				&pipeline->instances, audio_port->peer->plugin);
629			delay = MAX(upstream->total_delay, delay);
630		}
631
632		instance->total_delay = delay + module->get_delay(module);
633	}
634}
635
636int cras_dsp_pipeline_instantiate(struct pipeline *pipeline, int sample_rate)
637{
638	int i;
639	struct instance *instance;
640
641	FOR_ARRAY_ELEMENT(&pipeline->instances, i, instance) {
642		struct dsp_module *module = instance->module;
643		if (module->instantiate(module, sample_rate) != 0)
644			return -1;
645		instance->instantiated = 1;
646		syslog(LOG_DEBUG, "instantiate %s", instance->plugin->label);
647	}
648	pipeline->sample_rate = sample_rate;
649
650	FOR_ARRAY_ELEMENT(&pipeline->instances, i, instance) {
651		audio_port_array *audio_in = &instance->input_audio_ports;
652		audio_port_array *audio_out = &instance->output_audio_ports;
653		control_port_array *control_in = &instance->input_control_ports;
654		control_port_array *control_out =
655			&instance->output_control_ports;
656		int j;
657		struct audio_port *audio_port;
658		struct control_port *control_port;
659		struct dsp_module *module = instance->module;
660
661		/* connect audio ports */
662		FOR_ARRAY_ELEMENT(audio_in, j, audio_port) {
663			float *buf = pipeline->buffers[audio_port->buf_index];
664			module->connect_port(module,
665					     audio_port->original_index,
666					     buf);
667			syslog(LOG_DEBUG, "connect audio buf %d to %s:%d (in)",
668			       audio_port->buf_index, instance->plugin->title,
669			       audio_port->original_index);
670		}
671		FOR_ARRAY_ELEMENT(audio_out, j, audio_port) {
672			float *buf = pipeline->buffers[audio_port->buf_index];
673			module->connect_port(module,
674					     audio_port->original_index,
675					     buf);
676			syslog(LOG_DEBUG, "connect audio buf %d to %s:%d (out)",
677			       audio_port->buf_index, instance->plugin->title,
678			       audio_port->original_index);
679		}
680
681		/* connect control ports */
682		FOR_ARRAY_ELEMENT(control_in, j, control_port) {
683			/* Note for input control ports which has a
684			 * peer, we use &control_port->peer->value, so
685			 * we can get the peer port's output value
686			 * directly */
687			float *value = control_port->peer ?
688				&control_port->peer->value :
689				&control_port->value;
690			module->connect_port(module,
691					     control_port->original_index,
692					     value);
693			syslog(LOG_DEBUG,
694			       "connect control (val=%g) to %s:%d (in)",
695			       control_port->value, instance->plugin->title,
696			       control_port->original_index);
697		}
698		FOR_ARRAY_ELEMENT(control_out, j, control_port) {
699			module->connect_port(module,
700					     control_port->original_index,
701					     &control_port->value);
702			syslog(LOG_DEBUG,
703			       "connect control (val=%g) to %s:%d (out)",
704			       control_port->value, instance->plugin->title,
705			       control_port->original_index);
706		}
707	}
708
709	calculate_audio_delay(pipeline);
710	return 0;
711}
712
713void cras_dsp_pipeline_deinstantiate(struct pipeline *pipeline)
714{
715	int i;
716	struct instance *instance;
717
718	FOR_ARRAY_ELEMENT(&pipeline->instances, i, instance) {
719		struct dsp_module *module = instance->module;
720		if (instance->instantiated) {
721			module->deinstantiate(module);
722			instance->instantiated = 0;
723		}
724	}
725	pipeline->sample_rate = 0;
726}
727
728int cras_dsp_pipeline_get_delay(struct pipeline *pipeline)
729{
730	return pipeline->sink_instance->total_delay;
731}
732
733int cras_dsp_pipeline_get_sample_rate(struct pipeline *pipeline)
734{
735	return pipeline->sample_rate;
736}
737
738int cras_dsp_pipeline_get_num_input_channels(struct pipeline *pipeline)
739{
740	return pipeline->input_channels;
741}
742
743int cras_dsp_pipeline_get_num_output_channels(struct pipeline *pipeline)
744{
745	return pipeline->output_channels;
746}
747
748int cras_dsp_pipeline_get_peak_audio_buffers(struct pipeline *pipeline)
749{
750	return pipeline->peak_buf;
751}
752
753static float *find_buffer(struct pipeline *pipeline,
754			  audio_port_array *audio_ports,
755			  int index)
756{
757	int i;
758	struct audio_port *audio_port;
759
760	FOR_ARRAY_ELEMENT(audio_ports, i, audio_port) {
761		if (audio_port->original_index == index)
762			return pipeline->buffers[audio_port->buf_index];
763	}
764	return NULL;
765}
766
767float *cras_dsp_pipeline_get_source_buffer(struct pipeline *pipeline, int index)
768{
769	return find_buffer(pipeline,
770			   &pipeline->source_instance->output_audio_ports,
771			   index);
772}
773
774float *cras_dsp_pipeline_get_sink_buffer(struct pipeline *pipeline, int index)
775{
776	return find_buffer(pipeline,
777			   &pipeline->sink_instance->input_audio_ports,
778			   index);
779}
780
781void cras_dsp_pipeline_run(struct pipeline *pipeline, int sample_count)
782{
783	int i;
784	struct instance *instance;
785
786	FOR_ARRAY_ELEMENT(&pipeline->instances, i, instance) {
787		struct dsp_module *module = instance->module;
788		module->run(module, sample_count);
789	}
790}
791
792void cras_dsp_pipeline_add_statistic(struct pipeline *pipeline,
793				     const struct timespec *time_delta,
794				     int samples)
795{
796	int64_t t;
797	if (samples <= 0)
798		return;
799
800	t = time_delta->tv_sec * 1000000000LL + time_delta->tv_nsec;
801
802	if (pipeline->total_blocks == 0) {
803		pipeline->max_time = t;
804		pipeline->min_time = t;
805	} else {
806		pipeline->max_time = MAX(pipeline->max_time, t);
807		pipeline->min_time = MIN(pipeline->min_time, t);
808	}
809
810	pipeline->total_blocks++;
811	pipeline->total_samples += samples;
812	pipeline->total_time += t;
813}
814
815void cras_dsp_pipeline_apply(struct pipeline *pipeline,
816			     uint8_t *buf, unsigned int frames)
817{
818	size_t remaining;
819	size_t chunk;
820	size_t i;
821	int16_t *target;
822	unsigned int input_channels = pipeline->input_channels;
823	unsigned int output_channels = pipeline->output_channels;
824	float *source[input_channels];
825	float *sink[output_channels];
826	//struct timespec begin, end, delta;
827
828	if (!pipeline || frames == 0)
829		return;
830
831	//clock_gettime(CLOCK_THREAD_CPUTIME_ID, &begin);
832
833	target = (int16_t *)buf;
834
835	/* get pointers to source and sink buffers */
836	for (i = 0; i < input_channels; i++)
837		source[i] = cras_dsp_pipeline_get_source_buffer(pipeline, i);
838	for (i = 0; i < output_channels; i++)
839		sink[i] = cras_dsp_pipeline_get_sink_buffer(pipeline, i);
840
841	remaining = frames;
842
843	/* process at most DSP_BUFFER_SIZE frames each loop */
844	while (remaining > 0) {
845		chunk = MIN(remaining, (size_t)DSP_BUFFER_SIZE);
846
847		/* deinterleave and convert to float */
848		dsp_util_deinterleave(target, source, input_channels, chunk);
849
850		/* Run the pipeline */
851		cras_dsp_pipeline_run(pipeline, chunk);
852
853		/* interleave and convert back to int16_t */
854		dsp_util_interleave(sink, target, output_channels, chunk);
855
856		target += chunk * output_channels;
857		remaining -= chunk;
858	}
859
860	//clock_gettime(CLOCK_THREAD_CPUTIME_ID, &end);
861	//subtract_timespecs(&end, &begin, &delta);
862	//cras_dsp_pipeline_add_statistic(pipeline, &delta, frames);
863}
864
865void cras_dsp_pipeline_free(struct pipeline *pipeline)
866{
867	int i;
868	struct instance *instance;
869
870	FOR_ARRAY_ELEMENT(&pipeline->instances, i, instance) {
871		struct dsp_module *module = instance->module;
872		instance->plugin = NULL;
873		ARRAY_FREE(&instance->input_audio_ports);
874		ARRAY_FREE(&instance->input_control_ports);
875		ARRAY_FREE(&instance->output_audio_ports);
876		ARRAY_FREE(&instance->output_control_ports);
877
878		if (module) {
879			if (instance->instantiated) {
880				module->deinstantiate(module);
881				instance->instantiated = 0;
882			}
883			module->free_module(module);
884			instance->module = NULL;
885		}
886	}
887
888	pipeline->ini = NULL;
889	ARRAY_FREE(&pipeline->instances);
890
891	for (i = 0; i < pipeline->peak_buf; i++)
892		free(pipeline->buffers[i]);
893	free(pipeline->buffers);
894	free(pipeline);
895}
896