Skip to content

Commit 3e8aa01

Browse files
committed
Tools: Testbench: Add support for ALSA controls script
This patch adds to testbench command line option -s <controls file>. The controls file can contain comments with line starting with #, empty lines, amixer cset name= commands and sleep n commands. The script format is similar to what can be applied to a real SOF device running Linux OS. E.g. amixer -c0 cset name='Post Mixer Analog Playback DRC switch' off amixer -c0 cset name='Post Mixer Analog Playback Volume' 42,43 sleep 0.5 amixer -c0 cset name='Post Mixer Analog Playback Volume' 45 The result simulated waveform would show in the beginning left channel set to gain value 42, and right channel to gain value 43. After processing 0.5 seconds of audio both left and right channel gains are set to 45. The supported controls types are mixer, switch and enum. Signed-off-by: Seppo Ingalsuo <seppo.ingalsuo@linux.intel.com>
1 parent 166ebd1 commit 3e8aa01

7 files changed

Lines changed: 494 additions & 25 deletions

File tree

tools/testbench/include/testbench/topology_ipc4.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,10 @@ int tb_new_process(struct testbench_prm *tp);
4848
int tb_pipelines_set_state(struct testbench_prm *tp, int state, int dir);
4949
int tb_send_bytes_data(struct tb_mq_desc *ipc_tx, struct tb_mq_desc *ipc_rx,
5050
uint32_t module_id, uint32_t instance_id, struct sof_abi_hdr *abi);
51+
int tb_send_volume_control(struct tb_mq_desc *ipc_tx, struct tb_mq_desc *ipc_rx,
52+
struct tb_ctl *ctl, int *control_values, int num_values);
53+
int tb_send_alsa_control(struct tb_mq_desc *ipc_tx, struct tb_mq_desc *ipc_rx, struct tb_ctl *ctl,
54+
int *control_values, int num_values, int param_id);
5155
int tb_set_reset_state(struct testbench_prm *tp);
5256
int tb_set_running_state(struct testbench_prm *tp);
5357
int tb_set_up_pipeline(struct testbench_prm *tp, struct tplg_pipeline_info *pipe_info);

tools/testbench/include/testbench/utils.h

Lines changed: 35 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,10 @@
1919
#define TB_MAX_INPUT_FILE_NUM 16
2020
#define TB_MAX_OUTPUT_FILE_NUM 16
2121
#define TB_MAX_PIPELINES_NUM 16
22+
#define TB_MAX_CMD_CHARS 256
23+
#define TB_MAX_CTL_NAME_CHARS 128
24+
#define TB_MAX_VOLUME_SIZE 120
25+
#define TB_MAX_DATA_SIZE 512
2226

2327
/* number of widgets types supported in testbench */
2428
#define TB_NUM_WIDGETS_SUPPORTED 16
@@ -32,13 +36,34 @@ struct file_comp_lookup {
3236
struct file_state *state;
3337
};
3438

39+
struct tb_ctl {
40+
struct tplg_comp_info *comp_info;
41+
unsigned int module_id;
42+
unsigned int instance_id;
43+
unsigned int type;
44+
unsigned int volume_table[TB_MAX_VOLUME_SIZE];
45+
unsigned int index;
46+
char data[TB_MAX_DATA_SIZE];
47+
char name[TB_MAX_CTL_NAME_CHARS];
48+
union {
49+
struct snd_soc_tplg_mixer_control mixer_ctl;
50+
struct snd_soc_tplg_enum_control enum_ctl;
51+
struct snd_soc_tplg_bytes_control bytes_ctl;
52+
};
53+
};
54+
55+
struct tb_glb_state {
56+
char magic[8]; /* SOF_MAGIC */
57+
uint32_t num_ctls; /* number of ctls */
58+
size_t size; /* size of this structure in bytes */
59+
struct tb_ctl *ctl;
60+
};
61+
3562
#if CONFIG_IPC_MAJOR_4
3663

3764
#define TB_NAME_SIZE 256
3865
#define TB_MAX_CONFIG_COUNT 2
3966
#define TB_MAX_CONFIG_NAME_SIZE 64
40-
#define TB_MAX_VOLUME_SIZE 120
41-
#define TB_MAX_DATA_SIZE 512
4267
#define TB_MAX_CTLS 16
4368

