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