diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 46b50e131643..4f1fb1388c9b 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -5,6 +5,7 @@ add_subdirectory(arch) add_subdirectory(ipc) add_subdirectory(audio) add_subdirectory(lib) +add_subdirectory(math) add_local_sources(sof spinlock.c) if(CONFIG_LIBRARY) @@ -14,7 +15,6 @@ endif() add_subdirectory(debug) add_subdirectory(drivers) add_subdirectory(init) -add_subdirectory(math) add_subdirectory(schedule) if (CONFIG_TRACE) diff --git a/src/audio/CMakeLists.txt b/src/audio/CMakeLists.txt index 01ec7be261c2..c423d39261db 100644 --- a/src/audio/CMakeLists.txt +++ b/src/audio/CMakeLists.txt @@ -60,6 +60,11 @@ if(NOT CONFIG_LIBRARY) detect_test.c ) endif() + if(CONFIG_COMP_TEST_SMART_AMP) + add_local_sources(sof + smart_amp_test.c + ) + endif() add_subdirectory(pcm_converter) if(CONFIG_COMP_ASRC) add_subdirectory(asrc) diff --git a/src/audio/Kconfig b/src/audio/Kconfig index 36828d75ceb9..0fa7adb83de0 100644 --- a/src/audio/Kconfig +++ b/src/audio/Kconfig @@ -122,6 +122,13 @@ config COMP_DCBLOCK Select for DC Blocking Filter component. This component filters out the DC offset which often originates from a microphone's output. +config COMP_TEST_SMART_AMP + depends on CAVS && !CAVS_VERSION_1_5 + bool "Smart amplifier test component" + default y + help + Select for test smart amplifier component + config COMP_TEST_KEYPHRASE bool "KEYPHRASE_TEST component" default y diff --git a/src/audio/component.c b/src/audio/component.c index 84b6a5e677a3..91f00284238a 100644 --- a/src/audio/component.c +++ b/src/audio/component.c @@ -326,6 +326,158 @@ int comp_verify_params(struct comp_dev *dev, uint32_t flag, return 0; } +void comp_free_model_data(struct comp_dev *dev, struct comp_model_data *model) +{ + if (!model->data) + return; + + rfree(model->data); + model->data = NULL; + model->data_size = 0; + model->crc = 0; + model->data_pos = 0; +} + +int comp_alloc_model_data(struct comp_dev *dev, struct comp_model_data *model, + uint32_t size) +{ + if (!size) + return 0; + + comp_free_model_data(dev, model); + + model->data = rballoc(0, SOF_MEM_CAPS_RAM, size); + + if (!model->data) { + comp_err(dev, "comp_alloc_model_data(): model->data rballoc failed"); + return -ENOMEM; + } + + bzero(model->data, size); + model->data_size = size; + model->data_pos = 0; + model->crc = 0; + + return 0; +} + +int comp_set_model(struct comp_dev *dev, struct comp_model_data *model, + struct sof_ipc_ctrl_data *cdata) +{ + bool done = false; + int ret = 0; + + comp_dbg(dev, "comp_set_model() msg_index = %d, num_elems = %d, remaining = %d ", + cdata->msg_index, cdata->num_elems, + cdata->elems_remaining); + + /* in case when the current package is the first, we should allocate + * memory for whole model data + */ + if (!cdata->msg_index) { + ret = comp_alloc_model_data(dev, model, cdata->data->size); + if (ret < 0) + return ret; + } + + /* return an error in case when we do not have allocated memory for + * model data + */ + if (!model->data) { + comp_err(dev, "comp_set_model(): buffer not allocated"); + return -ENOMEM; + } + + if (!cdata->elems_remaining) { + /* when we receive the last package and do not fill the whole + * allocated buffer, we return an error + */ + if (cdata->num_elems + model->data_pos < model->data_size) { + comp_err(dev, "comp_set_model(): not enough data to fill the buffer"); + // TODO: handle this situation + + return -EINVAL; + } + + /* the whole data were received properly */ + done = true; + comp_dbg(dev, "comp_set_model(): final package received"); + } + + /* return an error in case when received data exceed allocated + * memory + */ + if (cdata->num_elems > model->data_size - model->data_pos) { + comp_err(dev, "comp_set_model(): too much data"); + return -EINVAL; + } + + ret = memcpy_s((char *)model->data + model->data_pos, + model->data_size - model->data_pos, + cdata->data->data, cdata->num_elems); + assert(!ret); + + /* update data_pos variable with received number of elements (num_elem) + */ + model->data_pos += cdata->num_elems; + + /* Update crc value when done */ + if (done) { + model->crc = crc32(0, model->data, model->data_size); + comp_dbg(dev, "comp_set_model() done, memory_size = 0x%x, crc = 0x%08x", + model->data_size, model->crc); + } + + return 0; +} + +int comp_get_model(struct comp_dev *dev, struct comp_model_data *model, + struct sof_ipc_ctrl_data *cdata, int size) +{ + size_t bs; + int ret = 0; + + comp_dbg(dev, "comp_get_model() msg_index = %d, num_elems = %d, remaining = %d ", + cdata->msg_index, cdata->num_elems, + cdata->elems_remaining); + + /* Copy back to user space */ + if (model->data) { + /* reset data_pos variable in case of copying first element */ + if (!cdata->msg_index) { + model->data_pos = 0; + comp_dbg(dev, "comp_get_model() model data_size = 0x%x", + model->data_size); + } + + bs = cdata->num_elems; + + /* return an error in case of mismatch between num_elems and + * required size + */ + if (bs > size) { + comp_err(dev, "comp_get_model(): invalid size %d", bs); + return -EINVAL; + } + + /* copy required size of data */ + ret = memcpy_s(cdata->data->data, size, + (char *)model->data + model->data_pos, + bs); + assert(!ret); + + cdata->data->abi = SOF_ABI_VERSION; + cdata->data->size = model->data_size; + model->data_pos += bs; + + } else { + comp_err(dev, "comp_get_model(): !model->data"); + ret = -EINVAL; + } + + return ret; +} + struct comp_dev *comp_make_shared(struct comp_dev *dev) { struct list_item *old_bsource_list = &dev->bsource_list; diff --git a/src/audio/detect_test.c b/src/audio/detect_test.c index 4745d3fc23f1..6dd9684a5b68 100644 --- a/src/audio/detect_test.c +++ b/src/audio/detect_test.c @@ -56,16 +56,9 @@ DECLARE_SOF_RT_UUID("kd-test", keyword_uuid, 0xeba8d51f, 0x7827, 0x47b5, DECLARE_TR_CTX(keyword_tr, SOF_UUID(keyword_uuid), LOG_LEVEL_INFO); -struct model_data { - uint32_t data_size; - void *data; - uint32_t crc; - uint32_t data_pos; /**< current copy position for model data */ -}; - struct comp_data { struct sof_detect_test_config config; - struct model_data model; + struct comp_model_data model; int32_t activation; uint32_t detected; uint32_t detect_preamble; /**< current keyphrase preamble length */ @@ -199,48 +192,6 @@ static void default_detect_test(struct comp_dev *dev, } } -static void free_mem_load(struct comp_data *cd) -{ - if (!cd) { - comp_cl_err(&comp_keyword, "free_mem_load(): invalid cd"); - return; - } - - if (cd->model.data) { - rfree(cd->model.data); - cd->model.data = NULL; - cd->model.data_size = 0; - cd->model.crc = 0; - cd->model.data_pos = 0; - } -} - -static int alloc_mem_load(struct comp_data *cd, uint32_t size) -{ - if (!size) - return 0; - - if (!cd) { - comp_cl_err(&comp_keyword, "alloc_mem_load(): invalid cd"); - return -EINVAL; - } - - free_mem_load(cd); - - cd->model.data = rballoc(0, SOF_MEM_CAPS_RAM, size); - - if (!cd->model.data) { - comp_cl_err(&comp_keyword, "alloc_mem_load() alloc failed"); - return -ENOMEM; - } - - bzero(cd->model.data, size); - cd->model.data_size = size; - cd->model.data_pos = 0; - - return 0; -} - static int test_keyword_get_threshold(struct comp_dev *dev, int sample_width) { switch (sample_width) { @@ -335,7 +286,7 @@ static struct comp_dev *test_keyword_new(const struct comp_driver *drv, } } - ret = alloc_mem_load(cd, INITIAL_MODEL_DATA_SIZE); + ret = comp_alloc_model_data(dev, &cd->model, INITIAL_MODEL_DATA_SIZE); if (ret < 0) { comp_err(dev, "test_keyword_new(): model data initial failed"); goto fail; @@ -369,7 +320,7 @@ static void test_keyword_free(struct comp_dev *dev) comp_info(dev, "test_keyword_free()"); ipc_msg_free(cd->msg); - free_mem_load(cd); + comp_free_model_data(dev, &cd->model); rfree(cd); rfree(dev); } @@ -456,70 +407,14 @@ static int test_keyword_set_config(struct comp_dev *dev, return test_keyword_apply_config(dev, cfg); } -static int test_keyword_set_model(struct comp_dev *dev, - struct sof_ipc_ctrl_data *cdata) -{ - struct comp_data *cd = comp_get_drvdata(dev); - int ret = 0; - bool done = false; - - comp_dbg(dev, "keyword_ctrl_set_model() msg_index = %d, num_elems = %d, remaining = %d ", - cdata->msg_index, cdata->num_elems, - cdata->elems_remaining); - - if (!cdata->msg_index) { - ret = alloc_mem_load(cd, cdata->data->size); - if (ret < 0) - return ret; - } - - if (!cd->model.data) { - comp_err(dev, "keyword_ctrl_set_model(): buffer not allocated"); - return -EINVAL; - } - - if (!cdata->elems_remaining) { - if (cdata->num_elems + cd->model.data_pos < - cd->model.data_size) { - comp_err(dev, "keyword_ctrl_set_model(): not enough data to fill the buffer"); - - /* TODO: anything to do in such a situation? */ - - return -EINVAL; - } - - done = true; - comp_info(dev, "test_keyword_set_model() final packet received"); - } - - if (cdata->num_elems > - cd->model.data_size - cd->model.data_pos) { - comp_err(dev, "keyword_ctrl_set_model(): too much data"); - return -EINVAL; - } - - ret = memcpy_s((char *)cd->model.data + cd->model.data_pos, - cd->model.data_size - cd->model.data_pos, - cdata->data->data, cdata->num_elems); - assert(!ret); - - cd->model.data_pos += cdata->num_elems; - - if (done) { - /* Set model data done, update crc value */ - cd->model.crc = crc32(0, cd->model.data, - cd->model.data_size); - comp_info(dev, "keyword_ctrl_set_model() done, memory_size = 0x%x, crc = 0x%08x", - cd->model.data_size, cd->model.crc); - } - return 0; -} - static int test_keyword_ctrl_set_bin_data(struct comp_dev *dev, struct sof_ipc_ctrl_data *cdata) { + struct comp_data *cd = comp_get_drvdata(dev); int ret = 0; + assert(cd); + if (dev->state != COMP_STATE_READY) { /* It is a valid request but currently this is not * supported during playback/capture. The driver will @@ -536,7 +431,7 @@ static int test_keyword_ctrl_set_bin_data(struct comp_dev *dev, ret = test_keyword_set_config(dev, cdata); break; case SOF_DETECT_TEST_MODEL: - ret = test_keyword_set_model(dev, cdata); + ret = comp_set_model(dev, &cd->model, cdata); break; default: comp_err(dev, "keyword_ctrl_set_bin_data(): unknown binary data type"); @@ -599,62 +494,21 @@ static int test_keyword_get_config(struct comp_dev *dev, return ret; } -static int test_keyword_get_model(struct comp_dev *dev, - struct sof_ipc_ctrl_data *cdata, int size) -{ - struct comp_data *cd = comp_get_drvdata(dev); - size_t bs; - int ret = 0; - - comp_dbg(dev, "test_keyword_get_model() msg_index = %d, num_elems = %d, remaining = %d ", - cdata->msg_index, cdata->num_elems, - cdata->elems_remaining); - - /* Copy back to user space */ - if (cd->model.data) { - if (!cdata->msg_index) { - /* reset copy offset */ - cd->model.data_pos = 0; - comp_info(dev, "test_keyword_get_model() model data_size = 0x%x, crc = 0x%08x", - cd->model.data_size, cd->model.crc); - } - - bs = cdata->num_elems; - if (bs > size) { - comp_err(dev, "test_keyword_get_model(): invalid size %d", - bs); - return -EINVAL; - } - - ret = memcpy_s(cdata->data->data, size, - (char *)cd->model.data + cd->model.data_pos, - bs); - assert(!ret); - - cdata->data->abi = SOF_ABI_VERSION; - cdata->data->size = cd->model.data_size; - cd->model.data_pos += bs; - - } else { - comp_err(dev, "test_keyword_get_model(): invalid cd->config"); - ret = -EINVAL; - } - - return ret; -} - static int test_keyword_ctrl_get_bin_data(struct comp_dev *dev, struct sof_ipc_ctrl_data *cdata, int size) { + struct comp_data *cd = comp_get_drvdata(dev); int ret = 0; + assert(cd); + switch (cdata->data->type) { case SOF_DETECT_TEST_CONFIG: ret = test_keyword_get_config(dev, cdata, size); break; case SOF_DETECT_TEST_MODEL: - ret = test_keyword_get_model(dev, cdata, size); + ret = comp_get_model(dev, &cd->model, cdata, size); break; default: comp_err(dev, "test_keyword_ctrl_get_bin_data(): unknown binary data type"); diff --git a/src/audio/smart_amp_test.c b/src/audio/smart_amp_test.c new file mode 100644 index 000000000000..4e118dc1f1dd --- /dev/null +++ b/src/audio/smart_amp_test.c @@ -0,0 +1,573 @@ +// SPDX-License-Identifier: BSD-3-Clause +// +// Copyright(c) 2020 Intel Corporation. All rights reserved. +// +// Author: Bartosz Kokoszko + +#include +#include +#include +#include + +static const struct comp_driver comp_smart_amp; + +/* 167a961e-8ae4-11ea-89f1-000c29ce1635 */ +DECLARE_SOF_RT_UUID("smart_amp-test", smart_amp_comp_uuid, 0x167a961e, 0x8ae4, + 0x11ea, 0x89, 0xf1, 0x00, 0x0c, 0x29, 0xce, 0x16, 0x35); + +DECLARE_TR_CTX(smart_amp_comp_tr, SOF_UUID(smart_amp_comp_uuid), + LOG_LEVEL_INFO); + +struct smart_amp_data { + struct sof_smart_amp_config config; + struct comp_model_data model; + + struct comp_buffer *source_buf; /**< stream source buffer */ + struct comp_buffer *feedback_buf; /**< feedback source buffer */ + struct comp_buffer *sink_buf; /**< sink buffer */ + + smart_amp_proc process; + + uint32_t in_channels; + uint32_t out_channels; +}; + +static struct comp_dev *smart_amp_new(const struct comp_driver *drv, + struct sof_ipc_comp *comp) +{ + struct comp_dev *dev; + struct sof_ipc_comp_process *sa; + struct sof_ipc_comp_process *ipc_sa = + (struct sof_ipc_comp_process *)comp; + struct smart_amp_data *sad; + struct sof_smart_amp_config *cfg; + size_t bs; + int ret; + + dev = comp_alloc(drv, COMP_SIZE(struct sof_ipc_comp_process)); + if (!dev) + return NULL; + + sad = rzalloc(SOF_MEM_ZONE_RUNTIME, 0, SOF_MEM_CAPS_RAM, sizeof(*sad)); + + if (!sad) { + rfree(dev); + return NULL; + } + + comp_set_drvdata(dev, sad); + + sa = COMP_GET_IPC(dev, sof_ipc_comp_process); + + ret = memcpy_s(sa, sizeof(*sa), ipc_sa, + sizeof(struct sof_ipc_comp_process)); + assert(!ret); + + cfg = (struct sof_smart_amp_config *)ipc_sa->data; + bs = ipc_sa->size; + + if ((bs > 0) && (bs < sizeof(struct sof_smart_amp_config))) { + comp_err(dev, "smart_amp_new(): failed to apply config"); + + if (sad) + rfree(sad); + rfree(sad); + return NULL; + } + + memcpy_s(&sad->config, sizeof(struct sof_smart_amp_config), cfg, bs); + + dev->state = COMP_STATE_READY; + + return dev; +} + +static int smart_amp_set_config(struct comp_dev *dev, + struct sof_ipc_ctrl_data *cdata) +{ + struct smart_amp_data *sad = comp_get_drvdata(dev); + struct sof_smart_amp_config *cfg; + size_t bs; + + /* Copy new config, find size from header */ + cfg = (struct sof_smart_amp_config *)cdata->data->data; + bs = cfg->size; + + comp_dbg(dev, "smart_amp_set_config(), actual blob size = %u, expected blob size = %u", + bs, sizeof(struct sof_smart_amp_config)); + + if (bs != sizeof(struct sof_smart_amp_config)) { + comp_err(dev, "smart_amp_set_config(): invalid blob size, actual blob size = %u, expected blob size = %u", + bs, sizeof(struct sof_smart_amp_config)); + return -EINVAL; + } + + memcpy_s(&sad->config, sizeof(struct sof_smart_amp_config), cfg, + sizeof(struct sof_smart_amp_config)); + + return 0; +} + +static int smart_amp_get_config(struct comp_dev *dev, + struct sof_ipc_ctrl_data *cdata, int size) +{ + struct smart_amp_data *sad = comp_get_drvdata(dev); + size_t bs; + int ret = 0; + + // Copy back to user space + bs = sad->config.size; + + comp_dbg(dev, "smart_amp_set_config(), actual blob size = %u, expected blob size = %u", + bs, sizeof(struct sof_smart_amp_config)); + + if (bs == 0 || bs > size) + return -EINVAL; + + ret = memcpy_s(cdata->data->data, size, &sad->config, bs); + assert(!ret); + + cdata->data->abi = SOF_ABI_VERSION; + cdata->data->size = bs; + + return ret; +} + +static int smart_amp_ctrl_get_bin_data(struct comp_dev *dev, + struct sof_ipc_ctrl_data *cdata, + int size) +{ + struct smart_amp_data *sad = comp_get_drvdata(dev); + int ret = 0; + + assert(sad); + + switch (cdata->data->type) { + case SOF_SMART_AMP_CONFIG: + ret = smart_amp_get_config(dev, cdata, size); + break; + case SOF_SMART_AMP_MODEL: + ret = comp_get_model(dev, &sad->model, cdata, size); + break; + default: + comp_err(dev, "smart_amp_ctrl_get_bin_data(): unknown binary data type"); + break; + } + + return ret; +} + +static int smart_amp_ctrl_get_data(struct comp_dev *dev, + struct sof_ipc_ctrl_data *cdata, int size) +{ + int ret = 0; + + comp_info(dev, "smart_amp_ctrl_get_data() size: %d", size); + + switch (cdata->cmd) { + case SOF_CTRL_CMD_BINARY: + ret = smart_amp_ctrl_get_bin_data(dev, cdata, size); + break; + default: + comp_err(dev, "smart_amp_ctrl_get_data(): invalid cdata->cmd"); + return -EINVAL; + } + + return ret; +} + +static int smart_amp_ctrl_set_bin_data(struct comp_dev *dev, + struct sof_ipc_ctrl_data *cdata) +{ + struct smart_amp_data *sad = comp_get_drvdata(dev); + int ret = 0; + + assert(sad); + + if (dev->state != COMP_STATE_READY) { + /* It is a valid request but currently this is not + * supported during playback/capture. The driver will + * re-send data in next resume when idle and the new + * configuration will be used when playback/capture + * starts. + */ + comp_err(dev, "smart_amp_ctrl_set_bin_data(): driver is busy"); + return -EBUSY; + } + + switch (cdata->data->type) { + case SOF_SMART_AMP_CONFIG: + ret = smart_amp_set_config(dev, cdata); + break; + case SOF_SMART_AMP_MODEL: + ret = comp_set_model(dev, &sad->model, cdata); + break; + default: + comp_err(dev, "smart_amp_ctrl_set_bin_data(): unknown binary data type"); + break; + } + + return ret; +} + +static int smart_amp_ctrl_set_data(struct comp_dev *dev, + struct sof_ipc_ctrl_data *cdata) +{ + int ret = 0; + + /* Check version from ABI header */ + if (SOF_ABI_VERSION_INCOMPATIBLE(SOF_ABI_VERSION, cdata->data->abi)) { + comp_err(dev, "smart_amp_ctrl_set_data(): invalid version"); + return -EINVAL; + } + + switch (cdata->cmd) { + case SOF_CTRL_CMD_ENUM: + comp_info(dev, "smart_amp_ctrl_set_data(), SOF_CTRL_CMD_ENUM"); + break; + case SOF_CTRL_CMD_BINARY: + comp_info(dev, "smart_amp_ctrl_set_data(), SOF_CTRL_CMD_BINARY"); + ret = smart_amp_ctrl_set_bin_data(dev, cdata); + break; + default: + comp_err(dev, "smart_amp_ctrl_set_data(): invalid cdata->cmd"); + ret = -EINVAL; + break; + } + + return ret; +} + +/* used to pass standard and bespoke commands (with data) to component */ +static int smart_amp_cmd(struct comp_dev *dev, int cmd, void *data, + int max_data_size) +{ + struct sof_ipc_ctrl_data *cdata = data; + + comp_info(dev, "smart_amp_cmd(): cmd: %d", cmd); + + switch (cmd) { + case COMP_CMD_SET_DATA: + return smart_amp_ctrl_set_data(dev, cdata); + case COMP_CMD_GET_DATA: + return smart_amp_ctrl_get_data(dev, cdata, max_data_size); + default: + return -EINVAL; + } +} + +static void smart_amp_free(struct comp_dev *dev) +{ + struct smart_amp_data *sad = comp_get_drvdata(dev); + + comp_info(dev, "smart_amp_free()"); + + comp_free_model_data(dev, &sad->model); + rfree(sad); + rfree(dev); +} + +static int smart_amp_verify_params(struct comp_dev *dev, + struct sof_ipc_stream_params *params) +{ + int ret; + + comp_info(dev, "smart_amp_verify_params()"); + + ret = comp_verify_params(dev, BUFF_PARAMS_CHANNELS, params); + if (ret < 0) { + comp_err(dev, "volume_verify_params() error: comp_verify_params() failed."); + return ret; + } + + return 0; +} + +static int smart_amp_params(struct comp_dev *dev, + struct sof_ipc_stream_params *params) +{ + int err; + + comp_info(dev, "smart_amp_params()"); + + err = smart_amp_verify_params(dev, params); + if (err < 0) { + comp_err(dev, "smart_amp_params(): pcm params verification failed."); + return -EINVAL; + } + + return 0; +} + +static int smart_amp_trigger(struct comp_dev *dev, int cmd) +{ + struct smart_amp_data *sad = comp_get_drvdata(dev); + int ret = 0; + + comp_info(dev, "smart_amp_trigger(), command = %u", cmd); + + ret = comp_set_state(dev, cmd); + + if (ret == COMP_STATUS_STATE_ALREADY_SET) + ret = PPL_STATUS_PATH_STOP; + + switch (cmd) { + case COMP_TRIGGER_START: + case COMP_TRIGGER_RELEASE: + buffer_zero(sad->feedback_buf); + break; + case COMP_TRIGGER_PAUSE: + case COMP_TRIGGER_STOP: + break; + default: + break; + } + + return ret; +} + +static int smart_amp_process_s16(struct comp_dev *dev, + const struct audio_stream *source, + const struct audio_stream *sink, + uint32_t frames, int8_t *chan_map) +{ + struct smart_amp_data *sad = comp_get_drvdata(dev); + int16_t *src; + int16_t *dest; + uint32_t in_frag = 0; + uint32_t out_frag = 0; + int i; + int j; + + comp_dbg(dev, "smart_amp_process_s16()"); + + for (i = 0; i < frames; i++) { + for (j = 0 ; j < sad->out_channels; j++) { + if (chan_map[j] != -1) { + src = audio_stream_read_frag_s16(source, + in_frag + + chan_map[j]); + dest = audio_stream_write_frag_s16(sink, + out_frag); + *dest = *src; + } + out_frag++; + } + in_frag += source->channels; + } + return 0; +} + +static int smart_amp_process_s32(struct comp_dev *dev, + const struct audio_stream *source, + const struct audio_stream *sink, + uint32_t frames, int8_t *chan_map) +{ + struct smart_amp_data *sad = comp_get_drvdata(dev); + int32_t *src; + int32_t *dest; + uint32_t in_frag = 0; + uint32_t out_frag = 0; + int i; + int j; + + comp_dbg(dev, "smart_amp_process_s32()"); + + for (i = 0; i < frames; i++) { + for (j = 0 ; j < sad->out_channels; j++) { + if (chan_map[j] != -1) { + src = audio_stream_read_frag_s32(source, + in_frag + + chan_map[j]); + dest = audio_stream_write_frag_s32(sink, + out_frag); + *dest = *src; + } + out_frag++; + } + in_frag += source->channels; + } + + return 0; +} + +static smart_amp_proc get_smart_amp_process(struct comp_dev *dev) +{ + struct smart_amp_data *sad = comp_get_drvdata(dev); + + switch (sad->source_buf->stream.frame_fmt) { + case SOF_IPC_FRAME_S16_LE: + return smart_amp_process_s16; + case SOF_IPC_FRAME_S24_4LE: + case SOF_IPC_FRAME_S32_LE: + return smart_amp_process_s32; + default: + comp_err(dev, "smart_amp_process() error: not supported frame format"); + return NULL; + } +} + +static int smart_amp_copy(struct comp_dev *dev) +{ + struct smart_amp_data *sad = comp_get_drvdata(dev); + uint32_t avail_passthrough_frames; + uint32_t avail_feedback_frames; + uint32_t avail_frames; + uint32_t source_bytes; + uint32_t sink_bytes; + uint32_t feedback_bytes; + uint32_t source_flags = 0; + uint32_t sink_flags = 0; + uint32_t feedback_flags = 0; + int ret = 0; + + comp_dbg(dev, "smart_amp_copy()"); + + buffer_lock(sad->source_buf, &source_flags); + buffer_lock(sad->sink_buf, &sink_flags); + + /* available bytes and samples calculation */ + avail_passthrough_frames = + audio_stream_avail_frames(&sad->source_buf->stream, + &sad->sink_buf->stream); + + buffer_unlock(sad->source_buf, source_flags); + buffer_unlock(sad->sink_buf, sink_flags); + + avail_frames = avail_passthrough_frames; + + comp_dbg(dev, "smart_amp_copy(): avail_passthrough_frames: %d", + avail_passthrough_frames); + + buffer_lock(sad->feedback_buf, &feedback_flags); + if (sad->feedback_buf->source->state == dev->state) { + /* feedback */ + avail_feedback_frames = sad->feedback_buf->stream.avail / + audio_stream_frame_bytes(&sad->feedback_buf->stream); + + avail_frames = MIN(avail_passthrough_frames, + avail_feedback_frames); + + feedback_bytes = avail_frames * + audio_stream_frame_bytes(&sad->feedback_buf->stream); + + buffer_unlock(sad->feedback_buf, feedback_flags); + + comp_dbg(dev, "smart_amp_copy(): processing %d feedback bytes", + feedback_bytes); + + sad->process(dev, &sad->feedback_buf->stream, + &sad->sink_buf->stream, avail_frames, + sad->config.feedback_ch_map); + + comp_update_buffer_consume(sad->feedback_buf, feedback_bytes); + } + + /* bytes calculation */ + buffer_lock(sad->source_buf, &source_flags); + source_bytes = avail_frames * + audio_stream_frame_bytes(&sad->source_buf->stream); + buffer_unlock(sad->source_buf, source_flags); + + buffer_lock(sad->sink_buf, &sink_flags); + sink_bytes = avail_frames * + audio_stream_frame_bytes(&sad->sink_buf->stream); + buffer_unlock(sad->sink_buf, sink_flags); + + /* process data */ + sad->process(dev, &sad->source_buf->stream, &sad->sink_buf->stream, + avail_frames, sad->config.source_ch_map); + + /* source/sink buffer pointers update */ + comp_update_buffer_consume(sad->source_buf, source_bytes); + comp_update_buffer_produce(sad->sink_buf, sink_bytes); + + return ret; +} + +static int smart_amp_reset(struct comp_dev *dev) +{ + comp_info(dev, "smart_amp_reset()"); + + comp_set_state(dev, COMP_TRIGGER_RESET); + + return 0; +} + +static int smart_amp_prepare(struct comp_dev *dev) +{ + struct smart_amp_data *sad = comp_get_drvdata(dev); + struct comp_buffer *source_buffer; + struct list_item *blist; + int ret; + + comp_info(dev, "smart_amp_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; + + /* searching for stream and feedback source buffers */ + list_for_item(blist, &dev->bsource_list) { + source_buffer = container_of(blist, struct comp_buffer, + sink_list); + + if (source_buffer->source->comp.type == SOF_COMP_DEMUX) + sad->feedback_buf = source_buffer; + else + sad->source_buf = source_buffer; + } + + sad->sink_buf = list_first_item(&dev->bsink_list, struct comp_buffer, + source_list); + + sad->in_channels = sad->source_buf->stream.channels; + sad->out_channels = sad->sink_buf->stream.channels; + + sad->feedback_buf->stream.channels = sad->config.feedback_channels; + + /* TODO: + * ATM feedback buffer frame_fmt is hardcoded to s32_le. It should be + * removed when parameters negotiation between pipelines will prepared + */ + sad->feedback_buf->stream.frame_fmt = SOF_IPC_FRAME_S32_LE; + + sad->process = get_smart_amp_process(dev); + if (!sad->process) { + comp_err(dev, "smart_amp_prepare(): get_smart_amp_process failed"); + return -EINVAL; + } + + return 0; +} + +static const struct comp_driver comp_smart_amp = { + .type = SOF_COMP_SMART_AMP, + .uid = SOF_RT_UUID(smart_amp_comp_uuid), + .tctx = &smart_amp_comp_tr, + .ops = { + .create = smart_amp_new, + .free = smart_amp_free, + .params = smart_amp_params, + .prepare = smart_amp_prepare, + .cmd = smart_amp_cmd, + .trigger = smart_amp_trigger, + .copy = smart_amp_copy, + .reset = smart_amp_reset, + }, +}; + +static SHARED_DATA struct comp_driver_info comp_smart_amp_info = { + .drv = &comp_smart_amp, +}; + +static void sys_comp_smart_amp_init(void) +{ + comp_register(platform_shared_get(&comp_smart_amp_info, + sizeof(comp_smart_amp_info))); +} + +DECLARE_MODULE(sys_comp_smart_amp_init); diff --git a/src/include/sof/audio/component.h b/src/include/sof/audio/component.h index 2b59fbdb88a5..ef8fc85c8faa 100644 --- a/src/include/sof/audio/component.h +++ b/src/include/sof/audio/component.h @@ -472,6 +472,16 @@ struct comp_copy_limits { int sink_frame_bytes; }; +/** \brief Struct for large component configs */ +struct comp_model_data { + uint32_t data_size; /**< size of component's model data */ + void *data; /**< pointer to model data */ + uint32_t crc; /**< crc value of model data */ + uint32_t data_pos; /**< indicates a data position in data + * sending/receiving process + */ +}; + /** \brief Computes size of the component device including ipc config. */ #define COMP_SIZE(x) \ (sizeof(struct comp_dev) - sizeof(struct sof_ipc_comp) + sizeof(x)) @@ -725,6 +735,45 @@ void comp_get_copy_limits_with_lock(struct comp_buffer *source, buffer_unlock(source, source_flags); } +/** + * Frees data for large component configurations. + * + * @param dev Component device + * @param model Component model struct + */ +void comp_free_model_data(struct comp_dev *dev, struct comp_model_data *model); + +/** + * Allocates data for large component configurations. + * + * @param dev Component device + * @param model Component model struct + * @param size Required size. + */ +int comp_alloc_model_data(struct comp_dev *dev, struct comp_model_data *model, + uint32_t size); + +/** + * Gets model data for large component configurations. + * + * @param dev Component device + * @param model Component model struct + * @param cdata IPC ctrl data + */ +int comp_set_model(struct comp_dev *dev, struct comp_model_data *model, + struct sof_ipc_ctrl_data *cdata); +/** + * + * Set model data for large component configurations. + * + * @param dev Component device + * @param model Component model struct + * @param cdata IPC ctrl data + * @param size Required size + */ +int comp_get_model(struct comp_dev *dev, struct comp_model_data *model, + struct sof_ipc_ctrl_data *cdata, int size); + /** * Called by component in params() function in order to set and update some of * downstream (playback) or upstream (capture) buffer parameters with pcm diff --git a/src/include/sof/audio/smart_amp_test.h b/src/include/sof/audio/smart_amp_test.h new file mode 100644 index 000000000000..0fbe14c20319 --- /dev/null +++ b/src/include/sof/audio/smart_amp_test.h @@ -0,0 +1,89 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * + * Copyright(c) 2020 Intel Corporation. All rights reserved. + * + * Author: Bartosz Kokoszko + */ + +#ifndef __SOF_AUDIO_SMART_AMP_H__ +#define __SOF_AUDIO_SMART_AMP_H__ + +#include +#include + +#define SMART_AMP_MAX_STREAM_CHAN 8 + +/** IPC blob types */ +#define SOF_SMART_AMP_CONFIG 0 +#define SOF_SMART_AMP_MODEL 1 + +struct smart_amp_model_data { + uint32_t data_size; + void *data; + uint32_t crc; + uint32_t data_pos; +}; + +typedef int(*smart_amp_proc)(struct comp_dev *dev, + const struct audio_stream *source, + const struct audio_stream *sink, uint32_t frames, + int8_t *chan_map); + +/* Each channel map specifies which channel from input (buffer between host + * and smart amp - source_chan_map[] or feedback buffer between smart amp and + * demux - feedback_chan_map[]) will be copied to specific smart amp output + * channel. Value -1 means that for this output channel we will not take any + * channel from specific input. + * + * E.g. assuming that a smart amplifier input stream is configured + * with channels parameter set to 2, feedback stream with channels set to 8 + * and smart amplifier output stream with channels set to 4 (smart amplifier + * converts stream from 2 to 4 channels) and source/feedback_ch_map's are as + * follows: + * + * source_ch_map = [0, 1, -1, -1, -1 ,-1 ,-1, -1] + * feedback_ch_map = [-1, -1, 0, 1, -1, -1, -1, -1] + * + * As a result smart amplifier test component will procces source and feedback + * streams in following way: + * + * + * + * PLAYBACK + * STREAM +---+ + * | 0 +------------+ + * +---+ | SMART AMPLIFIER + * | 1 +---------+ | OUTPUT + * +---+ | | +---+ + * | +-->+ 0 | + * | +---+ + * +----->+ 1 | + * +---+ + * +---+ +--->+ 2 | + * FEEDBACK | 0 +-----------+ +---+ + * STREAM +---+ +->| 3 | + * | 1 +-------------+ +---+ + * +---+ | 4 | + * | 2 | +---+ + * +---+ | 5 | + * | 3 | +---+ + * +---+ | 6 | + * | 4 | +---+ + * +---+ | 7 | + * | 5 | +---+ + * +---+ + * | 6 | + * +---+ + * | 7 | + * +---+ + * + */ + +struct sof_smart_amp_config { + uint32_t size; + uint32_t feedback_channels; + int8_t source_ch_map[PLATFORM_MAX_CHANNELS]; + int8_t feedback_ch_map[PLATFORM_MAX_CHANNELS]; +}; + +#endif /* __SOF_AUDIO_SMART_AMP_H__ */ diff --git a/src/math/CMakeLists.txt b/src/math/CMakeLists.txt index 0c0ad5189f52..1a5158f531cc 100644 --- a/src/math/CMakeLists.txt +++ b/src/math/CMakeLists.txt @@ -1,3 +1,9 @@ # SPDX-License-Identifier: BSD-3-Clause add_local_sources(sof numbers.c trig.c decibels.c) + +if(BUILD_LIBRARY) + return() +endif() + +add_local_sources(sof trig.c decibels.c) \ No newline at end of file diff --git a/test/cmocka/src/audio/component/mock.c b/test/cmocka/src/audio/component/mock.c index 1471ea3c9945..b54ceee3e42d 100644 --- a/test/cmocka/src/audio/component/mock.c +++ b/test/cmocka/src/audio/component/mock.c @@ -38,6 +38,11 @@ void pipeline_xrun(struct pipeline *p, struct comp_dev *dev, int32_t bytes) { } +uint32_t crc32(uint32_t base, const void *data, uint32_t bytes) +{ + return 0; +} + struct sof *sof_get(void) { return &sof; diff --git a/tools/testbench/include/testbench/common_test.h b/tools/testbench/include/testbench/common_test.h index 409e3a6a5606..a3dcfc4e766b 100644 --- a/tools/testbench/include/testbench/common_test.h +++ b/tools/testbench/include/testbench/common_test.h @@ -12,6 +12,7 @@ #include #include #include +#include #include #define DEBUG_MSG_LEN 256