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_DEBUG,
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 module = cras_dsp_module_load_ladspa(plugin);
472 if (!module)
473 return -1;
474 instance->module = module;
475 instance->properties = module->get_properties(module);
476 return 0;
477 }
478
use_buffers(char * busy,audio_port_array * audio_ports)479 static void use_buffers(char *busy, audio_port_array *audio_ports)
480 {
481 int i, k = 0;
482 struct audio_port *audio_port;
483
484 FOR_ARRAY_ELEMENT(audio_ports, i, audio_port) {
485 while (busy[k])
486 k++;
487 audio_port->buf_index = k;
488 busy[k] = 1;
489 }
490 }
491
unuse_buffers(char * busy,audio_port_array * audio_ports)492 static void unuse_buffers(char *busy, audio_port_array *audio_ports)
493 {
494 int i;
495 struct audio_port *audio_port;
496
497 FOR_ARRAY_ELEMENT(audio_ports, i, audio_port) {
498 busy[audio_port->buf_index] = 0;
499 }
500 }
501
502 /* assign which buffer each audio port on each instance should use */
allocate_buffers(struct pipeline * pipeline)503 static int allocate_buffers(struct pipeline *pipeline)
504 {
505 int i;
506 struct instance *instance;
507 int need_buf = 0, peak_buf = 0;
508 char *busy;
509
510 /* first figure out how many buffers do we need */
511 FOR_ARRAY_ELEMENT(&pipeline->instances, i, instance) {
512 int in = ARRAY_COUNT(&instance->input_audio_ports);
513 int out = ARRAY_COUNT(&instance->output_audio_ports);
514
515 if (instance->properties & MODULE_INPLACE_BROKEN) {
516 /* We cannot reuse input buffer as output
517 * buffer, so we need to use extra buffers */
518 need_buf += out;
519 peak_buf = MAX(peak_buf, need_buf);
520 need_buf -= in;
521 } else {
522 need_buf += out - in;
523 peak_buf = MAX(peak_buf, need_buf);
524 }
525 }
526
527 /* then allocate the buffers */
528 pipeline->peak_buf = peak_buf;
529 pipeline->buffers = (float **)calloc(peak_buf, sizeof(float *));
530
531 if (!pipeline->buffers) {
532 syslog(LOG_ERR, "failed to allocate buffers");
533 return -1;
534 }
535
536 for (i = 0; i < peak_buf; i++) {
537 size_t size = DSP_BUFFER_SIZE * sizeof(float);
538 float *buf = calloc(1, size);
539 if (!buf) {
540 syslog(LOG_ERR, "failed to allocate buf");
541 return -1;
542 }
543 pipeline->buffers[i] = buf;
544 }
545
546 /* Now assign buffer index for each instance's input/output ports */
547 busy = calloc(peak_buf, sizeof(*busy));
548 FOR_ARRAY_ELEMENT(&pipeline->instances, i, instance) {
549 int j;
550 struct audio_port *audio_port;
551
552 /* Collect input buffers from upstream */
553 FOR_ARRAY_ELEMENT(&instance->input_audio_ports, j, audio_port) {
554 audio_port->buf_index = audio_port->peer->buf_index;
555 }
556
557 /* If the module has the MODULE_INPLACE_BROKEN flag,
558 * we cannot reuse input buffers as output buffers, so
559 * we need to use extra buffers. For example, in this graph
560 *
561 * [A]
562 * output_0={x}
563 * output_1={y}
564 * output_2={z}
565 * output_3={w}
566 * [B]
567 * input_0={x}
568 * input_1={y}
569 * input_2={z}
570 * input_3={w}
571 * output_4={u}
572 *
573 * Then peak_buf for this pipeline is 4. However if
574 * plugin B has the MODULE_INPLACE_BROKEN flag, then
575 * peak_buf is 5 because plugin B cannot output to the
576 * same buffer used for input.
577 *
578 * This means if we don't have the flag, we can free
579 * the input buffers then allocate the output buffers,
580 * but if we have the flag, we have to allocate the
581 * output buffers before freeing the input buffers.
582 */
583 if (instance->properties & MODULE_INPLACE_BROKEN) {
584 use_buffers(busy, &instance->output_audio_ports);
585 unuse_buffers(busy, &instance->input_audio_ports);
586 } else {
587 unuse_buffers(busy, &instance->input_audio_ports);
588 use_buffers(busy, &instance->output_audio_ports);
589 }
590 }
591 free(busy);
592
593 return 0;
594 }
595
cras_dsp_pipeline_load(struct pipeline * pipeline)596 int cras_dsp_pipeline_load(struct pipeline *pipeline)
597 {
598 int i;
599 struct instance *instance;
600
601 FOR_ARRAY_ELEMENT(&pipeline->instances, i, instance) {
602 struct plugin *plugin = instance->plugin;
603 if (load_module(plugin, instance) != 0)
604 return -1;
605 }
606
607 if (allocate_buffers(pipeline) != 0)
608 return -1;
609
610 return 0;
611 }
612
613 /* Calculates the total buffering delay of each instance from the source */
calculate_audio_delay(struct pipeline * pipeline)614 static void calculate_audio_delay(struct pipeline *pipeline)
615 {
616 int i;
617 struct instance *instance;
618
619 FOR_ARRAY_ELEMENT(&pipeline->instances, i, instance) {
620 struct dsp_module *module = instance->module;
621 audio_port_array *audio_in = &instance->input_audio_ports;
622 struct audio_port *audio_port;
623 int delay = 0;
624 int j;
625
626 /* Finds the max delay of all modules that provide input to this
627 * instance. */
628 FOR_ARRAY_ELEMENT(audio_in, j, audio_port) {
629 struct instance *upstream = find_instance_by_plugin(
630 &pipeline->instances, audio_port->peer->plugin);
631 delay = MAX(upstream->total_delay, delay);
632 }
633
634 instance->total_delay = delay + module->get_delay(module);
635 }
636 }
637
cras_dsp_pipeline_instantiate(struct pipeline * pipeline,int sample_rate)638 int cras_dsp_pipeline_instantiate(struct pipeline *pipeline, int sample_rate)
639 {
640 int i;
641 struct instance *instance;
642
643 FOR_ARRAY_ELEMENT(&pipeline->instances, i, instance) {
644 struct dsp_module *module = instance->module;
645 if (module->instantiate(module, sample_rate) != 0)
646 return -1;
647 instance->instantiated = 1;
648 syslog(LOG_DEBUG, "instantiate %s", instance->plugin->label);
649 }
650 pipeline->sample_rate = sample_rate;
651
652 FOR_ARRAY_ELEMENT(&pipeline->instances, i, instance) {
653 audio_port_array *audio_in = &instance->input_audio_ports;
654 audio_port_array *audio_out = &instance->output_audio_ports;
655 control_port_array *control_in = &instance->input_control_ports;
656 control_port_array *control_out =
657 &instance->output_control_ports;
658 int j;
659 struct audio_port *audio_port;
660 struct control_port *control_port;
661 struct dsp_module *module = instance->module;
662
663 /* connect audio ports */
664 FOR_ARRAY_ELEMENT(audio_in, j, audio_port) {
665 float *buf = pipeline->buffers[audio_port->buf_index];
666 module->connect_port(module,
667 audio_port->original_index,
668 buf);
669 syslog(LOG_DEBUG, "connect audio buf %d to %s:%d (in)",
670 audio_port->buf_index, instance->plugin->title,
671 audio_port->original_index);
672 }
673 FOR_ARRAY_ELEMENT(audio_out, j, audio_port) {
674 float *buf = pipeline->buffers[audio_port->buf_index];
675 module->connect_port(module,
676 audio_port->original_index,
677 buf);
678 syslog(LOG_DEBUG, "connect audio buf %d to %s:%d (out)",
679 audio_port->buf_index, instance->plugin->title,
680 audio_port->original_index);
681 }
682
683 /* connect control ports */
684 FOR_ARRAY_ELEMENT(control_in, j, control_port) {
685 /* Note for input control ports which has a
686 * peer, we use &control_port->peer->value, so
687 * we can get the peer port's output value
688 * directly */
689 float *value = control_port->peer ?
690 &control_port->peer->value :
691 &control_port->value;
692 module->connect_port(module,
693 control_port->original_index,
694 value);
695 syslog(LOG_DEBUG,
696 "connect control (val=%g) to %s:%d (in)",
697 control_port->value, instance->plugin->title,
698 control_port->original_index);
699 }
700 FOR_ARRAY_ELEMENT(control_out, j, control_port) {
701 module->connect_port(module,
702 control_port->original_index,
703 &control_port->value);
704 syslog(LOG_DEBUG,
705 "connect control (val=%g) to %s:%d (out)",
706 control_port->value, instance->plugin->title,
707 control_port->original_index);
708 }
709 }
710
711 calculate_audio_delay(pipeline);
712 return 0;
713 }
714
cras_dsp_pipeline_deinstantiate(struct pipeline * pipeline)715 void cras_dsp_pipeline_deinstantiate(struct pipeline *pipeline)
716 {
717 int i;
718 struct instance *instance;
719
720 FOR_ARRAY_ELEMENT(&pipeline->instances, i, instance) {
721 struct dsp_module *module = instance->module;
722 if (instance->instantiated) {
723 module->deinstantiate(module);
724 instance->instantiated = 0;
725 }
726 }
727 pipeline->sample_rate = 0;
728 }
729
cras_dsp_pipeline_get_delay(struct pipeline * pipeline)730 int cras_dsp_pipeline_get_delay(struct pipeline *pipeline)
731 {
732 return pipeline->sink_instance->total_delay;
733 }
734
cras_dsp_pipeline_get_sample_rate(struct pipeline * pipeline)735 int cras_dsp_pipeline_get_sample_rate(struct pipeline *pipeline)
736 {
737 return pipeline->sample_rate;
738 }
739
cras_dsp_pipeline_get_num_input_channels(struct pipeline * pipeline)740 int cras_dsp_pipeline_get_num_input_channels(struct pipeline *pipeline)
741 {
742 return pipeline->input_channels;
743 }
744
cras_dsp_pipeline_get_num_output_channels(struct pipeline * pipeline)745 int cras_dsp_pipeline_get_num_output_channels(struct pipeline *pipeline)
746 {
747 return pipeline->output_channels;
748 }
749
cras_dsp_pipeline_get_peak_audio_buffers(struct pipeline * pipeline)750 int cras_dsp_pipeline_get_peak_audio_buffers(struct pipeline *pipeline)
751 {
752 return pipeline->peak_buf;
753 }
754
find_buffer(struct pipeline * pipeline,audio_port_array * audio_ports,int index)755 static float *find_buffer(struct pipeline *pipeline,
756 audio_port_array *audio_ports,
757 int index)
758 {
759 int i;
760 struct audio_port *audio_port;
761
762 FOR_ARRAY_ELEMENT(audio_ports, i, audio_port) {
763 if (audio_port->original_index == index)
764 return pipeline->buffers[audio_port->buf_index];
765 }
766 return NULL;
767 }
768
cras_dsp_pipeline_get_source_buffer(struct pipeline * pipeline,int index)769 float *cras_dsp_pipeline_get_source_buffer(struct pipeline *pipeline, int index)
770 {
771 return find_buffer(pipeline,
772 &pipeline->source_instance->output_audio_ports,
773 index);
774 }
775
cras_dsp_pipeline_get_sink_buffer(struct pipeline * pipeline,int index)776 float *cras_dsp_pipeline_get_sink_buffer(struct pipeline *pipeline, int index)
777 {
778 return find_buffer(pipeline,
779 &pipeline->sink_instance->input_audio_ports,
780 index);
781 }
782
cras_dsp_pipeline_set_sink_ext_module(struct pipeline * pipeline,struct ext_dsp_module * ext_module)783 void cras_dsp_pipeline_set_sink_ext_module(struct pipeline *pipeline,
784 struct ext_dsp_module *ext_module)
785 {
786 cras_dsp_module_set_sink_ext_module(
787 pipeline->sink_instance->module,
788 ext_module);
789 }
790
cras_dsp_pipeline_run(struct pipeline * pipeline,int sample_count)791 void cras_dsp_pipeline_run(struct pipeline *pipeline, int sample_count)
792 {
793 int i;
794 struct instance *instance;
795
796 FOR_ARRAY_ELEMENT(&pipeline->instances, i, instance) {
797 struct dsp_module *module = instance->module;
798 module->run(module, sample_count);
799 }
800 }
801
cras_dsp_pipeline_add_statistic(struct pipeline * pipeline,const struct timespec * time_delta,int samples)802 void cras_dsp_pipeline_add_statistic(struct pipeline *pipeline,
803 const struct timespec *time_delta,
804 int samples)
805 {
806 int64_t t;
807 if (samples <= 0)
808 return;
809
810 t = time_delta->tv_sec * 1000000000LL + time_delta->tv_nsec;
811
812 if (pipeline->total_blocks == 0) {
813 pipeline->max_time = t;
814 pipeline->min_time = t;
815 } else {
816 pipeline->max_time = MAX(pipeline->max_time, t);
817 pipeline->min_time = MIN(pipeline->min_time, t);
818 }
819
820 pipeline->total_blocks++;
821 pipeline->total_samples += samples;
822 pipeline->total_time += t;
823 }
824
cras_dsp_pipeline_apply(struct pipeline * pipeline,uint8_t * buf,snd_pcm_format_t format,unsigned int frames)825 int cras_dsp_pipeline_apply(struct pipeline *pipeline, uint8_t *buf,
826 snd_pcm_format_t format, unsigned int frames)
827 {
828 size_t remaining;
829 size_t chunk;
830 size_t i;
831 unsigned int input_channels = pipeline->input_channels;
832 unsigned int output_channels = pipeline->output_channels;
833 float *source[input_channels];
834 float *sink[output_channels];
835 struct timespec begin, end, delta;
836 int rc;
837
838 if (!pipeline || frames == 0)
839 return 0;
840
841 clock_gettime(CLOCK_THREAD_CPUTIME_ID, &begin);
842
843 /* get pointers to source and sink buffers */
844 for (i = 0; i < input_channels; i++)
845 source[i] = cras_dsp_pipeline_get_source_buffer(pipeline, i);
846 for (i = 0; i < output_channels; i++)
847 sink[i] = cras_dsp_pipeline_get_sink_buffer(pipeline, i);
848
849 remaining = frames;
850
851 /* process at most DSP_BUFFER_SIZE frames each loop */
852 while (remaining > 0) {
853 chunk = MIN(remaining, (size_t)DSP_BUFFER_SIZE);
854
855 /* deinterleave and convert to float */
856 rc = dsp_util_deinterleave(buf, source, input_channels,
857 format, chunk);
858 if (rc)
859 return rc;
860
861 /* Run the pipeline */
862 cras_dsp_pipeline_run(pipeline, chunk);
863
864 /* interleave and convert back to int16_t */
865 rc = dsp_util_interleave(sink, buf, output_channels,
866 format, chunk);
867 if (rc)
868 return rc;
869
870 buf += chunk * output_channels * PCM_FORMAT_WIDTH(format) / 8;
871 remaining -= chunk;
872 }
873
874 clock_gettime(CLOCK_THREAD_CPUTIME_ID, &end);
875 subtract_timespecs(&end, &begin, &delta);
876 cras_dsp_pipeline_add_statistic(pipeline, &delta, frames);
877 return 0;
878 }
879
cras_dsp_pipeline_free(struct pipeline * pipeline)880 void cras_dsp_pipeline_free(struct pipeline *pipeline)
881 {
882 int i;
883 struct instance *instance;
884
885 FOR_ARRAY_ELEMENT(&pipeline->instances, i, instance) {
886 struct dsp_module *module = instance->module;
887 instance->plugin = NULL;
888 ARRAY_FREE(&instance->input_audio_ports);
889 ARRAY_FREE(&instance->input_control_ports);
890 ARRAY_FREE(&instance->output_audio_ports);
891 ARRAY_FREE(&instance->output_control_ports);
892
893 if (module) {
894 if (instance->instantiated) {
895 module->deinstantiate(module);
896 instance->instantiated = 0;
897 }
898 module->free_module(module);
899 instance->module = NULL;
900 }
901 }
902
903 pipeline->ini = NULL;
904 ARRAY_FREE(&pipeline->instances);
905
906 for (i = 0; i < pipeline->peak_buf; i++)
907 free(pipeline->buffers[i]);
908 free(pipeline->buffers);
909 free(pipeline);
910 }
911
dump_audio_ports(struct dumper * d,const char * name,audio_port_array * audio_ports)912 static void dump_audio_ports(struct dumper *d, const char *name,
913 audio_port_array *audio_ports)
914 {
915 int i;
916 struct audio_port *audio_port;
917 int n = ARRAY_COUNT(audio_ports);
918
919 if (n == 0)
920 return;
921 dumpf(d, " %s (%d) =\n", name, n);
922
923 FOR_ARRAY_ELEMENT(audio_ports, i, audio_port) {
924 dumpf(d, " %p, peer %p, orig=%d, buf=%d\n",
925 audio_port, audio_port->peer,
926 audio_port->original_index, audio_port->buf_index);
927 }
928 }
929
dump_control_ports(struct dumper * d,const char * name,control_port_array * control_ports)930 static void dump_control_ports(struct dumper *d, const char *name,
931 control_port_array *control_ports)
932 {
933 int i;
934 struct control_port *control_port;
935 int n = ARRAY_COUNT(control_ports);
936
937 if (n == 0)
938 return;
939 dumpf(d, " %s (%d) =\n", name, ARRAY_COUNT(control_ports));
940
941 FOR_ARRAY_ELEMENT(control_ports, i, control_port) {
942 dumpf(d, " %p, peer %p, orig=%d, value=%g\n",
943 control_port, control_port->peer,
944 control_port->original_index, control_port->value);
945 }
946 }
947
cras_dsp_pipeline_dump(struct dumper * d,struct pipeline * pipeline)948 void cras_dsp_pipeline_dump(struct dumper *d, struct pipeline *pipeline)
949 {
950 int i;
951 struct instance *instance;
952
953 dumpf(d, "---- pipeline dump begin ----\n");
954 dumpf(d, "pipeline (%s):\n", pipeline->purpose);
955 dumpf(d, " input channels: %d\n", pipeline->input_channels);
956 dumpf(d, " output channels: %d\n", pipeline->output_channels);
957 dumpf(d, " sample_rate: %d\n", pipeline->sample_rate);
958 dumpf(d, " processed samples: %" PRId64 "\n", pipeline->total_samples);
959 dumpf(d, " processed blocks: %" PRId64 "\n", pipeline->total_blocks);
960 dumpf(d, " total processing time: %" PRId64 "ns\n",
961 pipeline->total_time);
962 if (pipeline->total_blocks) {
963 dumpf(d, " average block size: %" PRId64 "\n",
964 pipeline->total_samples / pipeline->total_blocks);
965 dumpf(d, " avg processing time per block: %" PRId64 "ns\n",
966 pipeline->total_time / pipeline->total_blocks);
967 }
968 dumpf(d, " min processing time per block: %" PRId64 "ns\n",
969 pipeline->min_time);
970 dumpf(d, " max processing time per block: %" PRId64 "ns\n",
971 pipeline->max_time);
972 dumpf(d, " cpu load: %g%%\n", pipeline->total_time * 1e-9
973 / pipeline->total_samples * pipeline->sample_rate * 100);
974 dumpf(d, " instances (%d):\n",
975 ARRAY_COUNT(&pipeline->instances));
976 FOR_ARRAY_ELEMENT(&pipeline->instances, i, instance) {
977 struct dsp_module *module = instance->module;
978 dumpf(d, " [%d]%s mod=%p, total delay=%d\n",
979 i, instance->plugin->title, module,
980 instance->total_delay);
981 if (module)
982 module->dump(module, d);
983 dump_audio_ports(d, "input_audio_ports",
984 &instance->input_audio_ports);
985 dump_audio_ports(d, "output_audio_ports",
986 &instance->output_audio_ports);
987 dump_control_ports(d, "input_control_ports",
988 &instance->input_control_ports);
989 dump_control_ports(d, "output_control_ports",
990 &instance->output_control_ports);
991 }
992 dumpf(d, " peak_buf = %d\n", pipeline->peak_buf);
993 dumpf(d, "---- pipeline dump end ----\n");
994 }
995