1 // SPDX-License-Identifier: BSD-3-Clause
2 //
3 // Copyright(c) 2018 Intel Corporation. All rights reserved.
4 //
5 // Author: Seppo Ingalsuo <seppo.ingalsuo@linux.intel.com>
6 // Ranjani Sridharan <ranjani.sridharan@linux.intel.com>
7
8 #include <sof/ipc/driver.h>
9 #include <sof/ipc/topology.h>
10 #include <platform/lib/ll_schedule.h>
11 #include <sof/list.h>
12 #include <getopt.h>
13 #include "testbench/common_test.h"
14 #include <tplg_parser/topology.h>
15 #include "testbench/trace.h"
16 #include "testbench/file.h"
17 #include <limits.h>
18 #include <stdlib.h>
19 #include <stdbool.h>
20
21 #define TESTBENCH_NCH 2
22
23 /*
24 * Parse output filenames from user input
25 * This function takes in the output filenames as an input in the format:
26 * "output_file1,output_file2,..."
27 * The max supported output filename number is 4, min is 1.
28 */
parse_output_files(char * outputs,struct testbench_prm * tp)29 static int parse_output_files(char *outputs, struct testbench_prm *tp)
30 {
31 char *output_token = NULL;
32 char *token = strtok_r(outputs, ",", &output_token);
33 int index;
34
35 for (index = 0; index < MAX_OUTPUT_FILE_NUM && token; index++) {
36 /* get output file name with current index */
37 tp->output_file[index] = strdup(token);
38
39 /* next output */
40 token = strtok_r(NULL, ",", &output_token);
41 }
42
43 if (index == MAX_OUTPUT_FILE_NUM && token) {
44 fprintf(stderr, "error: max output file number is %d\n",
45 MAX_OUTPUT_FILE_NUM);
46 for (index = 0; index < MAX_OUTPUT_FILE_NUM; index++)
47 free(tp->output_file[index]);
48 return -EINVAL;
49 }
50
51 /* set total output file number */
52 tp->output_file_num = index;
53 return 0;
54 }
55
56 /*
57 * Parse inputfilenames from user input
58 */
parse_input_files(char * inputs,struct testbench_prm * tp)59 static int parse_input_files(char *inputs, struct testbench_prm *tp)
60 {
61 char *input_token = NULL;
62 char *token = strtok_r(inputs, ",", &input_token);
63 int index;
64
65 for (index = 0; index < MAX_INPUT_FILE_NUM && token; index++) {
66 /* get input file name with current index */
67 tp->input_file[index] = strdup(token);
68
69 /* next input */
70 token = strtok_r(NULL, ",", &input_token);
71 }
72
73 if (index == MAX_INPUT_FILE_NUM && token) {
74 fprintf(stderr, "error: max input file number is %d\n",
75 MAX_INPUT_FILE_NUM);
76 for (index = 0; index < MAX_INPUT_FILE_NUM; index++)
77 free(tp->input_file[index]);
78 return -EINVAL;
79 }
80
81 /* set total input file number */
82 tp->input_file_num = index;
83 return 0;
84 }
85
parse_pipelines(char * pipelines,struct testbench_prm * tp)86 static int parse_pipelines(char *pipelines, struct testbench_prm *tp)
87 {
88 char *output_token = NULL;
89 char *token = strtok_r(pipelines, ",", &output_token);
90 int index;
91
92 for (index = 0; index < MAX_OUTPUT_FILE_NUM && token; index++) {
93 /* get output file name with current index */
94 tp->pipelines[index] = atoi(token);
95
96 /* next output */
97 token = strtok_r(NULL, ",", &output_token);
98 }
99
100 if (index == MAX_OUTPUT_FILE_NUM && token) {
101 fprintf(stderr, "error: max output file number is %d\n",
102 MAX_OUTPUT_FILE_NUM);
103 return -EINVAL;
104 }
105
106 /* set total output file number */
107 tp->pipeline_num = index;
108 return 0;
109 }
110
111 /* print usage for testbench */
print_usage(char * executable)112 static void print_usage(char *executable)
113 {
114 printf("Usage: %s <options> -i <input_file> ", executable);
115 printf("-o <output_file1,output_file2,...>\n\n");
116 printf("Options for processing:\n");
117 printf(" -t <topology file>\n");
118 printf(" -a <comp1=comp1_library,comp2=comp2_library>, override default library\n\n");
119 printf("Options to control test:\n");
120 printf(" -d Run in debug mode\n");
121 printf(" -q Run in quiet mode, suppress traces output\n");
122 printf(" -p <pipeline1,pipeline2,...>\n");
123 printf(" -s Use real time priorities for threads (needs sudo)\n");
124 printf(" -C <number of copy() iterations>\n");
125 printf(" -D <pipeline duration in ms>\n");
126 printf(" -P <number of dynamic pipeline iterations>\n");
127 printf(" -T <microseconds for tick, 0 for batch mode>\n");
128 printf("Options for input and output format override:\n");
129 printf(" -b <input_format>, S16_LE, S24_LE, or S32_LE\n");
130 printf(" -c <input channels>\n");
131 printf(" -n <output channels>\n");
132 printf(" -r <input rate>\n");
133 printf(" -R <output rate>\n\n");
134 printf("Environment variables\n");
135 printf(" SOF_HOST_CORE0=<i> - Map DSP core 0..N to host i..i+N\n");
136 printf("Help:\n");
137 printf(" -h\n\n");
138 printf("Example Usage:\n");
139 printf("%s -i in.txt -o out.txt -t test.tplg ", executable);
140 printf("-r 48000 -R 96000 -c 2 ");
141 printf("-b S16_LE -a volume=libsof_volume.so\n");
142 }
143
144 /* free components */
test_pipeline_free_comps(int pipeline_id)145 static void test_pipeline_free_comps(int pipeline_id)
146 {
147 struct list_item *clist;
148 struct list_item *temp;
149 struct ipc_comp_dev *icd = NULL;
150 int err;
151
152 /* remove the components for this pipeline */
153 list_for_item_safe(clist, temp, &sof_get()->ipc->comp_list) {
154 icd = container_of(clist, struct ipc_comp_dev, list);
155
156 switch (icd->type) {
157 case COMP_TYPE_COMPONENT:
158 if (icd->cd->pipeline->pipeline_id != pipeline_id)
159 break;
160 err = ipc_comp_free(sof_get()->ipc, icd->id);
161 if (err)
162 fprintf(stderr, "failed to free comp %d\n",
163 icd->id);
164 break;
165 case COMP_TYPE_BUFFER:
166 if (icd->cb->pipeline_id != pipeline_id)
167 break;
168 err = ipc_buffer_free(sof_get()->ipc, icd->id);
169 if (err)
170 fprintf(stderr, "failed to free buffer %d\n",
171 icd->id);
172 break;
173 default:
174 if (icd->pipeline->pipeline_id != pipeline_id)
175 break;
176 err = ipc_pipeline_free(sof_get()->ipc, icd->id);
177 if (err)
178 fprintf(stderr, "failed to free pipeline %d\n",
179 icd->id);
180 break;
181 }
182 }
183 }
184
test_pipeline_set_test_limits(int pipeline_id,int max_copies,int max_samples)185 static void test_pipeline_set_test_limits(int pipeline_id, int max_copies,
186 int max_samples)
187 {
188 struct list_item *clist;
189 struct list_item *temp;
190 struct ipc_comp_dev *icd = NULL;
191 struct comp_dev *cd;
192 struct dai_data *dd;
193 struct file_comp_data *fcd;
194
195 /* set the test limits for this pipeline */
196 list_for_item_safe(clist, temp, &sof_get()->ipc->comp_list) {
197 icd = container_of(clist, struct ipc_comp_dev, list);
198
199 switch (icd->type) {
200 case COMP_TYPE_COMPONENT:
201 cd = icd->cd;
202 if (cd->pipeline->pipeline_id != pipeline_id)
203 break;
204
205 switch (cd->drv->type) {
206 case SOF_COMP_HOST:
207 case SOF_COMP_DAI:
208 case SOF_COMP_FILEREAD:
209 case SOF_COMP_FILEWRITE:
210 /* only file limits supported today. TODO: add others */
211 dd = comp_get_drvdata(cd);
212 fcd = comp_get_drvdata(dd->dai);
213 fcd->max_samples = max_samples;
214 fcd->max_copies = max_copies;
215 break;
216 default:
217 break;
218 }
219 break;
220 case COMP_TYPE_BUFFER:
221 default:
222 break;
223 }
224 }
225 }
226
test_pipeline_get_file_stats(int pipeline_id)227 static void test_pipeline_get_file_stats(int pipeline_id)
228 {
229 struct list_item *clist;
230 struct list_item *temp;
231 struct ipc_comp_dev *icd;
232 struct comp_dev *cd;
233 struct dai_data *dd;
234 struct file_comp_data *fcd;
235 unsigned long time;
236
237 /* get the file IO status for each file in pipeline */
238 list_for_item_safe(clist, temp, &sof_get()->ipc->comp_list) {
239 icd = container_of(clist, struct ipc_comp_dev, list);
240
241 switch (icd->type) {
242 case COMP_TYPE_COMPONENT:
243 cd = icd->cd;
244 if (cd->pipeline->pipeline_id != pipeline_id)
245 break;
246 switch (cd->drv->type) {
247 case SOF_COMP_HOST:
248 case SOF_COMP_DAI:
249 case SOF_COMP_FILEREAD:
250 case SOF_COMP_FILEWRITE:
251 dd = comp_get_drvdata(cd);
252 fcd = comp_get_drvdata(dd->dai);
253
254 time = cd->pipeline->pipe_task->start;
255 if (fcd->fs.copy_count == 0)
256 fcd->fs.copy_count = 1;
257 printf("file %s: id %d: type %d: samples %d copies %d total time %zu uS avg time %zu uS\n",
258 fcd->fs.fn, cd->ipc_config.id, cd->drv->type, fcd->fs.n,
259 fcd->fs.copy_count, time, time / fcd->fs.copy_count);
260 break;
261 default:
262 break;
263 }
264 break;
265 case COMP_TYPE_BUFFER:
266 default:
267 break;
268 }
269 }
270 }
271
parse_input_args(int argc,char ** argv,struct testbench_prm * tp)272 static int parse_input_args(int argc, char **argv, struct testbench_prm *tp)
273 {
274 int option = 0;
275 int ret = 0;
276
277 while ((option = getopt(argc, argv, "hdqi:o:t:b:a:r:R:c:n:C:P:Vp:T:D:")) != -1) {
278 switch (option) {
279 /* input sample file */
280 case 'i':
281 ret = parse_input_files(optarg, tp);
282 break;
283
284 /* output sample files */
285 case 'o':
286 ret = parse_output_files(optarg, tp);
287 break;
288
289 /* topology file */
290 case 't':
291 tp->tplg_file = strdup(optarg);
292 break;
293
294 /* input samples bit format */
295 case 'b':
296 tp->bits_in = strdup(optarg);
297 tp->frame_fmt = tplg_find_format(tp->bits_in);
298 break;
299
300 /* input sample rate */
301 case 'r':
302 tp->fs_in = atoi(optarg);
303 break;
304
305 /* output sample rate */
306 case 'R':
307 tp->fs_out = atoi(optarg);
308 break;
309
310 /* input/output channels */
311 case 'c':
312 tp->channels_in = atoi(optarg);
313 break;
314
315 /* output channels */
316 case 'n':
317 tp->channels_out = atoi(optarg);
318 break;
319
320 /* enable debug prints */
321 case 'd':
322 debug = 1;
323 break;
324
325 /* number of pipeline copy() iterations */
326 case 'C':
327 tp->copy_iterations = atoi(optarg);
328 tp->copy_check = true;
329 break;
330
331 case 'q':
332 tp->quiet = true;
333 break;
334
335 /* number of dynamic pipeline iterations */
336 case 'P':
337 tp->dynamic_pipeline_iterations = atoi(optarg);
338 break;
339
340 /* output sample files */
341 case 'p':
342 ret = parse_pipelines(optarg, tp);
343 break;
344
345 /* Microseconds for tick, 0 = batch (tickless) */
346 case 'T':
347 tp->tick_period_us = atoi(optarg);
348 break;
349
350 /* pipeline duration in millisec, 0 = realtime (tickless) */
351 case 'D':
352 tp->pipeline_duration_ms = atoi(optarg);
353 break;
354
355 /* print usage */
356 default:
357 fprintf(stderr, "unknown option %c\n", option);
358 ret = -EINVAL;
359 __attribute__ ((fallthrough));
360 case 'h':
361 print_usage(argv[0]);
362 exit(EXIT_SUCCESS);
363 }
364
365 if (ret < 0)
366 return ret;
367 }
368
369 return ret;
370 }
371
get_pipeline_by_id(int id)372 static struct pipeline *get_pipeline_by_id(int id)
373 {
374 struct ipc_comp_dev *pcm_dev;
375 struct ipc *ipc = sof_get()->ipc;
376
377 pcm_dev = ipc_get_ppl_src_comp(ipc, id);
378 return pcm_dev->cd->pipeline;
379 }
380
test_pipeline_stop(struct testbench_prm * tp)381 static int test_pipeline_stop(struct testbench_prm *tp)
382 {
383 struct pipeline *p;
384 struct ipc *ipc = sof_get()->ipc;
385 int ret = 0;
386 int i;
387
388 for (i = 0; i < tp->pipeline_num; i++) {
389 p = get_pipeline_by_id(tp->pipelines[i]);
390 ret = tb_pipeline_stop(ipc, p);
391 if (ret < 0)
392 break;
393 }
394
395 return ret;
396 }
397
test_pipeline_reset(struct testbench_prm * tp)398 static int test_pipeline_reset(struct testbench_prm *tp)
399 {
400 struct pipeline *p;
401 struct ipc *ipc = sof_get()->ipc;
402 int ret = 0;
403 int i;
404
405 for (i = 0; i < tp->pipeline_num; i++) {
406 p = get_pipeline_by_id(tp->pipelines[i]);
407 ret = tb_pipeline_reset(ipc, p);
408 if (ret < 0)
409 break;
410 }
411
412 return ret;
413 }
414
test_pipeline_free(struct testbench_prm * tp)415 static void test_pipeline_free(struct testbench_prm *tp)
416 {
417 int i;
418
419 for (i = 0; i < tp->pipeline_num; i++)
420 test_pipeline_free_comps(tp->pipelines[i]);
421 }
422
test_pipeline_params(struct testbench_prm * tp,struct tplg_context * ctx)423 static int test_pipeline_params(struct testbench_prm *tp, struct tplg_context *ctx)
424 {
425 struct ipc_comp_dev *pcm_dev;
426 struct pipeline *p;
427 struct ipc *ipc = sof_get()->ipc;
428 int ret = 0;
429 int i;
430
431 /* Run pipeline until EOF from fileread */
432
433 for (i = 0; i < tp->pipeline_num; i++) {
434 pcm_dev = ipc_get_ppl_src_comp(ipc, tp->pipelines[i]);
435 if (!pcm_dev) {
436 fprintf(stderr, "error: pipeline %d has no source component\n",
437 tp->pipelines[i]);
438 return -EINVAL;
439 }
440
441 /* set up pipeline params */
442 p = pcm_dev->cd->pipeline;
443
444 /* input and output sample rate */
445 if (!tp->fs_in)
446 tp->fs_in = p->period * p->frames_per_sched;
447
448 if (!tp->fs_out)
449 tp->fs_out = p->period * p->frames_per_sched;
450
451 ret = tb_pipeline_params(tp, ipc, p, ctx);
452 if (ret < 0) {
453 fprintf(stderr, "error: pipeline params failed: %s\n",
454 strerror(ret));
455 return ret;
456 }
457 }
458
459
460 return 0;
461 }
462
test_pipeline_start(struct testbench_prm * tp)463 static int test_pipeline_start(struct testbench_prm *tp)
464 {
465 struct pipeline *p;
466 struct ipc *ipc = sof_get()->ipc;
467 int i;
468
469 /* Run pipeline until EOF from fileread */
470 for (i = 0; i < tp->pipeline_num; i++) {
471 p = get_pipeline_by_id(tp->pipelines[i]);
472
473 /* do we need to apply copy count limit ? */
474 if (tp->copy_check)
475 test_pipeline_set_test_limits(tp->pipelines[i], tp->copy_iterations, 0);
476
477 /* set pipeline params and trigger start */
478 if (tb_pipeline_start(ipc, p) < 0) {
479 fprintf(stderr, "error: pipeline params\n");
480 return -EINVAL;
481 }
482 }
483
484 return 0;
485 }
486
test_pipeline_check_state(struct testbench_prm * tp,int state)487 static bool test_pipeline_check_state(struct testbench_prm *tp, int state)
488 {
489 struct pipeline *p;
490 int i;
491
492 schedule_ll_run_tasks();
493
494 /* Run pipeline until EOF from fileread */
495 for (i = 0; i < tp->pipeline_num; i++) {
496 p = get_pipeline_by_id(tp->pipelines[i]);
497 if (p->pipe_task->state == state)
498 return true;
499 }
500
501 return false;
502 }
503
test_pipeline_load(struct testbench_prm * tp,struct tplg_context * ctx)504 static int test_pipeline_load(struct testbench_prm *tp, struct tplg_context *ctx)
505 {
506 int ret;
507
508 /* setup the thread virtual core config */
509 memset(ctx, 0, sizeof(*ctx));
510 ctx->comp_id = 1;
511 ctx->core_id = 0;
512 ctx->sof = sof_get();
513 ctx->tplg_file = tp->tplg_file;
514 ctx->ipc_major = 3;
515
516 /* parse topology file and create pipeline */
517 ret = tb_parse_topology(tp, ctx);
518 if (ret < 0)
519 fprintf(stderr, "error: parsing topology\n");
520
521 return ret;
522 }
523
test_pipeline_stats(struct testbench_prm * tp,struct tplg_context * ctx,uint64_t delta)524 static void test_pipeline_stats(struct testbench_prm *tp,
525 struct tplg_context *ctx, uint64_t delta)
526 {
527 int count = 1;
528 struct ipc_comp_dev *icd;
529 struct comp_dev *cd;
530 struct dai_data *dd;
531 struct pipeline *p;
532 struct file_comp_data *frcd, *fwcd;
533 int n_in, n_out;
534 int i;
535
536 /* Get pointer to filewrite */
537 icd = ipc_get_comp_by_id(sof_get()->ipc, tp->fw_id);
538 if (!icd) {
539 fprintf(stderr, "error: failed to get pointers to filewrite\n");
540 exit(EXIT_FAILURE);
541 }
542 cd = icd->cd;
543 dd = comp_get_drvdata(cd);
544 fwcd = comp_get_drvdata(dd->dai);
545
546 /* Get pointer to fileread */
547 icd = ipc_get_comp_by_id(sof_get()->ipc, tp->fr_id);
548 if (!icd) {
549 fprintf(stderr, "error: failed to get pointers to fileread\n");
550 exit(EXIT_FAILURE);
551 }
552 cd = icd->cd;
553 dd = comp_get_drvdata(cd);
554 frcd = comp_get_drvdata(dd->dai);
555
556 /* Run pipeline until EOF from fileread */
557 icd = ipc_get_comp_by_id(sof_get()->ipc, ctx->sched_id);
558 p = icd->cd->pipeline;
559
560 /* input and output sample rate */
561 if (!tp->fs_in)
562 tp->fs_in = p->period * p->frames_per_sched;
563
564 if (!tp->fs_out)
565 tp->fs_out = p->period * p->frames_per_sched;
566
567 n_in = frcd->fs.n;
568 n_out = fwcd->fs.n;
569
570 /* print test summary */
571 printf("==========================================================\n");
572 printf(" Test Summary %d\n", count);
573 printf("==========================================================\n");
574 printf("Test Pipeline:\n");
575 printf("%s\n", tp->pipeline_string);
576 test_pipeline_get_file_stats(ctx->pipeline_id);
577
578 printf("Input bit format: %s\n", tp->bits_in);
579 printf("Input sample rate: %d\n", tp->fs_in);
580 printf("Output sample rate: %d\n", tp->fs_out);
581 for (i = 0; i < tp->input_file_num; i++) {
582 printf("Input[%d] read from file: \"%s\"\n",
583 i, tp->input_file[i]);
584 }
585 for (i = 0; i < tp->output_file_num; i++) {
586 printf("Output[%d] written to file: \"%s\"\n",
587 i, tp->output_file[i]);
588 }
589 printf("Input sample (frame) count: %d (%d)\n", n_in, n_in / tp->channels_in);
590 printf("Output sample (frame) count: %d (%d)\n", n_out, n_out / tp->channels_out);
591 printf("Total execution time: %zu us, %.2f x realtime\n\n",
592 delta, (double)((double)n_out / tp->channels_out / tp->fs_out) * 1000000 / delta);
593 }
594
595 /*
596 * Tester thread, one for each virtual core. This is NOT the thread that will
597 * execute the virtual core.
598 */
pipline_test(struct testbench_prm * tp)599 static int pipline_test(struct testbench_prm *tp)
600 {
601 int dp_count = 0;
602 struct tplg_context ctx;
603 struct timespec ts;
604 struct timespec td0, td1;
605 int err;
606 int nsleep_time;
607 int nsleep_limit;
608 uint64_t delta;
609
610 /* build, run and teardown pipelines */
611 while (dp_count < tp->dynamic_pipeline_iterations) {
612 fprintf(stdout, "pipeline run %d/%d\n", dp_count,
613 tp->dynamic_pipeline_iterations);
614
615 /* print test summary */
616 printf("==========================================================\n");
617 printf(" Test Start %d\n", dp_count);
618 printf("==========================================================\n");
619
620 err = test_pipeline_load(tp, &ctx);
621 if (err < 0) {
622 fprintf(stderr, "error: pipeline load %d failed %d\n",
623 dp_count, err);
624 break;
625 }
626
627 err = test_pipeline_params(tp, &ctx);
628 if (err < 0) {
629 fprintf(stderr, "error: pipeline params %d failed %d\n",
630 dp_count, err);
631 break;
632 }
633
634 err = test_pipeline_start(tp);
635 if (err < 0) {
636 fprintf(stderr, "error: pipeline run %d failed %d\n",
637 dp_count, err);
638 break;
639 }
640 clock_gettime(CLOCK_MONOTONIC, &td0);
641
642 /* sleep to let the pipeline work - we exit at timeout OR
643 * if copy iterations OR max_samples is reached (whatever first)
644 */
645 nsleep_time = 0;
646 ts.tv_sec = tp->tick_period_us / 1000000;
647 ts.tv_nsec = (tp->tick_period_us % 1000000) * 1000;
648 if (!tp->copy_check)
649 nsleep_limit = INT_MAX;
650 else
651 nsleep_limit = tp->copy_iterations *
652 tp->pipeline_duration_ms;
653
654 while (nsleep_time < nsleep_limit) {
655 /* wait for next tick */
656 err = nanosleep(&ts, &ts);
657 if (err == 0) {
658 nsleep_time += tp->tick_period_us; /* sleep fully completed */
659 if (test_pipeline_check_state(tp, SOF_TASK_STATE_CANCEL)) {
660 fprintf(stdout, "pipeline cancelled !\n");
661 break;
662 }
663 } else {
664 if (err == EINTR) {
665 continue; /* interrupted - keep going */
666 } else {
667 printf("error: sleep failed: %s\n", strerror(err));
668 break;
669 }
670 }
671 }
672
673 clock_gettime(CLOCK_MONOTONIC, &td1);
674 err = test_pipeline_stop(tp);
675 if (err < 0) {
676 fprintf(stderr, "error: pipeline stop %d failed %d\n",
677 dp_count, err);
678 break;
679 }
680
681 delta = (td1.tv_sec - td0.tv_sec) * 1000000;
682 delta += (td1.tv_nsec - td0.tv_nsec) / 1000;
683 test_pipeline_stats(tp, &ctx, delta);
684
685 err = test_pipeline_reset(tp);
686 if (err < 0) {
687 fprintf(stderr, "error: pipeline stop %d failed %d\n",
688 dp_count, err);
689 break;
690 }
691
692 test_pipeline_free(tp);
693
694 dp_count++;
695 }
696
697 return 0;
698 }
699
700 static struct testbench_prm tp;
701
main(int argc,char ** argv)702 int main(int argc, char **argv)
703 {
704 int i, err;
705
706 /* initialize input and output sample rates, files, etc. */
707 debug = 0;
708 tp.fs_in = 0;
709 tp.fs_out = 0;
710 tp.bits_in = 0;
711 tp.tplg_file = NULL;
712 tp.input_file_num = 0;
713 tp.output_file_num = 0;
714 for (i = 0; i < MAX_OUTPUT_FILE_NUM; i++)
715 tp.output_file[i] = NULL;
716
717 for (i = 0; i < MAX_INPUT_FILE_NUM; i++)
718 tp.input_file[i] = NULL;
719
720 tp.channels_in = TESTBENCH_NCH;
721 tp.channels_out = 0;
722 tp.max_pipeline_id = 0;
723 tp.copy_check = false;
724 tp.quiet = 0;
725 tp.dynamic_pipeline_iterations = 1;
726 tp.pipeline_string = calloc(1, DEBUG_MSG_LEN);
727 tp.pipelines[0] = 1;
728 tp.pipeline_num = 1;
729 tp.tick_period_us = 0; /* Execute fast non-real time, for 1 ms tick use -T 1000 */
730 tp.pipeline_duration_ms = 5000;
731 tp.copy_iterations = 1;
732
733 /* command line arguments*/
734 err = parse_input_args(argc, argv, &tp);
735 if (err < 0)
736 goto out;
737
738 if (!tp.channels_out)
739 tp.channels_out = tp.channels_in;
740
741 /* check mandatory args */
742 if (!tp.tplg_file) {
743 fprintf(stderr, "topology file not specified, use -t file.tplg\n");
744 print_usage(argv[0]);
745 exit(EXIT_FAILURE);
746 }
747
748 if (!tp.input_file_num) {
749 fprintf(stderr, "input files not specified, use -i file1,file2\n");
750 print_usage(argv[0]);
751 exit(EXIT_FAILURE);
752 }
753
754 if (!tp.output_file_num) {
755 fprintf(stderr, "output files not specified, use -o file1,file2\n");
756 print_usage(argv[0]);
757 exit(EXIT_FAILURE);
758 }
759
760 if (!tp.bits_in) {
761 fprintf(stderr, "input format not specified, use -b format\n");
762 print_usage(argv[0]);
763 exit(EXIT_FAILURE);
764 }
765
766 if (tp.quiet)
767 tb_enable_trace(false); /* reduce trace output */
768 else
769 tb_enable_trace(true);
770
771 /* initialize ipc and scheduler */
772 if (tb_setup(sof_get(), &tp) < 0) {
773 fprintf(stderr, "error: pipeline init\n");
774 exit(EXIT_FAILURE);
775 }
776
777 /* build, run and teardown pipelines */
778 pipline_test(&tp);
779
780 /* free other core FW services */
781 tb_free(sof_get());
782
783 out:
784 /* free all other data */
785 free(tp.bits_in);
786 free(tp.tplg_file);
787 for (i = 0; i < tp.output_file_num; i++)
788 free(tp.output_file[i]);
789
790 for (i = 0; i < tp.input_file_num; i++)
791 free(tp.input_file[i]);
792
793 free(tp.pipeline_string);
794
795 return EXIT_SUCCESS;
796 }
797