diff --git a/src/audio/src/src.c b/src/audio/src/src.c index cdbf3373fdbd..2b56dec6df39 100644 --- a/src/audio/src/src.c +++ b/src/audio/src/src.c @@ -12,6 +12,7 @@ #include #include #include +#include #include #include #include @@ -54,15 +55,21 @@ #define MAX_FIR_DELAY_SIZE_XNCH (PLATFORM_MAX_CHANNELS * MAX_FIR_DELAY_SIZE) #define MAX_OUT_DELAY_SIZE_XNCH (PLATFORM_MAX_CHANNELS * MAX_OUT_DELAY_SIZE) -static const struct comp_driver comp_src; - LOG_MODULE_REGISTER(src, CONFIG_SOF_LOG_LEVEL); #if CONFIG_IPC_MAJOR_4 +/* src component private data */ +struct ipc4_config_src { + struct ipc4_base_module_cfg base; + uint32_t sink_rate; +}; + /* e61bb28d-149a-4c1f-b709-46823ef5f5a3 */ DECLARE_SOF_RT_UUID("src", src_uuid, 0xe61bb28d, 0x149a, 0x4c1f, 0xb7, 0x09, 0x46, 0x82, 0x3e, 0xf5, 0xf5, 0xae); #elif CONFIG_IPC_MAJOR_3 +static const struct comp_driver comp_src; + /* c1c5326d-8390-46b4-aa47-95c3beca6550 */ DECLARE_SOF_RT_UUID("src", src_uuid, 0xc1c5326d, 0x8390, 0x46b4, 0xaa, 0x47, 0x95, 0xc3, 0xbe, 0xca, 0x65, 0x50); @@ -72,12 +79,6 @@ DECLARE_SOF_RT_UUID("src", src_uuid, 0xc1c5326d, 0x8390, 0x46b4, DECLARE_TR_CTX(src_tr, SOF_UUID(src_uuid), LOG_LEVEL_INFO); -/* src component private data */ -struct ipc4_config_src { - struct ipc4_base_module_cfg base; - uint32_t sink_rate; -}; - struct comp_data { #if CONFIG_IPC_MAJOR_4 struct ipc4_config_src ipc_config; @@ -97,6 +98,7 @@ struct comp_data { int sink_frames; int sample_container_bytes; void (*src_func)(struct comp_dev *dev, + struct comp_data *cd, const struct audio_stream __sparse_cache *source, struct audio_stream __sparse_cache *sink, int *consumed, @@ -130,17 +132,25 @@ static int src_find_fs(int fs_list[], int list_length, int fs) } /* Calculates buffers to allocate for a SRC mode */ -int src_buffer_lengths(struct src_param *a, int fs_in, int fs_out, int nch, - int source_frames) +static int src_buffer_lengths(struct comp_dev *dev, struct comp_data *cd, + int nch) { struct src_stage *stage1; struct src_stage *stage2; + struct src_param *a; + int fs_in, fs_out; + int source_frames; int r1; + a = &cd->param; + fs_in = cd->source_rate; + fs_out = cd->sink_rate; + source_frames = cd->source_frames; + if (nch > PLATFORM_MAX_CHANNELS) { /* TODO: should be device, not class */ - comp_cl_err(&comp_src, "src_buffer_lengths(): nch = %u > PLATFORM_MAX_CHANNELS", - nch); + comp_err(dev, "src_buffer_lengths(): nch = %u > PLATFORM_MAX_CHANNELS", + nch); return -EINVAL; } @@ -150,8 +160,8 @@ int src_buffer_lengths(struct src_param *a, int fs_in, int fs_out, int nch, /* Check that both in and out rates are supported */ if (a->idx_in < 0 || a->idx_out < 0) { - comp_cl_err(&comp_src, "src_buffer_lengths(): rates not supported, fs_in: %u, fs_out: %u", - fs_in, fs_out); + comp_err(dev, "src_buffer_lengths(): rates not supported, fs_in: %u, fs_out: %u", + fs_in, fs_out); return -EINVAL; } @@ -160,8 +170,8 @@ int src_buffer_lengths(struct src_param *a, int fs_in, int fs_out, int nch, /* Check from stage1 parameter for a deleted in/out rate combination.*/ if (stage1->filter_length < 1) { - comp_cl_err(&comp_src, "src_buffer_lengths(): Non-supported combination sfs_in = %d, fs_out = %d", - fs_in, fs_out); + comp_err(dev, "src_buffer_lengths(): Non-supported combination sfs_in = %d, fs_out = %d", + fs_in, fs_out); return -EINVAL; } @@ -325,7 +335,7 @@ int src_polyphase_init(struct polyphase_src *src, struct src_param *p, } /* Fallback function */ -static void src_fallback(struct comp_dev *dev, +static void src_fallback(struct comp_dev *dev, struct comp_data *cd, const struct audio_stream __sparse_cache *source, struct audio_stream __sparse_cache *sink, int *n_read, int *n_written) { @@ -334,7 +344,8 @@ static void src_fallback(struct comp_dev *dev, } /* Normal 2 stage SRC */ -static void src_2s(struct comp_dev *dev, const struct audio_stream __sparse_cache *source, +static void src_2s(struct comp_dev *dev, struct comp_data *cd, + const struct audio_stream __sparse_cache *source, struct audio_stream __sparse_cache *sink, int *n_read, int *n_written) { struct src_stage_prm s1; @@ -343,7 +354,6 @@ static void src_2s(struct comp_dev *dev, const struct audio_stream __sparse_cach int s1_blk_out; int s2_blk_in; int s2_blk_out; - struct comp_data *cd = comp_get_drvdata(dev); void *sbuf_addr = cd->delay_lines; void *sbuf_end_addr = &cd->delay_lines[cd->param.sbuf_length]; size_t sbuf_size = cd->param.sbuf_length * sizeof(int32_t); @@ -426,11 +436,11 @@ static void src_2s(struct comp_dev *dev, const struct audio_stream __sparse_cach } /* 1 stage SRC for simple conversions */ -static void src_1s(struct comp_dev *dev, const struct audio_stream __sparse_cache *source, +static void src_1s(struct comp_dev *dev, struct comp_data *cd, + const struct audio_stream __sparse_cache *source, struct audio_stream __sparse_cache *sink, int *n_read, int *n_written) { struct src_stage_prm s1; - struct comp_data *cd = comp_get_drvdata(dev); s1.times = cd->param.stage1_times; s1.x_rptr = source->r_ptr; @@ -451,12 +461,11 @@ static void src_1s(struct comp_dev *dev, const struct audio_stream __sparse_cach } /* A fast copy function for same in and out rate */ -static void src_copy_sxx(struct comp_dev *dev, +static void src_copy_sxx(struct comp_dev *dev, struct comp_data *cd, const struct audio_stream __sparse_cache *source, struct audio_stream __sparse_cache *sink, int *n_read, int *n_written) { - struct comp_data *cd = comp_get_drvdata(dev); int frames = cd->param.blk_in; switch (sink->frame_fmt) { @@ -475,21 +484,6 @@ static void src_copy_sxx(struct comp_dev *dev, } #if CONFIG_IPC_MAJOR_4 -static int src_get_attribute(struct comp_dev *dev, uint32_t type, void *value) -{ - struct comp_data *cd = comp_get_drvdata(dev); - - switch (type) { - case COMP_ATTR_BASE_CONFIG: - *(struct ipc4_base_module_cfg *)value = cd->ipc_config.base; - break; - default: - return -EINVAL; - } - - return 0; -} - static int src_rate_check(const void *spec) { const struct ipc4_config_src *ipc_src = spec; @@ -516,8 +510,10 @@ static int src_stream_pcm_source_rate_check(struct ipc4_config_src cfg, */ static void src_set_params(struct comp_dev *dev, struct sof_ipc_stream_params *params) { - struct comp_data *cd = comp_get_drvdata(dev); + struct processing_module *mod = comp_get_drvdata(dev); + struct comp_data *cd = module_get_private_data(mod); struct comp_buffer *sinkb; + struct comp_buffer __sparse_cache *sink_c; memset(params, 0, sizeof(*params)); params->channels = cd->ipc_config.base.audio_fmt.channels_count; @@ -529,12 +525,15 @@ static void src_set_params(struct comp_dev *dev, struct sof_ipc_stream_params *p params->buffer.size = cd->ipc_config.base.ibs; sinkb = list_first_item(&dev->bsink_list, struct comp_buffer, source_list); - sinkb->stream.rate = cd->ipc_config.sink_rate; + sink_c = buffer_acquire(sinkb); + sink_c->stream.rate = cd->ipc_config.sink_rate; + buffer_release(sink_c); } static void src_set_sink_params(struct comp_dev *dev, struct comp_buffer __sparse_cache *sinkb) { - struct comp_data *cd = comp_get_drvdata(dev); + struct processing_module *mod = comp_get_drvdata(dev); + struct comp_data *cd = module_get_private_data(mod); /* convert IPC4 config to format used by the module */ audio_stream_fmt_conversion(cd->ipc_config.base.audio_fmt.depth, @@ -546,6 +545,27 @@ static void src_set_sink_params(struct comp_dev *dev, struct comp_buffer __spars sinkb->buffer_fmt = cd->ipc_config.base.audio_fmt.interleaving_style; } +static inline void src_update_buffer_position(struct input_stream_buffer *input_buffers, + struct output_stream_buffer *output_buffers, + int *n_read, int *n_written) +{ + struct audio_stream __sparse_cache *source = input_buffers->data; + struct audio_stream __sparse_cache *sink = output_buffers->data; + + input_buffers->consumed += audio_stream_frame_bytes(source) * (*n_read); + output_buffers->size += audio_stream_frame_bytes(sink) * (*n_written); +} + +static void src_set_alignment(struct audio_stream __sparse_cache *source, + struct audio_stream __sparse_cache *sink) +{ + const uint32_t byte_align = 1; + const uint32_t frame_align_req = 1; + + audio_stream_init_alignment_constants(byte_align, frame_align_req, source); + audio_stream_init_alignment_constants(byte_align, frame_align_req, sink); +} + #elif CONFIG_IPC_MAJOR_3 static int src_rate_check(const void *spec) { @@ -573,62 +593,9 @@ static void src_set_sink_params(struct comp_dev *dev, struct comp_buffer __spars #error "No or invalid IPC MAJOR version selected." #endif /* CONFIG_IPC_MAJOR_4 */ -static struct comp_dev *src_new(const struct comp_driver *drv, - const struct comp_ipc_config *config, - const void *spec) -{ - struct comp_dev *dev; - struct comp_data *cd; - - comp_cl_info(&comp_src, "src_new()"); - - /* validate init data - either SRC sink or source rate must be set */ - if (src_rate_check(spec) < 0) { - comp_cl_err(&comp_src, "src_new(): SRC sink and source rate are not set"); - return NULL; - } - - dev = comp_alloc(drv, sizeof(*dev)); - if (!dev) - return NULL; - dev->ipc_config = *config; - - cd = rzalloc(SOF_MEM_ZONE_RUNTIME, 0, SOF_MEM_CAPS_RAM, sizeof(*cd)); - if (!cd) { - rfree(dev); - return NULL; - } - - comp_set_drvdata(dev, cd); - memcpy_s(&cd->ipc_config, sizeof(cd->ipc_config), spec, sizeof(cd->ipc_config)); - - cd->delay_lines = NULL; - cd->src_func = src_fallback; - cd->polyphase_func = NULL; - src_polyphase_reset(&cd->src); - - dev->state = COMP_STATE_READY; - return dev; -} - -static void src_free(struct comp_dev *dev) -{ - struct comp_data *cd = comp_get_drvdata(dev); - - comp_info(dev, "src_free()"); - - /* Free dynamically reserved buffers for SRC algorithm */ - if (cd->delay_lines) - rfree(cd->delay_lines); - - rfree(cd); - rfree(dev); -} - -static int src_verify_params(struct comp_dev *dev, +static int src_verify_params(struct comp_dev *dev, struct comp_data *cd, struct sof_ipc_stream_params *params) { - struct comp_data *cd = comp_get_drvdata(dev); int ret; comp_dbg(dev, "src_verify_params()"); @@ -645,7 +612,7 @@ static int src_verify_params(struct comp_dev *dev, return ret; } } else { - if (cd->ipc_config.sink_rate && (params->rate != cd->ipc_config.sink_rate)) { + if (cd->ipc_config.sink_rate && params->rate != cd->ipc_config.sink_rate) { comp_err(dev, "src_verify_params(): runtime stream pcm rate %u does not match rate %u fetched from ipc.", params->rate, cd->ipc_config.sink_rate); return -EINVAL; @@ -655,18 +622,103 @@ static int src_verify_params(struct comp_dev *dev, /* update downstream (playback) or upstream (capture) buffer parameters */ ret = comp_verify_params(dev, BUFF_PARAMS_RATE, params); - if (ret < 0) { + if (ret < 0) comp_err(dev, "src_verify_params(): comp_verify_params() failed."); - } return ret; } -/* set component audio stream parameters */ -static int src_params(struct comp_dev *dev, - struct sof_ipc_stream_params *params) +static int src_get_copy_limits(struct comp_data *cd, + const struct comp_buffer __sparse_cache *source, + const struct comp_buffer __sparse_cache *sink) +{ + struct src_param *sp; + struct src_stage *s1; + struct src_stage *s2; + int frames_src; + int frames_snk; + + /* Get SRC parameters */ + sp = &cd->param; + s1 = cd->src.stage1; + s2 = cd->src.stage2; + + /* Calculate how many blocks can be processed with + * available source and free sink frames amount. + */ + if (s2->filter_length > 1) { + /* Two polyphase filters case */ + frames_snk = audio_stream_get_free_frames(&sink->stream); + frames_snk = MIN(frames_snk, cd->sink_frames + s2->blk_out); + sp->stage2_times = frames_snk / s2->blk_out; + frames_src = audio_stream_get_avail_frames(&source->stream); + frames_src = MIN(frames_src, cd->source_frames + s1->blk_in); + sp->stage1_times = frames_src / s1->blk_in; + sp->blk_in = sp->stage1_times * s1->blk_in; + sp->blk_out = sp->stage2_times * s2->blk_out; + } else { + /* Single polyphase filter case */ + frames_snk = audio_stream_get_free_frames(&sink->stream); + frames_snk = MIN(frames_snk, cd->sink_frames + s1->blk_out); + sp->stage1_times = frames_snk / s1->blk_out; + frames_src = audio_stream_get_avail_frames(&source->stream); + sp->stage1_times = MIN(sp->stage1_times, + frames_src / s1->blk_in); + sp->blk_in = sp->stage1_times * s1->blk_in; + sp->blk_out = sp->stage1_times * s1->blk_out; + } + + if (sp->blk_in == 0 && sp->blk_out == 0) + return -EIO; + + return 0; +} + +static int src_check_buffer_sizes(struct comp_dev *dev, struct comp_data *cd, + struct audio_stream __sparse_cache *source_stream, + struct audio_stream __sparse_cache *sink_stream) +{ + struct src_stage *s1 = cd->src.stage1; + struct src_stage *s2 = cd->src.stage2; + int stage1_times; + int stage2_times; + int blk_in; + int blk_out; + int n; + + if (s2->filter_length > 1) { + /* Two polyphase filters case */ + stage2_times = ceil_divide(cd->sink_frames, s2->blk_out); + stage1_times = ceil_divide(cd->source_frames, s1->blk_in); + blk_in = stage1_times * s1->blk_in; + blk_out = stage2_times * s2->blk_out; + } else { + /* Single polyphase filter case */ + stage1_times = ceil_divide(cd->sink_frames, s1->blk_out); + n = ceil_divide(cd->source_frames, s1->blk_in); + stage1_times = MAX(stage1_times, n); + blk_in = stage1_times * s1->blk_in; + blk_out = stage1_times * s1->blk_out; + } + + n = audio_stream_frame_bytes(source_stream) * (blk_in + cd->source_frames); + if (source_stream->size < n) { + comp_warn(dev, "Source size %d is less than required %d", + source_stream->size, n); + } + + n = audio_stream_frame_bytes(sink_stream) * (blk_out + cd->sink_frames); + if (sink_stream->size < n) { + comp_warn(dev, "Sink size %d is less than required %d", + sink_stream->size, n); + } + + return 0; +} + +static int src_params_general(struct comp_dev *dev, struct comp_data *cd, + struct sof_ipc_stream_params *params) { - struct comp_data *cd = comp_get_drvdata(dev); struct comp_buffer *sourceb, *sinkb; struct comp_buffer __sparse_cache *source_c, *sink_c; size_t delay_lines_size; @@ -677,7 +729,7 @@ static int src_params(struct comp_dev *dev, comp_info(dev, "src_params()"); src_set_params(dev, params); - err = src_verify_params(dev, params); + err = src_verify_params(dev, cd, params); if (err < 0) { comp_err(dev, "src_params(): pcm params verification failed."); return -EINVAL; @@ -714,8 +766,7 @@ static int src_params(struct comp_dev *dev, cd->source_rate, cd->sink_rate, source_c->stream.frame_fmt); comp_info(dev, "src_params(), sourceb->channels = %u, sinkb->channels = %u, dev->frames = %u", source_c->stream.channels, sink_c->stream.channels, dev->frames); - err = src_buffer_lengths(&cd->param, cd->source_rate, cd->sink_rate, - source_c->stream.channels, cd->source_frames); + err = src_buffer_lengths(dev, cd, source_c->stream.channels); if (err < 0) { comp_err(dev, "src_params(): src_buffer_lengths() failed"); goto out; @@ -730,8 +781,7 @@ static int src_params(struct comp_dev *dev, } /* free any existing delay lines. TODO reuse if same size */ - if (cd->delay_lines) - rfree(cd->delay_lines); + rfree(cd->delay_lines); cd->delay_lines = rballoc(0, SOF_MEM_CAPS_RAM, delay_lines_size); if (!cd->delay_lines) { @@ -780,88 +830,320 @@ static int src_params(struct comp_dev *dev, return err; } -static int src_ctrl_cmd(struct comp_dev *dev, struct sof_ipc_ctrl_data *cdata) -{ - comp_err(dev, "src_ctrl_cmd()"); - return -EINVAL; -} - -/* used to pass standard and bespoke commands (with data) to component */ -static int src_cmd(struct comp_dev *dev, int cmd, void *data, - int max_data_size) +static int src_prepare_general(struct comp_dev *dev, struct comp_data *cd) { - struct sof_ipc_ctrl_data *cdata = ASSUME_ALIGNED(data, 4); - int ret = 0; + struct comp_buffer *sourceb, *sinkb; + struct comp_buffer __sparse_cache *source_c, *sink_c; + enum sof_ipc_frame source_format; + enum sof_ipc_frame sink_format; + int ret; - comp_info(dev, "src_cmd()"); + /* SRC component will only ever have 1 source and 1 sink buffer */ + sourceb = list_first_item(&dev->bsource_list, + struct comp_buffer, sink_list); + sinkb = list_first_item(&dev->bsink_list, + struct comp_buffer, source_list); - if (cmd == COMP_CMD_SET_VALUE) - ret = src_ctrl_cmd(dev, cdata); + source_c = buffer_acquire(sourceb); + sink_c = buffer_acquire(sinkb); - return ret; -} +#if CONFIG_IPC_MAJOR_4 + /* set align requirements */ + src_set_alignment(&source_c->stream, &sink_c->stream); +#endif -static int src_trigger(struct comp_dev *dev, int cmd) -{ - struct comp_data *cd = comp_get_drvdata(dev); + /* get source/sink data format */ + source_format = source_c->stream.frame_fmt; + sink_format = sink_c->stream.frame_fmt; - comp_info(dev, "src_trigger()"); + ret = src_check_buffer_sizes(dev, cd, &source_c->stream, &sink_c->stream); + if (ret < 0) + goto out; - if (cmd == COMP_TRIGGER_START || cmd == COMP_TRIGGER_RELEASE) { - if (!cd->polyphase_func) { - comp_err(dev, "polyphase_func is not set"); - return -EINVAL; - } + /* SRC supports S16_LE, S24_4LE and S32_LE formats */ + if (source_format != sink_format) { + comp_err(dev, "src_prepare(): Source fmt %d and sink fmt %d are different.", + source_format, sink_format); + ret = -EINVAL; + goto out; } - return comp_set_state(dev, cmd); -} - -static int src_get_copy_limits(struct comp_data *cd, - const struct comp_buffer __sparse_cache *source, - const struct comp_buffer __sparse_cache *sink) -{ - struct src_param *sp; - struct src_stage *s1; - struct src_stage *s2; - int frames_src; - int frames_snk; - - /* Get SRC parameters */ - sp = &cd->param; - s1 = cd->src.stage1; - s2 = cd->src.stage2; - /* Calculate how many blocks can be processed with - * available source and free sink frames amount. - */ - if (s2->filter_length > 1) { - /* Two polyphase filters case */ - frames_snk = audio_stream_get_free_frames(&sink->stream); - frames_snk = MIN(frames_snk, cd->sink_frames + s2->blk_out); - sp->stage2_times = frames_snk / s2->blk_out; - frames_src = audio_stream_get_avail_frames(&source->stream); - frames_src = MIN(frames_src, cd->source_frames + s1->blk_in); - sp->stage1_times = frames_src / s1->blk_in; - sp->blk_in = sp->stage1_times * s1->blk_in; - sp->blk_out = sp->stage2_times * s2->blk_out; - } else { - /* Single polyphase filter case */ - frames_snk = audio_stream_get_free_frames(&sink->stream); - frames_snk = MIN(frames_snk, cd->sink_frames + s1->blk_out); - sp->stage1_times = frames_snk / s1->blk_out; - frames_src = audio_stream_get_avail_frames(&source->stream); - sp->stage1_times = MIN(sp->stage1_times, - frames_src / s1->blk_in); - sp->blk_in = sp->stage1_times * s1->blk_in; - sp->blk_out = sp->stage1_times * s1->blk_out; + switch (source_format) { +#if CONFIG_FORMAT_S16LE + case SOF_IPC_FRAME_S16_LE: + cd->data_shift = 0; + cd->polyphase_func = src_polyphase_stage_cir_s16; + break; +#endif /* CONFIG_FORMAT_S16LE */ +#if CONFIG_FORMAT_S24LE + case SOF_IPC_FRAME_S24_4LE: + cd->data_shift = 8; + cd->polyphase_func = src_polyphase_stage_cir; + break; +#endif /* CONFIG_FORMAT_S24LE */ +#if CONFIG_FORMAT_S32LE + case SOF_IPC_FRAME_S32_LE: + cd->data_shift = 0; + cd->polyphase_func = src_polyphase_stage_cir; + break; +#endif /* CONFIG_FORMAT_S32LE */ + default: + comp_err(dev, "src_prepare(): invalid format %d", source_format); + ret = -EINVAL; + goto out; } - if (sp->blk_in == 0 && sp->blk_out == 0) - return -EIO; +out: + if (ret < 0) + comp_set_state(dev, COMP_TRIGGER_RESET); + + buffer_release(sink_c); + buffer_release(source_c); + + return ret; +} + +#if CONFIG_IPC_MAJOR_4 +static int src_init(struct processing_module *mod) +{ + struct module_data *md = &mod->priv; + struct module_config *cfg = &md->cfg; + struct comp_dev *dev = mod->dev; + struct comp_data *cd = NULL; + + comp_dbg(dev, "src_init()"); + + /* validate init data - either SRC sink or source rate must be set */ + if (src_rate_check(cfg->init_data) < 0) { + comp_err(dev, "src_init(): SRC sink and source rate are not set"); + return -EINVAL; + } + + cd = rzalloc(SOF_MEM_ZONE_RUNTIME, 0, SOF_MEM_CAPS_RAM, sizeof(*cd)); + if (!cd) { + rfree(dev); + return -ENOMEM; + } + + memcpy_s(&cd->ipc_config, sizeof(cd->ipc_config), cfg->init_data, sizeof(cd->ipc_config)); + + cd->delay_lines = NULL; + cd->src_func = src_fallback; + cd->polyphase_func = NULL; + src_polyphase_reset(&cd->src); + + md->private = cd; + + mod->simple_copy = true; + + return 0; +} + +static int src_prepare(struct processing_module *mod) +{ + struct comp_data *cd = module_get_private_data(mod); + struct sof_ipc_stream_params *params = mod->stream_params; + struct comp_dev *dev = mod->dev; + int ret; + + comp_info(dev, "src_prepare()"); + + ret = src_params_general(dev, cd, params); + if (ret < 0) + return ret; + + return src_prepare_general(dev, cd); +} + +static int src_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_data *cd = module_get_private_data(mod); + struct comp_dev *dev = mod->dev; + struct comp_buffer *source, *sink; + struct comp_buffer __sparse_cache *source_c, *sink_c; + int consumed = 0; + int produced = 0; + int ret; + + comp_dbg(dev, "src_process()"); + + /* src component needs 1 source and 1 sink buffer */ + source = list_first_item(&dev->bsource_list, struct comp_buffer, + sink_list); + sink = list_first_item(&dev->bsink_list, struct comp_buffer, + source_list); + + source_c = buffer_acquire(source); + sink_c = buffer_acquire(sink); + + ret = src_get_copy_limits(cd, source_c, sink_c); + if (ret) { + comp_dbg(dev, "No data to process."); + goto out; + } + + cd->src_func(dev, cd, &source_c->stream, &sink_c->stream, &consumed, &produced); + src_update_buffer_position(input_buffers, output_buffers, &consumed, &produced); + + comp_dbg(dev, "src_process(), consumed = %u, produced = %u", consumed, produced); + +out: + buffer_release(sink_c); + buffer_release(source_c); return 0; } +static int src_set_config(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) +{ + return -EINVAL; +} + +static int src_get_config(struct processing_module *mod, uint32_t config_id, + uint32_t *data_offset_size, uint8_t *fragment, size_t fragment_size) +{ + return -EINVAL; +} + +static int src_reset(struct processing_module *mod) +{ + struct comp_data *cd = module_get_private_data(mod); + + comp_info(mod->dev, "src_reset()"); + + cd->src_func = src_fallback; + src_polyphase_reset(&cd->src); + + return 0; +} + +static int src_free(struct processing_module *mod) +{ + struct comp_data *cd = module_get_private_data(mod); + + comp_info(mod->dev, "src_free()"); + + /* Free dynamically reserved buffers for SRC algorithm */ + rfree(cd->delay_lines); + + rfree(cd); + return 0; +} + +static struct module_interface src_interface = { + .init = src_init, + .prepare = src_prepare, + .process = src_process, + .set_configuration = src_set_config, + .get_configuration = src_get_config, + .reset = src_reset, + .free = src_free, +}; + +DECLARE_MODULE_ADAPTER(src_interface, src_uuid, src_tr); + +#elif CONFIG_IPC_MAJOR_3 +static struct comp_dev *src_new(const struct comp_driver *drv, + const struct comp_ipc_config *config, + const void *spec) +{ + struct comp_dev *dev; + struct comp_data *cd; + + comp_cl_info(&comp_src, "src_new()"); + + /* validate init data - either SRC sink or source rate must be set */ + if (src_rate_check(spec) < 0) { + comp_cl_err(&comp_src, "src_new(): SRC sink and source rate are not set"); + return NULL; + } + + dev = comp_alloc(drv, sizeof(*dev)); + if (!dev) + return NULL; + dev->ipc_config = *config; + + cd = rzalloc(SOF_MEM_ZONE_RUNTIME, 0, SOF_MEM_CAPS_RAM, sizeof(*cd)); + if (!cd) { + rfree(dev); + return NULL; + } + + comp_set_drvdata(dev, cd); + memcpy_s(&cd->ipc_config, sizeof(cd->ipc_config), spec, sizeof(cd->ipc_config)); + + cd->delay_lines = NULL; + cd->src_func = src_fallback; + cd->polyphase_func = NULL; + src_polyphase_reset(&cd->src); + + dev->state = COMP_STATE_READY; + return dev; +} + +static void src_free(struct comp_dev *dev) +{ + struct comp_data *cd = comp_get_drvdata(dev); + + comp_info(dev, "src_free()"); + + /* Free dynamically reserved buffers for SRC algorithm */ + rfree(cd->delay_lines); + + rfree(cd); + rfree(dev); +} + +/* set component audio stream parameters */ +static int src_params(struct comp_dev *dev, + struct sof_ipc_stream_params *params) +{ + struct comp_data *cd = comp_get_drvdata(dev); + + return src_params_general(dev, cd, params); +} + +static int src_ctrl_cmd(struct comp_dev *dev, struct sof_ipc_ctrl_data *cdata) +{ + comp_err(dev, "src_ctrl_cmd()"); + return -EINVAL; +} + +/* used to pass standard and bespoke commands (with data) to component */ +static int src_cmd(struct comp_dev *dev, int cmd, void *data, + int max_data_size) +{ + struct sof_ipc_ctrl_data *cdata = ASSUME_ALIGNED(data, 4); + int ret = 0; + + comp_info(dev, "src_cmd()"); + + if (cmd == COMP_CMD_SET_VALUE) + ret = src_ctrl_cmd(dev, cdata); + + return ret; +} + +static int src_trigger(struct comp_dev *dev, int cmd) +{ + struct comp_data *cd = comp_get_drvdata(dev); + + comp_info(dev, "src_trigger()"); + + if (cmd == COMP_TRIGGER_START || cmd == COMP_TRIGGER_RELEASE) { + if (!cd->polyphase_func) { + comp_err(dev, "polyphase_func is not set"); + return -EINVAL; + } + } + return comp_set_state(dev, cmd); +} + static void src_process(struct comp_dev *dev, struct comp_buffer __sparse_cache *source, struct comp_buffer __sparse_cache *sink) { @@ -871,7 +1153,7 @@ static void src_process(struct comp_dev *dev, struct comp_buffer __sparse_cache /* consumed bytes are not known at this point */ buffer_stream_invalidate(source, source->stream.size); - cd->src_func(dev, &source->stream, &sink->stream, &consumed, &produced); + cd->src_func(dev, cd, &source->stream, &sink->stream, &consumed, &produced); buffer_stream_writeback(sink, produced * audio_stream_frame_bytes(&sink->stream)); comp_dbg(dev, "src_copy(), consumed = %u, produced = %u", @@ -918,55 +1200,9 @@ static int src_copy(struct comp_dev *dev) return 0; } -static int src_check_buffer_sizes(struct comp_data *cd, - struct audio_stream __sparse_cache *source_stream, - struct audio_stream __sparse_cache *sink_stream) -{ - struct src_stage *s1 = cd->src.stage1; - struct src_stage *s2 = cd->src.stage2; - int stage1_times; - int stage2_times; - int blk_in; - int blk_out; - int n; - - if (s2->filter_length > 1) { - /* Two polyphase filters case */ - stage2_times = ceil_divide(cd->sink_frames, s2->blk_out); - stage1_times = ceil_divide(cd->source_frames, s1->blk_in); - blk_in = stage1_times * s1->blk_in; - blk_out = stage2_times * s2->blk_out; - } else { - /* Single polyphase filter case */ - stage1_times = ceil_divide(cd->sink_frames, s1->blk_out); - n = ceil_divide(cd->source_frames, s1->blk_in); - stage1_times = MAX(stage1_times, n); - blk_in = stage1_times * s1->blk_in; - blk_out = stage1_times * s1->blk_out; - } - - n = audio_stream_frame_bytes(source_stream) * (blk_in + cd->source_frames); - if (source_stream->size < n) { - comp_cl_warn(&comp_src, "Source size %d is less than required %d", - source_stream->size, n); - } - - n = audio_stream_frame_bytes(sink_stream) * (blk_out + cd->sink_frames); - if (sink_stream->size < n) { - comp_cl_warn(&comp_src, "Sink size %d is less than required %d", - sink_stream->size, n); - } - - return 0; -} - static int src_prepare(struct comp_dev *dev) { struct comp_data *cd = comp_get_drvdata(dev); - struct comp_buffer *sourceb, *sinkb; - struct comp_buffer __sparse_cache *source_c, *sink_c; - enum sof_ipc_frame source_format; - enum sof_ipc_frame sink_format; int ret; comp_info(dev, "src_prepare()"); @@ -978,66 +1214,7 @@ static int src_prepare(struct comp_dev *dev) if (ret == COMP_STATUS_STATE_ALREADY_SET) return PPL_STATUS_PATH_STOP; - /* SRC component will only ever have 1 source and 1 sink buffer */ - sourceb = list_first_item(&dev->bsource_list, - struct comp_buffer, sink_list); - sinkb = list_first_item(&dev->bsink_list, - struct comp_buffer, source_list); - - source_c = buffer_acquire(sourceb); - sink_c = buffer_acquire(sinkb); - - /* get source data format */ - source_format = source_c->stream.frame_fmt; - - /* get sink data format */ - sink_format = sink_c->stream.frame_fmt; - - ret = src_check_buffer_sizes(cd, &source_c->stream, &sink_c->stream); - if (ret < 0) - goto out; - - /* SRC supports S16_LE, S24_4LE and S32_LE formats */ - if (source_format != sink_format) { - comp_err(dev, "src_prepare(): Source fmt %d and sink fmt %d are different.", - source_format, sink_format); - ret = -EINVAL; - goto out; - } - - switch (source_format) { -#if CONFIG_FORMAT_S16LE - case SOF_IPC_FRAME_S16_LE: - cd->data_shift = 0; - cd->polyphase_func = src_polyphase_stage_cir_s16; - break; -#endif /* CONFIG_FORMAT_S16LE */ -#if CONFIG_FORMAT_S24LE - case SOF_IPC_FRAME_S24_4LE: - cd->data_shift = 8; - cd->polyphase_func = src_polyphase_stage_cir; - break; -#endif /* CONFIG_FORMAT_S24LE */ -#if CONFIG_FORMAT_S32LE - case SOF_IPC_FRAME_S32_LE: - cd->data_shift = 0; - cd->polyphase_func = src_polyphase_stage_cir; - break; -#endif /* CONFIG_FORMAT_S32LE */ - default: - comp_err(dev, "src_prepare(): invalid format %d", source_format); - ret = -EINVAL; - goto out; - } - -out: - if (ret < 0) - comp_set_state(dev, COMP_TRIGGER_RESET); - - buffer_release(sink_c); - buffer_release(source_c); - - return ret; + return src_prepare_general(dev, cd); } static int src_reset(struct comp_dev *dev) @@ -1066,9 +1243,6 @@ static const struct comp_driver comp_src = { .copy = src_copy, .prepare = src_prepare, .reset = src_reset, -#if CONFIG_IPC_MAJOR_4 - .get_attribute = src_get_attribute, -#endif }, }; @@ -1083,3 +1257,6 @@ UT_STATIC void sys_comp_src_init(void) } DECLARE_MODULE(sys_comp_src_init); +#else +#error "No or invalid IPC MAJOR version selected." +#endif diff --git a/src/include/sof/audio/src/src.h b/src/include/sof/audio/src/src.h index 03d1a345d1d5..6fa936fc74eb 100644 --- a/src/include/sof/audio/src/src.h +++ b/src/include/sof/audio/src/src.h @@ -115,9 +115,6 @@ void src_polyphase_stage_cir(struct src_stage_prm *s); void src_polyphase_stage_cir_s16(struct src_stage_prm *s); #endif /* CONFIG_FORMAT_S16LE */ -int src_buffer_lengths(struct src_param *a, int fs_in, int fs_out, int nch, - int source_frames); - int32_t src_input_rates(void); int32_t src_output_rates(void); diff --git a/zephyr/wrapper.c b/zephyr/wrapper.c index e715a120abd2..a0b4b380b210 100644 --- a/zephyr/wrapper.c +++ b/zephyr/wrapper.c @@ -191,8 +191,10 @@ void sys_comp_dai_init(void); void sys_comp_src_init(void); void sys_comp_mux_init(void); #if CONFIG_IPC_MAJOR_3 +void sys_comp_src_init(void); void sys_comp_selector_init(void); #else +void sys_comp_module_src_interface_init(void); void sys_comp_module_selector_interface_init(void); #endif void sys_comp_switch_init(void); @@ -286,8 +288,13 @@ int task_main_start(struct sof *sof) if (IS_ENABLED(CONFIG_COMP_DAI)) sys_comp_dai_init(); - if (IS_ENABLED(CONFIG_COMP_SRC)) + if (IS_ENABLED(CONFIG_COMP_SRC)) { +#if CONFIG_IPC_MAJOR_3 sys_comp_src_init(); +#else + sys_comp_module_src_interface_init(); +#endif + } if (IS_ENABLED(CONFIG_COMP_SEL)) #if CONFIG_IPC_MAJOR_3