4469
struct tb_mq_desc {
@@ -55,27 +80,6 @@ struct tb_config {
5580
int channels;
5681
unsigned long format;
5782
};
58-
59-
struct tb_ctl {
60-
unsigned int module_id;
61-
unsigned int instance_id;
62-
unsigned int type;
63-
unsigned int volume_table[TB_MAX_VOLUME_SIZE];
64-
unsigned int index;
65-
char data[TB_MAX_DATA_SIZE];
66-
union {
67-
struct snd_soc_tplg_mixer_control mixer_ctl;
68-
struct snd_soc_tplg_enum_control enum_ctl;
69-
struct snd_soc_tplg_bytes_control bytes_ctl;
70-
};
71-
};
72-
73-
struct tb_glb_state {
74-
char magic[8]; /* SOF_MAGIC */
75-
uint32_t num_ctls; /* number of ctls */
76-
size_t size; /* size of this structure in bytes */
77-
struct tb_ctl *ctl;
78-
};
7983
#endif
8084

8185
/*
@@ -93,6 +97,7 @@ struct testbench_prm {
9397
char *output_file[TB_MAX_OUTPUT_FILE_NUM]; /* output file names */
9498
char *tplg_file; /* topology file to use */
9599
char *bits_in; /* input bit format */
100+
char *control_file;
96101
int input_file_num; /* number of input files */
97102
int output_file_num; /* number of output files */
98103
int pipeline_num;
@@ -123,6 +128,9 @@ struct testbench_prm {
123128
/* topology */
124129
struct tplg_context tplg;
125130

131+
FILE *control_fh;
132+
struct tb_glb_state glb_ctx;
133+
126134
#if CONFIG_IPC_MAJOR_4
127135
struct list_item widget_list;
128136
struct list_item route_list;
@@ -136,12 +144,12 @@ struct testbench_prm {
136144
struct tb_config config[TB_MAX_CONFIG_COUNT];
137145
int num_configs;
138146
int period_frames;
139-
struct tb_glb_state glb_ctx;
140147
#endif
141148
};
142149

143150
extern int debug;
144151

152+
int tb_decode_enum(struct snd_soc_tplg_enum_control *enum_ctl, char *token);
145153
int tb_find_file_components(struct testbench_prm *tp);
146154
int tb_free_all_pipelines(struct testbench_prm *tp);
147155
int tb_load_topology(struct testbench_prm *tp);
@@ -150,7 +158,10 @@ int tb_pipeline_params(struct testbench_prm *tp, struct ipc *ipc, struct pipelin
150158
int tb_pipeline_reset(struct ipc *ipc, struct pipeline *p);
151159
int tb_pipeline_start(struct ipc *ipc, struct pipeline *p);
152160
int tb_pipeline_stop(struct ipc *ipc, struct pipeline *p);
161+
int tb_read_controls(struct testbench_prm *tp, int64_t *sleep_ns);
162+
int tb_set_enum_control(struct testbench_prm *tp, struct tb_ctl *ctl, char *control_params);
153163
int tb_set_reset_state(struct testbench_prm *tp);
164+
int tb_set_mixer_control(struct testbench_prm *tp, struct tb_ctl *ctl, char *control_params);
154165
int tb_set_running_state(struct testbench_prm *tp);
155166
int tb_set_up_all_pipelines(struct testbench_prm *tp);
156167
int tb_setup(struct sof *sof, struct testbench_prm *tp);

tools/testbench/testbench.c

Lines changed: 54 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -129,6 +129,7 @@ static void print_usage(char *executable)
129129
printf(" -p <pipeline1,pipeline2,...>\n");
130130
printf(" -C <number of copy() iterations>\n");
131131
printf(" -P <number of dynamic pipeline iterations>\n");
132+
printf(" -s <script file to set controls, with amixer and sleep commands>\n\n");
132133
printf("Options for input and output format override:\n");
133134
printf(" -b <input_format>, S16_LE, S24_LE, or S32_LE\n");
134135
printf(" -c <input channels>\n");
@@ -146,7 +147,7 @@ static int parse_input_args(int argc, char **argv, struct testbench_prm *tp)
146147
int option = 0;
147148
int ret = 0;
148149

149-
while ((option = getopt(argc, argv, "hd:i:o:t:b:r:R:c:n:C:P:p:")) != -1) {
150+
while ((option = getopt(argc, argv, "hd:i:o:t:b:r:R:c:n:C:P:p:s:")) != -1) {
150151
switch (option) {
151152
/* input sample file */
152153
case 'i':
@@ -216,6 +217,11 @@ static int parse_input_args(int argc, char **argv, struct testbench_prm *tp)
216217
ret = parse_pipelines(optarg, tp);
217218
break;
218219

220+
/* control script file name */
221+
case 's':
222+
tp->control_file = strdup(optarg);
223+
break;
224+
219225
/* print usage */
220226
case 'h':
221227
print_usage(argv[0]);
@@ -302,9 +308,13 @@ static void test_pipeline_stats(struct testbench_prm *tp, long long delta_t)
302308
*/
303309
static int pipline_test(struct testbench_prm *tp)
304310
{
311+
float samples_to_ns;
305312
int dp_count = 0;
306313
struct timespec td0, td1;
314+
struct file_state *out_stat;
307315
long long delta_t;
316+
int64_t next_control_ns;
317+
int64_t time_ns;
308318
int err;
309319

310320
/* build, run and teardown pipelines */
@@ -341,17 +351,46 @@ static int pipline_test(struct testbench_prm *tp)
341351
break;
342352
}
343353

354+
/* Use first file writer to create simulation time. Calculate coefficient
355+
* to calculate current time from file write samples count
356+
*/
357+
out_stat = tp->fw[0].state;
358+
samples_to_ns = 1.0e9 / ((float)out_stat->channels * out_stat->rate);
359+
360+
/* Apply initial controls time to call again controls handler */
361+
err = tb_read_controls(tp, &next_control_ns);
362+
if (err) {
363+
fprintf(stderr, "error: failed to read control commands.\n");
364+
goto out;
365+
}
366+
344367
tb_gettime(&td0);
345368

346369
while (true) {
347370
if (tb_schedule_pipeline_check_state(tp))
348371
break;
372+
373+
if (next_control_ns) {
374+
time_ns = (int64_t)(samples_to_ns * out_stat->n);
375+
if (time_ns >= next_control_ns) {
376+
err = tb_read_controls(tp, &next_control_ns);
377+
if (err) {
378+
fprintf(stderr,
379+
"error: failed to read control commands.\n");
380+
goto out;
381+
}
382+
383+
if (next_control_ns)
384+
next_control_ns += time_ns;
385+
}
386+
}
349387
}
350388

351389
tb_schedule_pipeline_check_state(tp); /* Once more to flush out remaining data */
352390

353391
tb_gettime(&td1);
354392

393+
out:
355394
err = tb_set_reset_state(tp);
356395
if (err < 0) {
357396
fprintf(stderr, "error: pipeline reset %d failed %d\n",
@@ -445,6 +484,16 @@ int main(int argc, char **argv)
445484
goto out;
446485
}
447486

487+
if (tp->control_file) {
488+
tp->control_fh = fopen(tp->control_file, "r");
489+
if (!tp->control_fh) {
490+
fprintf(stderr, "error: opening script %s (%s).\n",
491+
tp->control_file, strerror(errno));
492+
ret = -errno;
493+
goto out;
494+
}
495+
}
496+
448497
/* build, run and teardown pipelines */
449498
pipline_test(tp);
450499

@@ -456,6 +505,10 @@ int main(int argc, char **argv)
456505
/* free all other data */
457506
free(tp->bits_in);
458507
free(tp->tplg_file);
508+
free(tp->control_file);
509+
if (tp->control_fh)
510+
fclose(tp->control_fh);
511+
459512
for (i = 0; i < tp->output_file_num; i++)
460513
free(tp->output_file[i]);
461514

0 commit comments

Comments
 (0)