diff options
Diffstat (limited to 'cras/src/server/cras_dsp_pipeline.c')
-rw-r--r-- | cras/src/server/cras_dsp_pipeline.c | 1007 |
1 files changed, 0 insertions, 1007 deletions
diff --git a/cras/src/server/cras_dsp_pipeline.c b/cras/src/server/cras_dsp_pipeline.c deleted file mode 100644 index 9e492ac5..00000000 --- a/cras/src/server/cras_dsp_pipeline.c +++ /dev/null @@ -1,1007 +0,0 @@ -/* Copyright (c) 2012 The Chromium OS Authors. All rights reserved. - * Use of this source code is governed by a BSD-style license that can be - * found in the LICENSE file. - */ - -#include <inttypes.h> -#include <sys/param.h> -#include <syslog.h> - -#include "cras_util.h" -#include "cras_dsp_module.h" -#include "cras_dsp_pipeline.h" -#include "dsp_util.h" - -/* We have a static representation of the dsp graph in a "struct ini", - * and here we will construct a dynamic representation of it in a - * "struct pipeline". The difference between the static one and the - * dynamic one is that we will only include the subset of the dsp - * graph actually needed in the dynamic one (so those plugins that are - * disabled will not be included). Here are the mapping between the - * static representation and the dynamic representation: - * - * static dynamic - * ------------- -------------------------------------- - * struct ini struct pipeline - * struct plugin struct instance - * strict port struct audio_port, struct control_port - * - * For example, if the ini file specifies these plugins and their - * connections: - * - * [A] - * output_0={audio} - * [B] - * input_0={audio} - * output_1={result} - * [C] - * input_0={result} - * - * That is, A connects to B, and B connects to C. If the plugin B is - * now disabled, in the pipeline we construct there will only be two - * instances (A and C) and the audio ports on these instances will - * connect to each other directly, bypassing B. - */ - -/* This represents an audio port on an instance. */ -struct audio_port { - struct audio_port *peer; /* the audio port this port connects to */ - struct plugin *plugin; /* the plugin corresponds to the instance */ - int original_index; /* the port index in the plugin */ - int buf_index; /* the buffer index in the pipeline */ -}; - -/* This represents a control port on an instance. */ -struct control_port { - struct control_port *peer; /* the control port this port connects to */ - struct plugin *plugin; /* the plugin corresponds to the instance */ - int original_index; /* the port index in the plugin */ - float value; /* the value of the control port */ -}; - -DECLARE_ARRAY_TYPE(struct audio_port, audio_port_array); -DECLARE_ARRAY_TYPE(struct control_port, control_port_array); - -/* An instance is a dynamic representation of a plugin. We only create - * an instance when a plugin is needed (data actually flows through it - * and it is not disabled). An instance also contains a pointer to a - * struct dsp_module, which is the implementation of the plugin */ -struct instance { - /* The plugin this instance corresponds to */ - struct plugin *plugin; - - /* These are the ports on this instance. The difference - * between this and the port array in a struct plugin is that - * the ports skip disabled plugins and connect to the upstream - * ports directly. - */ - audio_port_array input_audio_ports; - audio_port_array output_audio_ports; - control_port_array input_control_ports; - control_port_array output_control_ports; - - /* The implementation of the plugin */ - struct dsp_module *module; - - /* Whether this module's instantiate() function has been called */ - int instantiated; - - /* This caches the value returned from get_properties() of a module */ - int properties; - - /* This is the total buffering delay from source to this instance. It is - * in number of frames. */ - int total_delay; -}; - -DECLARE_ARRAY_TYPE(struct instance, instance_array) - -/* An pipeline is a dynamic representation of a dsp ini file. */ -struct pipeline { - /* The purpose of the pipeline. "playback" or "capture" */ - const char *purpose; - - /* The ini file this pipeline comes from */ - struct ini *ini; - - /* All needed instances for this pipeline. It is sorted in an - * order that if instance B depends on instance A, then A will - * appear in front of B. */ - instance_array instances; - - /* The maximum number of audio buffers that will be used at - * the same time for this pipeline */ - int peak_buf; - - /* The audio data buffers */ - float **buffers; - - /* The instance where the audio data flow in */ - struct instance *source_instance; - - /* The instance where the audio data flow out */ - struct instance *sink_instance; - - /* The number of audio channels for this pipeline */ - int input_channels; - int output_channels; - - /* The audio sampling rate for this pipleine. It is zero if - * cras_dsp_pipeline_instantiate() has not been called. */ - int sample_rate; - - /* The total time it takes to run the pipeline, in nanoseconds. */ - int64_t total_time; - - /* The max/min time it takes to run the pipeline, in nanoseconds. */ - int64_t max_time; - int64_t min_time; - - /* The number of blocks the pipeline. */ - int64_t total_blocks; - - /* The total number of sample frames the pipeline processed */ - int64_t total_samples; -}; - -static struct instance *find_instance_by_plugin(const instance_array *instances, - const struct plugin *plugin) -{ - int i; - struct instance *instance; - - ARRAY_ELEMENT_FOREACH (instances, i, instance) { - if (instance->plugin == plugin) - return instance; - } - - return NULL; -} - -/* Finds out where the data sent to plugin:index come from. The issue - * we need to handle here is the previous plugin may be disabled, so - * we need to go upstream until we find the real origin */ -static int find_origin_port(struct ini *ini, const instance_array *instances, - const struct plugin *plugin, int index, - const struct plugin **origin, int *origin_index) -{ - enum port_type type; - struct port *port; - int flow_id; - struct flow *flow; - int i, k; - int found; - - port = ARRAY_ELEMENT(&plugin->ports, index); - type = port->type; - flow_id = port->flow_id; - if (flow_id == INVALID_FLOW_ID) - return -1; - flow = ARRAY_ELEMENT(&ini->flows, flow_id); - - /* move to the previous plugin */ - plugin = flow->from; - index = flow->from_port; - - /* if the plugin is not disabled, it will be pointed by some instance */ - if (find_instance_by_plugin(instances, plugin)) { - *origin = plugin; - *origin_index = index; - return 0; - } - - /* Now we know the previous plugin is disabled, we need to go - * upstream. We assume the k-th output port of the plugin - * corresponds to the k-th input port of the plugin (with the - * same type) */ - - k = 0; - found = 0; - ARRAY_ELEMENT_FOREACH (&plugin->ports, i, port) { - if (index == i) { - found = 1; - break; - } - if (port->direction == PORT_OUTPUT && port->type == type) - k++; - } - if (!found) - return -1; - - found = 0; - ARRAY_ELEMENT_FOREACH (&plugin->ports, i, port) { - if (port->direction == PORT_INPUT && port->type == type) { - if (k-- == 0) { - index = i; - found = 1; - break; - } - } - } - if (!found) - return -1; - - return find_origin_port(ini, instances, plugin, index, origin, - origin_index); -} - -static struct audio_port *find_output_audio_port(instance_array *instances, - const struct plugin *plugin, - int index) -{ - int i; - struct instance *instance; - struct audio_port *audio_port; - - instance = find_instance_by_plugin(instances, plugin); - if (!instance) - return NULL; - - ARRAY_ELEMENT_FOREACH (&instance->output_audio_ports, i, audio_port) { - if (audio_port->original_index == index) - return audio_port; - } - - return NULL; -} - -static struct control_port *find_output_control_port(instance_array *instances, - const struct plugin *plugin, - int index) -{ - int i; - struct instance *instance; - struct control_port *control_port; - - instance = find_instance_by_plugin(instances, plugin); - if (!instance) - return NULL; - - ARRAY_ELEMENT_FOREACH (&instance->output_control_ports, i, - control_port) { - if (control_port->original_index == index) - return control_port; - } - - return NULL; -} - -static char is_disabled(struct plugin *plugin, struct cras_expr_env *env) -{ - char disabled; - return (plugin->disable_expr && - cras_expr_expression_eval_boolean(plugin->disable_expr, env, - &disabled) == 0 && - disabled == 1); -} - -static int topological_sort(struct pipeline *pipeline, - struct cras_expr_env *env, struct plugin *plugin, - char *visited) -{ - struct port *port; - struct flow *flow; - int index; - int i; - int flow_id; - struct instance *instance; - struct ini *ini = pipeline->ini; - - index = ARRAY_INDEX(&ini->plugins, plugin); - if (visited[index]) - return 0; - visited[index] = 1; - - ARRAY_ELEMENT_FOREACH (&plugin->ports, i, port) { - if (port->flow_id == INVALID_FLOW_ID) - continue; - flow_id = port->flow_id; - flow = ARRAY_ELEMENT(&ini->flows, flow_id); - if (!flow->from) { - syslog(LOG_ERR, "no plugin flows to %s:%d", - plugin->title, i); - return -1; - } - if (topological_sort(pipeline, env, flow->from, visited) < 0) - return -1; - } - - /* if the plugin is disabled, we don't construct an instance for it */ - if (is_disabled(plugin, env)) - return 0; - - instance = ARRAY_APPEND_ZERO(&pipeline->instances); - instance->plugin = plugin; - - /* constructs audio and control ports for the instance */ - ARRAY_ELEMENT_FOREACH (&plugin->ports, i, port) { - int need_connect = (port->flow_id != INVALID_FLOW_ID && - port->direction == PORT_INPUT); - const struct plugin *origin = NULL; - int origin_index = 0; - - if (need_connect) { - if (find_origin_port(ini, &pipeline->instances, plugin, - i, &origin, &origin_index) < 0) - return -1; - } - - if (port->type == PORT_AUDIO) { - audio_port_array *audio_port_array = - (port->direction == PORT_INPUT) ? - &instance->input_audio_ports : - &instance->output_audio_ports; - struct audio_port *audio_port = - ARRAY_APPEND_ZERO(audio_port_array); - audio_port->plugin = plugin; - audio_port->original_index = i; - if (need_connect) { - struct audio_port *from; - from = find_output_audio_port( - &pipeline->instances, origin, - origin_index); - if (!from) - return -1; - from->peer = audio_port; - audio_port->peer = from; - } - } else if (port->type == PORT_CONTROL) { - control_port_array *control_port_array = - (port->direction == PORT_INPUT) ? - &instance->input_control_ports : - &instance->output_control_ports; - struct control_port *control_port = - ARRAY_APPEND_ZERO(control_port_array); - control_port->plugin = plugin; - control_port->original_index = i; - control_port->value = port->init_value; - if (need_connect) { - struct control_port *from; - from = find_output_control_port( - &pipeline->instances, origin, - origin_index); - if (!from) - return -1; - from->peer = control_port; - control_port->peer = from; - } - } - } - - return 0; -} - -static struct plugin *find_enabled_builtin_plugin(struct ini *ini, - const char *label, - const char *purpose, - struct cras_expr_env *env) -{ - int i; - struct plugin *plugin, *found = NULL; - - ARRAY_ELEMENT_FOREACH (&ini->plugins, i, plugin) { - if (strcmp(plugin->library, "builtin") != 0) - continue; - if (strcmp(plugin->label, label) != 0) - continue; - if (!plugin->purpose || strcmp(plugin->purpose, purpose) != 0) - continue; - if (is_disabled(plugin, env)) - continue; - if (found) { - syslog(LOG_ERR, "two %s plugins enabled: %s and %s", - label, found->title, plugin->title); - return NULL; - } - found = plugin; - } - - return found; -} - -struct pipeline *cras_dsp_pipeline_create(struct ini *ini, - struct cras_expr_env *env, - const char *purpose) -{ - struct pipeline *pipeline; - int n; - char *visited; - int rc; - struct plugin *source = - find_enabled_builtin_plugin(ini, "source", purpose, env); - struct plugin *sink = - find_enabled_builtin_plugin(ini, "sink", purpose, env); - - if (!source || !sink) { - syslog(LOG_DEBUG, - "no enabled source or sink found %p/%p for %s", source, - sink, purpose); - return NULL; - } - - pipeline = calloc(1, sizeof(struct pipeline)); - if (!pipeline) { - syslog(LOG_ERR, "no memory for pipeline"); - return NULL; - } - - pipeline->ini = ini; - pipeline->purpose = purpose; - /* create instances for needed plugins, in the order of dependency */ - n = ARRAY_COUNT(&ini->plugins); - visited = calloc(1, n); - rc = topological_sort(pipeline, env, sink, visited); - free(visited); - - if (rc < 0) { - syslog(LOG_ERR, "failed to construct pipeline"); - cras_dsp_pipeline_free(pipeline); - return NULL; - } - - pipeline->source_instance = - find_instance_by_plugin(&pipeline->instances, source); - pipeline->sink_instance = - find_instance_by_plugin(&pipeline->instances, sink); - - if (!pipeline->source_instance || !pipeline->sink_instance) { - syslog(LOG_ERR, "source(%p) or sink(%p) missing/disabled?", - source, sink); - cras_dsp_pipeline_free(pipeline); - return NULL; - } - - pipeline->input_channels = - ARRAY_COUNT(&pipeline->source_instance->output_audio_ports); - pipeline->output_channels = - ARRAY_COUNT(&pipeline->sink_instance->input_audio_ports); - if (pipeline->output_channels > pipeline->input_channels) { - /* Can't increase channel count, no where to put them. */ - syslog(LOG_ERR, "DSP output more channels than input\n"); - cras_dsp_pipeline_free(pipeline); - return NULL; - } - - return pipeline; -} - -static int load_module(struct plugin *plugin, struct instance *instance) -{ - struct dsp_module *module; - module = cras_dsp_module_load_builtin(plugin); - if (!module) - module = cras_dsp_module_load_ladspa(plugin); - if (!module) - return -1; - instance->module = module; - instance->properties = module->get_properties(module); - return 0; -} - -static void use_buffers(char *busy, audio_port_array *audio_ports) -{ - int i, k = 0; - struct audio_port *audio_port; - - ARRAY_ELEMENT_FOREACH (audio_ports, i, audio_port) { - while (busy[k]) - k++; - audio_port->buf_index = k; - busy[k] = 1; - } -} - -static void unuse_buffers(char *busy, audio_port_array *audio_ports) -{ - int i; - struct audio_port *audio_port; - - ARRAY_ELEMENT_FOREACH (audio_ports, i, audio_port) { - busy[audio_port->buf_index] = 0; - } -} - -/* assign which buffer each audio port on each instance should use */ -static int allocate_buffers(struct pipeline *pipeline) -{ - int i; - struct instance *instance; - int need_buf = 0, peak_buf = 0; - char *busy; - - /* first figure out how many buffers do we need */ - ARRAY_ELEMENT_FOREACH (&pipeline->instances, i, instance) { - int in = ARRAY_COUNT(&instance->input_audio_ports); - int out = ARRAY_COUNT(&instance->output_audio_ports); - - if (instance->properties & MODULE_INPLACE_BROKEN) { - /* We cannot reuse input buffer as output - * buffer, so we need to use extra buffers */ - need_buf += out; - peak_buf = MAX(peak_buf, need_buf); - need_buf -= in; - } else { - need_buf += out - in; - peak_buf = MAX(peak_buf, need_buf); - } - } - /* - * cras_dsp_pipeline_create creates pipeline with source and sink and it - * makes sure all ports could be accessed from some sources, which means - * that there is at least one source with out > 0 and in == 0. - * This will give us peak_buf > 0 in the previous calculation. - */ - if (peak_buf <= 0) { - syslog(LOG_ERR, "peak_buf = %d, which must be greater than 0.", - peak_buf); - return -1; - } - - /* then allocate the buffers */ - pipeline->peak_buf = peak_buf; - pipeline->buffers = (float **)calloc(peak_buf, sizeof(float *)); - - if (!pipeline->buffers) { - syslog(LOG_ERR, "failed to allocate buffers"); - return -1; - } - - for (i = 0; i < peak_buf; i++) { - size_t size = DSP_BUFFER_SIZE * sizeof(float); - float *buf = calloc(1, size); - if (!buf) { - syslog(LOG_ERR, "failed to allocate buf"); - return -1; - } - pipeline->buffers[i] = buf; - } - - /* Now assign buffer index for each instance's input/output ports */ - busy = calloc(peak_buf, sizeof(*busy)); - ARRAY_ELEMENT_FOREACH (&pipeline->instances, i, instance) { - int j; - struct audio_port *audio_port; - - /* Collect input buffers from upstream */ - ARRAY_ELEMENT_FOREACH (&instance->input_audio_ports, j, - audio_port) { - audio_port->buf_index = audio_port->peer->buf_index; - } - - /* If the module has the MODULE_INPLACE_BROKEN flag, - * we cannot reuse input buffers as output buffers, so - * we need to use extra buffers. For example, in this graph - * - * [A] - * output_0={x} - * output_1={y} - * output_2={z} - * output_3={w} - * [B] - * input_0={x} - * input_1={y} - * input_2={z} - * input_3={w} - * output_4={u} - * - * Then peak_buf for this pipeline is 4. However if - * plugin B has the MODULE_INPLACE_BROKEN flag, then - * peak_buf is 5 because plugin B cannot output to the - * same buffer used for input. - * - * This means if we don't have the flag, we can free - * the input buffers then allocate the output buffers, - * but if we have the flag, we have to allocate the - * output buffers before freeing the input buffers. - */ - if (instance->properties & MODULE_INPLACE_BROKEN) { - use_buffers(busy, &instance->output_audio_ports); - unuse_buffers(busy, &instance->input_audio_ports); - } else { - unuse_buffers(busy, &instance->input_audio_ports); - use_buffers(busy, &instance->output_audio_ports); - } - } - free(busy); - - return 0; -} - -int cras_dsp_pipeline_load(struct pipeline *pipeline) -{ - int i; - struct instance *instance; - - ARRAY_ELEMENT_FOREACH (&pipeline->instances, i, instance) { - struct plugin *plugin = instance->plugin; - if (load_module(plugin, instance) != 0) - return -1; - } - - if (allocate_buffers(pipeline) != 0) - return -1; - - return 0; -} - -/* Calculates the total buffering delay of each instance from the source */ -static void calculate_audio_delay(struct pipeline *pipeline) -{ - int i; - struct instance *instance; - - ARRAY_ELEMENT_FOREACH (&pipeline->instances, i, instance) { - struct dsp_module *module = instance->module; - audio_port_array *audio_in = &instance->input_audio_ports; - struct audio_port *audio_port; - int delay = 0; - int j; - - /* Finds the max delay of all modules that provide input to this - * instance. */ - ARRAY_ELEMENT_FOREACH (audio_in, j, audio_port) { - struct instance *upstream = find_instance_by_plugin( - &pipeline->instances, audio_port->peer->plugin); - delay = MAX(upstream->total_delay, delay); - } - - instance->total_delay = delay + module->get_delay(module); - } -} - -int cras_dsp_pipeline_instantiate(struct pipeline *pipeline, int sample_rate) -{ - int i; - struct instance *instance; - - ARRAY_ELEMENT_FOREACH (&pipeline->instances, i, instance) { - struct dsp_module *module = instance->module; - if (module->instantiate(module, sample_rate) != 0) - return -1; - instance->instantiated = 1; - syslog(LOG_DEBUG, "instantiate %s", instance->plugin->label); - } - pipeline->sample_rate = sample_rate; - - ARRAY_ELEMENT_FOREACH (&pipeline->instances, i, instance) { - audio_port_array *audio_in = &instance->input_audio_ports; - audio_port_array *audio_out = &instance->output_audio_ports; - control_port_array *control_in = &instance->input_control_ports; - control_port_array *control_out = - &instance->output_control_ports; - int j; - struct audio_port *audio_port; - struct control_port *control_port; - struct dsp_module *module = instance->module; - - /* connect audio ports */ - ARRAY_ELEMENT_FOREACH (audio_in, j, audio_port) { - float *buf = pipeline->buffers[audio_port->buf_index]; - module->connect_port(module, audio_port->original_index, - buf); - syslog(LOG_DEBUG, "connect audio buf %d to %s:%d (in)", - audio_port->buf_index, instance->plugin->title, - audio_port->original_index); - } - ARRAY_ELEMENT_FOREACH (audio_out, j, audio_port) { - float *buf = pipeline->buffers[audio_port->buf_index]; - module->connect_port(module, audio_port->original_index, - buf); - syslog(LOG_DEBUG, "connect audio buf %d to %s:%d (out)", - audio_port->buf_index, instance->plugin->title, - audio_port->original_index); - } - - /* connect control ports */ - ARRAY_ELEMENT_FOREACH (control_in, j, control_port) { - /* Note for input control ports which has a - * peer, we use &control_port->peer->value, so - * we can get the peer port's output value - * directly */ - float *value = control_port->peer ? - &control_port->peer->value : - &control_port->value; - module->connect_port( - module, control_port->original_index, value); - syslog(LOG_DEBUG, - "connect control (val=%g) to %s:%d (in)", - control_port->value, instance->plugin->title, - control_port->original_index); - } - ARRAY_ELEMENT_FOREACH (control_out, j, control_port) { - module->connect_port(module, - control_port->original_index, - &control_port->value); - syslog(LOG_DEBUG, - "connect control (val=%g) to %s:%d (out)", - control_port->value, instance->plugin->title, - control_port->original_index); - } - } - - calculate_audio_delay(pipeline); - return 0; -} - -void cras_dsp_pipeline_deinstantiate(struct pipeline *pipeline) -{ - int i; - struct instance *instance; - - ARRAY_ELEMENT_FOREACH (&pipeline->instances, i, instance) { - struct dsp_module *module = instance->module; - if (instance->instantiated) { - module->deinstantiate(module); - instance->instantiated = 0; - } - } - pipeline->sample_rate = 0; -} - -int cras_dsp_pipeline_get_delay(struct pipeline *pipeline) -{ - return pipeline->sink_instance->total_delay; -} - -int cras_dsp_pipeline_get_sample_rate(struct pipeline *pipeline) -{ - return pipeline->sample_rate; -} - -int cras_dsp_pipeline_get_num_input_channels(struct pipeline *pipeline) -{ - return pipeline->input_channels; -} - -int cras_dsp_pipeline_get_num_output_channels(struct pipeline *pipeline) -{ - return pipeline->output_channels; -} - -int cras_dsp_pipeline_get_peak_audio_buffers(struct pipeline *pipeline) -{ - return pipeline->peak_buf; -} - -static float *find_buffer(struct pipeline *pipeline, - audio_port_array *audio_ports, int index) -{ - int i; - struct audio_port *audio_port; - - ARRAY_ELEMENT_FOREACH (audio_ports, i, audio_port) { - if (audio_port->original_index == index) - return pipeline->buffers[audio_port->buf_index]; - } - return NULL; -} - -float *cras_dsp_pipeline_get_source_buffer(struct pipeline *pipeline, int index) -{ - return find_buffer(pipeline, - &pipeline->source_instance->output_audio_ports, - index); -} - -float *cras_dsp_pipeline_get_sink_buffer(struct pipeline *pipeline, int index) -{ - return find_buffer(pipeline, - &pipeline->sink_instance->input_audio_ports, index); -} - -void cras_dsp_pipeline_set_sink_ext_module(struct pipeline *pipeline, - struct ext_dsp_module *ext_module) -{ - cras_dsp_module_set_sink_ext_module(pipeline->sink_instance->module, - ext_module); -} - -struct ini *cras_dsp_pipeline_get_ini(struct pipeline *pipeline) -{ - return pipeline->ini; -} - -void cras_dsp_pipeline_run(struct pipeline *pipeline, int sample_count) -{ - int i; - struct instance *instance; - - ARRAY_ELEMENT_FOREACH (&pipeline->instances, i, instance) { - struct dsp_module *module = instance->module; - module->run(module, sample_count); - } -} - -void cras_dsp_pipeline_add_statistic(struct pipeline *pipeline, - const struct timespec *time_delta, - int samples) -{ - int64_t t; - if (samples <= 0) - return; - - t = time_delta->tv_sec * 1000000000LL + time_delta->tv_nsec; - - if (pipeline->total_blocks == 0) { - pipeline->max_time = t; - pipeline->min_time = t; - } else { - pipeline->max_time = MAX(pipeline->max_time, t); - pipeline->min_time = MIN(pipeline->min_time, t); - } - - pipeline->total_blocks++; - pipeline->total_samples += samples; - pipeline->total_time += t; -} - -int cras_dsp_pipeline_apply(struct pipeline *pipeline, uint8_t *buf, - snd_pcm_format_t format, unsigned int frames) -{ - size_t remaining; - size_t chunk; - size_t i; - unsigned int input_channels = pipeline->input_channels; - unsigned int output_channels = pipeline->output_channels; - float *source[input_channels]; - float *sink[output_channels]; - struct timespec begin, end, delta; - int rc; - - if (!pipeline || frames == 0) - return 0; - - clock_gettime(CLOCK_THREAD_CPUTIME_ID, &begin); - - /* get pointers to source and sink buffers */ - for (i = 0; i < input_channels; i++) - source[i] = cras_dsp_pipeline_get_source_buffer(pipeline, i); - for (i = 0; i < output_channels; i++) - sink[i] = cras_dsp_pipeline_get_sink_buffer(pipeline, i); - - remaining = frames; - - /* process at most DSP_BUFFER_SIZE frames each loop */ - while (remaining > 0) { - chunk = MIN(remaining, (size_t)DSP_BUFFER_SIZE); - - /* deinterleave and convert to float */ - rc = dsp_util_deinterleave(buf, source, input_channels, format, - chunk); - if (rc) - return rc; - - /* Run the pipeline */ - cras_dsp_pipeline_run(pipeline, chunk); - - /* interleave and convert back to int16_t */ - rc = dsp_util_interleave(sink, buf, output_channels, format, - chunk); - if (rc) - return rc; - - buf += chunk * output_channels * PCM_FORMAT_WIDTH(format) / 8; - remaining -= chunk; - } - - clock_gettime(CLOCK_THREAD_CPUTIME_ID, &end); - subtract_timespecs(&end, &begin, &delta); - cras_dsp_pipeline_add_statistic(pipeline, &delta, frames); - return 0; -} - -void cras_dsp_pipeline_free(struct pipeline *pipeline) -{ - int i; - struct instance *instance; - - ARRAY_ELEMENT_FOREACH (&pipeline->instances, i, instance) { - struct dsp_module *module = instance->module; - instance->plugin = NULL; - ARRAY_FREE(&instance->input_audio_ports); - ARRAY_FREE(&instance->input_control_ports); - ARRAY_FREE(&instance->output_audio_ports); - ARRAY_FREE(&instance->output_control_ports); - - if (module) { - if (instance->instantiated) { - module->deinstantiate(module); - instance->instantiated = 0; - } - module->free_module(module); - instance->module = NULL; - } - } - - pipeline->ini = NULL; - ARRAY_FREE(&pipeline->instances); - - for (i = 0; i < pipeline->peak_buf; i++) - free(pipeline->buffers[i]); - free(pipeline->buffers); - free(pipeline); -} - -static void dump_audio_ports(struct dumper *d, const char *name, - audio_port_array *audio_ports) -{ - int i; - struct audio_port *audio_port; - int n = ARRAY_COUNT(audio_ports); - - if (n == 0) - return; - dumpf(d, " %s (%d) =\n", name, n); - - ARRAY_ELEMENT_FOREACH (audio_ports, i, audio_port) { - dumpf(d, " %p, peer %p, orig=%d, buf=%d\n", audio_port, - audio_port->peer, audio_port->original_index, - audio_port->buf_index); - } -} - -static void dump_control_ports(struct dumper *d, const char *name, - control_port_array *control_ports) -{ - int i; - struct control_port *control_port; - int n = ARRAY_COUNT(control_ports); - - if (n == 0) - return; - dumpf(d, " %s (%d) =\n", name, ARRAY_COUNT(control_ports)); - - ARRAY_ELEMENT_FOREACH (control_ports, i, control_port) { - dumpf(d, " %p, peer %p, orig=%d, value=%g\n", control_port, - control_port->peer, control_port->original_index, - control_port->value); - } -} - -void cras_dsp_pipeline_dump(struct dumper *d, struct pipeline *pipeline) -{ - int i; - struct instance *instance; - - dumpf(d, "---- pipeline dump begin ----\n"); - dumpf(d, "pipeline (%s):\n", pipeline->purpose); - dumpf(d, " input channels: %d\n", pipeline->input_channels); - dumpf(d, " output channels: %d\n", pipeline->output_channels); - dumpf(d, " sample_rate: %d\n", pipeline->sample_rate); - dumpf(d, " processed samples: %" PRId64 "\n", pipeline->total_samples); - dumpf(d, " processed blocks: %" PRId64 "\n", pipeline->total_blocks); - dumpf(d, " total processing time: %" PRId64 "ns\n", - pipeline->total_time); - if (pipeline->total_blocks) { - dumpf(d, " average block size: %" PRId64 "\n", - pipeline->total_samples / pipeline->total_blocks); - dumpf(d, " avg processing time per block: %" PRId64 "ns\n", - pipeline->total_time / pipeline->total_blocks); - } - dumpf(d, " min processing time per block: %" PRId64 "ns\n", - pipeline->min_time); - dumpf(d, " max processing time per block: %" PRId64 "ns\n", - pipeline->max_time); - if (pipeline->total_samples) - dumpf(d, " cpu load: %g%%\n", - pipeline->total_time * 1e-9 / pipeline->total_samples * - pipeline->sample_rate * 100); - dumpf(d, " instances (%d):\n", ARRAY_COUNT(&pipeline->instances)); - ARRAY_ELEMENT_FOREACH (&pipeline->instances, i, instance) { - struct dsp_module *module = instance->module; - dumpf(d, " [%d]%s mod=%p, total delay=%d\n", i, - instance->plugin->title, module, instance->total_delay); - if (module) - module->dump(module, d); - dump_audio_ports(d, "input_audio_ports", - &instance->input_audio_ports); - dump_audio_ports(d, "output_audio_ports", - &instance->output_audio_ports); - dump_control_ports(d, "input_control_ports", - &instance->input_control_ports); - dump_control_ports(d, "output_control_ports", - &instance->output_control_ports); - } - dumpf(d, " peak_buf = %d\n", pipeline->peak_buf); - dumpf(d, "---- pipeline dump end ----\n"); -} |