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 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 */ 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 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 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 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 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 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 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 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 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 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 */ 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 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 */ 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 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 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 730 int cras_dsp_pipeline_get_delay(struct pipeline *pipeline) 731 { 732 return pipeline->sink_instance->total_delay; 733 } 734 735 int cras_dsp_pipeline_get_sample_rate(struct pipeline *pipeline) 736 { 737 return pipeline->sample_rate; 738 } 739 740 int cras_dsp_pipeline_get_num_input_channels(struct pipeline *pipeline) 741 { 742 return pipeline->input_channels; 743 } 744 745 int cras_dsp_pipeline_get_num_output_channels(struct pipeline *pipeline) 746 { 747 return pipeline->output_channels; 748 } 749 750 int cras_dsp_pipeline_get_peak_audio_buffers(struct pipeline *pipeline) 751 { 752 return pipeline->peak_buf; 753 } 754 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 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 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 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 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 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 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 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 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 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 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