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