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