diff --git a/src/audio/module_adapter/CMakeLists.txt b/src/audio/module_adapter/CMakeLists.txt index 25c9281dc64d..779c0f656a04 100644 --- a/src/audio/module_adapter/CMakeLists.txt +++ b/src/audio/module_adapter/CMakeLists.txt @@ -10,8 +10,12 @@ is_zephyr(zephyr) if(zephyr) ### Zephyr ### # modules and codecs in alphabetical order - - zephyr_library_sources_ifdef(CONFIG_CADENCE_CODEC module/cadence.c) +if (CONFIG_IPC_MAJOR_3) + zephyr_library_sources_ifdef(CONFIG_CADENCE_CODEC module/cadence.c module/cadence_ipc3.c) +elseif (CONFIG_IPC_MAJOR_4) + zephyr_include_directories(${sof_top_dir}/src/include/sof/audio/cadence) + zephyr_library_sources_ifdef(CONFIG_CADENCE_CODEC module/cadence.c module/cadence_ipc4.c) +endif() if (CONFIG_CADENCE_CODEC_AAC_DEC) zephyr_library_import(xa_aac_dec ${CONFIG_CADENCE_CODEC_AAC_DEC_LIB}) diff --git a/src/audio/module_adapter/module/cadence.c b/src/audio/module_adapter/module/cadence.c index df936790bb7e..e04e9f621890 100644 --- a/src/audio/module_adapter/module/cadence.c +++ b/src/audio/module_adapter/module/cadence.c @@ -1,15 +1,7 @@ // SPDX-License-Identifier: BSD-3-Clause // -// Copyright(c) 2020 Intel Corporation. All rights reserved. +// Copyright(c) 2020 - 2026 Intel Corporation. All rights reserved. // -// Author: Marcin Rajwa - -/* - * \file cadence.c - * \brief Cadence Codec API - * \author Marcin Rajwa - * - */ #include #include @@ -18,29 +10,10 @@ LOG_MODULE_REGISTER(cadence_codec, CONFIG_SOF_LOG_LEVEL); -SOF_DEFINE_REG_UUID(cadence_codec); - -DECLARE_TR_CTX(cadence_codec_tr, SOF_UUID(cadence_codec_uuid), LOG_LEVEL_INFO); - -enum cadence_api_id { - CADENCE_CODEC_WRAPPER_ID = 0x01, - CADENCE_CODEC_AAC_DEC_ID = 0x02, - CADENCE_CODEC_BSAC_DEC_ID = 0x03, - CADENCE_CODEC_DAB_DEC_ID = 0x04, - CADENCE_CODEC_DRM_DEC_ID = 0x05, - CADENCE_CODEC_MP3_DEC_ID = 0x06, - CADENCE_CODEC_SBC_DEC_ID = 0x07, - CADENCE_CODEC_VORBIS_DEC_ID = 0x08, - CADENCE_CODEC_SRC_PP_ID = 0x09, - CADENCE_CODEC_MP3_ENC_ID = 0x0A, -}; - -#define DEFAULT_CODEC_ID CADENCE_CODEC_WRAPPER_ID - /*****************************************************************************/ /* Cadence API functions array */ /*****************************************************************************/ -static struct cadence_api cadence_api_table[] = { +struct cadence_api cadence_api_table[] = { #ifdef CONFIG_CADENCE_CODEC_WRAPPER { .id = CADENCE_CODEC_WRAPPER_ID, @@ -103,52 +76,15 @@ static struct cadence_api cadence_api_table[] = { #endif }; -#if CONFIG_IPC_MAJOR_4 -static int cadence_codec_resolve_api(struct processing_module *mod) -{ - struct comp_dev *dev = mod->dev; - struct cadence_codec_data *cd = module_get_private_data(mod); - uint32_t api_id = CODEC_GET_API_ID(DEFAULT_CODEC_ID); - uint32_t n_apis = ARRAY_SIZE(cadence_api_table); - struct module_data *codec = &mod->priv; - struct module_param *param; - int i; - xa_codec_func_t *api = NULL; - - /* For ipc4 protocol codec parameters has to be retrieved from configuration */ - if (!codec->cfg.data) { - comp_err(dev, "could not find cadence config"); - return -EINVAL; - } - param = codec->cfg.data; - api_id = param->id >> 16; - - /* Find and assign API function */ - for (i = 0; i < n_apis; i++) { - if (cadence_api_table[i].id == api_id) { - api = cadence_api_table[i].api; - break; - } - } - - /* Verify API assignment */ - if (!api) { - comp_err(dev, "could not find API function for id %x", - api_id); - return -EINVAL; - } - cd->api = api; - cd->api_id = api_id; - - return 0; -} -#elif CONFIG_IPC_MAJOR_3 -static int cadence_code_get_api_id(uint32_t compress_id) +static int cadence_codec_get_api_id(uint32_t compress_id, uint32_t direction) { /* convert compress id to SOF cadence SOF id */ switch (compress_id) { case SND_AUDIOCODEC_MP3: - return CADENCE_CODEC_MP3_DEC_ID; + if (direction == SOF_IPC_STREAM_PLAYBACK) + return CADENCE_CODEC_MP3_DEC_ID; + + return CADENCE_CODEC_MP3_ENC_ID; case SND_AUDIOCODEC_AAC: return CADENCE_CODEC_AAC_DEC_ID; case SND_AUDIOCODEC_VORBIS: @@ -158,311 +94,7 @@ static int cadence_code_get_api_id(uint32_t compress_id) } } -static int cadence_codec_resolve_api(struct processing_module *mod) -{ - int ret; - struct snd_codec codec_params; - struct comp_dev *dev = mod->dev; - struct cadence_codec_data *cd = module_get_private_data(mod); - uint32_t api_id = CODEC_GET_API_ID(DEFAULT_CODEC_ID); - uint32_t n_apis = ARRAY_SIZE(cadence_api_table); - int i; - xa_codec_func_t *api = NULL; - - if (mod->stream_params->ext_data_length) { - ret = memcpy_s(&codec_params, mod->stream_params->ext_data_length, - (uint8_t *)mod->stream_params + sizeof(*mod->stream_params), - mod->stream_params->ext_data_length); - if (ret < 0) - return ret; - - ret = cadence_code_get_api_id(codec_params.id); - if (ret < 0) - return ret; - - api_id = ret; - } - - /* Find and assign API function */ - for (i = 0; i < n_apis; i++) { - if (cadence_api_table[i].id == api_id) { - api = cadence_api_table[i].api; - break; - } - } - - /* Verify API assignment */ - if (!api) { - comp_err(dev, "could not find API function for id %x", - api_id); - return -EINVAL; - } - cd->api = api; - cd->api_id = api_id; - - return 0; -} -#else -#error Unknown IPC major version -#endif - -static int cadence_codec_post_init(struct processing_module *mod) -{ - int ret; - struct comp_dev *dev = mod->dev; - struct cadence_codec_data *cd = module_get_private_data(mod); - uint32_t obj_size; - - comp_dbg(dev, "cadence_codec_post_init() start"); - - ret = cadence_codec_resolve_api(mod); - if (ret < 0) - return ret; - - /* Obtain codec name */ - API_CALL(cd, XA_API_CMD_GET_LIB_ID_STRINGS, - XA_CMD_TYPE_LIB_NAME, cd->name, ret); - if (ret != LIB_NO_ERROR) { - comp_err(dev, "cadence_codec_init() error %x: failed to get lib name", - ret); - return ret; - } - /* Get codec object size */ - API_CALL(cd, XA_API_CMD_GET_API_SIZE, 0, &obj_size, ret); - if (ret != LIB_NO_ERROR) { - comp_err(dev, "cadence_codec_init() error %x: failed to get lib object size", - ret); - return ret; - } - /* Allocate space for codec object */ - cd->self = mod_balloc(mod, obj_size); - if (!cd->self) { - comp_err(dev, "failed to allocate space for lib object"); - return -ENOMEM; - } - - comp_dbg(dev, "allocated %d bytes for lib object", obj_size); - - /* Set all params to their default values */ - API_CALL(cd, XA_API_CMD_INIT, XA_CMD_TYPE_INIT_API_PRE_CONFIG_PARAMS, - NULL, ret); - if (ret != LIB_NO_ERROR) { - mod_free(mod, cd->self); - return ret; - } - - comp_dbg(dev, "cadence_codec_post_init() done"); - - return 0; -} - -#if CONFIG_IPC_MAJOR_4 -static int cadence_codec_init(struct processing_module *mod) -{ - const struct ipc4_cadence_module_cfg *cfg; - struct module_data *codec = &mod->priv; - struct cadence_codec_data *cd; - struct module_config *setup_cfg; - struct comp_dev *dev = mod->dev; - int ret; - - comp_dbg(dev, "cadence_codec_init() start"); - - cd = mod_zalloc(mod, sizeof(struct cadence_codec_data)); - if (!cd) { - comp_err(dev, "failed to allocate memory for cadence codec data"); - return -ENOMEM; - } - - codec->private = cd; - codec->mpd.init_done = 0; - - /* copy the setup config only for the first init */ - if (codec->state == MODULE_DISABLED && codec->cfg.avail) { - setup_cfg = &cd->setup_cfg; - - cfg = (const struct ipc4_cadence_module_cfg *)codec->cfg.init_data; - - /* allocate memory for set up config */ - setup_cfg->data = mod_alloc(mod, cfg->param_size); - if (!setup_cfg->data) { - comp_err(dev, "failed to alloc setup config"); - ret = -ENOMEM; - goto free; - } - - /* allocate memory for runtime set up config */ - codec->cfg.data = mod_alloc(mod, cfg->param_size); - if (!codec->cfg.data) { - comp_err(dev, "failed to alloc runtime setup config"); - ret = -ENOMEM; - goto free_cfg; - } - - codec->cfg.size = cfg->param_size; - ret = memcpy_s(codec->cfg.data, codec->cfg.size, - cfg->param, cfg->param_size); - if (ret) { - comp_err(dev, "failed to init runtime config %d", - ret); - goto free_cfg2; - } - codec->cfg.avail = true; - - setup_cfg->size = cfg->param_size; - ret = memcpy_s(setup_cfg->data, setup_cfg->size, - cfg->param, cfg->param_size); - if (ret) { - comp_err(dev, "failed to copy setup config %d", ret); - goto free_cfg2; - } - setup_cfg->avail = true; - } - - comp_dbg(dev, "cadence_codec_init() done"); - - return 0; - -free_cfg2: - mod_free(mod, codec->cfg.data); -free_cfg: - mod_free(mod, setup_cfg->data); -free: - mod_free(mod, cd); - return ret; -} - -#elif CONFIG_IPC_MAJOR_3 -static int cadence_codec_init(struct processing_module *mod) -{ - struct module_data *codec = &mod->priv; - struct cadence_codec_data *cd; - struct comp_dev *dev = mod->dev; - struct module_config *setup_cfg; - int ret; - - comp_dbg(dev, "cadence_codec_init() start"); - - cd = mod_zalloc(mod, sizeof(struct cadence_codec_data)); - if (!cd) { - comp_err(dev, "failed to allocate memory for cadence codec data"); - return -ENOMEM; - } - - codec->private = cd; - codec->mpd.init_done = 0; - - /* copy the setup config only for the first init */ - if (codec->state == MODULE_DISABLED && codec->cfg.avail) { - setup_cfg = &cd->setup_cfg; - - /* allocate memory for set up config */ - setup_cfg->data = mod_alloc(mod, codec->cfg.size); - if (!setup_cfg->data) { - comp_err(dev, "failed to alloc setup config"); - ret = -ENOMEM; - goto free; - } - - /* copy the setup config */ - setup_cfg->size = codec->cfg.size; - ret = memcpy_s(setup_cfg->data, setup_cfg->size, - codec->cfg.init_data, setup_cfg->size); - if (ret) { - comp_err(dev, "failed to copy setup config %d", ret); - goto free_cfg; - } - setup_cfg->avail = true; - } - - comp_dbg(dev, "cadence_codec_init() done"); - - return 0; - -free_cfg: - mod_free(mod, setup_cfg->data); -free: - mod_free(mod, cd); - return ret; -} - -#else -#error Unknown IPC major version -#endif - -static int cadence_codec_apply_config(struct processing_module *mod) -{ - int ret = 0; - int size; - uint16_t param_id; - uint16_t codec_id; - struct module_config *cfg; - void *data; - struct module_param *param; - struct comp_dev *dev = mod->dev; - struct module_data *codec = &mod->priv; - struct cadence_codec_data *cd = codec->private; - - comp_dbg(dev, "cadence_codec_apply_config() start"); - - cfg = &codec->cfg; - - /* use setup config if no runtime config available. This will be true during reset */ - if (!cfg->avail) - cfg = &cd->setup_cfg; - - data = cfg->data; - size = cfg->size; - - if (!cfg->avail || !size) { - comp_err(dev, "cadence_codec_apply_config() error: no config available"); - return -EIO; - } - - /* Read parameters stored in `data` - it may keep plenty of - * parameters. The `size` variable is equal to param->size * count, - * where count is number of parameters stored in `data`. - */ - while (size > 0) { - param = data; - comp_dbg(dev, "cadence_codec_apply_config() applying param %d value %d", - param->id, param->data[0]); - - param_id = param->id & 0xFF; - codec_id = param->id >> 16; - - /* if the parameter is not for current codec skip it! */ - if (codec_id && codec_id != cd->api_id) { - /* Obtain next parameter */ - data = (char *)data + param->size; - size -= param->size; - continue; - } - - /* Set read parameter */ - API_CALL(cd, XA_API_CMD_SET_CONFIG_PARAM, param_id, - param->data, ret); - if (ret != LIB_NO_ERROR) { - if (LIB_IS_FATAL_ERROR(ret)) { - comp_err(dev, "failed to apply parameter: %d value: %d error: %#x", - param->id, *(int32_t *)param->data, ret); - - return ret; - } - comp_warn(dev, "applied parameter %d value %d with return code: %#x", - param->id, *(int32_t *)param->data, ret); - } - /* Obtain next parameter, it starts right after the preceding one */ - data = (char *)data + param->size; - size -= param->size; - } - - comp_dbg(dev, "cadence_codec_apply_config() done"); - - return 0; -} - -static void free_memory_tables(struct processing_module *mod) +void cadence_codec_free_memory_tables(struct processing_module *mod) { struct cadence_codec_data *cd = module_get_private_data(mod); int i; @@ -476,7 +108,7 @@ static void free_memory_tables(struct processing_module *mod) cd->mem_to_be_freed_len = 0; } -static int init_memory_tables(struct processing_module *mod) +int cadence_codec_init_memory_tables(struct processing_module *mod) { int ret, no_mem_tables, i, mem_type, mem_size, mem_alignment; void *ptr, *scratch, *persistent; @@ -579,12 +211,17 @@ static int init_memory_tables(struct processing_module *mod) return 0; err: - free_memory_tables(mod); + cadence_codec_free_memory_tables(mod); return ret; } -static int cadence_codec_get_samples(struct processing_module *mod) +size_t cadence_api_table_size(void) +{ + return ARRAY_SIZE(cadence_api_table); +} + +int cadence_codec_get_samples(struct processing_module *mod) { struct cadence_codec_data *cd = module_get_private_data(mod); struct comp_dev *dev = mod->dev; @@ -606,19 +243,7 @@ static int cadence_codec_get_samples(struct processing_module *mod) return 0; } -static int cadence_codec_deep_buff_allowed(struct processing_module *mod) -{ - struct cadence_codec_data *cd = module_get_private_data(mod); - - switch (cd->api_id) { - case CADENCE_CODEC_MP3_ENC_ID: - return 0; - default: - return 1; - } -} - -static int cadence_codec_init_process(struct processing_module *mod) +int cadence_codec_init_process(struct processing_module *mod) { int ret; struct module_data *codec = &mod->priv; @@ -669,261 +294,214 @@ static int cadence_codec_init_process(struct processing_module *mod) return 0; } -static int cadence_codec_prepare(struct processing_module *mod, - struct sof_source **sources, int num_of_sources, - struct sof_sink **sinks, int num_of_sinks) +int cadence_codec_free(struct processing_module *mod) { - int ret = 0, mem_tabs_size; - struct comp_dev *dev = mod->dev; - struct module_data *codec = &mod->priv; - struct cadence_codec_data *cd = codec->private; + struct cadence_codec_data *cd = module_get_private_data(mod); + + mod_free(mod, cd->setup_cfg.data); + + cadence_codec_free_memory_tables(mod); + mod_free(mod, cd->mem_tabs); + + mod_free(mod, cd->self); + mod_free(mod, cd); + return 0; +} - comp_dbg(dev, "cadence_codec_prepare() start"); +int cadence_codec_set_configuration(struct processing_module *mod, uint32_t config_id, + enum module_cfg_fragment_position pos, + uint32_t data_offset_size, const uint8_t *fragment, + size_t fragment_size, uint8_t *response, size_t response_size) +{ + struct module_data *md = &mod->priv; + struct comp_dev *dev = mod->dev; + int ret; - ret = cadence_codec_post_init(mod); - if (ret) + ret = module_set_configuration(mod, config_id, pos, data_offset_size, fragment, + fragment_size, response, response_size); + if (ret < 0) return ret; + /* return if more fragments are expected or if the module is not prepared */ + if ((pos != MODULE_CFG_FRAGMENT_LAST && pos != MODULE_CFG_FRAGMENT_SINGLE) || + md->state < MODULE_IDLE) + return 0; + + /* whole configuration received, apply it now */ ret = cadence_codec_apply_config(mod); if (ret) { - comp_err(dev, "cadence_codec_prepare() error %x: failed to apply config", - ret); - return ret; - } - - /* Allocate memory for the codec */ - API_CALL(cd, XA_API_CMD_GET_MEMTABS_SIZE, 0, &mem_tabs_size, ret); - if (ret != LIB_NO_ERROR) { - comp_err(dev, "cadence_codec_prepare() error %x: failed to get memtabs size", - ret); + comp_err(dev, "runtime config apply failed with error %x: ", ret); return ret; } - cd->mem_tabs = mod_alloc(mod, mem_tabs_size); - if (!cd->mem_tabs) { - comp_err(dev, "cadence_codec_prepare() error: failed to allocate space for memtabs"); - return -ENOMEM; - } - - comp_dbg(dev, "allocated %d bytes for memtabs", mem_tabs_size); - - API_CALL(cd, XA_API_CMD_SET_MEMTABS_PTR, 0, cd->mem_tabs, ret); - if (ret != LIB_NO_ERROR) { - comp_err(dev, "cadence_codec_prepare() error %x: failed to set memtabs", - ret); - goto free; - } + comp_dbg(dev, "config applied"); - ret = init_memory_tables(mod); - if (ret != LIB_NO_ERROR) { - comp_err(dev, "cadence_codec_prepare() error %x: failed to init memory tables", - ret); - goto free; - } - /* Check init done status. Note, it may happen that init_done flag will return - * false value, this is normal since some codec variants needs input in order to - * fully finish initialization. That's why at codec_adapter_copy() we call - * codec_init_process() base on result obtained below. - */ -#ifdef CONFIG_CADENCE_CODEC_WRAPPER - /* TODO: remove the "#ifdef CONFIG_CADENCE_CODEC_WRAPPER" once cadence fixes the bug - * in the init/prepare sequence. Basically below API_CALL shall return 1 for - * PCM streams and 0 for compress ones. As it turns out currently it returns 1 - * in both cases so in turn compress stream won't finish its prepare during first copy - * in codec_adapter_copy(). - */ - API_CALL(cd, XA_API_CMD_INIT, XA_CMD_TYPE_INIT_DONE_QUERY, - &codec->mpd.init_done, ret); - if (ret != LIB_NO_ERROR) { - comp_err(dev, "cadence_codec_init_process() error %x: failed to get lib init status", - ret); - return ret; - } -#endif - comp_dbg(dev, "cadence_codec_prepare() done"); return 0; -free: - mod_free(mod, cd->mem_tabs); - return ret; } -static int -cadence_codec_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 cadence_codec_apply_params(struct processing_module *mod, int size, void *data) { - struct comp_buffer *local_buff; - struct comp_dev *dev = mod->dev; struct module_data *codec = &mod->priv; + struct comp_dev *dev = mod->dev; struct cadence_codec_data *cd = codec->private; - int free_bytes, output_bytes = cadence_codec_get_samples(mod) * - mod->stream_params->sample_container_bytes * - mod->stream_params->channels; - uint32_t remaining = input_buffers[0].size; + struct module_param *param; + uint16_t param_id; + uint16_t codec_id; int ret; - if (!cadence_codec_deep_buff_allowed(mod)) { - mod->deep_buff_bytes = 0; - } + /* Read parameters stored in `data` - it may keep plenty of + * parameters. The `size` variable is equal to param->size * count, + * where count is number of parameters stored in `data`. + */ + while (size > 0) { + param = data; + comp_dbg(dev, "cadence_codec_apply_config() applying param %d value %d", + param->id, param->data[0]); - /* Proceed only if we have enough data to fill the module buffer completely */ - if (input_buffers[0].size < codec->mpd.in_buff_size) { - comp_dbg(dev, "not enough data to process"); - return -ENODATA; - } + param_id = param->id & 0xFF; + codec_id = param->id >> 16; - if (!codec->mpd.init_done) { - memcpy_s(codec->mpd.in_buff, codec->mpd.in_buff_size, input_buffers[0].data, - codec->mpd.in_buff_size); - codec->mpd.avail = codec->mpd.in_buff_size; + /* if the parameter is not for current codec skip it! */ + if (codec_id && codec_id != cd->api_id) { + /* Obtain next parameter */ + data = (char *)data + param->size; + size -= param->size; + continue; + } - ret = cadence_codec_init_process(mod); - if (ret) - return ret; + /* Set read parameter */ + API_CALL(cd, XA_API_CMD_SET_CONFIG_PARAM, param_id, + param->data, ret); + if (ret != LIB_NO_ERROR) { + if (LIB_IS_FATAL_ERROR(ret)) { + comp_err(dev, "failed to apply parameter: %d value: %d error: %#x", + param->id, *(int32_t *)param->data, ret); - remaining -= codec->mpd.consumed; - input_buffers[0].consumed = codec->mpd.consumed; + return ret; + } + comp_warn(dev, "applied parameter %d value %d with return code: %#x", + param->id, *(int32_t *)param->data, ret); + } + /* Obtain next parameter, it starts right after the preceding one */ + data = (char *)data + param->size; + size -= param->size; } - /* do not proceed with processing if not enough free space left in the local buffer */ - local_buff = list_first_item(&mod->raw_data_buffers_list, struct comp_buffer, buffers_list); - free_bytes = audio_stream_get_free(&local_buff->stream); - if (free_bytes < output_bytes) - return -ENOSPC; - - /* Proceed only if we have enough data to fill the module buffer completely */ - if (remaining < codec->mpd.in_buff_size) - return -ENODATA; - - memcpy_s(codec->mpd.in_buff, codec->mpd.in_buff_size, - (uint8_t *)input_buffers[0].data + input_buffers[0].consumed, - codec->mpd.in_buff_size); - codec->mpd.avail = codec->mpd.in_buff_size; + return 0; +} - comp_dbg(dev, "cadence_codec_process() start"); +int cadence_init_codec_object(struct processing_module *mod) +{ + int ret; + struct comp_dev *dev = mod->dev; + struct cadence_codec_data *cd = module_get_private_data(mod); + uint32_t obj_size; - API_CALL(cd, XA_API_CMD_SET_INPUT_BYTES, 0, &codec->mpd.avail, ret); - if (ret != LIB_NO_ERROR) { - comp_err(dev, "cadence_codec_process() error %x: failed to set size of input data", - ret); + ret = cadence_codec_resolve_api(mod); + if (ret < 0) return ret; - } - API_CALL(cd, XA_API_CMD_EXECUTE, XA_CMD_TYPE_DO_EXECUTE, NULL, ret); + /* Obtain codec name */ + API_CALL(cd, XA_API_CMD_GET_LIB_ID_STRINGS, + XA_CMD_TYPE_LIB_NAME, cd->name, ret); if (ret != LIB_NO_ERROR) { - if (LIB_IS_FATAL_ERROR(ret)) { - comp_err(dev, "cadence_codec_process() error %x: processing failed", - ret); - return ret; - } - comp_warn(dev, "cadence_codec_process() nonfatal error %x", ret); + comp_err(dev, "failed to get lib name error: %x: ", ret); + return ret; } - - API_CALL(cd, XA_API_CMD_GET_OUTPUT_BYTES, 0, &codec->mpd.produced, ret); + /* Get codec object size */ + API_CALL(cd, XA_API_CMD_GET_API_SIZE, 0, &obj_size, ret); if (ret != LIB_NO_ERROR) { - comp_err(dev, "cadence_codec_process() error %x: could not get produced bytes", - ret); + comp_err(dev, "failed to get lib object size error %x:", ret); return ret; } + /* Allocate space for codec object */ + cd->self = mod_balloc(mod, obj_size); + if (!cd->self) { + comp_err(dev, "failed to allocate space for lib object"); + return -ENOMEM; + } - API_CALL(cd, XA_API_CMD_GET_CURIDX_INPUT_BUF, 0, &codec->mpd.consumed, ret); + comp_dbg(dev, "allocated %d bytes for lib object", obj_size); + + /* Set all params to their default values */ + API_CALL(cd, XA_API_CMD_INIT, XA_CMD_TYPE_INIT_API_PRE_CONFIG_PARAMS, + NULL, ret); if (ret != LIB_NO_ERROR) { - comp_err(dev, "cadence_codec_process() error %x: could not get consumed bytes", - ret); + mod_free(mod, cd->self); return ret; } - /* update consumed with the number of samples consumed during init */ - input_buffers[0].consumed += codec->mpd.consumed; - codec->mpd.consumed = input_buffers[0].consumed; - - /* copy the produced samples into the output buffer */ - memcpy_s(output_buffers[0].data, codec->mpd.produced, codec->mpd.out_buff, - codec->mpd.produced); - output_buffers[0].size = codec->mpd.produced; - - comp_dbg(dev, "cadence_codec_process() done"); - return 0; } -static int cadence_codec_reset(struct processing_module *mod) -{ - struct module_data *codec = &mod->priv; - struct cadence_codec_data *cd = codec->private; - int ret; - - free_memory_tables(mod); - mod_free(mod, cd->mem_tabs); - - /* reset to default params */ - API_CALL(cd, XA_API_CMD_INIT, XA_CMD_TYPE_INIT_API_PRE_CONFIG_PARAMS, NULL, ret); - if (ret != LIB_NO_ERROR) - return ret; - - codec->mpd.init_done = 0; - - mod_free(mod, cd->self); - cd->self = NULL; - - return ret; -} - -static int cadence_codec_free(struct processing_module *mod) +int cadence_codec_resolve_api_with_id(struct processing_module *mod, uint32_t codec_id, + uint32_t direction) { struct cadence_codec_data *cd = module_get_private_data(mod); + struct comp_dev *dev = mod->dev; + uint32_t api_id; + uint32_t n_apis = cadence_api_table_size(); + xa_codec_func_t *api = NULL; + int i; - mod_free(mod, cd->setup_cfg.data); + api_id = cadence_codec_get_api_id(codec_id, direction); + if (api_id < 0) + return api_id; - free_memory_tables(mod); - mod_free(mod, cd->mem_tabs); + /* Find and assign API function */ + for (i = 0; i < n_apis; i++) { + if (cadence_api_table[i].id == api_id) { + api = cadence_api_table[i].api; + break; + } + } + + /* Verify API assignment */ + if (!api) { + comp_err(dev, "could not find API function for id %x", + api_id); + return -EINVAL; + } + cd->api = api; + cd->api_id = api_id; - mod_free(mod, cd->self); - mod_free(mod, cd); return 0; } -static int -cadence_codec_set_configuration(struct processing_module *mod, uint32_t config_id, - enum module_cfg_fragment_position pos, uint32_t data_offset_size, - const uint8_t *fragment, size_t fragment_size, uint8_t *response, - size_t response_size) +int cadence_codec_process_data(struct processing_module *mod) { - struct module_data *md = &mod->priv; + struct cadence_codec_data *cd = module_get_private_data(mod); + struct module_data *codec = &mod->priv; struct comp_dev *dev = mod->dev; int ret; - ret = module_set_configuration(mod, config_id, pos, data_offset_size, fragment, - fragment_size, response, response_size); - if (ret < 0) + API_CALL(cd, XA_API_CMD_SET_INPUT_BYTES, 0, &codec->mpd.avail, ret); + if (ret != LIB_NO_ERROR) { + comp_err(dev, "failed to set size of input data with error: %x:", ret); return ret; + } - /* return if more fragments are expected or if the module is not prepared */ - if ((pos != MODULE_CFG_FRAGMENT_LAST && pos != MODULE_CFG_FRAGMENT_SINGLE) || - md->state < MODULE_IDLE) - return 0; + API_CALL(cd, XA_API_CMD_EXECUTE, XA_CMD_TYPE_DO_EXECUTE, NULL, ret); + if (ret != LIB_NO_ERROR) { + if (LIB_IS_FATAL_ERROR(ret)) { + comp_err(dev, "processing failed with error: %x", ret); + return ret; + } + comp_warn(dev, "processing failed with nonfatal error: %x", ret); + } - /* whole configuration received, apply it now */ - ret = cadence_codec_apply_config(mod); - if (ret) { - comp_err(dev, "error %x: runtime config apply failed", + API_CALL(cd, XA_API_CMD_GET_OUTPUT_BYTES, 0, &codec->mpd.produced, ret); + if (ret != LIB_NO_ERROR) { + comp_err(dev, "could not get produced bytes, error %x:", ret); return ret; } - comp_dbg(dev, "config applied"); + API_CALL(cd, XA_API_CMD_GET_CURIDX_INPUT_BUF, 0, &codec->mpd.consumed, ret); + if (ret != LIB_NO_ERROR) { + comp_err(dev, "could not get consumed bytes, error: %x", ret); + return ret; + } return 0; } - -static const struct module_interface cadence_codec_interface = { - .init = cadence_codec_init, - .prepare = cadence_codec_prepare, - .process_raw_data = cadence_codec_process, - .set_configuration = cadence_codec_set_configuration, - .reset = cadence_codec_reset, - .free = cadence_codec_free -}; - -DECLARE_MODULE_ADAPTER(cadence_codec_interface, cadence_codec_uuid, cadence_codec_tr); -SOF_MODULE_INIT(cadence_codec, sys_comp_module_cadence_codec_interface_init); diff --git a/src/audio/module_adapter/module/cadence_ipc3.c b/src/audio/module_adapter/module/cadence_ipc3.c new file mode 100644 index 000000000000..2bafe766de07 --- /dev/null +++ b/src/audio/module_adapter/module/cadence_ipc3.c @@ -0,0 +1,317 @@ +// SPDX-License-Identifier: BSD-3-Clause +// +// Copyright(c) 2020 Intel Corporation. All rights reserved. +// +// Author: Marcin Rajwa + +/* + * \file cadence.c + * \brief Cadence Codec API + * \author Marcin Rajwa + * + */ + +#include +#include +#include + +SOF_DEFINE_REG_UUID(cadence_codec); +LOG_MODULE_DECLARE(cadence_codec, CONFIG_SOF_LOG_LEVEL); +DECLARE_TR_CTX(cadence_codec_tr, SOF_UUID(cadence_codec_uuid), LOG_LEVEL_INFO); + +int cadence_codec_resolve_api(struct processing_module *mod) +{ + int ret; + struct snd_codec codec_params; + uint32_t codec_id = DEFAULT_CODEC_ID; + + if (mod->stream_params->ext_data_length) { + ret = memcpy_s(&codec_params, mod->stream_params->ext_data_length, + (uint8_t *)mod->stream_params + sizeof(*mod->stream_params), + mod->stream_params->ext_data_length); + if (ret < 0) + return ret; + + codec_id = codec_params.id; + } + + /* IPC3 only supports playback */ + return cadence_codec_resolve_api_with_id(mod, codec_id, mod->stream_params->direction); +} + +static int cadence_codec_init(struct processing_module *mod) +{ + struct module_data *codec = &mod->priv; + struct cadence_codec_data *cd; + struct comp_dev *dev = mod->dev; + struct module_config *setup_cfg; + int ret; + + comp_dbg(dev, "cadence_codec_init() start"); + + cd = mod_zalloc(mod, sizeof(struct cadence_codec_data)); + if (!cd) { + comp_err(dev, "failed to allocate memory for cadence codec data"); + return -ENOMEM; + } + + codec->private = cd; + codec->mpd.init_done = 0; + + /* copy the setup config only for the first init */ + if (codec->state == MODULE_DISABLED && codec->cfg.avail) { + setup_cfg = &cd->setup_cfg; + + /* allocate memory for set up config */ + setup_cfg->data = mod_alloc(mod, codec->cfg.size); + if (!setup_cfg->data) { + comp_err(dev, "failed to alloc setup config"); + ret = -ENOMEM; + goto free; + } + + /* copy the setup config */ + setup_cfg->size = codec->cfg.size; + ret = memcpy_s(setup_cfg->data, setup_cfg->size, + codec->cfg.init_data, setup_cfg->size); + if (ret) { + comp_err(dev, "failed to copy setup config %d", ret); + goto free_cfg; + } + setup_cfg->avail = true; + } + + comp_dbg(dev, "cadence_codec_init() done"); + + return 0; + +free_cfg: + mod_free(mod, setup_cfg->data); +free: + mod_free(mod, cd); + return ret; +} + +int cadence_codec_apply_config(struct processing_module *mod) +{ + int size; + struct module_config *cfg; + void *data; + struct comp_dev *dev = mod->dev; + struct module_data *codec = &mod->priv; + struct cadence_codec_data *cd = codec->private; + + comp_dbg(dev, "cadence_codec_apply_config() start"); + + cfg = &codec->cfg; + + /* use setup config if no runtime config available. This will be true during reset */ + if (!cfg->avail) + cfg = &cd->setup_cfg; + + data = cfg->data; + size = cfg->size; + + if (!cfg->avail || !size) { + comp_err(dev, "cadence_codec_apply_config() error: no config available"); + return -EIO; + } + + return cadence_codec_apply_params(mod, size, data); +} + +static int cadence_codec_deep_buff_allowed(struct processing_module *mod) +{ + struct cadence_codec_data *cd = module_get_private_data(mod); + + switch (cd->api_id) { + case CADENCE_CODEC_MP3_ENC_ID: + return 0; + default: + return 1; + } +} + +static int cadence_codec_prepare(struct processing_module *mod, + struct sof_source **sources, int num_of_sources, + struct sof_sink **sinks, int num_of_sinks) +{ + int ret = 0, mem_tabs_size; + struct comp_dev *dev = mod->dev; + struct module_data *codec = &mod->priv; + struct cadence_codec_data *cd = codec->private; + + comp_dbg(dev, "cadence_codec_prepare() start"); + + ret = cadence_init_codec_object(mod); + if (ret) + return ret; + + ret = cadence_codec_apply_config(mod); + if (ret) { + comp_err(dev, "cadence_codec_prepare() error %x: failed to apply config", + ret); + return ret; + } + + /* Allocate memory for the codec */ + API_CALL(cd, XA_API_CMD_GET_MEMTABS_SIZE, 0, &mem_tabs_size, ret); + if (ret != LIB_NO_ERROR) { + comp_err(dev, "cadence_codec_prepare() error %x: failed to get memtabs size", + ret); + return ret; + } + + cd->mem_tabs = mod_alloc(mod, mem_tabs_size); + if (!cd->mem_tabs) { + comp_err(dev, "cadence_codec_prepare() error: failed to allocate space for memtabs"); + return -ENOMEM; + } + + comp_dbg(dev, "allocated %d bytes for memtabs", mem_tabs_size); + + API_CALL(cd, XA_API_CMD_SET_MEMTABS_PTR, 0, cd->mem_tabs, ret); + if (ret != LIB_NO_ERROR) { + comp_err(dev, "cadence_codec_prepare() error %x: failed to set memtabs", + ret); + goto free; + } + + ret = cadence_codec_init_memory_tables(mod); + if (ret != LIB_NO_ERROR) { + comp_err(dev, "cadence_codec_prepare() error %x: failed to init memory tables", + ret); + goto free; + } + /* Check init done status. Note, it may happen that init_done flag will return + * false value, this is normal since some codec variants needs input in order to + * fully finish initialization. That's why at codec_adapter_copy() we call + * codec_init_process() base on result obtained below. + */ +#ifdef CONFIG_CADENCE_CODEC_WRAPPER + /* TODO: remove the "#ifdef CONFIG_CADENCE_CODEC_WRAPPER" once cadence fixes the bug + * in the init/prepare sequence. Basically below API_CALL shall return 1 for + * PCM streams and 0 for compress ones. As it turns out currently it returns 1 + * in both cases so in turn compress stream won't finish its prepare during first copy + * in codec_adapter_copy(). + */ + API_CALL(cd, XA_API_CMD_INIT, XA_CMD_TYPE_INIT_DONE_QUERY, + &codec->mpd.init_done, ret); + if (ret != LIB_NO_ERROR) { + comp_err(dev, "cadence_codec_init_process() error %x: failed to get lib init status", + ret); + return ret; + } +#endif + comp_dbg(dev, "cadence_codec_prepare() done"); + return 0; +free: + mod_free(mod, cd->mem_tabs); + return ret; +} + +static int +cadence_codec_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) +{ + struct comp_buffer *local_buff; + struct comp_dev *dev = mod->dev; + struct module_data *codec = &mod->priv; + struct cadence_codec_data *cd = codec->private; + int free_bytes, output_bytes = cadence_codec_get_samples(mod) * + mod->stream_params->sample_container_bytes * + mod->stream_params->channels; + uint32_t remaining = input_buffers[0].size; + int ret; + + if (!cadence_codec_deep_buff_allowed(mod)) + mod->deep_buff_bytes = 0; + + /* Proceed only if we have enough data to fill the module buffer completely */ + if (input_buffers[0].size < codec->mpd.in_buff_size) { + comp_dbg(dev, "not enough data to process"); + return -ENODATA; + } + + if (!codec->mpd.init_done) { + memcpy_s(codec->mpd.in_buff, codec->mpd.in_buff_size, input_buffers[0].data, + codec->mpd.in_buff_size); + codec->mpd.avail = codec->mpd.in_buff_size; + + ret = cadence_codec_init_process(mod); + if (ret) + return ret; + + remaining -= codec->mpd.consumed; + input_buffers[0].consumed = codec->mpd.consumed; + } + + /* do not proceed with processing if not enough free space left in the local buffer */ + local_buff = list_first_item(&mod->raw_data_buffers_list, struct comp_buffer, buffers_list); + free_bytes = audio_stream_get_free(&local_buff->stream); + if (free_bytes < output_bytes) + return -ENOSPC; + + /* Proceed only if we have enough data to fill the module buffer completely */ + if (remaining < codec->mpd.in_buff_size) + return -ENODATA; + + memcpy_s(codec->mpd.in_buff, codec->mpd.in_buff_size, + (uint8_t *)input_buffers[0].data + input_buffers[0].consumed, + codec->mpd.in_buff_size); + codec->mpd.avail = codec->mpd.in_buff_size; + + comp_dbg(dev, "cadence_codec_process() start"); + + ret = cadence_codec_process_data(mod); + if (ret) + return ret; + + /* update consumed with the number of samples consumed during init */ + input_buffers[0].consumed += codec->mpd.consumed; + codec->mpd.consumed = input_buffers[0].consumed; + + /* copy the produced samples into the output buffer */ + memcpy_s(output_buffers[0].data, codec->mpd.produced, codec->mpd.out_buff, + codec->mpd.produced); + output_buffers[0].size = codec->mpd.produced; + + comp_dbg(dev, "cadence_codec_process() done"); + + return 0; +} + +static int cadence_codec_reset(struct processing_module *mod) +{ + struct module_data *codec = &mod->priv; + struct cadence_codec_data *cd = codec->private; + int ret; + + cadence_codec_free_memory_tables(mod); + mod_free(mod, cd->mem_tabs); + + /* reset to default params */ + API_CALL(cd, XA_API_CMD_INIT, XA_CMD_TYPE_INIT_API_PRE_CONFIG_PARAMS, NULL, ret); + if (ret != LIB_NO_ERROR) + return ret; + + codec->mpd.init_done = 0; + + mod_free(mod, cd->self); + cd->self = NULL; + + return ret; +} + +static const struct module_interface cadence_codec_interface = { + .init = cadence_codec_init, + .prepare = cadence_codec_prepare, + .process_raw_data = cadence_codec_process, + .set_configuration = cadence_codec_set_configuration, + .reset = cadence_codec_reset, + .free = cadence_codec_free +}; + +DECLARE_MODULE_ADAPTER(cadence_codec_interface, cadence_codec_uuid, cadence_codec_tr); +SOF_MODULE_INIT(cadence_codec, sys_comp_module_cadence_codec_interface_init); diff --git a/src/audio/module_adapter/module/cadence_ipc4.c b/src/audio/module_adapter/module/cadence_ipc4.c new file mode 100644 index 000000000000..99210e1a1a1e --- /dev/null +++ b/src/audio/module_adapter/module/cadence_ipc4.c @@ -0,0 +1,543 @@ +// SPDX-License-Identifier: BSD-3-Clause +// +// Copyright(c) 2025-2026 Intel Corporation. All rights reserved. +// + +#include +#include +#include +#include +#include +#include +#include +#include + +SOF_DEFINE_REG_UUID(cadence_codec); +LOG_MODULE_DECLARE(cadence_codec, CONFIG_SOF_LOG_LEVEL); +DECLARE_TR_CTX(cadence_codec_tr, SOF_UUID(cadence_codec_uuid), LOG_LEVEL_INFO); + +int cadence_codec_resolve_api(struct processing_module *mod) +{ + struct cadence_codec_data *cd = module_get_private_data(mod); + struct module_config *setup_cfg = &cd->setup_cfg; + struct snd_codec *codec_params; + uint32_t codec_id = DEFAULT_CODEC_ID; + + /* update codec_id if setup_cfg is available */ + if (setup_cfg->avail) { + codec_params = (struct snd_codec *)cd->setup_cfg.data; + codec_id = codec_params->id; + } + + return cadence_codec_resolve_api_with_id(mod, codec_id, cd->direction); +} + +static int cadence_configure_mp3_dec_params(struct processing_module *mod) +{ + struct cadence_codec_data *cd = module_get_private_data(mod); + struct comp_dev *dev = mod->dev; + int word_size; + int ret; + + /* Cadence module only supports 16bit or 24 bits for word size */ + switch (cd->base_cfg.audio_fmt.depth) { + case IPC4_DEPTH_16BIT: + word_size = 16; + break; + case IPC4_DEPTH_24BIT: + case IPC4_DEPTH_32BIT: + word_size = 24; + break; + default: + comp_err(dev, "Unsupported bit depth: %d", cd->base_cfg.audio_fmt.depth); + return -EINVAL; + } + + API_CALL(cd, XA_API_CMD_SET_CONFIG_PARAM, XA_MP3DEC_CONFIG_PARAM_PCM_WDSZ, + (void *)&word_size, ret); + if (ret != LIB_NO_ERROR) { + if (LIB_IS_FATAL_ERROR(ret)) { + comp_err(dev, "failed to apply config param word size: error: %#x", ret); + return ret; + } + comp_warn(dev, "applied param word size return code: %#x", ret); + } + + return 0; +} + +static int cadence_configure_mp3_enc_params(struct processing_module *mod) +{ + struct cadence_codec_data *cd = module_get_private_data(mod); + struct comp_dev *dev = mod->dev; + int word_size = 16; + int ret; + + /* Cadence encoder only supports 16-bit word size */ + switch (cd->base_cfg.audio_fmt.depth) { + case IPC4_DEPTH_24BIT: + case IPC4_DEPTH_32BIT: + comp_err(dev, "Unsupported bit depth: %d for MP3 encoder", + cd->base_cfg.audio_fmt.depth); + return -EINVAL; + default: + break; + } + + API_CALL(cd, XA_API_CMD_SET_CONFIG_PARAM, XA_MP3ENC_CONFIG_PARAM_PCM_WDSZ, + (void *)&word_size, ret); + if (ret != LIB_NO_ERROR) { + if (LIB_IS_FATAL_ERROR(ret)) { + comp_err(dev, "failed to apply config param word size: error: %#x", ret); + return ret; + } + comp_warn(dev, "applied param word size return code: %#x", ret); + } + + int num_channels = cd->base_cfg.audio_fmt.channels_count; + + API_CALL(cd, XA_API_CMD_SET_CONFIG_PARAM, XA_MP3ENC_CONFIG_PARAM_NUM_CHANNELS, + (void *)&num_channels, ret); + if (ret != LIB_NO_ERROR) { + if (LIB_IS_FATAL_ERROR(ret)) { + comp_err(dev, "failed to apply config num_channels: error: %#x", ret); + return ret; + } + } + + int sampling_freq = cd->base_cfg.audio_fmt.sampling_frequency; + + API_CALL(cd, XA_API_CMD_SET_CONFIG_PARAM, XA_MP3ENC_CONFIG_PARAM_SAMP_FREQ, + (void *)&sampling_freq, ret); + if (ret != LIB_NO_ERROR) { + if (LIB_IS_FATAL_ERROR(ret)) { + comp_err(dev, "failed to apply config sampling_frequency: error: %#x", ret); + return ret; + } + } + + int bitrate = CADENCE_MP3_ENCODER_DEFAULT_BITRATE; + + API_CALL(cd, XA_API_CMD_SET_CONFIG_PARAM, XA_MP3ENC_CONFIG_PARAM_BITRATE, + (void *)&bitrate, ret); + if (ret != LIB_NO_ERROR) { + if (LIB_IS_FATAL_ERROR(ret)) { + comp_err(dev, "failed to apply config bitrate: error: %#x", ret); + return ret; + } + } + + return 0; +} + +static int cadence_configure_aac_dec_params(struct processing_module *mod) +{ + struct cadence_codec_data *cd = module_get_private_data(mod); + struct module_config *setup_cfg = &cd->setup_cfg; + struct comp_dev *dev = mod->dev; + struct snd_codec *codec_params; + int bitstream_format = XA_AACDEC_EBITSTREAM_TYPE_AAC_ADTS; + int word_size; + int ret; + + /* check bitstream format. Only MPEG-4 ADTS supported for now */ + if (setup_cfg->avail) { + codec_params = (struct snd_codec *)cd->setup_cfg.data; + if (codec_params->format != SND_AUDIOSTREAMFORMAT_MP4ADTS) { + comp_err(dev, "Unsupported AAC format: %d", codec_params->format); + return -EINVAL; + } + } else { + comp_err(dev, "No setup config available for AAC decoder"); + return -EINVAL; + } + + /* AAC decoder module only supports 16bit or 24 bits for word size */ + switch (cd->base_cfg.audio_fmt.depth) { + case IPC4_DEPTH_16BIT: + word_size = 16; + break; + case IPC4_DEPTH_24BIT: + case IPC4_DEPTH_32BIT: + word_size = 24; + break; + default: + comp_err(dev, "Unsupported bit depth: %d", cd->base_cfg.audio_fmt.depth); + return -EINVAL; + } + + API_CALL(cd, XA_API_CMD_SET_CONFIG_PARAM, XA_AACDEC_CONFIG_PARAM_PCM_WDSZ, + (void *)&word_size, ret); + if (ret != LIB_NO_ERROR) { + if (LIB_IS_FATAL_ERROR(ret)) { + comp_err(dev, "failed to apply config param word size: error: %#x", ret); + return ret; + } + comp_warn(dev, "applied param word size return code: %#x", ret); + } + + API_CALL(cd, XA_API_CMD_SET_CONFIG_PARAM, XA_AACDEC_CONFIG_PARAM_EXTERNALBSFORMAT, + (void *)&bitstream_format, ret); + if (ret != LIB_NO_ERROR) { + if (LIB_IS_FATAL_ERROR(ret)) { + comp_err(dev, "failed to apply config param bitstream format: error: %#x", + ret); + return ret; + } + comp_warn(dev, "applied param bitstream format return code: %#x", ret); + } + + return 0; +} + +static int cadence_configure_codec_params(struct processing_module *mod) +{ + struct cadence_codec_data *cd = module_get_private_data(mod); + + switch (cd->api_id) { + case CADENCE_CODEC_MP3_DEC_ID: + return cadence_configure_mp3_dec_params(mod); + case CADENCE_CODEC_MP3_ENC_ID: + return cadence_configure_mp3_enc_params(mod); + case CADENCE_CODEC_AAC_DEC_ID: + return cadence_configure_aac_dec_params(mod); + default: + break; + } + + return 0; +} + +static int cadence_codec_init(struct processing_module *mod) +{ + struct module_data *codec = &mod->priv; + struct module_config *cfg = &codec->cfg; + struct cadence_codec_data *cd; + struct module_config *setup_cfg; + struct comp_dev *dev = mod->dev; + int mem_tabs_size; + int ret; + + comp_dbg(dev, "cadence_codec_init() start"); + + cd = mod_zalloc(mod, sizeof(struct cadence_codec_data)); + if (!cd) { + comp_err(dev, "failed to allocate memory for cadence codec data"); + return -ENOMEM; + } + + codec->private = cd; + memcpy_s(&cd->base_cfg, sizeof(cd->base_cfg), &cfg->base_cfg, sizeof(cd->base_cfg)); + + codec->mpd.init_done = 0; + + /* copy the setup config only for the first init */ + if (codec->state == MODULE_DISABLED && codec->cfg.avail) { + int size = cfg->size; + + setup_cfg = &cd->setup_cfg; + + /* allocate memory for set up config (codec params) */ + setup_cfg->data = mod_alloc(mod, size); + if (!setup_cfg->data) { + comp_err(dev, "failed to alloc setup config"); + ret = -ENOMEM; + goto free_cd; + } + + setup_cfg->size = size; + ret = memcpy_s(setup_cfg->data, size, codec->cfg.init_data, size); + if (ret) { + comp_err(dev, "failed to copy setup config %d", ret); + goto free_cfg; + } + setup_cfg->avail = true; + codec->cfg.avail = false; + + /* direction follows the codec params in init data */ + cd->direction = *((uint32_t *)codec->cfg.init_data + + sizeof(struct snd_codec) / sizeof(uint32_t)); + comp_info(dev, "codec direction set to %u", cd->direction); + } + + ret = cadence_init_codec_object(mod); + if (ret) + goto free_cfg; + + ret = cadence_configure_codec_params(mod); + if (ret) + goto free_cfg; + + /* Allocate memory for the codec */ + API_CALL(cd, XA_API_CMD_GET_MEMTABS_SIZE, 0, &mem_tabs_size, ret); + if (ret != LIB_NO_ERROR) { + comp_err(dev, "cadence_codec_prepare() error %x: failed to get memtabs size", + ret); + goto free_cfg; + } + + cd->mem_tabs = mod_alloc(mod, mem_tabs_size); + if (!cd->mem_tabs) { + comp_err(dev, + "cadence_codec_prepare() error: failed to allocate space for memtabs"); + goto free_cfg; + } + + comp_dbg(dev, "allocated %d bytes for memtabs", mem_tabs_size); + + API_CALL(cd, XA_API_CMD_SET_MEMTABS_PTR, 0, cd->mem_tabs, ret); + if (ret != LIB_NO_ERROR) { + comp_err(dev, "cadence_codec_prepare() error %x: failed to set memtabs", + ret); + goto free; + } + + ret = cadence_codec_init_memory_tables(mod); + if (ret != LIB_NO_ERROR) { + comp_err(dev, "cadence_codec_prepare() error %x: failed to init memory tables", + ret); + goto free; + } + + comp_dbg(dev, "cadence_codec_init() done"); + + return 0; +free: + mod_free(mod, cd->mem_tabs); +free_cfg: + mod_free(mod, setup_cfg->data); +free_cd: + mod_free(mod, cd); + + return ret; +} + +int cadence_codec_apply_config(struct processing_module *mod) +{ + int size; + struct module_config *cfg; + void *data; + struct comp_dev *dev = mod->dev; + struct module_data *codec = &mod->priv; + + cfg = &codec->cfg; + + /* this will be true during prepare if there's no config available after init */ + if (!cfg->avail) + return 0; + + data = cfg->data; + size = cfg->size; + + if (!size) { + comp_err(dev, "error: no data available in config to apply"); + return -EIO; + } + + return cadence_codec_apply_params(mod, size, data); +} + +static int cadence_codec_prepare(struct processing_module *mod, + struct sof_source **sources, int num_of_sources, + struct sof_sink **sinks, int num_of_sinks) +{ + int ret = 0; + struct comp_dev *dev = mod->dev; + struct module_data *codec = &mod->priv; + + comp_dbg(dev, "cadence_codec_prepare() start"); + + ret = cadence_codec_apply_config(mod); + if (ret) { + comp_err(dev, "failed to apply config error %x:", ret); + return ret; + } + + /* Check init done status. Note, it may happen that init_done flag will return + * false value, this is normal since some codec variants needs input in order to + * fully finish initialization. That's why at codec_adapter_copy() we call + * codec_init_process() base on result obtained below. + */ +#ifdef CONFIG_CADENCE_CODEC_WRAPPER + /* TODO: remove the "#ifdef CONFIG_CADENCE_CODEC_WRAPPER" once cadence fixes the bug + * in the init/prepare sequence. Basically below API_CALL shall return 1 for + * PCM streams and 0 for compress ones. As it turns out currently it returns 1 + * in both cases so in turn compress stream won't finish its prepare during first copy + * in codec_adapter_copy(). + */ + API_CALL(cd, XA_API_CMD_INIT, XA_CMD_TYPE_INIT_DONE_QUERY, + &codec->mpd.init_done, ret); + if (ret != LIB_NO_ERROR) { + comp_err(dev, "failed to get lib init status error %x:", ret); + return ret; + } +#endif + + /* set the period based on the minimum required input data size */ + dev->period = 1000000ULL * codec->mpd.in_buff_size / + (source_get_frame_bytes(sources[0]) * source_get_rate(sources[0])); + comp_dbg(dev, "period set to %u usec", dev->period); + + /* align down period to LL cycle time */ + dev->period /= LL_TIMER_PERIOD_US; + dev->period *= LL_TIMER_PERIOD_US; + + comp_dbg(dev, "cadence_codec_prepare() done"); + return 0; +} + +static void cadence_copy_data_from_buffer(void *dest, const void *buffer_ptr, size_t bytes_to_copy, + size_t buffer_size, uint8_t const *buffer_start) +{ + size_t bytes_to_end = (size_t)((uint8_t *)buffer_start + + buffer_size - (uint8_t *)buffer_ptr); + + if (bytes_to_end >= bytes_to_copy) { + /* No wrap, copy directly */ + memcpy_s(dest, bytes_to_copy, buffer_ptr, bytes_to_copy); + return; + } + + /* Wrap occurs, copy in two parts */ + memcpy_s(dest, bytes_to_end, buffer_ptr, bytes_to_end); + memcpy_s((uint8_t *)dest + bytes_to_end, bytes_to_copy - bytes_to_end, + buffer_start, bytes_to_copy - bytes_to_end); +} + +static int cadence_codec_process(struct processing_module *mod, struct sof_source **sources, + int num_of_sources, struct sof_sink **sinks, int num_of_sinks) +{ + struct comp_dev *dev = mod->dev; + struct module_data *codec = &mod->priv; + size_t in_size = source_get_data_available(sources[0]); + size_t out_space = sink_get_free_size(sinks[0]); + uint8_t const *source_buffer_start; + int consumed_during_init = 0; + uint32_t remaining = in_size; + const void *src_ptr; + size_t src_bytes; + int ret; + + if (!codec->mpd.init_done) { + /* Acquire data from the source buffer */ + ret = source_get_data(sources[0], codec->mpd.in_buff_size, &src_ptr, + (const void **)&source_buffer_start, &src_bytes); + if (ret) { + comp_err(dev, "cannot get data from source buffer"); + return ret; + } + + cadence_copy_data_from_buffer(codec->mpd.in_buff, src_ptr, codec->mpd.in_buff_size, + src_bytes, source_buffer_start); + + codec->mpd.avail = codec->mpd.in_buff_size; + ret = cadence_codec_init_process(mod); + if (ret) + return ret; + + remaining -= codec->mpd.consumed; + source_release_data(sources[0], codec->mpd.consumed); + consumed_during_init = codec->mpd.consumed; + } + + codec->mpd.consumed = 0; + + /* Proceed only if we have enough data to fill the module buffer completely */ + if (remaining < codec->mpd.in_buff_size) + return -ENODATA; + + /* Acquire data from the source buffer */ + ret = source_get_data(sources[0], codec->mpd.in_buff_size, &src_ptr, + (const void **)&source_buffer_start, &src_bytes); + + cadence_copy_data_from_buffer(codec->mpd.in_buff, src_ptr, codec->mpd.in_buff_size, + src_bytes, source_buffer_start); + codec->mpd.avail = codec->mpd.in_buff_size; + + comp_dbg(dev, "cadence_codec_process() start"); + + ret = cadence_codec_process_data(mod); + if (ret) { + source_release_data(sources[0], 0); + return ret; + } + + /* do not proceed if not enough free space left */ + if (out_space < codec->mpd.produced) { + source_release_data(sources[0], 0); + return -ENOSPC; + } + + void *sink_ptr; + size_t sink_bytes; + uint8_t const *sink_buffer_start; + + ret = sink_get_buffer(sinks[0], codec->mpd.produced, &sink_ptr, + (void **)&sink_buffer_start, &sink_bytes); + if (ret) { + comp_err(dev, "cannot get sink buffer"); + return ret; + } + + /* Copy the produced samples into the output buffer */ + size_t bytes_to_end = (size_t)((uint8_t *)sink_buffer_start + + sink_bytes - (uint8_t *)sink_ptr); + + if (bytes_to_end >= codec->mpd.produced) { + /* No wrap, copy directly */ + memcpy_s(sink_ptr, codec->mpd.produced, codec->mpd.out_buff, + codec->mpd.produced); + } else { + /* Wrap occurs, copy in two parts */ + memcpy_s(sink_ptr, bytes_to_end, codec->mpd.out_buff, bytes_to_end); + memcpy_s((uint8_t *)sink_buffer_start, codec->mpd.produced - bytes_to_end, + (uint8_t *)codec->mpd.out_buff + bytes_to_end, + codec->mpd.produced - bytes_to_end); + } + + source_release_data(sources[0], codec->mpd.consumed); + sink_commit_buffer(sinks[0], codec->mpd.produced); + + /* reset produced and consumed */ + codec->mpd.consumed = 0; + codec->mpd.produced = 0; + + comp_dbg(dev, "cadence_codec_process() done"); + + return 0; +} + +static int cadence_codec_reset(struct processing_module *mod) +{ + struct module_data *codec = &mod->priv; + + codec->mpd.init_done = 0; + + return 0; +} + +static bool cadence_is_ready_to_process(struct processing_module *mod, + struct sof_source **sources, int num_of_sources, + struct sof_sink **sinks, int num_of_sinks) +{ + struct module_data *codec = &mod->priv; + + if (source_get_data_available(sources[0]) < codec->mpd.in_buff_size || + sink_get_free_size(sinks[0]) < codec->mpd.out_buff_size) + return false; + + return true; +} + +static const struct module_interface cadence_codec_interface = { + .init = cadence_codec_init, + .prepare = cadence_codec_prepare, + .process = cadence_codec_process, + .set_configuration = cadence_codec_set_configuration, + .reset = cadence_codec_reset, + .free = cadence_codec_free, + .is_ready_to_process = cadence_is_ready_to_process, +}; + +DECLARE_MODULE_ADAPTER(cadence_codec_interface, cadence_codec_uuid, cadence_codec_tr); +SOF_MODULE_INIT(cadence_codec, sys_comp_module_cadence_codec_interface_init); diff --git a/src/audio/module_adapter/module_adapter_ipc4.c b/src/audio/module_adapter/module_adapter_ipc4.c index 54ee3dd94f5e..b1c45d153d7a 100644 --- a/src/audio/module_adapter/module_adapter_ipc4.c +++ b/src/audio/module_adapter/module_adapter_ipc4.c @@ -78,6 +78,15 @@ module_ext_init_decode(struct comp_dev *dev, struct module_config *dst, dp_data->domain_id, dp_data->stack_bytes, dp_data->heap_bytes); break; } + case IPC4_MOD_INIT_DATA_ID_MODULE_DATA: + { + /* set the module init_data */ + dst->init_data = (const void *)(obj + 1); + dst->avail = true; + dst->size = obj->object_words * sizeof(uint32_t); + comp_info(dev, "module init data size %u bytes", dst->size); + break; + } default: comp_info(dev, "Unknown ext init object id %u of %u words", obj->object_id, obj->object_words); @@ -148,8 +157,11 @@ int module_adapter_init_data(struct comp_dev *dev, } } - dst->init_data = cfg; /* legacy API */ - dst->avail = true; + if (!config->ipc_extended_init) { + dst->init_data = cfg; /* legacy API */ + dst->avail = true; + } + return 0; } diff --git a/src/include/ipc4/module.h b/src/include/ipc4/module.h index a73ede0b0bd5..f157cddd3f65 100644 --- a/src/include/ipc4/module.h +++ b/src/include/ipc4/module.h @@ -77,7 +77,8 @@ struct ipc4_vendor_error { enum ipc4_mod_init_data_glb_id { IPC4_MOD_INIT_DATA_ID_INVALID = 0, IPC4_MOD_INIT_DATA_ID_DP_DATA = 1, - IPC4_MOD_INIT_DATA_ID_MAX = IPC4_MOD_INIT_DATA_ID_DP_DATA, + IPC4_MOD_INIT_DATA_ID_MODULE_DATA = 2, + IPC4_MOD_INIT_DATA_ID_MAX = IPC4_MOD_INIT_DATA_ID_MODULE_DATA, }; /* data object for vendor bespoke data with ABI growth and backwards compat */ diff --git a/src/include/sof/audio/cadence/mp3_enc/xa_mp3_enc_api.h b/src/include/sof/audio/cadence/mp3_enc/xa_mp3_enc_api.h new file mode 100644 index 000000000000..aac961e63cf9 --- /dev/null +++ b/src/include/sof/audio/cadence/mp3_enc/xa_mp3_enc_api.h @@ -0,0 +1,91 @@ +/* + * Copyright (c) 2022-2025 Cadence Design Systems, Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY + * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + + + +#ifndef __XA_MP3ENC_CONFIG_PARAMS_H__ +#define __XA_MP3ENC_CONFIG_PARAMS_H__ + +/* mp3_enc-specific configuration parameters */ +enum xa_config_param_mp3_enc { + XA_MP3ENC_CONFIG_PARAM_PCM_WDSZ = 0, + XA_MP3ENC_CONFIG_PARAM_SAMP_FREQ = 1, + XA_MP3ENC_CONFIG_PARAM_NUM_CHANNELS = 2, + XA_MP3ENC_CONFIG_PARAM_BITRATE = 3 +#ifdef ENABLE_CUT_OFF_FREQ_CONFIG + , XA_MP3ENC_CONFIG_FATAL_FRAC_BANDWIDTH = 4 +#endif // ENABLE_CUT_OFF_FREQ_CONFIG +}; + +/* commands */ +#include "xa_apicmd_standards.h" + +/* mp3_enc-specific commands */ +/* (none) */ + +/* mp3_enc-specific command types */ +/* (none) */ + +/* error codes */ +#include "xa_error_standards.h" + +#define XA_CODEC_MP3_ENC 2 + +/* mp3_enc-specific error_codes */ +/*****************************************************************************/ +/* Class 0: API Errors */ +/*****************************************************************************/ +/* Nonfatal Errors */ +/* (none) */ +/* Fatal Errors */ +/* (none) */ + +/*****************************************************************************/ +/* Class 1: Configuration Errors */ +/*****************************************************************************/ +/* Nonfatal Errors */ +enum xa_error_nonfatal_config_mp3_enc { + XA_MP3ENC_CONFIG_NONFATAL_INVALID_BITRATE = XA_ERROR_CODE(xa_severity_nonfatal, xa_class_config, XA_CODEC_MP3_ENC, 0) +}; + +/* Fatal Errors */ +enum xa_error_fatal_config_mp3_enc { + XA_MP3ENC_CONFIG_FATAL_SAMP_FREQ = XA_ERROR_CODE(xa_severity_fatal, xa_class_config, XA_CODEC_MP3_ENC, 0), + XA_MP3ENC_CONFIG_FATAL_NUM_CHANNELS = XA_ERROR_CODE(xa_severity_fatal, xa_class_config, XA_CODEC_MP3_ENC, 1), + XA_MP3ENC_CONFIG_FATAL_PCM_WDSZ = XA_ERROR_CODE(xa_severity_fatal, xa_class_config, XA_CODEC_MP3_ENC, 2) +#ifdef ENABLE_CUT_OFF_FREQ_CONFIG + , XA_MP3ENC_CONFIG_PARAM_FRAC_BANDWIDTH = XA_ERROR_CODE(xa_severity_fatal, xa_class_config, XA_CODEC_MP3_ENC, 3) +#endif // ENABLE_CUT_OFF_FREQ_CONFIG +}; +/* (none) */ + +#include "xa_type_def.h" + +#if defined(__cplusplus) +extern "C" { +#endif /* __cplusplus */ +xa_codec_func_t xa_mp3_enc; +#if defined(__cplusplus) +} +#endif /* __cplusplus */ +#endif /* __XA_MP3ENC_CONFIG_PARAMS_H__ */ diff --git a/src/include/sof/audio/module_adapter/module/cadence.h b/src/include/sof/audio/module_adapter/module/cadence.h index 32444fd62b13..baefbaeea08f 100644 --- a/src/include/sof/audio/module_adapter/module/cadence.h +++ b/src/include/sof/audio/module_adapter/module/cadence.h @@ -17,6 +17,7 @@ #define LIB_NO_ERROR XA_NO_ERROR #define LIB_IS_FATAL_ERROR(e) ((e) & XA_FATAL_ERROR) #define CODEC_GET_API_ID(id) ((id) & 0xFF) +#define CADENCE_MP3_ENCODER_DEFAULT_BITRATE 320 /*****************************************************************************/ /* Cadence API functions */ @@ -32,6 +33,8 @@ extern xa_codec_func_t xa_sbc_dec; extern xa_codec_func_t xa_vorbis_dec; extern xa_codec_func_t xa_src_pp; +#define DEFAULT_CODEC_ID CADENCE_CODEC_WRAPPER_ID + #define API_CALL(cd, cmd, sub_cmd, value, ret) \ do { \ ret = (cd)->api((cd)->self, \ @@ -49,6 +52,10 @@ struct cadence_api { }; struct cadence_codec_data { +#if CONFIG_IPC_MAJOR_4 + struct ipc4_base_module_cfg base_cfg; + uint32_t direction; +#endif char name[LIB_NAME_MAX_LEN]; void *self; xa_codec_func_t *api; @@ -59,6 +66,19 @@ struct cadence_codec_data { struct module_config setup_cfg; }; +enum cadence_api_id { + CADENCE_CODEC_WRAPPER_ID = 0x01, + CADENCE_CODEC_AAC_DEC_ID = 0x02, + CADENCE_CODEC_BSAC_DEC_ID = 0x03, + CADENCE_CODEC_DAB_DEC_ID = 0x04, + CADENCE_CODEC_DRM_DEC_ID = 0x05, + CADENCE_CODEC_MP3_DEC_ID = 0x06, + CADENCE_CODEC_SBC_DEC_ID = 0x07, + CADENCE_CODEC_VORBIS_DEC_ID = 0x08, + CADENCE_CODEC_SRC_PP_ID = 0x09, + CADENCE_CODEC_MP3_ENC_ID = 0x0A, +}; + #if CONFIG_IPC_MAJOR_4 struct ipc4_cadence_module_cfg { struct ipc4_base_module_cfg base_cfg; @@ -67,4 +87,24 @@ struct ipc4_cadence_module_cfg { } __packed __aligned(4); #endif +extern struct cadence_api cadence_api_table[]; + +int cadence_codec_set_configuration(struct processing_module *mod, uint32_t config_id, + enum module_cfg_fragment_position pos, + uint32_t data_offset_size, const uint8_t *fragment, + size_t fragment_size, uint8_t *response, size_t response_size); +int cadence_codec_resolve_api_with_id(struct processing_module *mod, uint32_t codec_id, + uint32_t direction); +int cadence_codec_apply_params(struct processing_module *mod, int size, void *data); +int cadence_codec_process_data(struct processing_module *mod); +int cadence_codec_apply_config(struct processing_module *mod); +void cadence_codec_free_memory_tables(struct processing_module *mod); +int cadence_codec_init_memory_tables(struct processing_module *mod); +int cadence_codec_get_samples(struct processing_module *mod); +int cadence_codec_init_process(struct processing_module *mod); +int cadence_init_codec_object(struct processing_module *mod); +int cadence_codec_resolve_api(struct processing_module *mod); +int cadence_codec_free(struct processing_module *mod); +size_t cadence_api_table_size(void); + #endif /* __SOF_AUDIO_CADENCE_CODEC__ */ diff --git a/src/ipc/ipc4/helper.c b/src/ipc/ipc4/helper.c index 0bc49a7f0df3..226bd3a680e1 100644 --- a/src/ipc/ipc4/helper.c +++ b/src/ipc/ipc4/helper.c @@ -630,9 +630,15 @@ __cold int ipc_comp_connect(struct ipc *ipc, ipc_pipe_comp_connect *_connect) source->ipc_config.proc_domain == COMP_PROCESSING_DOMAIN_DP) { struct sof_source *src = audio_buffer_get_source(&buffer->audio_buffer); struct sof_sink *snk = audio_buffer_get_sink(&buffer->audio_buffer); + struct processing_module *srcmod = comp_mod(source); + struct module_data *src_module_data = &srcmod->priv; + struct processing_module *dstmod = comp_mod(sink); + struct module_data *dst_module_data = &dstmod->priv; - ring_buffer = ring_buffer_create(dp, source_get_min_available(src), - sink_get_min_free_space(snk), + ring_buffer = ring_buffer_create(dp, MAX(source_get_min_available(src), + dst_module_data->mpd.in_buff_size), + MAX(sink_get_min_free_space(snk), + src_module_data->mpd.out_buff_size), audio_buffer_is_shared(&buffer->audio_buffer), buf_get_id(buffer)); if (!ring_buffer) {