diff --git a/src/audio/module_adapter/module_adapter_ipc3.c b/src/audio/module_adapter/module_adapter_ipc3.c index 6949ea2a4957..765c3e2b82fe 100644 --- a/src/audio/module_adapter/module_adapter_ipc3.c +++ b/src/audio/module_adapter/module_adapter_ipc3.c @@ -80,6 +80,8 @@ int module_adapter_init_data(struct comp_dev *dev, case SOF_COMP_DCBLOCK: case SOF_COMP_SMART_AMP: case SOF_COMP_MODULE_ADAPTER: + case SOF_COMP_FILEREAD: + case SOF_COMP_FILEWRITE: case SOF_COMP_NONE: { const struct ipc_config_process *ipc_module_adapter = spec; diff --git a/src/include/ipc/topology.h b/src/include/ipc/topology.h index b2cd833cf1fb..a83b806a3467 100644 --- a/src/include/ipc/topology.h +++ b/src/include/ipc/topology.h @@ -243,8 +243,16 @@ struct sof_ipc_comp_process { /* IPC file component used by testbench only */ struct sof_ipc_comp_file { + /* These need to be the same as in above sof_ipc_comp_process */ struct sof_ipc_comp comp; struct sof_ipc_comp_config config; + uint32_t size; /**< size of bespoke data section in bytes */ + uint32_t type; /**< sof_ipc_process_type */ + + /* reserved for future use */ + uint32_t reserved[7]; + + /* These are additional parameters for file */ uint32_t rate; uint32_t channels; char *fn; diff --git a/src/include/sof/audio/ipc-config.h b/src/include/sof/audio/ipc-config.h index ccabb8628e35..f0c74f2da2a2 100644 --- a/src/include/sof/audio/ipc-config.h +++ b/src/include/sof/audio/ipc-config.h @@ -143,6 +143,7 @@ struct ipc_config_process { /* file IO ipc comp */ struct ipc_comp_file { + struct ipc_config_process module_header; /* Needed for module_adapter_init_data() */ uint32_t rate; uint32_t channels; char *fn; diff --git a/src/ipc/ipc3/helper.c b/src/ipc/ipc3/helper.c index e86d7c25d94d..beda189aea72 100644 --- a/src/ipc/ipc3/helper.c +++ b/src/ipc/ipc3/helper.c @@ -202,10 +202,9 @@ static int comp_specific_builder(struct sof_ipc_comp *comp, { #if CONFIG_LIBRARY struct sof_ipc_comp_file *file = (struct sof_ipc_comp_file *)comp; -#else +#endif struct sof_ipc_comp_host *host = (struct sof_ipc_comp_host *)comp; struct sof_ipc_comp_dai *dai = (struct sof_ipc_comp_dai *)comp; -#endif struct sof_ipc_comp_volume *vol = (struct sof_ipc_comp_volume *)comp; struct sof_ipc_comp_process *proc = (struct sof_ipc_comp_process *)comp; struct sof_ipc_comp_src *src = (struct sof_ipc_comp_src *)comp; @@ -217,20 +216,25 @@ static int comp_specific_builder(struct sof_ipc_comp *comp, switch (comp->type) { #if CONFIG_LIBRARY /* test bench maps host and DAIs to a file */ - case SOF_COMP_HOST: - case SOF_COMP_SG_HOST: - case SOF_COMP_DAI: - case SOF_COMP_SG_DAI: + case SOF_COMP_FILEREAD: + case SOF_COMP_FILEWRITE: if (IPC_TAIL_IS_SIZE_INVALID(*file)) return -EBADMSG; + config->file.channels = file->channels; config->file.fn = file->fn; config->file.frame_fmt = file->frame_fmt; config->file.mode = file->mode; config->file.rate = file->rate; config->file.direction = file->direction; + + /* For module_adapter_init_data() ipc_module_adapter compatibility */ + config->file.module_header.type = proc->type; + config->file.module_header.size = proc->size; + config->file.module_header.data = (uint8_t *)proc->data - + sizeof(struct ipc_config_process); break; -#else +#endif case SOF_COMP_HOST: case SOF_COMP_SG_HOST: if (IPC_TAIL_IS_SIZE_INVALID(*host)) @@ -247,7 +251,6 @@ static int comp_specific_builder(struct sof_ipc_comp *comp, config->dai.direction = dai->direction; config->dai.type = dai->type; break; -#endif case SOF_COMP_VOLUME: if (IPC_TAIL_IS_SIZE_INVALID(*vol)) return -EBADMSG; diff --git a/tools/testbench/common_test.c b/tools/testbench/common_test.c index c3497ce582c4..f4481b38af02 100644 --- a/tools/testbench/common_test.c +++ b/tools/testbench/common_test.c @@ -1,33 +1,35 @@ // SPDX-License-Identifier: BSD-3-Clause // -// Copyright(c) 2018 Intel Corporation. All rights reserved. +// Copyright(c) 2018-2024 Intel Corporation. All rights reserved. -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include +#include +#include #include #include #include #include #include +#include #include #include #include #include +#include +#include +#include +#include #include -#include -#include +#include +#include +#include +#include +#include +#include +#include + #include "testbench/common_test.h" #include "testbench/trace.h" -#include +#include "testbench/file.h" #if defined __XCC__ #include @@ -43,7 +45,6 @@ int tb_setup(struct sof *sof, struct testbench_prm *tp) /* init components */ sys_comp_init(sof); - sys_comp_file_init(); sys_comp_selector_init(); /* Module adapter components */ @@ -53,6 +54,7 @@ int tb_setup(struct sof *sof, struct testbench_prm *tp) sys_comp_module_drc_interface_init(); sys_comp_module_eq_fir_interface_init(); sys_comp_module_eq_iir_interface_init(); + sys_comp_module_file_interface_init(); sys_comp_module_google_rtc_audio_processing_interface_init(); sys_comp_module_igo_nr_interface_init(); sys_comp_module_mfcc_interface_init(); diff --git a/tools/testbench/file.c b/tools/testbench/file.c index 1ce8b578d6c7..846d19c0fb06 100644 --- a/tools/testbench/file.c +++ b/tools/testbench/file.c @@ -1,33 +1,33 @@ // SPDX-License-Identifier: BSD-3-Clause // -// Copyright(c) 2018 Intel Corporation. All rights reserved. +// Copyright(c) 2018-2024 Intel Corporation. All rights reserved. /* file component for reading/writing pcm samples to/from a file */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include +#include #include #include +#include #include +#include +#include #include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include #include "testbench/common_test.h" #include "testbench/file.h" SOF_DEFINE_REG_UUID(file); DECLARE_TR_CTX(file_tr, SOF_UUID(file_uuid), LOG_LEVEL_INFO); - -static const struct comp_driver comp_file_dai; -static const struct comp_driver comp_file_host; +LOG_MODULE_REGISTER(file, CONFIG_SOF_LOG_LEVEL); /* * Helpers for s24_4le data. To avoid an overflown 24 bit to be taken as valid 32 bit @@ -409,18 +409,16 @@ static int write_samples_s16(struct file_comp_data *cd, struct audio_stream *sou } /* Default file copy function, just return error if called */ -static int file_default(struct comp_dev *dev, struct audio_stream *sink, +static int file_default(struct file_comp_data *cd, struct audio_stream *sink, struct audio_stream *source, uint32_t frames) { return -EINVAL; } /* function for processing 32-bit samples */ -static int file_s32(struct comp_dev *dev, struct audio_stream *sink, +static int file_s32(struct file_comp_data *cd, struct audio_stream *sink, struct audio_stream *source, uint32_t frames) { - struct dai_data *dd = comp_get_drvdata(dev); - struct file_comp_data *cd = comp_get_drvdata(dd->dai); int nch; int n_samples = 0; @@ -450,11 +448,9 @@ static int file_s32(struct comp_dev *dev, struct audio_stream *sink, } /* function for processing 16-bit samples */ -static int file_s16(struct comp_dev *dev, struct audio_stream *sink, +static int file_s16(struct file_comp_data *cd, struct audio_stream *sink, struct audio_stream *source, uint32_t frames) { - struct dai_data *dd = comp_get_drvdata(dev); - struct file_comp_data *cd = comp_get_drvdata(dd->dai); int nch; int n_samples; @@ -484,11 +480,9 @@ static int file_s16(struct comp_dev *dev, struct audio_stream *sink, } /* function for processing 24-bit samples */ -static int file_s24(struct comp_dev *dev, struct audio_stream *sink, +static int file_s24(struct file_comp_data *cd, struct audio_stream *sink, struct audio_stream *source, uint32_t frames) { - struct dai_data *dd = comp_get_drvdata(dev); - struct file_comp_data *cd = comp_get_drvdata(dd->dai); int nch; int n_samples = 0; @@ -530,45 +524,46 @@ static enum file_format get_file_format(char *filename) return FILE_RAW; } -static struct comp_dev *file_new(const struct comp_driver *drv, - const struct comp_ipc_config *config, - const void *spec) +static int file_init_set_dai_data(struct comp_dev *dev) { - const struct dai_driver *fdrv; - struct comp_dev *dev; - const struct ipc_comp_file *ipc_file = spec; struct dai_data *dd; - struct dai *fdai; - struct file_comp_data *cd; - - debug_print("file_new()\n"); - dev = comp_alloc(drv, sizeof(*dev)); - if (!dev) - return NULL; - dev->ipc_config = *config; - - /* allocate memory for file comp data */ dd = rzalloc(SOF_MEM_ZONE_RUNTIME_SHARED, 0, SOF_MEM_CAPS_RAM, sizeof(*dd)); if (!dd) - goto error_skip_dd; + return -ENOMEM; - fdai = rzalloc(SOF_MEM_ZONE_RUNTIME_SHARED, 0, SOF_MEM_CAPS_RAM, sizeof(*fdai)); - if (!fdai) - goto error_skip_dai; + /* Member dd->dai remains NULL. It's sufficient for dai_get_init_delay_ms(). + * In such case the functions returns zero delay. Testbench currently has + * no use for the feature. + */ + dev->priv_data = dd; + return 0; +} - fdrv = rzalloc(SOF_MEM_ZONE_RUNTIME_SHARED, 0, SOF_MEM_CAPS_RAM, sizeof(*fdrv)); - if (!fdrv) - goto error_skip_drv; +static void file_free_dai_data(struct comp_dev *dev) +{ + struct dai_data *dd; + + dd = comp_get_drvdata(dev); + free(dd); +} + +static int file_init(struct processing_module *mod) +{ + struct comp_dev *dev = mod->dev; + struct module_data *mod_data = &mod->priv; + const struct ipc_comp_file *ipc_file = + (const struct ipc_comp_file *)mod_data->cfg.init_data; + struct file_comp_data *cd; + int ret; + + debug_print("file_init()\n"); cd = rzalloc(SOF_MEM_ZONE_RUNTIME_SHARED, 0, SOF_MEM_CAPS_RAM, sizeof(*cd)); if (!cd) - goto error_skip_cd; + return -ENOMEM; - fdai->drv = fdrv; - dd->dai = fdai; - comp_set_drvdata(dev, dd); - comp_set_drvdata(dd->dai, cd); + mod_data->private = cd; /* default function for processing samples */ cd->file_func = file_default; @@ -590,6 +585,18 @@ static struct comp_dev *file_new(const struct comp_driver *drv, /* open file handle(s) depending on mode */ switch (cd->fs.mode) { case FILE_READ: + /* Change to DAI type is needed to avoid uninitialized hw params in + * pipeline_params, A file host can be left as SOF_COMP_MODULE_ADAPTER + */ + if (dev->direction == SOF_IPC_STREAM_CAPTURE) { + dev->ipc_config.type = SOF_COMP_DAI; + ret = file_init_set_dai_data(dev); + if (ret) { + fprintf(stderr, "error: failed set dai data.\n"); + goto error; + } + } + cd->fs.rfh = fopen(cd->fs.fn, "r"); if (!cd->fs.rfh) { fprintf(stderr, "error: opening file %s for reading - %s\n", @@ -598,6 +605,18 @@ static struct comp_dev *file_new(const struct comp_driver *drv, } break; case FILE_WRITE: + /* Change to DAI type is needed to avoid uninitialized hw params in + * pipeline_params, A file host can be left as SOF_COMP_MODULE_ADAPTER + */ + if (dev->direction == SOF_IPC_STREAM_PLAYBACK) { + dev->ipc_config.type = SOF_COMP_DAI; + ret = file_init_set_dai_data(dev); + if (ret) { + fprintf(stderr, "error: failed set dai data.\n"); + goto error; + } + } + cd->fs.wfh = fopen(cd->fs.fn, "w+"); if (!cd->fs.wfh) { fprintf(stderr, "error: opening file %s for writing - %s\n", @@ -616,32 +635,19 @@ static struct comp_dev *file_new(const struct comp_driver *drv, cd->fs.n = 0; cd->fs.copy_count = 0; cd->fs.cycles_count = 0; - dev->state = COMP_STATE_READY; - return dev; + + return 0; error: free(cd); - -error_skip_cd: - free((void *)fdrv); - -error_skip_drv: - free(fdai); - -error_skip_dai: - free(dd); - -error_skip_dd: - free(dev); - return NULL; + return -EINVAL; } -static void file_free(struct comp_dev *dev) +static int file_free(struct processing_module *mod) { - struct dai_data *dd = comp_get_drvdata(dev); - struct file_comp_data *cd = comp_get_drvdata(dd->dai); + struct file_comp_data *cd = module_get_private_data(mod); - comp_dbg(dev, "file_free()"); + debug_print("file_free()"); if (cd->fs.mode == FILE_READ) fclose(cd->fs.rfh); @@ -650,64 +656,89 @@ static void file_free(struct comp_dev *dev) free(cd->fs.fn); free(cd); - free((void *)dd->dai->drv); - free(dd->dai); - free(dd); - free(dev); + file_free_dai_data(mod->dev); + return 0; } -static int file_verify_params(struct comp_dev *dev, - struct sof_ipc_stream_params *params) +/* + * copy and process stream samples + * returns the number of bytes copied + */ +static int file_process(struct processing_module *mod, + struct input_stream_buffer *input_buffers, int num_input_buffers, + struct output_stream_buffer *output_buffers, int num_output_buffers) { - int ret; + struct comp_dev *dev = mod->dev; + struct file_comp_data *cd = module_get_private_data(mod); + struct audio_stream *source; + struct audio_stream *sink; + struct comp_buffer *buffer; + uint32_t frames; + uint64_t cycles0, cycles1; + int samples; + int ret = 0; - comp_dbg(dev, "file_verify_params()"); + if (cd->fs.reached_eof) + return -ENODATA; - ret = comp_verify_params(dev, 0, params); - if (ret < 0) { - comp_err(dev, "file_verify_params() error: comp_verify_params() failed."); - return ret; + /* Note: a SOF_COMP_DAI does not have input_buffers and output buffers set */ + tb_getcycles(&cycles0); + switch (cd->fs.mode) { + case FILE_READ: + /* read PCM samples from file */ + buffer = list_first_item(&dev->bsink_list, struct comp_buffer, source_list); + sink = &buffer->stream; + frames = audio_stream_get_free_frames(sink); + frames = MIN(frames, cd->max_frames); + samples = cd->file_func(cd, sink, NULL, frames); + audio_stream_produce(sink, audio_stream_sample_bytes(sink) * samples); + break; + case FILE_WRITE: + /* write PCM samples into file */ + buffer = list_first_item(&dev->bsource_list, struct comp_buffer, sink_list); + source = &buffer->stream; + frames = audio_stream_get_avail_frames(source); + frames = MIN(frames, cd->max_frames); + samples = cd->file_func(cd, NULL, source, frames); + audio_stream_consume(source, audio_stream_sample_bytes(source) * samples); + break; + default: + /* TODO: duplex mode */ + ret = -EINVAL; + break; } - return 0; + cd->fs.copy_count++; + if (cd->fs.reached_eof || (cd->max_copies && cd->fs.copy_count >= cd->max_copies)) { + cd->fs.reached_eof = 1; + debug_print("file_process(): reached EOF"); + schedule_task_cancel(mod->dev->pipeline->pipe_task); + } + + tb_getcycles(&cycles1); + cd->fs.cycles_count += cycles1 - cycles0; + return ret; } -/** - * \brief Sets file component audio stream parameters. - * \param[in,out] dev Volume base component device. - * \param[in] params Audio (PCM) stream parameters (ignored for this component) - * \return Error code. - * - * All done in prepare() since we need to know source and sink component params. - */ -static int file_params(struct comp_dev *dev, - struct sof_ipc_stream_params *params) +static int file_prepare(struct processing_module *mod, + struct sof_source **sources, int num_of_sources, + struct sof_sink **sinks, int num_of_sinks) { - struct comp_buffer *buffer; - struct dai_data *dd = comp_get_drvdata(dev); - struct file_comp_data *cd = comp_get_drvdata(dd->dai); struct audio_stream *stream; - int periods; - int samples; - int ret; - - comp_info(dev, "file_params()"); + struct comp_buffer *buffer; + struct comp_dev *dev = mod->dev; + struct file_comp_data *cd = module_get_private_data(mod); - ret = file_verify_params(dev, params); - if (ret < 0) { - comp_err(dev, "file_params(): pcm params verification failed."); - return ret; - } + debug_print("file_prepare()"); /* file component sink/source buffer period count */ + cd->max_frames = dev->frames; switch (cd->fs.mode) { case FILE_READ: buffer = list_first_item(&dev->bsink_list, struct comp_buffer, source_list); - periods = dev->ipc_config.periods_sink; break; case FILE_WRITE: buffer = list_first_item(&dev->bsource_list, struct comp_buffer, sink_list); - periods = dev->ipc_config.periods_source; break; default: /* TODO: duplex mode */ @@ -715,38 +746,16 @@ static int file_params(struct comp_dev *dev, return -EINVAL; } - /* set downstream buffer size */ + /* set file function */ stream = &buffer->stream; - samples = periods * dev->frames * audio_stream_get_channels(stream); switch (audio_stream_get_frm_fmt(stream)) { case SOF_IPC_FRAME_S16_LE: - ret = buffer_set_size(buffer, samples * sizeof(int16_t), 0); - if (ret < 0) { - fprintf(stderr, "error: file buffer size set\n"); - return ret; - } - - /* set file function */ cd->file_func = file_s16; break; case SOF_IPC_FRAME_S24_4LE: - ret = buffer_set_size(buffer, samples * sizeof(int32_t), 0); - if (ret < 0) { - fprintf(stderr, "error: file buffer size set\n"); - return ret; - } - - /* set file function */ cd->file_func = file_s24; break; case SOF_IPC_FRAME_S32_LE: - ret = buffer_set_size(buffer, samples * sizeof(int32_t), 0); - if (ret < 0) { - fprintf(stderr, "error: file buffer size set\n"); - return ret; - } - - /* set file function */ cd->file_func = file_s32; break; default: @@ -755,148 +764,30 @@ static int file_params(struct comp_dev *dev, return -EINVAL; } - cd->sample_container_bytes = audio_stream_sample_bytes(stream); - buffer_reset_pos(buffer, NULL); - return 0; } -static int fr_cmd(struct comp_dev *dev, struct sof_ipc_ctrl_data *cdata) -{ - fprintf(stderr, "Warning: Set data is not implemented\n"); - return -EINVAL; -} - -static int file_trigger(struct comp_dev *dev, int cmd) -{ - comp_info(dev, "file_trigger()"); - return comp_set_state(dev, cmd); -} - -/* used to pass standard and bespoke commands (with data) to component */ -static int file_cmd(struct comp_dev *dev, int cmd, void *data, - int max_data_size) +static int file_reset(struct processing_module *mod) { - struct sof_ipc_ctrl_data *cdata = ASSUME_ALIGNED(data, 4); - int ret = 0; - - comp_info(dev, "file_cmd()"); - switch (cmd) { - case COMP_CMD_SET_DATA: - ret = fr_cmd(dev, cdata); - break; - default: - fprintf(stderr, "Warning: Unknown file command %d\n", cmd); - return -EINVAL; - } - - return ret; -} - -/* - * copy and process stream samples - * returns the number of bytes copied - */ -static int file_copy(struct comp_dev *dev) -{ - struct comp_buffer *buffer; - struct dai_data *dd = comp_get_drvdata(dev); - struct file_comp_data *cd = comp_get_drvdata(dd->dai); - uint64_t cycles0, cycles1; - int snk_frames; - int src_frames; - int bytes = cd->sample_container_bytes; - int ret = 0; + debug_print("file_reset()"); - tb_getcycles(&cycles0); - switch (cd->fs.mode) { - case FILE_READ: - /* file component sink buffer */ - buffer = list_first_item(&dev->bsink_list, struct comp_buffer, - source_list); - - /* test sink has enough free frames */ - snk_frames = MIN(audio_stream_get_free_frames(&buffer->stream), dev->frames); - if (snk_frames > 0 && !cd->fs.reached_eof) { - /* read PCM samples from file */ - ret = cd->file_func(dev, &buffer->stream, NULL, - snk_frames); - - /* update sink buffer pointers */ - if (ret > 0) - comp_update_buffer_produce(buffer, - ret * bytes); - } - break; - case FILE_WRITE: - /* file component source buffer */ - buffer = list_first_item(&dev->bsource_list, - struct comp_buffer, sink_list); - - /* test source has enough free frames */ - src_frames = audio_stream_get_avail_frames(&buffer->stream); - if (src_frames > 0) { - /* write PCM samples into file */ - ret = cd->file_func(dev, NULL, &buffer->stream, - src_frames); - - /* update source buffer pointers */ - if (ret > 0) - comp_update_buffer_consume(buffer, - ret * bytes); - } - break; - default: - /* TODO: duplex mode */ - ret = -EINVAL; - break; - } - - cd->fs.copy_count++; - if (cd->fs.reached_eof || (cd->max_copies && cd->fs.copy_count >= cd->max_copies)) { - cd->fs.reached_eof = 1; - comp_info(dev, "file_copy(): copies %d max %d eof %d", - cd->fs.copy_count, cd->max_copies, - cd->fs.reached_eof); - schedule_task_cancel(dev->pipeline->pipe_task); - } - - tb_getcycles(&cycles1); - cd->fs.cycles_count += cycles1 - cycles0; - return ret; + return 0; } -static int file_prepare(struct comp_dev *dev) +static int file_trigger(struct comp_dev *dev, int cmd) { - int ret = 0; - - comp_info(dev, "file_prepare()"); - - ret = comp_set_state(dev, COMP_TRIGGER_PREPARE); - if (ret < 0) - return ret; - - if (ret == COMP_STATUS_STATE_ALREADY_SET) - return PPL_STATUS_PATH_STOP; - - dev->state = COMP_STATE_PREPARE; - return ret; -} + debug_print("asrc_trigger()"); -static int file_reset(struct comp_dev *dev) -{ - comp_info(dev, "file_reset()"); - comp_set_state(dev, COMP_TRIGGER_RESET); - return 0; + return comp_set_state(dev, cmd); } static int file_get_hw_params(struct comp_dev *dev, struct sof_ipc_stream_params *params, int dir) { - struct dai_data *dd = comp_get_drvdata(dev); - struct file_comp_data *cd = comp_get_drvdata(dd->dai); + struct processing_module *mod = comp_mod(dev); + struct file_comp_data *cd = module_get_private_data(mod); - comp_info(dev, "file_hw_params()"); + debug_print("file_hw_params()"); params->direction = dir; params->rate = cd->rate; params->channels = cd->channels; @@ -905,50 +796,20 @@ static int file_get_hw_params(struct comp_dev *dev, return 0; } -static const struct comp_driver comp_file_host = { - .type = SOF_COMP_HOST, - .uid = SOF_RT_UUID(file_uuid), - .tctx = &file_tr, - .ops = { - .create = file_new, - .free = file_free, - .params = file_params, - .cmd = file_cmd, - .trigger = file_trigger, - .copy = file_copy, - .prepare = file_prepare, - .reset = file_reset, - }, - -}; - -static const struct comp_driver comp_file_dai = { - .type = SOF_COMP_DAI, - .uid = SOF_RT_UUID(file_uuid), - .tctx = &file_tr, - .ops = { - .create = file_new, - .free = file_free, - .params = file_params, - .cmd = file_cmd, - .trigger = file_trigger, - .copy = file_copy, - .prepare = file_prepare, - .reset = file_reset, - .dai_get_hw_params = file_get_hw_params, - }, -}; - -static struct comp_driver_info comp_file_host_info = { - .drv = &comp_file_host, +/* Needed for SOF_COMP_DAI */ +static struct module_endpoint_ops file_endpoint_ops = { + .dai_get_hw_params = file_get_hw_params, + .trigger = file_trigger, }; -static struct comp_driver_info comp_file_dai_info = { - .drv = &comp_file_dai, +static const struct module_interface file_interface = { + .init = file_init, + .prepare = file_prepare, + .process_audio_stream = file_process, + .reset = file_reset, + .free = file_free, + .endpoint_ops = &file_endpoint_ops, }; -void sys_comp_file_init(void) -{ - comp_register(&comp_file_host_info); - comp_register(&comp_file_dai_info); -} +DECLARE_MODULE_ADAPTER(file_interface, file_uuid, file_tr); +SOF_MODULE_INIT(file, sys_comp_module_file_interface_init); diff --git a/tools/testbench/include/testbench/common_test.h b/tools/testbench/include/testbench/common_test.h index dd43c29ab0eb..4960c13e2d02 100644 --- a/tools/testbench/include/testbench/common_test.h +++ b/tools/testbench/include/testbench/common_test.h @@ -87,10 +87,6 @@ int tb_parse_topology(struct testbench_prm *tb, struct tplg_context *ctx); int edf_scheduler_init(void); -void sys_comp_file_init(void); - -void sys_comp_filewrite_init(void); - int tb_setup(struct sof *sof, struct testbench_prm *tp); void tb_free(struct sof *sof); diff --git a/tools/testbench/include/testbench/file.h b/tools/testbench/include/testbench/file.h index d18f97972985..438c7b519d21 100644 --- a/tools/testbench/include/testbench/file.h +++ b/tools/testbench/include/testbench/file.h @@ -8,8 +8,8 @@ * Ranjani Sridharan */ -#ifndef _FILE_H -#define _FILE_H +#ifndef _TESTBENCH_FILE_H +#define _TESTBENCH_FILE_H #include @@ -42,6 +42,8 @@ struct file_state { bool write_failed; }; +struct file_comp_data; + /* file comp data */ struct file_comp_data { struct file_state fs; @@ -49,12 +51,15 @@ struct file_comp_data { uint32_t channels; uint32_t rate; int sample_container_bytes; - int (*file_func)(struct comp_dev *dev, struct audio_stream *sink, + int (*file_func)(struct file_comp_data *cd, struct audio_stream *sink, struct audio_stream *source, uint32_t frames); /* maximum limits */ int max_samples; int max_copies; + int max_frames; }; -#endif +void sys_comp_module_file_interface_init(void); + +#endif /* _TESTBENCH_FILE */ diff --git a/tools/testbench/testbench.c b/tools/testbench/testbench.c index d4b03538792c..0f464d577f1f 100644 --- a/tools/testbench/testbench.c +++ b/tools/testbench/testbench.c @@ -1,10 +1,11 @@ // SPDX-License-Identifier: BSD-3-Clause // -// Copyright(c) 2018 Intel Corporation. All rights reserved. +// Copyright(c) 2018-2024 Intel Corporation. All rights reserved. // // Author: Seppo Ingalsuo // Ranjani Sridharan +#include #include #include #include @@ -533,8 +534,8 @@ static void test_pipeline_stats(struct testbench_prm *tp, { int count = 1; struct ipc_comp_dev *icd; - struct comp_dev *cd; - struct dai_data *dd; + struct comp_dev *file_dev; + struct processing_module *file_mod; struct pipeline *p; struct file_comp_data *frcd, *fwcd; long long file_cycles, pipeline_cycles; @@ -548,9 +549,9 @@ static void test_pipeline_stats(struct testbench_prm *tp, fprintf(stderr, "error: failed to get pointers to filewrite\n"); exit(EXIT_FAILURE); } - cd = icd->cd; - dd = comp_get_drvdata(cd); - fwcd = comp_get_drvdata(dd->dai); + file_dev = icd->cd; + file_mod = comp_mod(file_dev); + fwcd = module_get_private_data(file_mod); /* Get pointer to fileread */ icd = ipc_get_comp_by_id(sof_get()->ipc, tp->fr_id); @@ -558,9 +559,9 @@ static void test_pipeline_stats(struct testbench_prm *tp, fprintf(stderr, "error: failed to get pointers to fileread\n"); exit(EXIT_FAILURE); } - cd = icd->cd; - dd = comp_get_drvdata(cd); - frcd = comp_get_drvdata(dd->dai); + file_dev = icd->cd; + file_mod = comp_mod(file_dev); + frcd = module_get_private_data(file_mod); /* Run pipeline until EOF from fileread */ icd = ipc_get_comp_by_id(sof_get()->ipc, ctx->sched_id); diff --git a/tools/testbench/topology.c b/tools/testbench/topology.c index 95e1450df693..00364b61a398 100644 --- a/tools/testbench/topology.c +++ b/tools/testbench/topology.c @@ -1,23 +1,24 @@ // SPDX-License-Identifier: BSD-3-Clause // -// Copyright(c) 2018 Intel Corporation. All rights reserved. +// Copyright(c) 2018-2024 Intel Corporation. All rights reserved. // // Author: Ranjani Sridharan // Liam Girdwood /* Topology loader to set up components and pipeline */ -#include -#include -#include -#include -#include -#include #include #include #include -#include +#include +#include +#include #include +#include +#include +#include +#include +#include #include "testbench/common_test.h" #include "testbench/file.h" @@ -286,11 +287,13 @@ static int tb_new_fileread(struct tplg_context *ctx, fileread->comp.id = comp_id; /* use fileread comp as scheduling comp */ + fileread->size = sizeof(struct ipc_comp_file); fileread->comp.core = ctx->core_id; - fileread->comp.hdr.size = sizeof(struct sof_ipc_comp_file); + fileread->comp.hdr.size = sizeof(struct sof_ipc_comp_file) + UUID_SIZE; fileread->comp.type = SOF_COMP_FILEREAD; fileread->comp.pipeline_id = ctx->pipeline_id; fileread->config.hdr.size = sizeof(struct sof_ipc_comp_config); + fileread->comp.ext_data_length = UUID_SIZE; return 0; } @@ -338,10 +341,12 @@ static int tb_new_filewrite(struct tplg_context *ctx, filewrite->comp.core = ctx->core_id; filewrite->comp.id = comp_id; filewrite->mode = FILE_WRITE; - filewrite->comp.hdr.size = sizeof(struct sof_ipc_comp_file); + filewrite->size = sizeof(struct ipc_comp_file); + filewrite->comp.hdr.size = sizeof(struct sof_ipc_comp_file) + UUID_SIZE; filewrite->comp.type = SOF_COMP_FILEWRITE; filewrite->comp.pipeline_id = ctx->pipeline_id; filewrite->config.hdr.size = sizeof(struct sof_ipc_comp_config); + filewrite->comp.ext_data_length = UUID_SIZE; return 0; } @@ -350,17 +355,22 @@ static int tb_register_fileread(struct testbench_prm *tp, struct tplg_context *ctx, int dir) { struct sof *sof = ctx->sof; - struct sof_ipc_comp_file fileread = {{{0}}}; + struct sof_ipc_comp_file *fileread; + struct sof_uuid *file_uuid; int ret; - fileread.config.frame_fmt = tplg_find_format(tp->bits_in); + fileread = calloc(MAX_TPLG_OBJECT_SIZE, 1); + if (!fileread) + return -ENOMEM; + + fileread->config.frame_fmt = tplg_find_format(tp->bits_in); - ret = tb_new_fileread(ctx, &fileread); + ret = tb_new_fileread(ctx, fileread); if (ret < 0) return ret; /* configure fileread */ - fileread.fn = strdup(tp->input_file[tp->input_file_index]); + fileread->fn = strdup(tp->input_file[tp->input_file_index]); if (tp->input_file_index == 0) tp->fr_id = ctx->comp_id; @@ -369,23 +379,33 @@ static int tb_register_fileread(struct testbench_prm *tp, tp->input_file_index++; /* Set format from testbench command line*/ - fileread.rate = tp->fs_in; - fileread.channels = tp->channels_in; - fileread.frame_fmt = tp->frame_fmt; - fileread.direction = dir; - - /* Set type depending on direction */ - fileread.comp.type = (dir == SOF_IPC_STREAM_PLAYBACK) ? - SOF_COMP_HOST : SOF_COMP_DAI; + fileread->rate = tp->fs_in; + fileread->channels = tp->channels_in; + fileread->frame_fmt = tp->frame_fmt; + fileread->direction = dir; + + file_uuid = (struct sof_uuid *)((uint8_t *)fileread + sizeof(struct sof_ipc_comp_file)); + file_uuid->a = 0xbfc7488c; + file_uuid->b = 0x75aa; + file_uuid->c = 0x4ce8; + file_uuid->d[0] = 0x9d; + file_uuid->d[1] = 0xbe; + file_uuid->d[2] = 0xd8; + file_uuid->d[3] = 0xda; + file_uuid->d[4] = 0x08; + file_uuid->d[5] = 0xa6; + file_uuid->d[6] = 0x98; + file_uuid->d[7] = 0xc2; /* create fileread component */ - if (ipc_comp_new(sof->ipc, ipc_to_comp_new(&fileread)) < 0) { + if (ipc_comp_new(sof->ipc, ipc_to_comp_new(fileread)) < 0) { fprintf(stderr, "error: file read\n"); - free(fileread.fn); + free(fileread->fn); return -EINVAL; } - free(fileread.fn); + free(fileread->fn); + free(fileread); return 0; } @@ -394,10 +414,15 @@ static int tb_register_filewrite(struct testbench_prm *tp, struct tplg_context *ctx, int dir) { struct sof *sof = ctx->sof; - struct sof_ipc_comp_file filewrite = {{{0}}}; + struct sof_ipc_comp_file *filewrite; + struct sof_uuid *file_uuid; int ret; - ret = tb_new_filewrite(ctx, &filewrite); + filewrite = calloc(MAX_TPLG_OBJECT_SIZE, 1); + if (!filewrite) + return -ENOMEM; + + ret = tb_new_filewrite(ctx, filewrite); if (ret < 0) return ret; @@ -407,29 +432,39 @@ static int tb_register_filewrite(struct testbench_prm *tp, tp->output_file_index); return -EINVAL; } - filewrite.fn = strdup(tp->output_file[tp->output_file_index]); + filewrite->fn = strdup(tp->output_file[tp->output_file_index]); if (tp->output_file_index == 0) tp->fw_id = ctx->comp_id; tp->output_file_index++; /* Set format from testbench command line*/ - filewrite.rate = tp->fs_out; - filewrite.channels = tp->channels_out; - filewrite.frame_fmt = tp->frame_fmt; - filewrite.direction = dir; - - /* Set type depending on direction */ - filewrite.comp.type = (dir == SOF_IPC_STREAM_PLAYBACK) ? - SOF_COMP_DAI : SOF_COMP_HOST; + filewrite->rate = tp->fs_out; + filewrite->channels = tp->channels_out; + filewrite->frame_fmt = tp->frame_fmt; + filewrite->direction = dir; + + file_uuid = (struct sof_uuid *)((uint8_t *)filewrite + sizeof(struct sof_ipc_comp_file)); + file_uuid->a = 0xbfc7488c; + file_uuid->b = 0x75aa; + file_uuid->c = 0x4ce8; + file_uuid->d[0] = 0x9d; + file_uuid->d[1] = 0xbe; + file_uuid->d[2] = 0xd8; + file_uuid->d[3] = 0xda; + file_uuid->d[4] = 0x08; + file_uuid->d[5] = 0xa6; + file_uuid->d[6] = 0x98; + file_uuid->d[7] = 0xc2; /* create filewrite component */ - if (ipc_comp_new(sof->ipc, ipc_to_comp_new(&filewrite)) < 0) { + if (ipc_comp_new(sof->ipc, ipc_to_comp_new(filewrite)) < 0) { fprintf(stderr, "error: new file write\n"); - free(filewrite.fn); + free(filewrite->fn); return -EINVAL; } - free(filewrite.fn); + free(filewrite->fn); + free(filewrite); return 0; }