19c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid/* Copyright (c) 2012 The Chromium OS Authors. All rights reserved.
29c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid * Use of this source code is governed by a BSD-style license that can be
39c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid * found in the LICENSE file.
49c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid */
59c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid
69c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid#include <inttypes.h>
79c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid#include <sys/param.h>
89c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid#include <syslog.h>
99c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid
109c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid//#include "cras_util.h"
119c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid#include "cras_dsp_module.h"
129c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid#include "cras_dsp_pipeline.h"
139c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid#include "dsp_util.h"
149c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid
159c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid/* We have a static representation of the dsp graph in a "struct ini",
169c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid * and here we will construct a dynamic representation of it in a
179c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid * "struct pipeline". The difference between the static one and the
189c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid * dynamic one is that we will only include the subset of the dsp
199c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid * graph actually needed in the dynamic one (so those plugins that are
209c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid * disabled will not be included). Here are the mapping between the
219c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid * static representation and the dynamic representation:
229c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid *
239c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid *      static                      dynamic
249c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid *  -------------    --------------------------------------
259c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid *  struct ini       struct pipeline
269c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid *  struct plugin    struct instance
279c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid *  strict port      struct audio_port, struct control_port
289c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid *
299c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid * For example, if the ini file specifies these plugins and their
309c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid * connections:
319c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid *
329c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid * [A]
339c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid * output_0={audio}
349c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid * [B]
359c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid * input_0={audio}
369c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid * output_1={result}
379c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid * [C]
389c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid * input_0={result}
399c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid *
409c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid * That is, A connects to B, and B connects to C. If the plugin B is
419c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid * now disabled, in the pipeline we construct there will only be two
429c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid * instances (A and C) and the audio ports on these instances will
439c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid * connect to each other directly, bypassing B.
449c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid */
459c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid
469c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid/* This represents an audio port on an instance. */
479c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reidstruct audio_port {
489c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid	struct audio_port *peer;  /* the audio port this port connects to */
499c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid	struct plugin *plugin;  /* the plugin corresponds to the instance */
509c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid	int original_index;  /* the port index in the plugin */
519c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid	int buf_index; /* the buffer index in the pipeline */
529c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid};
539c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid
549c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid/* This represents a control port on an instance. */
559c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reidstruct control_port {
569c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid	struct control_port *peer;  /* the control port this port connects to */
579c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid	struct plugin *plugin;  /* the plugin corresponds to the instance */
589c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid	int original_index;  /* the port index in the plugin */
599c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid	float value;  /* the value of the control port */
609c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid};
619c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid
629c94a7e4053538cacb9695b15da4b1cc7857d09dDylan ReidDECLARE_ARRAY_TYPE(struct audio_port, audio_port_array);
639c94a7e4053538cacb9695b15da4b1cc7857d09dDylan ReidDECLARE_ARRAY_TYPE(struct control_port, control_port_array);
649c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid
659c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid/* An instance is a dynamic representation of a plugin. We only create
669c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid * an instance when a plugin is needed (data actually flows through it
679c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid * and it is not disabled). An instance also contains a pointer to a
689c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid * struct dsp_module, which is the implementation of the plugin */
699c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reidstruct instance {
709c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid	/* The plugin this instance corresponds to */
719c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid	struct plugin *plugin;
729c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid
739c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid	/* These are the ports on this instance. The difference
749c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid	 * between this and the port array in a struct plugin is that
759c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid	 * the ports skip disabled plugins and connect to the upstream
769c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid	 * ports directly.
779c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid	 */
789c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid	audio_port_array input_audio_ports;
799c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid	audio_port_array output_audio_ports;
809c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid	control_port_array input_control_ports;
819c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid	control_port_array output_control_ports;
829c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid
839c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid	/* The implementation of the plugin */
849c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid	struct dsp_module *module;
859c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid
869c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid	/* Whether this module's instantiate() function has been called */
879c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid	int instantiated;
889c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid
899c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid	/* This caches the value returned from get_properties() of a module */
909c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid	int properties;
919c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid
929c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid	/* This is the total buffering delay from source to this instance. It is
939c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid	 * in number of frames. */
949c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid	int total_delay;
959c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid};
969c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid
979c94a7e4053538cacb9695b15da4b1cc7857d09dDylan ReidDECLARE_ARRAY_TYPE(struct instance, instance_array)
989c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid
999c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid/* An pipeline is a dynamic representation of a dsp ini file. */
1009c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reidstruct pipeline {
1019c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid	/* The purpose of the pipeline. "playback" or "capture" */
1029c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid	const char *purpose;
1039c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid
1049c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid	/* The ini file this pipeline comes from */
1059c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid	struct ini *ini;
1069c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid
1079c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid	/* All needed instances for this pipeline. It is sorted in an
1089c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid	 * order that if instance B depends on instance A, then A will
1099c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid	 * appear in front of B. */
1109c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid	instance_array instances;
1119c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid
1129c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid	/* The maximum number of audio buffers that will be used at
1139c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid	 * the same time for this pipeline */
1149c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid	int peak_buf;
1159c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid
1169c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid	/* The audio data buffers */
1179c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid	float **buffers;
1189c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid
1199c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid	/* The instance where the audio data flow in */
1209c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid	struct instance *source_instance;
1219c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid
1229c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid	/* The instance where the audio data flow out */
1239c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid	struct instance *sink_instance;
1249c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid
1259c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid	/* The number of audio channels for this pipeline */
1269c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid	int input_channels;
1279c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid	int output_channels;
1289c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid
1299c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid	/* The audio sampling rate for this pipleine. It is zero if
1309c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid	 * cras_dsp_pipeline_instantiate() has not been called. */
1319c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid	int sample_rate;
1329c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid
1339c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid	/* The total time it takes to run the pipeline, in nanoseconds. */
1349c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid	int64_t total_time;
1359c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid
1369c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid	/* The max/min time it takes to run the pipeline, in nanoseconds. */
1379c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid	int64_t max_time;
1389c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid	int64_t min_time;
1399c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid
1409c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid	/* The number of blocks the pipeline. */
1419c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid	int64_t total_blocks;
1429c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid
1439c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid	/* The total number of sample frames the pipeline processed */
1449c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid	int64_t total_samples;
1459c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid};
1469c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid
1479c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reidstatic struct instance *find_instance_by_plugin(instance_array *instances,
1489c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid						struct plugin *plugin)
1499c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid{
1509c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid	int i;
1519c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid	struct instance *instance;
1529c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid
1539c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid	FOR_ARRAY_ELEMENT(instances, i, instance) {
1549c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid		if (instance->plugin == plugin)
1559c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid			return instance;
1569c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid	}
1579c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid
1589c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid	return NULL;
1599c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid}
1609c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid
1619c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid/* Finds out where the data sent to plugin:index come from. The issue
1629c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid * we need to handle here is the previous plugin may be disabled, so
1639c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid * we need to go upstream until we find the real origin */
1649c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reidstatic int find_origin_port(struct ini *ini, instance_array *instances,
1659c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid			    struct plugin *plugin, int index,
1669c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid			    struct plugin **origin, int *origin_index)
1679c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid{
1689c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid	enum port_type type;
1699c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid	struct port *port;
1709c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid	int flow_id;
1719c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid	struct flow *flow;
1729c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid	int i, k;
1739c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid	int found;
1749c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid
1759c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid	port = ARRAY_ELEMENT(&plugin->ports, index);
1769c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid	type = port->type;
1779c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid	flow_id = port->flow_id;
1789c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid	if (flow_id == INVALID_FLOW_ID)
1799c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid		return -1;
1809c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid	flow = ARRAY_ELEMENT(&ini->flows, flow_id);
1819c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid
1829c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid	/* move to the previous plugin */
1839c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid	plugin = flow->from;
1849c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid	index = flow->from_port;
1859c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid
1869c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid	/* if the plugin is not disabled, it will be pointed by some instance */
1879c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid	if (find_instance_by_plugin(instances, plugin)) {
1889c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid		*origin = plugin;
1899c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid		*origin_index = index;
1909c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid		return 0;
1919c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid	}
1929c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid
1939c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid	/* Now we know the previous plugin is disabled, we need to go
1949c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid	 * upstream. We assume the k-th output port of the plugin
1959c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid	 * corresponds to the k-th input port of the plugin (with the
1969c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid	 * same type) */
1979c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid
1989c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid	k = 0;
1999c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid	found = 0;
2009c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid	FOR_ARRAY_ELEMENT(&plugin->ports, i, port) {
2019c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid		if (index == i) {
2029c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid			found = 1;
2039c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid			break;
2049c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid		}
2059c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid		if (port->direction == PORT_OUTPUT && port->type == type)
2069c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid			k++;
2079c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid	}
2089c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid	if (!found)
2099c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid		return -1;
2109c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid
2119c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid	found = 0;
2129c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid	FOR_ARRAY_ELEMENT(&plugin->ports, i, port) {
2139c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid		if (port->direction == PORT_INPUT && port->type == type) {
2149c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid			if (k-- == 0) {
2159c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid				index = i;
2169c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid				found = 1;
2179c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid				break;
2189c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid			}
2199c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid		}
2209c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid	}
2219c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid	if (!found)
2229c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid		return -1;
2239c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid
2249c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid	return find_origin_port(ini, instances, plugin, index, origin,
2259c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid				origin_index);
2269c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid}
2279c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid
2289c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reidstatic struct audio_port *find_output_audio_port(instance_array *instances,
2299c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid						 struct plugin *plugin,
2309c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid						 int index)
2319c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid{
2329c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid	int i;
2339c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid	struct instance *instance;
2349c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid	struct audio_port *audio_port;
2359c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid
2369c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid	instance = find_instance_by_plugin(instances, plugin);
2379c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid	if (!instance)
2389c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid		return NULL;
2399c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid
2409c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid	FOR_ARRAY_ELEMENT(&instance->output_audio_ports, i, audio_port) {
2419c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid		if (audio_port->original_index == index)
2429c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid			return audio_port;
2439c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid	}
2449c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid
2459c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid	return NULL;
2469c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid}
2479c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid
2489c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reidstatic struct control_port *find_output_control_port(instance_array *instances,
2499c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid						     struct plugin *plugin,
2509c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid						     int index)
2519c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid{
2529c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid	int i;
2539c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid	struct instance *instance;
2549c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid	struct control_port *control_port;
2559c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid
2569c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid	instance = find_instance_by_plugin(instances, plugin);
2579c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid	if (!instance)
2589c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid		return NULL;
2599c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid
2609c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid	FOR_ARRAY_ELEMENT(&instance->output_control_ports, i, control_port) {
2619c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid		if (control_port->original_index == index)
2629c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid			return control_port;
2639c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid	}
2649c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid
2659c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid	return NULL;
2669c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid}
2679c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid
2689c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reidstatic char is_disabled(struct plugin *plugin, struct cras_expr_env *env)
2699c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid{
2709c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid	char disabled;
2719c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid	return (plugin->disable_expr &&
2729c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid		cras_expr_expression_eval_boolean(
2739c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid			plugin->disable_expr, env, &disabled) == 0 &&
2749c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid		disabled == 1);
2759c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid}
2769c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid
2779c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reidstatic int topological_sort(struct pipeline *pipeline,
2789c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid			    struct cras_expr_env *env,
2799c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid			    struct plugin *plugin, char* visited)
2809c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid{
2819c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid	struct port *port;
2829c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid	struct flow *flow;
2839c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid	int index;
2849c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid	int i;
2859c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid	int flow_id;
2869c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid	struct instance *instance;
2879c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid	struct ini *ini = pipeline->ini;
2889c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid
2899c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid	index = ARRAY_INDEX(&ini->plugins, plugin);
2909c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid	if (visited[index])
2919c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid		return 0;
2929c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid	visited[index] = 1;
2939c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid
2949c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid	FOR_ARRAY_ELEMENT(&plugin->ports, i, port) {
2959c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid		if (port->flow_id == INVALID_FLOW_ID)
2969c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid			continue;
2979c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid		flow_id = port->flow_id;
2989c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid		flow = ARRAY_ELEMENT(&ini->flows, flow_id);
2999c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid		if (!flow->from) {
3009c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid			syslog(LOG_ERR, "no plugin flows to %s:%d",
3019c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid			       plugin->title, i);
3029c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid			return -1;
3039c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid		}
3049c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid		if (topological_sort(pipeline, env, flow->from, visited) < 0)
3059c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid			return -1;
3069c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid	}
3079c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid
3089c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid	/* if the plugin is disabled, we don't construct an instance for it */
3099c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid	if (is_disabled(plugin, env))
3109c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid		return 0;
3119c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid
3129c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid	instance = ARRAY_APPEND_ZERO(&pipeline->instances);
3139c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid	instance->plugin = plugin;
3149c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid
3159c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid	/* constructs audio and control ports for the instance */
3169c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid	FOR_ARRAY_ELEMENT(&plugin->ports, i, port) {
3179c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid		int need_connect = (port->flow_id != INVALID_FLOW_ID &&
3189c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid				    port->direction == PORT_INPUT);
3199c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid                struct plugin *origin = NULL;
3209c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid		int origin_index = 0;
3219c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid
3229c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid		if (need_connect) {
3239c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid			if (find_origin_port(ini, &pipeline->instances, plugin,
3249c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid					     i, &origin, &origin_index) < 0)
3259c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid				return -1;
3269c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid		}
3279c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid
3289c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid		if (port->type == PORT_AUDIO) {
3299c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid			audio_port_array *audio_port_array =
3309c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid				(port->direction == PORT_INPUT) ?
3319c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid				&instance->input_audio_ports :
3329c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid				&instance->output_audio_ports;
3339c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid			struct audio_port *audio_port =
3349c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid				ARRAY_APPEND_ZERO(audio_port_array);
3359c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid			audio_port->plugin = plugin;
3369c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid			audio_port->original_index = i;
3379c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid			if (need_connect) {
3389c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid				struct audio_port *from;
3399c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid				from = find_output_audio_port(
3409c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid					&pipeline->instances, origin,
3419c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid					origin_index);
3429c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid				if (!from)
3439c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid					return -1;
3449c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid				from->peer = audio_port;
3459c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid				audio_port->peer = from;
3469c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid			}
3479c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid		} else if (port->type == PORT_CONTROL) {
3489c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid			control_port_array *control_port_array =
3499c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid				(port->direction == PORT_INPUT) ?
3509c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid				&instance->input_control_ports :
3519c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid				&instance->output_control_ports;
3529c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid			struct control_port *control_port =
3539c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid				ARRAY_APPEND_ZERO(control_port_array);
3549c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid			control_port->plugin = plugin;
3559c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid			control_port->original_index = i;
3569c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid			control_port->value = port->init_value;
3579c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid			if (need_connect) {
3589c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid				struct control_port *from;
3599c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid				from = find_output_control_port(
3609c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid					&pipeline->instances, origin,
3619c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid					origin_index);
3629c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid				if (!from)
3639c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid					return -1;
3649c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid				from->peer = control_port;
3659c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid				control_port->peer = from;
3669c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid			}
3679c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid		}
3689c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid	}
3699c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid
3709c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid	return 0;
3719c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid}
3729c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid
3739c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reidstatic struct plugin *find_enabled_builtin_plugin(struct ini *ini,
3749c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid						  const char *label,
3759c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid						  const char *purpose,
3769c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid						  struct cras_expr_env *env)
3779c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid{
3789c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid	int i;
3799c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid	struct plugin *plugin, *found = NULL;
3809c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid
3819c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid	FOR_ARRAY_ELEMENT(&ini->plugins, i, plugin) {
3829c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid		if (strcmp(plugin->library, "builtin") != 0)
3839c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid			continue;
3849c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid		if (strcmp(plugin->label, label) != 0)
3859c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid			continue;
3869c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid		if (!plugin->purpose || strcmp(plugin->purpose, purpose) != 0)
3879c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid			continue;
3889c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid		if (is_disabled(plugin, env))
3899c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid			continue;
3909c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid		if (found) {
3919c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid			syslog(LOG_ERR, "two %s plugins enabled: %s and %s",
3929c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid			       label, found->title, plugin->title);
3939c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid			return NULL;
3949c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid		}
3959c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid		found = plugin;
3969c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid	}
3979c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid
3989c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid	return found;
3999c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid}
4009c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid
4019c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reidstruct pipeline *cras_dsp_pipeline_create(struct ini *ini,
4029c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid					  struct cras_expr_env *env,
4039c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid					  const char *purpose)
4049c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid{
4059c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid	struct pipeline *pipeline;
4069c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid	int n;
4079c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid	char *visited;
4089c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid	int rc;
4099c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid	struct plugin *source = find_enabled_builtin_plugin(
4109c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid		ini, "source", purpose, env);
4119c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid	struct plugin *sink = find_enabled_builtin_plugin(
4129c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid		ini, "sink", purpose, env);
4139c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid
4149c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid	if (!source || !sink) {
4159c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid		syslog(LOG_INFO,
4169c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid		       "no enabled source or sink found %p/%p for %s",
4179c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid		       source, sink, purpose);
4189c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid		return NULL;
4199c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid	}
4209c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid
4219c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid	pipeline = calloc(1, sizeof(struct pipeline));
4229c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid	if (!pipeline) {
4239c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid		syslog(LOG_ERR, "no memory for pipeline");
4249c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid		return NULL;
4259c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid	}
4269c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid
4279c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid	pipeline->ini = ini;
4289c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid	pipeline->purpose = purpose;
4299c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid	/* create instances for needed plugins, in the order of dependency */
4309c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid	n = ARRAY_COUNT(&ini->plugins);
4319c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid	visited = calloc(1, n);
4329c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid	rc = topological_sort(pipeline, env, sink, visited);
4339c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid	free(visited);
4349c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid
4359c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid	if (rc < 0) {
4369c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid		syslog(LOG_ERR, "failed to construct pipeline");
4379c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid		return NULL;
4389c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid	}
4399c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid
4409c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid	pipeline->source_instance = find_instance_by_plugin(
4419c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid		&pipeline->instances, source);
4429c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid	pipeline->sink_instance = find_instance_by_plugin(
4439c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid		&pipeline->instances, sink);
4449c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid
4459c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid	if (!pipeline->source_instance || !pipeline->sink_instance) {
4469c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid		syslog(LOG_ERR, "source(%p) or sink(%p) missing/disabled?",
4479c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid		       source, sink);
4489c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid		cras_dsp_pipeline_free(pipeline);
4499c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid		return NULL;
4509c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid	}
4519c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid
4529c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid	pipeline->input_channels = ARRAY_COUNT(
4539c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid		&pipeline->source_instance->output_audio_ports);
4549c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid	pipeline->output_channels = ARRAY_COUNT(
4559c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid		&pipeline->sink_instance->input_audio_ports);
4569c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid	if (pipeline->output_channels > pipeline->input_channels) {
4579c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid		/* Can't increase channel count, no where to put them. */
4589c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid		syslog(LOG_ERR, "DSP output more channels than input\n");
4599c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid		cras_dsp_pipeline_free(pipeline);
4609c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid		return NULL;
4619c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid	}
4629c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid
4639c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid	return pipeline;
4649c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid}
4659c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid
4669c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reidstatic int load_module(struct plugin *plugin, struct instance *instance)
4679c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid{
4689c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid	struct dsp_module *module;
4699c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid	module = cras_dsp_module_load_builtin(plugin);
4709c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid	if (!module)
4719c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid		return -1;
4729c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid	instance->module = module;
4739c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid	instance->properties = module->get_properties(module);
4749c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid	return 0;
4759c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid}
4769c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid
4779c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reidstatic void use_buffers(char *busy, audio_port_array *audio_ports)
4789c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid{
4799c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid	int i, k = 0;
4809c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid	struct audio_port *audio_port;
4819c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid
4829c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid	FOR_ARRAY_ELEMENT(audio_ports, i, audio_port) {
4839c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid		while (busy[k])
4849c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid			k++;
4859c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid		audio_port->buf_index = k;
4869c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid		busy[k] = 1;
4879c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid	}
4889c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid}
4899c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid
4909c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reidstatic void unuse_buffers(char *busy, audio_port_array *audio_ports)
4919c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid{
4929c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid	int i;
4939c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid	struct audio_port *audio_port;
4949c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid
4959c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid	FOR_ARRAY_ELEMENT(audio_ports, i, audio_port) {
4969c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid		busy[audio_port->buf_index] = 0;
4979c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid	}
4989c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid}
4999c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid
5009c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid/* assign which buffer each audio port on each instance should use */
5019c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reidstatic int allocate_buffers(struct pipeline *pipeline)
5029c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid{
5039c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid	int i;
5049c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid	struct instance *instance;
5059c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid	int need_buf = 0, peak_buf = 0;
5069c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid	char *busy;
5079c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid
5089c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid	/* first figure out how many buffers do we need */
5099c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid	FOR_ARRAY_ELEMENT(&pipeline->instances, i, instance) {
5109c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid		int in = ARRAY_COUNT(&instance->input_audio_ports);
5119c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid		int out = ARRAY_COUNT(&instance->output_audio_ports);
5129c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid
5139c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid		if (instance->properties & MODULE_INPLACE_BROKEN) {
5149c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid			/* We cannot reuse input buffer as output
5159c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid			 * buffer, so we need to use extra buffers */
5169c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid			need_buf += out;
5179c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid			peak_buf = MAX(peak_buf, need_buf);
5189c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid			need_buf -= in;
5199c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid		} else {
5209c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid			need_buf += out - in;
5219c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid			peak_buf = MAX(peak_buf, need_buf);
5229c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid		}
5239c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid	}
5249c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid
5259c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid	/* then allocate the buffers */
5269c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid	pipeline->peak_buf = peak_buf;
5279c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid	pipeline->buffers = (float **)calloc(peak_buf, sizeof(float *));
5289c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid
5299c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid	if (!pipeline->buffers) {
5309c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid		syslog(LOG_ERR, "failed to allocate buffers");
5319c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid		return -1;
5329c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid	}
5339c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid
5349c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid	for (i = 0; i < peak_buf; i++) {
5359c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid		size_t size = DSP_BUFFER_SIZE * sizeof(float);
5369c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid		float *buf = calloc(1, size);
5379c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid		if (!buf) {
5389c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid			syslog(LOG_ERR, "failed to allocate buf");
5399c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid			return -1;
5409c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid		}
5419c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid		pipeline->buffers[i] = buf;
5429c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid	}
5439c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid
5449c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid	/* Now assign buffer index for each instance's input/output ports */
5459c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid	busy = calloc(peak_buf, sizeof(*busy));
5469c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid	FOR_ARRAY_ELEMENT(&pipeline->instances, i, instance) {
5479c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid		int j;
5489c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid		struct audio_port *audio_port;
5499c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid
5509c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid		/* Collect input buffers from upstream */
5519c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid		FOR_ARRAY_ELEMENT(&instance->input_audio_ports, j, audio_port) {
5529c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid			audio_port->buf_index = audio_port->peer->buf_index;
5539c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid		}
5549c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid
5559c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid		/* If the module has the MODULE_INPLACE_BROKEN flag,
5569c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid		 * we cannot reuse input buffers as output buffers, so
5579c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid		 * we need to use extra buffers. For example, in this graph
5589c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid		 *
5599c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid		 * [A]
5609c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid		 * output_0={x}
5619c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid		 * output_1={y}
5629c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid		 * output_2={z}
5639c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid		 * output_3={w}
5649c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid		 * [B]
5659c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid		 * input_0={x}
5669c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid		 * input_1={y}
5679c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid		 * input_2={z}
5689c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid		 * input_3={w}
5699c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid		 * output_4={u}
5709c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid		 *
5719c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid		 * Then peak_buf for this pipeline is 4. However if
5729c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid		 * plugin B has the MODULE_INPLACE_BROKEN flag, then
5739c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid		 * peak_buf is 5 because plugin B cannot output to the
5749c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid		 * same buffer used for input.
5759c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid		 *
5769c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid		 * This means if we don't have the flag, we can free
5779c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid		 * the input buffers then allocate the output buffers,
5789c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid		 * but if we have the flag, we have to allocate the
5799c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid		 * output buffers before freeing the input buffers.
5809c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid		 */
5819c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid		if (instance->properties & MODULE_INPLACE_BROKEN) {
5829c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid			use_buffers(busy, &instance->output_audio_ports);
5839c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid			unuse_buffers(busy, &instance->input_audio_ports);
5849c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid		} else {
5859c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid			unuse_buffers(busy, &instance->input_audio_ports);
5869c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid			use_buffers(busy, &instance->output_audio_ports);
5879c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid		}
5889c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid	}
5899c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid	free(busy);
5909c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid
5919c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid	return 0;
5929c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid}
5939c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid
5949c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reidint cras_dsp_pipeline_load(struct pipeline *pipeline)
5959c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid{
5969c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid	int i;
5979c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid	struct instance *instance;
5989c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid
5999c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid	FOR_ARRAY_ELEMENT(&pipeline->instances, i, instance) {
6009c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid		struct plugin *plugin = instance->plugin;
6019c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid		if (load_module(plugin, instance) != 0)
6029c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid			return -1;
6039c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid	}
6049c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid
6059c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid	if (allocate_buffers(pipeline) != 0)
6069c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid		return -1;
6079c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid
6089c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid	return 0;
6099c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid}
6109c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid
6119c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid/* Calculates the total buffering delay of each instance from the source */
6129c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reidstatic void calculate_audio_delay(struct pipeline *pipeline)
6139c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid{
6149c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid	int i;
6159c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid	struct instance *instance;
6169c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid
6179c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid	FOR_ARRAY_ELEMENT(&pipeline->instances, i, instance) {
6189c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid		struct dsp_module *module = instance->module;
6199c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid		audio_port_array *audio_in = &instance->input_audio_ports;
6209c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid		struct audio_port *audio_port;
6219c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid		int delay = 0;
6229c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid		int j;
6239c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid
6249c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid		/* Finds the max delay of all modules that provide input to this
6259c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid		 * instance. */
6269c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid		FOR_ARRAY_ELEMENT(audio_in, j, audio_port) {
6279c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid			struct instance *upstream = find_instance_by_plugin(
6289c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid				&pipeline->instances, audio_port->peer->plugin);
6299c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid			delay = MAX(upstream->total_delay, delay);
6309c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid		}
6319c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid
6329c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid		instance->total_delay = delay + module->get_delay(module);
6339c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid	}
6349c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid}
6359c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid
6369c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reidint cras_dsp_pipeline_instantiate(struct pipeline *pipeline, int sample_rate)
6379c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid{
6389c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid	int i;
6399c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid	struct instance *instance;
6409c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid
6419c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid	FOR_ARRAY_ELEMENT(&pipeline->instances, i, instance) {
6429c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid		struct dsp_module *module = instance->module;
6439c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid		if (module->instantiate(module, sample_rate) != 0)
6449c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid			return -1;
6459c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid		instance->instantiated = 1;
6469c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid		syslog(LOG_DEBUG, "instantiate %s", instance->plugin->label);
6479c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid	}
6489c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid	pipeline->sample_rate = sample_rate;
6499c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid
6509c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid	FOR_ARRAY_ELEMENT(&pipeline->instances, i, instance) {
6519c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid		audio_port_array *audio_in = &instance->input_audio_ports;
6529c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid		audio_port_array *audio_out = &instance->output_audio_ports;
6539c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid		control_port_array *control_in = &instance->input_control_ports;
6549c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid		control_port_array *control_out =
6559c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid			&instance->output_control_ports;
6569c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid		int j;
6579c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid		struct audio_port *audio_port;
6589c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid		struct control_port *control_port;
6599c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid		struct dsp_module *module = instance->module;
6609c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid
6619c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid		/* connect audio ports */
6629c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid		FOR_ARRAY_ELEMENT(audio_in, j, audio_port) {
6639c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid			float *buf = pipeline->buffers[audio_port->buf_index];
6649c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid			module->connect_port(module,
6659c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid					     audio_port->original_index,
6669c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid					     buf);
6679c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid			syslog(LOG_DEBUG, "connect audio buf %d to %s:%d (in)",
6689c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid			       audio_port->buf_index, instance->plugin->title,
6699c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid			       audio_port->original_index);
6709c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid		}
6719c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid		FOR_ARRAY_ELEMENT(audio_out, j, audio_port) {
6729c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid			float *buf = pipeline->buffers[audio_port->buf_index];
6739c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid			module->connect_port(module,
6749c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid					     audio_port->original_index,
6759c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid					     buf);
6769c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid			syslog(LOG_DEBUG, "connect audio buf %d to %s:%d (out)",
6779c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid			       audio_port->buf_index, instance->plugin->title,
6789c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid			       audio_port->original_index);
6799c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid		}
6809c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid
6819c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid		/* connect control ports */
6829c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid		FOR_ARRAY_ELEMENT(control_in, j, control_port) {
6839c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid			/* Note for input control ports which has a
6849c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid			 * peer, we use &control_port->peer->value, so
6859c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid			 * we can get the peer port's output value
6869c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid			 * directly */
6879c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid			float *value = control_port->peer ?
6889c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid				&control_port->peer->value :
6899c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid				&control_port->value;
6909c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid			module->connect_port(module,
6919c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid					     control_port->original_index,
6929c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid					     value);
6939c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid			syslog(LOG_DEBUG,
6949c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid			       "connect control (val=%g) to %s:%d (in)",
6959c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid			       control_port->value, instance->plugin->title,
6969c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid			       control_port->original_index);
6979c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid		}
6989c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid		FOR_ARRAY_ELEMENT(control_out, j, control_port) {
6999c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid			module->connect_port(module,
7009c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid					     control_port->original_index,
7019c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid					     &control_port->value);
7029c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid			syslog(LOG_DEBUG,
7039c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid			       "connect control (val=%g) to %s:%d (out)",
7049c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid			       control_port->value, instance->plugin->title,
7059c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid			       control_port->original_index);
7069c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid		}
7079c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid	}
7089c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid
7099c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid	calculate_audio_delay(pipeline);
7109c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid	return 0;
7119c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid}
7129c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid
7139c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reidvoid cras_dsp_pipeline_deinstantiate(struct pipeline *pipeline)
7149c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid{
7159c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid	int i;
7169c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid	struct instance *instance;
7179c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid
7189c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid	FOR_ARRAY_ELEMENT(&pipeline->instances, i, instance) {
7199c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid		struct dsp_module *module = instance->module;
7209c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid		if (instance->instantiated) {
7219c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid			module->deinstantiate(module);
7229c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid			instance->instantiated = 0;
7239c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid		}
7249c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid	}
7259c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid	pipeline->sample_rate = 0;
7269c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid}
7279c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid
7289c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reidint cras_dsp_pipeline_get_delay(struct pipeline *pipeline)
7299c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid{
7309c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid	return pipeline->sink_instance->total_delay;
7319c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid}
7329c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid
7339c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reidint cras_dsp_pipeline_get_sample_rate(struct pipeline *pipeline)
7349c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid{
7359c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid	return pipeline->sample_rate;
7369c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid}
7379c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid
7389c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reidint cras_dsp_pipeline_get_num_input_channels(struct pipeline *pipeline)
7399c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid{
7409c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid	return pipeline->input_channels;
7419c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid}
7429c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid
7439c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reidint cras_dsp_pipeline_get_num_output_channels(struct pipeline *pipeline)
7449c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid{
7459c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid	return pipeline->output_channels;
7469c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid}
7479c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid
7489c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reidint cras_dsp_pipeline_get_peak_audio_buffers(struct pipeline *pipeline)
7499c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid{
7509c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid	return pipeline->peak_buf;
7519c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid}
7529c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid
7539c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reidstatic float *find_buffer(struct pipeline *pipeline,
7549c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid			  audio_port_array *audio_ports,
7559c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid			  int index)
7569c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid{
7579c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid	int i;
7589c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid	struct audio_port *audio_port;
7599c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid
7609c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid	FOR_ARRAY_ELEMENT(audio_ports, i, audio_port) {
7619c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid		if (audio_port->original_index == index)
7629c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid			return pipeline->buffers[audio_port->buf_index];
7639c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid	}
7649c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid	return NULL;
7659c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid}
7669c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid
7679c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reidfloat *cras_dsp_pipeline_get_source_buffer(struct pipeline *pipeline, int index)
7689c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid{
7699c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid	return find_buffer(pipeline,
7709c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid			   &pipeline->source_instance->output_audio_ports,
7719c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid			   index);
7729c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid}
7739c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid
7749c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reidfloat *cras_dsp_pipeline_get_sink_buffer(struct pipeline *pipeline, int index)
7759c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid{
7769c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid	return find_buffer(pipeline,
7779c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid			   &pipeline->sink_instance->input_audio_ports,
7789c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid			   index);
7799c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid}
7809c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid
7819c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reidvoid cras_dsp_pipeline_run(struct pipeline *pipeline, int sample_count)
7829c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid{
7839c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid	int i;
7849c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid	struct instance *instance;
7859c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid
7869c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid	FOR_ARRAY_ELEMENT(&pipeline->instances, i, instance) {
7879c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid		struct dsp_module *module = instance->module;
7889c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid		module->run(module, sample_count);
7899c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid	}
7909c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid}
7919c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid
7929c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reidvoid cras_dsp_pipeline_add_statistic(struct pipeline *pipeline,
7939c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid				     const struct timespec *time_delta,
7949c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid				     int samples)
7959c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid{
7969c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid	int64_t t;
7979c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid	if (samples <= 0)
7989c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid		return;
7999c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid
8009c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid	t = time_delta->tv_sec * 1000000000LL + time_delta->tv_nsec;
8019c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid
8029c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid	if (pipeline->total_blocks == 0) {
8039c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid		pipeline->max_time = t;
8049c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid		pipeline->min_time = t;
8059c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid	} else {
8069c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid		pipeline->max_time = MAX(pipeline->max_time, t);
8079c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid		pipeline->min_time = MIN(pipeline->min_time, t);
8089c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid	}
8099c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid
8109c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid	pipeline->total_blocks++;
8119c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid	pipeline->total_samples += samples;
8129c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid	pipeline->total_time += t;
8139c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid}
8149c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid
8159c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reidvoid cras_dsp_pipeline_apply(struct pipeline *pipeline,
8169c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid			     uint8_t *buf, unsigned int frames)
8179c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid{
8189c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid	size_t remaining;
8199c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid	size_t chunk;
8209c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid	size_t i;
8219c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid	int16_t *target;
8229c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid	unsigned int input_channels = pipeline->input_channels;
8239c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid	unsigned int output_channels = pipeline->output_channels;
8249c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid	float *source[input_channels];
8259c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid	float *sink[output_channels];
8269c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid	//struct timespec begin, end, delta;
8279c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid
8289c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid	if (!pipeline || frames == 0)
8299c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid		return;
8309c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid
8319c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid	//clock_gettime(CLOCK_THREAD_CPUTIME_ID, &begin);
8329c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid
8339c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid	target = (int16_t *)buf;
8349c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid
8359c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid	/* get pointers to source and sink buffers */
8369c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid	for (i = 0; i < input_channels; i++)
8379c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid		source[i] = cras_dsp_pipeline_get_source_buffer(pipeline, i);
8389c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid	for (i = 0; i < output_channels; i++)
8399c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid		sink[i] = cras_dsp_pipeline_get_sink_buffer(pipeline, i);
8409c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid
8419c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid	remaining = frames;
8429c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid
8439c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid	/* process at most DSP_BUFFER_SIZE frames each loop */
8449c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid	while (remaining > 0) {
8459c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid		chunk = MIN(remaining, (size_t)DSP_BUFFER_SIZE);
8469c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid
8479c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid		/* deinterleave and convert to float */
8489c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid		dsp_util_deinterleave(target, source, input_channels, chunk);
8499c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid
8509c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid		/* Run the pipeline */
8519c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid		cras_dsp_pipeline_run(pipeline, chunk);
8529c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid
8539c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid		/* interleave and convert back to int16_t */
8549c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid		dsp_util_interleave(sink, target, output_channels, chunk);
8559c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid
8569c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid		target += chunk * output_channels;
8579c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid		remaining -= chunk;
8589c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid	}
8599c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid
8609c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid	//clock_gettime(CLOCK_THREAD_CPUTIME_ID, &end);
8619c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid	//subtract_timespecs(&end, &begin, &delta);
8629c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid	//cras_dsp_pipeline_add_statistic(pipeline, &delta, frames);
8639c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid}
8649c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid
8659c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reidvoid cras_dsp_pipeline_free(struct pipeline *pipeline)
8669c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid{
8679c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid	int i;
8689c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid	struct instance *instance;
8699c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid
8709c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid	FOR_ARRAY_ELEMENT(&pipeline->instances, i, instance) {
8719c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid		struct dsp_module *module = instance->module;
8729c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid		instance->plugin = NULL;
8739c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid		ARRAY_FREE(&instance->input_audio_ports);
8749c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid		ARRAY_FREE(&instance->input_control_ports);
8759c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid		ARRAY_FREE(&instance->output_audio_ports);
8769c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid		ARRAY_FREE(&instance->output_control_ports);
8779c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid
8789c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid		if (module) {
8799c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid			if (instance->instantiated) {
8809c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid				module->deinstantiate(module);
8819c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid				instance->instantiated = 0;
8829c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid			}
8839c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid			module->free_module(module);
8849c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid			instance->module = NULL;
8859c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid		}
8869c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid	}
8879c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid
8889c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid	pipeline->ini = NULL;
8899c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid	ARRAY_FREE(&pipeline->instances);
8909c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid
8919c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid	for (i = 0; i < pipeline->peak_buf; i++)
8929c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid		free(pipeline->buffers[i]);
8939c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid	free(pipeline->buffers);
8949c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid	free(pipeline);
8959c94a7e4053538cacb9695b15da4b1cc7857d09dDylan Reid}
896