diff --git a/src/audio/mixin_mixout/mixin_mixout.c b/src/audio/mixin_mixout/mixin_mixout.c index 0847007bfa40..ec575cc0073a 100644 --- a/src/audio/mixin_mixout/mixin_mixout.c +++ b/src/audio/mixin_mixout/mixin_mixout.c @@ -75,8 +75,7 @@ struct mixin_sink_config { /* mixin component private data */ struct mixin_data { - normal_mix_func normal_mix_channel; - mute_func mute_channel; + mix_func mix; struct mixin_sink_config sink_config[MIXIN_MAX_SINKS]; }; @@ -104,6 +103,15 @@ struct mixout_data { * by mixin but not yet produced in mixout. */ struct pending_frames pending_frames[MIXOUT_MAX_SOURCES]; + + /* + * When several mixins are connected to one mixout (a typical case) mixout sink + * buffer is acquired (via sink_get_buffer() call) in mixin_process() of first + * mixin. Other connected mixins just use a pointer to the buffer stored below. + * The buffer is released (committed by sink_commit_buffer() call) in mixout_process(). + */ + struct cir_buf_ptr acquired_buf; + uint32_t acquired_buf_free_frames; }; /* NULL is also a valid mixin argument: in such case the function returns first unused entry */ @@ -183,10 +191,10 @@ static int mixout_free(struct processing_module *mod) return 0; } -static int mix_and_remap(struct comp_dev *dev, const struct mixin_data *mixin_data, - uint16_t sink_index, struct audio_stream *sink, - uint32_t start_frame, uint32_t mixed_frames, - const struct audio_stream *source, uint32_t frame_count) +static int mix(struct comp_dev *dev, const struct mixin_data *mixin_data, + uint16_t sink_index, struct cir_buf_ptr *sink, + uint32_t start_sample, uint32_t mixed_samples, + const struct cir_buf_ptr *source, uint32_t sample_count) { const struct mixin_sink_config *sink_config; @@ -198,43 +206,32 @@ static int mix_and_remap(struct comp_dev *dev, const struct mixin_data *mixin_da sink_config = &mixin_data->sink_config[sink_index]; - /* Mix streams. mix_channel() is reused here to mix streams, not individual - * channels. To do so, (multichannel) stream is treated as single channel: - * channel count is passed as 1, channel index is 0, frame indices (start_frame - * and mixed_frame) and frame count are multiplied by real stream channel count. - */ - mixin_data->normal_mix_channel(sink, start_frame * audio_stream_get_channels(sink), - mixed_frames * audio_stream_get_channels(sink), - source, - frame_count * audio_stream_get_channels(sink), - sink_config->gain); - + mixin_data->mix(sink, start_sample, mixed_samples, + source, sample_count, sink_config->gain); return 0; } /* mix silence into stream, i.e. set not yet mixed data in stream to zero */ -static void silence(struct audio_stream *stream, uint32_t start_frame, - uint32_t mixed_frames, uint32_t frame_count) +static void silence(struct cir_buf_ptr *stream, uint32_t start_offset, + uint32_t mixed_bytes, uint32_t size) { - uint32_t skip_mixed_frames; + uint32_t skip_mixed_bytes; uint8_t *ptr; - uint32_t size; int n; - assert(mixed_frames >= start_frame); - skip_mixed_frames = mixed_frames - start_frame; + assert(mixed_bytes >= start_offset); + skip_mixed_bytes = mixed_bytes - start_offset; - if (frame_count <= skip_mixed_frames) + if (size <= skip_mixed_bytes) return; - size = audio_stream_period_bytes(stream, frame_count - skip_mixed_frames); - ptr = (uint8_t *)audio_stream_get_wptr(stream) + - audio_stream_period_bytes(stream, mixed_frames); + size -= skip_mixed_bytes; + ptr = (uint8_t *)stream->ptr + mixed_bytes; while (size) { - ptr = audio_stream_wrap(stream, ptr); - n = MIN(audio_stream_bytes_without_wrap(stream, ptr), size); + ptr = cir_buf_wrap(ptr, stream->buf_start, stream->buf_end); + n = MIN((uint8_t *)stream->buf_end - ptr, size); memset(ptr, 0, n); size -= n; ptr += n; @@ -258,31 +255,28 @@ static void silence(struct audio_stream *stream, uint32_t start_frame, * was actually mixed and so xxx_produce() is called for that amount. */ static int mixin_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 sof_source **sources, int num_of_sources, + struct sof_sink **sinks, int num_of_sinks) { struct mixin_data *mixin_data = module_get_private_data(mod); struct comp_dev *dev = mod->dev; uint32_t source_avail_frames, sinks_free_frames; - struct comp_dev *active_mixouts[MIXIN_MAX_SINKS]; + struct processing_module *active_mixouts[MIXIN_MAX_SINKS]; uint16_t sinks_ids[MIXIN_MAX_SINKS]; - uint32_t bytes_to_consume_from_source_buf; + uint32_t bytes_to_consume = 0; uint32_t frames_to_copy; struct pending_frames *pending_frames; int i, ret; + struct cir_buf_ptr source_ptr; comp_dbg(dev, "mixin_process()"); - source_avail_frames = audio_stream_get_avail_frames(input_buffers[0].data); + source_avail_frames = source_get_data_frames_available(sources[0]); sinks_free_frames = INT32_MAX; - /* block mixin pipeline until at least one mixout pipeline started */ - if (num_output_buffers == 0) - return 0; - - if (num_output_buffers > MIXIN_MAX_SINKS) { - comp_err(dev, "mixin_process(): Invalid output buffer count %d", - num_output_buffers); + if (num_of_sinks > MIXIN_MAX_SINKS) { + comp_err(dev, "mixin_process(): Invalid output sink count %d", + num_of_sinks); return -EINVAL; } @@ -290,27 +284,54 @@ static int mixin_process(struct processing_module *mod, * it is a nimimal value among frames available in source buffer * and frames free in each connected mixout sink buffer. */ - for (i = 0; i < num_output_buffers; i++) { - struct comp_buffer *unused_in_between_buf_c; + for (i = 0; i < num_of_sinks; i++) { + struct audio_stream *stream; + struct comp_buffer *unused_in_between_buf; struct comp_dev *mixout; - uint16_t sink_id; - struct comp_buffer *sink; + struct sof_sink *mixout_sink; struct mixout_data *mixout_data; struct processing_module *mixout_mod; uint32_t free_frames; + /* WORKAROUND: since mixin is always connected to mixout, we can safely assume + * mixin sink interface is implemented via comp_buffer. This is, of course, + * not the case for other modules. + * TODO: find out a solution to reach mixout without knowledge of mixin + * sof_sink implementation. + */ + stream = container_of(sinks[i], struct audio_stream, sink_api); /* unused buffer between mixin and mixout */ - unused_in_between_buf_c = container_of(output_buffers[i].data, - struct comp_buffer, stream); - mixout = unused_in_between_buf_c->sink; - sink_id = IPC4_SRC_QUEUE_ID(buf_get_id(unused_in_between_buf_c)); - - active_mixouts[i] = mixout; - sinks_ids[i] = sink_id; + unused_in_between_buf = container_of(stream, struct comp_buffer, stream); + mixout = unused_in_between_buf->sink; - sink = list_first_item(&mixout->bsink_list, struct comp_buffer, source_list); + /* Skip non-active mixout like it is not connected so it does not + * block other possibly connected mixouts. In addition, non-active + * mixouts might have their sink buffer/interface not yet configured. + */ + if (mixout->state != COMP_STATE_ACTIVE) { + active_mixouts[i] = NULL; + continue; + } mixout_mod = comp_get_drvdata(mixout); + active_mixouts[i] = mixout_mod; + mixout_sink = mixout_mod->sinks[0]; + + /* mixout might be created on another pipeline. Its sink stream params are usually + * configured in .prepare(). It is possible that such .prepare() was not yet called + * for mixout pipeline. Hence the check above if mixout state is active. However, + * let's just in case check here if sink stream params are really configured as + * proceeding with unconfigured sink will lead to hard to debug bugs. + * Unconfigured stream params are filled with zeros. + * TODO: introduce something like sink_is_configured() ? + */ + if (!mixout_sink || sink_get_channels(mixout_sink) == 0) { + comp_err(dev, "mixout sink not configured!"); + return -EINVAL; + } + + sinks_ids[i] = IPC4_SRC_QUEUE_ID(buf_get_id(unused_in_between_buf)); + mixout_data = module_get_private_data(mixout_mod); pending_frames = get_mixin_pending_frames(mixout_data, dev); if (!pending_frames) { @@ -318,16 +339,14 @@ static int mixin_process(struct processing_module *mod, return -EINVAL; } - /* Normally this should never happen as we checked above - * that mixout is in active state and so its sink buffer - * should be already initialized in mixout .params(). + /* In theory, though unlikely, mixout sink can be connected to some module on + * another core. In this case free space in mixout sink buffer can suddenly increase + * (data consumed on another core) after the buffer was already acquired. Let's only + * access free space that was at the moment of acquiring the buffer. */ - if (!sink->hw_params_configured) { - comp_err(dev, "Uninitialized mixout sink buffer!"); - return -EINVAL; - } - - free_frames = audio_stream_get_free_frames(&sink->stream); + free_frames = mixout_data->acquired_buf.ptr ? + mixout_data->acquired_buf_free_frames : + sink_get_free_frames(mixout_sink); /* mixout sink buffer may still have not yet produced data -- data * consumed and written there by mixin on previous mixin_process() run. @@ -337,40 +356,39 @@ static int mixin_process(struct processing_module *mod, sinks_free_frames = MIN(sinks_free_frames, free_frames - pending_frames->frames); } + if (sinks_free_frames == 0 || sinks_free_frames == INT32_MAX) + return 0; + if (source_avail_frames > 0) { - struct comp_buffer *source_c; + size_t buf_size; frames_to_copy = MIN(source_avail_frames, sinks_free_frames); - bytes_to_consume_from_source_buf = - audio_stream_period_bytes(input_buffers[0].data, frames_to_copy); - if (bytes_to_consume_from_source_buf > 0) { - input_buffers[0].consumed = bytes_to_consume_from_source_buf; - source_c = container_of(input_buffers[0].data, struct comp_buffer, - stream); - buffer_stream_invalidate(source_c, bytes_to_consume_from_source_buf); - } + bytes_to_consume = frames_to_copy * source_get_frame_bytes(sources[0]); + + source_get_data(sources[0], bytes_to_consume, (const void **)&source_ptr.ptr, + (const void **)&source_ptr.buf_start, &buf_size); + source_ptr.buf_end = (uint8_t *)source_ptr.buf_start + buf_size; } else { /* if source does not produce any data -- do NOT block mixing but generate * silence as that source output. * * here frames_to_copy is silence size. + * + * FIXME: does not work properly for freq like 44.1 kHz. */ frames_to_copy = MIN(dev->frames, sinks_free_frames); } /* iterate over all connected mixouts and mix source data into each mixout sink buffer */ - for (i = 0; i < num_output_buffers; i++) { - struct comp_dev *mixout; - struct comp_buffer *sink; + for (i = 0; i < num_of_sinks; i++) { struct mixout_data *mixout_data; struct processing_module *mixout_mod; uint32_t start_frame; - uint32_t writeback_size; - mixout = active_mixouts[i]; - sink = list_first_item(&mixout->bsink_list, struct comp_buffer, source_list); + mixout_mod = active_mixouts[i]; + if (!mixout_mod) + continue; - mixout_mod = comp_get_drvdata(mixout); mixout_data = module_get_private_data(mixout_mod); pending_frames = get_mixin_pending_frames(mixout_data, dev); if (!pending_frames) { @@ -384,56 +402,70 @@ static int mixin_process(struct processing_module *mod, */ start_frame = pending_frames->frames; + /* mixout sink buffer is acquired here by its first connected mixin and is + * released in mixout_process(). Other connected mixins just use a pointer + * stored in mixout_data->acquired_buf. + */ + if (!mixout_data->acquired_buf.ptr) { + struct sof_sink *sink = mixout_mod->sinks[0]; + uint32_t free_bytes = sink_get_free_size(sink); + uint32_t buf_size; + + sink_get_buffer(sink, free_bytes, &mixout_data->acquired_buf.ptr, + &mixout_data->acquired_buf.buf_start, &buf_size); + mixout_data->acquired_buf.buf_end = + (uint8_t *)mixout_data->acquired_buf.buf_start + buf_size; + mixout_data->acquired_buf_free_frames = + free_bytes / sink_get_frame_bytes(sink); + } + /* if source does not produce any data but mixin is in active state -- generate * silence instead of that source data */ if (source_avail_frames == 0) { + uint32_t frame_bytes = sink_get_frame_bytes(mixout_mod->sinks[0]); + /* generate silence */ - silence(&sink->stream, start_frame, mixout_data->mixed_frames, - frames_to_copy); + silence(&mixout_data->acquired_buf, start_frame * frame_bytes, + mixout_data->mixed_frames * frame_bytes, + frames_to_copy * frame_bytes); } else { + uint32_t channel_count = sink_get_channels(mixout_mod->sinks[0]); + /* basically, if sink buffer has no data -- copy source data there, if * sink buffer has some data (written by another mixin) mix that data * with source data. */ - ret = mix_and_remap(dev, mixin_data, sinks_ids[i], &sink->stream, - start_frame, mixout_data->mixed_frames, - input_buffers[0].data, frames_to_copy); - if (ret < 0) { + ret = mix(dev, mixin_data, sinks_ids[i], &mixout_data->acquired_buf, + start_frame * channel_count, + mixout_data->mixed_frames * channel_count, + &source_ptr, frames_to_copy * channel_count); + if (ret < 0) return ret; - } } - /* it would be better to writeback memory region starting from start_frame and - * of frames_to_copy size (converted to bytes, of course). However, seems - * there is no appropreate API. Anyway, start_frame would be 0 most of the time. - */ - writeback_size = audio_stream_period_bytes(&sink->stream, - frames_to_copy + start_frame); - if (writeback_size > 0) - buffer_stream_writeback(sink, writeback_size); - pending_frames->frames += frames_to_copy; if (frames_to_copy + start_frame > mixout_data->mixed_frames) mixout_data->mixed_frames = frames_to_copy + start_frame; } + if (bytes_to_consume) + source_release_data(sources[0], bytes_to_consume); + return 0; } -/* mixout just calls xxx_produce() on data mixed into its sink buffer by - * mixins. - */ +/* mixout just commits its sink buffer with data already mixed by mixins */ static int mixout_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 sof_source **sources, int num_of_sources, + struct sof_sink **sinks, int num_of_sinks) { struct comp_dev *dev = mod->dev; struct mixout_data *md; uint32_t frames_to_produce = INT32_MAX; + uint32_t bytes_to_produce; struct pending_frames *pending_frames; - uint32_t sink_bytes; int i; comp_dbg(dev, "mixout_process()"); @@ -444,38 +476,42 @@ static int mixout_process(struct processing_module *mod, * (i.e., mixed into mixout sink buffer). That is the amount that can/should be * produced now. */ - for (i = 0; i < num_input_buffers; i++) { + for (i = 0; i < num_of_sources; i++) { const struct audio_stream *source_stream; struct comp_buffer *unused_in_between_buf; - struct comp_dev *source; + struct comp_dev *mixin; - source_stream = input_buffers[i].data; + /* WORKAROUND: since mixin is always connected to mixout, we can safely assume + * mixout source interface is implemented via comp_buffer. This is, of course, + * not the case for other modules. + * TODO: find out a solution to reach mixin without knowledge of mixout + * sof_source implementation. + */ + source_stream = container_of(sources[i], struct audio_stream, source_api); unused_in_between_buf = container_of(source_stream, struct comp_buffer, stream); + mixin = unused_in_between_buf->source; - source = unused_in_between_buf->source; - - pending_frames = get_mixin_pending_frames(md, source); + pending_frames = get_mixin_pending_frames(md, mixin); if (!pending_frames) continue; - if (source->state == COMP_STATE_ACTIVE || pending_frames->frames) + if (mixin->state == COMP_STATE_ACTIVE || pending_frames->frames) frames_to_produce = MIN(frames_to_produce, pending_frames->frames); } if (frames_to_produce > 0 && frames_to_produce < INT32_MAX) { - for (i = 0; i < num_input_buffers; i++) { + for (i = 0; i < num_of_sources; i++) { const struct audio_stream *source_stream; struct comp_buffer *unused_in_between_buf; - struct comp_dev *source; + struct comp_dev *mixin; - source_stream = input_buffers[i].data; + source_stream = container_of(sources[i], struct audio_stream, source_api); unused_in_between_buf = container_of(source_stream, struct comp_buffer, stream); + mixin = unused_in_between_buf->source; - source = unused_in_between_buf->source; - - pending_frames = get_mixin_pending_frames(md, source); + pending_frames = get_mixin_pending_frames(md, mixin); if (!pending_frames) continue; @@ -488,17 +524,27 @@ static int mixout_process(struct processing_module *mod, assert(md->mixed_frames >= frames_to_produce); md->mixed_frames -= frames_to_produce; - sink_bytes = frames_to_produce * - audio_stream_frame_bytes(output_buffers[0].data); - output_buffers[0].size = sink_bytes; + bytes_to_produce = frames_to_produce * sink_get_frame_bytes(sinks[0]); } else { - sink_bytes = dev->frames * audio_stream_frame_bytes(output_buffers[0].data); - if (!audio_stream_set_zero(output_buffers[0].data, sink_bytes)) - output_buffers[0].size = sink_bytes; - else - output_buffers[0].size = 0; + /* FIXME: does not work properly for freq like 44.1 kHz */ + bytes_to_produce = dev->frames * sink_get_frame_bytes(sinks[0]); + bytes_to_produce = MIN(bytes_to_produce, sink_get_free_size(sinks[0])); + + if (!md->acquired_buf.ptr) { + size_t buf_size; + + sink_get_buffer(sinks[0], bytes_to_produce, &md->acquired_buf.ptr, + &md->acquired_buf.buf_start, &buf_size); + md->acquired_buf.buf_end = (uint8_t *)md->acquired_buf.buf_start + buf_size; + } + + cir_buf_set_zero(md->acquired_buf.ptr, md->acquired_buf.buf_start, + md->acquired_buf.buf_end, bytes_to_produce); } + sink_commit_buffer(sinks[0], bytes_to_produce); + md->acquired_buf.ptr = NULL; + return 0; } @@ -509,8 +555,7 @@ static int mixin_reset(struct processing_module *mod) comp_dbg(dev, "mixin_reset()"); - mixin_data->normal_mix_channel = NULL; - mixin_data->mute_channel = NULL; + mixin_data->mix = NULL; return 0; } @@ -518,20 +563,31 @@ static int mixin_reset(struct processing_module *mod) static int mixout_reset(struct processing_module *mod) { struct comp_dev *dev = mod->dev; - struct list_item *blist; comp_dbg(dev, "mixout_reset()"); /* FIXME: move this to module_adapter_reset() */ if (dev->pipeline->source_comp->direction == SOF_IPC_STREAM_PLAYBACK) { - list_for_item(blist, &dev->bsource_list) { - struct comp_buffer *source; + int i; + + for (i = 0; i < mod->num_of_sources; i++) { + const struct audio_stream *source_stream; + const struct comp_buffer *source_buf; bool stop; - /* FIXME: this is racy and implicitly protected by serialised IPCs */ - source = container_of(blist, struct comp_buffer, sink_list); - stop = (dev->pipeline == source->source->pipeline && - source->source->state > COMP_STATE_PAUSED); + /* WORKAROUND: since mixin is always connected to mixout, we can safely + * assume mixout source interface is implemented via comp_buffer. This is, + * of course, not the case for other modules. + * TODO: find out a solution to reach mixin without knowledge of mixout + * sof_source implementation. + */ + source_stream = container_of(mod->sources[i], + struct audio_stream, source_api); + source_buf = container_of(source_stream, struct comp_buffer, + stream); + + stop = (dev->pipeline == source_buf->source->pipeline && + source_buf->source->state > COMP_STATE_PAUSED); if (stop) /* should not reset the downstream components */ @@ -546,9 +602,8 @@ static int mixout_reset(struct processing_module *mod) static int mixin_params(struct processing_module *mod) { struct sof_ipc_stream_params *params = mod->stream_params; - struct mixin_data *md = module_get_private_data(mod); struct comp_dev *dev = mod->dev; - struct list_item *blist; + int i; int ret; comp_dbg(dev, "mixin_params()"); @@ -558,28 +613,27 @@ static int mixin_params(struct processing_module *mod) /* Buffers between mixins and mixouts are not used (mixin writes data directly to mixout * sink). But, anyway, let's setup these buffers properly just in case. */ - list_for_item(blist, &dev->bsink_list) { - struct comp_buffer *sink; - enum sof_ipc_frame frame_fmt, valid_fmt; - uint16_t sink_id; - sink = buffer_from_list(blist, PPL_DIR_DOWNSTREAM); + /* FIXME: there are 2 problems with the loop below: + * + * (1) struct sof_audio_stream_params contains two frame format members: frame_fmt + * and valid_sample_fmt both of type enum sof_ipc_frame. That is excessive as + * enum sof_ipc_frame describes both container and sample size and so having one + * variable of this type is enough. frame_fmt is set by comp_verify_params(), however, + * valid_sample_fmt does not. Hence valid_sample_fmt is set below in a loop. If mess + * with having both frame_fmt and valid_sample_fmt in SOF is solved when this loop can + * be removed. + * + * (2) comp_verify_params() setup sink buffers for playback pipeline and source buffers + * for capture pipelines. So in case problem (1) is solved the loop is only needed if + * mixin is on capture pipeline and mixout is in playback pipeline. Such topology seems + * makes not much sense and probably never used. In all other cases comp_verify_params() + * will be sufficient to setup buffers and so the loop below may be removed. + */ + for (i = 0; i < mod->num_of_sinks; i++) { + enum sof_ipc_frame frame_fmt, valid_fmt; - audio_stream_set_channels(&sink->stream, - mod->priv.cfg.base_cfg.audio_fmt.channels_count); - - /* Applying channel remapping may produce sink stream with channel count - * different from source channel count. - */ - sink_id = IPC4_SRC_QUEUE_ID(buf_get_id(sink)); - if (sink_id >= MIXIN_MAX_SINKS) { - comp_err(dev, "Sink index out of range: %u, max sink count: %u", - (uint32_t)sink_id, MIXIN_MAX_SINKS); - return -EINVAL; - } - if (md->sink_config[sink_id].mixer_mode == IPC4_MIXER_CHANNEL_REMAPPING_MODE) - audio_stream_set_channels(&sink->stream, - md->sink_config[sink_id].output_channel_count); + sink_set_channels(mod->sinks[i], mod->priv.cfg.base_cfg.audio_fmt.channels_count); /* comp_verify_params() does not modify valid_sample_fmt (a BUG?), * let's do this here @@ -589,12 +643,11 @@ static int mixin_params(struct processing_module *mod) &frame_fmt, &valid_fmt, mod->priv.cfg.base_cfg.audio_fmt.s_type); - audio_stream_set_frm_fmt(&sink->stream, frame_fmt); - audio_stream_set_valid_fmt(&sink->stream, valid_fmt); + sink_set_frm_fmt(mod->sinks[i], frame_fmt); + sink_set_valid_fmt(mod->sinks[i], valid_fmt); } - /* use BUFF_PARAMS_CHANNELS to skip updating channel count */ - ret = comp_verify_params(dev, BUFF_PARAMS_CHANNELS, params); + ret = comp_verify_params(dev, 0, params); if (ret < 0) { comp_err(dev, "mixin_params(): comp_verify_params() failed!"); return -EINVAL; @@ -617,7 +670,6 @@ static int mixin_prepare(struct processing_module *mod, { struct mixin_data *md = module_get_private_data(mod); struct comp_dev *dev = mod->dev; - struct comp_buffer *sink; enum sof_ipc_frame fmt; int ret; @@ -627,23 +679,21 @@ static int mixin_prepare(struct processing_module *mod, if (ret < 0) return ret; - sink = list_first_item(&dev->bsink_list, struct comp_buffer, source_list); - fmt = audio_stream_get_valid_fmt(&sink->stream); + fmt = sink_get_valid_fmt(sinks[0]); /* currently inactive so setup mixer */ switch (fmt) { case SOF_IPC_FRAME_S16_LE: case SOF_IPC_FRAME_S24_4LE: case SOF_IPC_FRAME_S32_LE: - md->normal_mix_channel = normal_mix_get_processing_function(fmt); - md->mute_channel = mute_mix_get_processing_function(fmt); + md->mix = mixin_get_processing_function(fmt); break; default: comp_err(dev, "unsupported data format %d", fmt); return -EINVAL; } - if (!md->normal_mix_channel || !md->mute_channel) { + if (!md->mix) { comp_err(dev, "have not found the suitable processing function"); return -EINVAL; } @@ -654,10 +704,8 @@ static int mixin_prepare(struct processing_module *mod, static int mixout_params(struct processing_module *mod) { struct sof_ipc_stream_params *params = mod->stream_params; - struct comp_buffer *sink; struct comp_dev *dev = mod->dev; enum sof_ipc_frame frame_fmt, valid_fmt; - uint32_t sink_period_bytes, sink_stream_size; int ret; comp_dbg(dev, "mixout_params()"); @@ -670,7 +718,9 @@ static int mixout_params(struct processing_module *mod) return -EINVAL; } - sink = list_first_item(&dev->bsink_list, struct comp_buffer, source_list); + /* FIXME: the code below could/should be removed once mess with having both frame_fmt + * and valid_sample_fmt is solved (see comment in mixin_params()). + */ /* comp_verify_params() does not modify valid_sample_fmt (a BUG?), let's do this here */ audio_stream_fmt_conversion(mod->priv.cfg.base_cfg.audio_fmt.depth, @@ -678,25 +728,7 @@ static int mixout_params(struct processing_module *mod) &frame_fmt, &valid_fmt, mod->priv.cfg.base_cfg.audio_fmt.s_type); - audio_stream_set_valid_fmt(&sink->stream, valid_fmt); - audio_stream_set_channels(&sink->stream, params->channels); - - sink_stream_size = audio_stream_get_size(&sink->stream); - - /* calculate period size based on config */ - sink_period_bytes = audio_stream_period_bytes(&sink->stream, - dev->frames); - - if (sink_period_bytes == 0) { - comp_err(dev, "mixout_params(): period_bytes = 0"); - return -EINVAL; - } - - if (sink_stream_size < sink_period_bytes) { - comp_err(dev, "mixout_params(): sink buffer size %d is insufficient < %d", - sink_stream_size, sink_period_bytes); - return -ENOMEM; - } + sink_set_valid_fmt(mod->sinks[0], valid_fmt); return 0; } @@ -905,7 +937,7 @@ static int mixin_set_config(struct processing_module *mod, uint32_t config_id, static const struct module_interface mixin_interface = { .init = mixin_init, .prepare = mixin_prepare, - .process_audio_stream = mixin_process, + .process = mixin_process, .set_configuration = mixin_set_config, .reset = mixin_reset, .free = mixin_free @@ -917,7 +949,7 @@ SOF_MODULE_INIT(mixin, sys_comp_module_mixin_interface_init); static const struct module_interface mixout_interface = { .init = mixout_init, .prepare = mixout_prepare, - .process_audio_stream = mixout_process, + .process = mixout_process, .reset = mixout_reset, .free = mixout_free, .bind = mixout_bind, diff --git a/src/audio/mixin_mixout/mixin_mixout.h b/src/audio/mixin_mixout/mixin_mixout.h index 49184e2aa51b..8ac844383917 100644 --- a/src/audio/mixin_mixout/mixin_mixout.h +++ b/src/audio/mixin_mixout/mixin_mixout.h @@ -102,60 +102,43 @@ struct ipc4_mixer_mode_config { struct ipc4_mixer_mode_sink_config mixer_mode_sink_configs[1]; } __packed __aligned(4); -/** - * \brief normal mode mixin_mixout processing function interface - */ -typedef void (*normal_mix_func)(struct audio_stream *sink, int32_t start_frame, - int32_t mixed_frames, - const struct audio_stream *source, - int32_t frame_count, uint16_t gain); +/* Pointer to data in circular buffer together with buffer boundaries */ +struct cir_buf_ptr { + void *buf_start; + void *buf_end; + void *ptr; +}; /** - * \brief mixin_mixout mute processing function interface + * \brief mixin processing function interface */ -typedef void (*mute_func) (struct audio_stream *stream, int32_t channel_index, - int32_t start_frame, int32_t mixed_frames, int32_t frame_count); +typedef void (*mix_func)(struct cir_buf_ptr *sink, int32_t start_sample, + int32_t mixed_samples, + const struct cir_buf_ptr *source, + int32_t sample_count, uint16_t gain); /** - * @brief mixin_mixout processing functions map. + * @brief mixin processing functions map. */ struct mix_func_map { - uint16_t frame_fmt; /* frame format */ - normal_mix_func normal_func; /* normal mode mixin_mixout processing function */ - mute_func mute_func; /* mute processing function */ + uint16_t frame_fmt; /* frame format */ + mix_func func; /* mixin processing function */ }; extern const struct mix_func_map mix_func_map[]; extern const size_t mix_count; /** - * \brief Retrievies normal mode mixer processing function. - * \param[in] fmt stream PCM frame format - */ -static inline normal_mix_func normal_mix_get_processing_function(int fmt) -{ - int i; - - /* map the normal mode mixin_mixout function for source and sink buffers */ - for (i = 0; i < mix_count; i++) { - if (fmt == mix_func_map[i].frame_fmt) - return mix_func_map[i].normal_func; - } - - return NULL; -} - -/** - * \brief Retrievies normal mode mixer processing function. + * \brief Retrievies mixin processing function. * \param[in] fmt stream PCM frame format */ -static inline mute_func mute_mix_get_processing_function(int fmt) +static inline mix_func mixin_get_processing_function(int fmt) { int i; - /* map the mute function for source and sink buffers */ + /* map mixin processing function for source and sink buffers */ for (i = 0; i < mix_count; i++) { if (fmt == mix_func_map[i].frame_fmt) - return mix_func_map[i].mute_func; + return mix_func_map[i].func; } return NULL; diff --git a/src/audio/mixin_mixout/mixin_mixout_generic.c b/src/audio/mixin_mixout/mixin_mixout_generic.c index 793a7f5d12c7..c69305073660 100644 --- a/src/audio/mixin_mixout/mixin_mixout_generic.c +++ b/src/audio/mixin_mixout/mixin_mixout_generic.c @@ -12,36 +12,29 @@ #ifdef MIXIN_MIXOUT_GENERIC #if CONFIG_FORMAT_S16LE -/* Instead of using audio_stream_get_channels(sink) and audio_stream_get_channels(source), - * sink_channel_count and source_channel_count are supplied as parameters. This is done to reuse - * the function to also mix an entire stream. In this case the function is called with fake stream - * parameters: multichannel stream is treated as single channel and so the entire stream - * contents is mixed. - */ -static void normal_mix_channel_s16(struct audio_stream *sink, int32_t start_frame, - int32_t mixed_frames, - const struct audio_stream *source, - int32_t frame_count, uint16_t gain) +static void mix_s16(struct cir_buf_ptr *sink, int32_t start_sample, int32_t mixed_samples, + const struct cir_buf_ptr *source, + int32_t sample_count, uint16_t gain) { - int32_t frames_to_mix, frames_to_copy, left_frames; + int32_t samples_to_mix, samples_to_copy, left_samples; int32_t n, nmax, i; - /* audio_stream_wrap() is required and is done below in a loop */ - int16_t *dst = (int16_t *)audio_stream_get_wptr(sink) + start_frame; - int16_t *src = audio_stream_get_rptr(source); + /* cir_buf_wrap() is required and is done below in a loop */ + int16_t *dst = (int16_t *)sink->ptr + start_sample; + int16_t *src = source->ptr; - assert(mixed_frames >= start_frame); - frames_to_mix = mixed_frames - start_frame; - frames_to_mix = MIN(frames_to_mix, frame_count); - frames_to_copy = frame_count - frames_to_mix; + assert(mixed_samples >= start_sample); + samples_to_mix = mixed_samples - start_sample; + samples_to_mix = MIN(samples_to_mix, sample_count); + samples_to_copy = sample_count - samples_to_mix; - for (left_frames = frames_to_mix; left_frames > 0; left_frames -= n) { - src = audio_stream_wrap(source, src); - dst = audio_stream_wrap(sink, dst); + for (left_samples = samples_to_mix; left_samples > 0; left_samples -= n) { + src = cir_buf_wrap(src, source->buf_start, source->buf_end); + dst = cir_buf_wrap(dst, sink->buf_start, sink->buf_end); /* calculate the remaining samples*/ - nmax = audio_stream_samples_without_wrap_s16(source, src); - n = MIN(left_frames, nmax); - nmax = audio_stream_samples_without_wrap_s16(sink, dst); + nmax = (int16_t *)source->buf_end - src; + n = MIN(left_samples, nmax); + nmax = (int16_t *)sink->buf_end - dst; n = MIN(n, nmax); for (i = 0; i < n; i++) { *dst = sat_int16(*dst + *src++); @@ -49,82 +42,43 @@ static void normal_mix_channel_s16(struct audio_stream *sink, int32_t start_fram } } - for (left_frames = frames_to_copy; left_frames > 0; left_frames -= n) { - src = audio_stream_wrap(source, src); - dst = audio_stream_wrap(sink, dst); - nmax = audio_stream_samples_without_wrap_s16(source, src); - n = MIN(left_frames, nmax); - nmax = audio_stream_samples_without_wrap_s16(sink, dst); + for (left_samples = samples_to_copy; left_samples > 0; left_samples -= n) { + src = cir_buf_wrap(src, source->buf_start, source->buf_end); + dst = cir_buf_wrap(dst, sink->buf_start, sink->buf_end); + nmax = (int16_t *)source->buf_end - src; + n = MIN(left_samples, nmax); + nmax = (int16_t *)sink->buf_end - dst; n = MIN(n, nmax); memcpy_s(dst, n * sizeof(int16_t), src, n * sizeof(int16_t)); dst += n; src += n; } } - -static void mute_channel_s16(struct audio_stream *stream, int32_t channel_index, - int32_t start_frame, int32_t mixed_frames, int32_t frame_count) -{ - int32_t skip_mixed_frames, n, left_frames, i, channel_count, frames, samples; - int16_t *ptr; - - assert(mixed_frames >= start_frame); - skip_mixed_frames = mixed_frames - start_frame; - - if (frame_count <= skip_mixed_frames) - return; - frame_count -= skip_mixed_frames; - channel_count = audio_stream_get_channels(stream); - /* audio_stream_wrap() is needed here and it is just below in a loop */ - ptr = (int16_t *)audio_stream_get_wptr(stream) + - mixed_frames * audio_stream_get_channels(stream) + - channel_index; - - for (left_frames = frame_count; left_frames; left_frames -= frames) { - ptr = audio_stream_wrap(stream, ptr); - n = audio_stream_samples_without_wrap_s16(stream, ptr); - samples = left_frames * channel_count; - n = MIN(samples, n); - frames = 0; - for (i = 0; i < n; i += channel_count) { - *ptr = 0; - ptr += channel_count; - frames++; - } - } -} #endif /* CONFIG_FORMAT_S16LE */ #if CONFIG_FORMAT_S24LE -/* Instead of using audio_stream_get_channels(sink) and audio_stream_get_channels(source), - * sink_channel_count and source_channel_count are supplied as parameters. This is done to reuse - * the function to also mix an entire stream. In this case the function is called with fake stream - * parameters: multichannel stream is treated as single channel and so the entire stream - * contents is mixed. - */ -static void normal_mix_channel_s24(struct audio_stream *sink, int32_t start_frame, - int32_t mixed_frames, - const struct audio_stream *source, - int32_t frame_count, uint16_t gain) +static void mix_s24(struct cir_buf_ptr *sink, int32_t start_sample, int32_t mixed_samples, + const struct cir_buf_ptr *source, + int32_t sample_count, uint16_t gain) { - int32_t frames_to_mix, frames_to_copy, left_frames; + int32_t samples_to_mix, samples_to_copy, left_samples; int32_t n, nmax, i; - /* audio_stream_wrap() is required and is done below in a loop */ - int32_t *dst = (int32_t *)audio_stream_get_wptr(sink) + start_frame; - int32_t *src = audio_stream_get_rptr(source); - - assert(mixed_frames >= start_frame); - frames_to_mix = mixed_frames - start_frame; - frames_to_mix = MIN(frames_to_mix, frame_count); - frames_to_copy = frame_count - frames_to_mix; - - for (left_frames = frames_to_mix; left_frames > 0; left_frames -= n) { - src = audio_stream_wrap(source, src); - dst = audio_stream_wrap(sink, dst); + /* cir_buf_wrap() is required and is done below in a loop */ + int32_t *dst = (int32_t *)sink->ptr + start_sample; + int32_t *src = source->ptr; + + assert(mixed_samples >= start_sample); + samples_to_mix = mixed_samples - start_sample; + samples_to_mix = MIN(samples_to_mix, sample_count); + samples_to_copy = sample_count - samples_to_mix; + + for (left_samples = samples_to_mix; left_samples > 0; left_samples -= n) { + src = cir_buf_wrap(src, source->buf_start, source->buf_end); + dst = cir_buf_wrap(dst, sink->buf_start, sink->buf_end); /* calculate the remaining samples*/ - nmax = audio_stream_samples_without_wrap_s24(source, src); - n = MIN(left_frames, nmax); - nmax = audio_stream_samples_without_wrap_s24(sink, dst); + nmax = (int32_t *)source->buf_end - src; + n = MIN(left_samples, nmax); + nmax = (int32_t *)sink->buf_end - dst; n = MIN(n, nmax); for (i = 0; i < n; i++) { *dst = sat_int24(sign_extend_s24(*dst) + sign_extend_s24(*src++)); @@ -132,12 +86,12 @@ static void normal_mix_channel_s24(struct audio_stream *sink, int32_t start_fram } } - for (left_frames = frames_to_copy; left_frames > 0; left_frames -= n) { - src = audio_stream_wrap(source, src); - dst = audio_stream_wrap(sink, dst); - nmax = audio_stream_samples_without_wrap_s24(source, src); - n = MIN(left_frames, nmax); - nmax = audio_stream_samples_without_wrap_s24(sink, dst); + for (left_samples = samples_to_copy; left_samples > 0; left_samples -= n) { + src = cir_buf_wrap(src, source->buf_start, source->buf_end); + dst = cir_buf_wrap(dst, sink->buf_start, sink->buf_end); + nmax = (int32_t *)source->buf_end - src; + n = MIN(left_samples, nmax); + nmax = (int32_t *)sink->buf_end - dst; n = MIN(n, nmax); memcpy_s(dst, n * sizeof(int32_t), src, n * sizeof(int32_t)); dst += n; @@ -148,34 +102,27 @@ static void normal_mix_channel_s24(struct audio_stream *sink, int32_t start_fram #endif /* CONFIG_FORMAT_S24LE */ #if CONFIG_FORMAT_S32LE -/* Instead of using audio_stream_get_channels(sink) and audio_stream_get_channels(source), - * sink_channel_count and source_channel_count are supplied as parameters. This is done to reuse - * the function to also mix an entire stream. In this case the function is called with fake stream - * parameters: multichannel stream is treated as single channel and so the entire stream - * contents is mixed. - */ -static void normal_mix_channel_s32(struct audio_stream *sink, int32_t start_frame, - int32_t mixed_frames, - const struct audio_stream *source, - int32_t frame_count, uint16_t gain) +static void mix_s32(struct cir_buf_ptr *sink, int32_t start_sample, int32_t mixed_samples, + const struct cir_buf_ptr *source, + int32_t sample_count, uint16_t gain) { - int32_t frames_to_mix, frames_to_copy, left_frames; + int32_t samples_to_mix, samples_to_copy, left_samples; int32_t n, nmax, i; - int32_t *dst = (int32_t *)audio_stream_get_wptr(sink) + start_frame; - int32_t *src = audio_stream_get_rptr(source); + int32_t *dst = (int32_t *)sink->ptr + start_sample; + int32_t *src = source->ptr; - assert(mixed_frames >= start_frame); - frames_to_mix = mixed_frames - start_frame; - frames_to_mix = MIN(frames_to_mix, frame_count); - frames_to_copy = frame_count - frames_to_mix; + assert(mixed_samples >= start_sample); + samples_to_mix = mixed_samples - start_sample; + samples_to_mix = MIN(samples_to_mix, sample_count); + samples_to_copy = sample_count - samples_to_mix; - for (left_frames = frames_to_mix; left_frames > 0; left_frames -= n) { - src = audio_stream_wrap(source, src); - dst = audio_stream_wrap(sink, dst); + for (left_samples = samples_to_mix; left_samples > 0; left_samples -= n) { + src = cir_buf_wrap(src, source->buf_start, source->buf_end); + dst = cir_buf_wrap(dst, sink->buf_start, sink->buf_end); /* calculate the remaining samples*/ - nmax = audio_stream_samples_without_wrap_s32(source, src); - n = MIN(left_frames, nmax); - nmax = audio_stream_samples_without_wrap_s32(sink, dst); + nmax = (int32_t *)source->buf_end - src; + n = MIN(left_samples, nmax); + nmax = (int32_t *)sink->buf_end - dst; n = MIN(n, nmax); for (i = 0; i < n; i++) { *dst = sat_int32((int64_t)*dst + (int64_t)*src++); @@ -183,12 +130,12 @@ static void normal_mix_channel_s32(struct audio_stream *sink, int32_t start_fram } } - for (left_frames = frames_to_copy; left_frames > 0; left_frames -= n) { - src = audio_stream_wrap(source, src); - dst = audio_stream_wrap(sink, dst); - nmax = audio_stream_samples_without_wrap_s32(source, src); - n = MIN(left_frames, nmax); - nmax = audio_stream_samples_without_wrap_s32(sink, dst); + for (left_samples = samples_to_copy; left_samples > 0; left_samples -= n) { + src = cir_buf_wrap(src, source->buf_start, source->buf_end); + dst = cir_buf_wrap(dst, sink->buf_start, sink->buf_end); + nmax = (int32_t *)source->buf_end - src; + n = MIN(left_samples, nmax); + nmax = (int32_t *)sink->buf_end - dst; n = MIN(n, nmax); memcpy_s(dst, n * sizeof(int32_t), src, n * sizeof(int32_t)); dst += n; @@ -198,50 +145,15 @@ static void normal_mix_channel_s32(struct audio_stream *sink, int32_t start_fram #endif /* CONFIG_FORMAT_S32LE */ -#if CONFIG_FORMAT_S32LE || CONFIG_FORMAT_S24LE -static void mute_channel_s32(struct audio_stream *stream, int32_t channel_index, - int32_t start_frame, int32_t mixed_frames, int32_t frame_count) -{ - int32_t skip_mixed_frames, left_frames, n, channel_count, i, frames, samples; - int32_t *ptr; - - assert(mixed_frames >= start_frame); - skip_mixed_frames = mixed_frames - start_frame; - - if (frame_count <= skip_mixed_frames) - return; - frame_count -= skip_mixed_frames; - channel_count = audio_stream_get_channels(stream); - - ptr = (int32_t *)audio_stream_get_wptr(stream) + - mixed_frames * audio_stream_get_channels(stream) + - channel_index; - - for (left_frames = frame_count; left_frames > 0; left_frames -= frames) { - ptr = audio_stream_wrap(stream, ptr); - n = audio_stream_samples_without_wrap_s32(stream, ptr); - samples = left_frames * channel_count; - n = MIN(samples, n); - frames = 0; - for (i = 0; i < n; i += channel_count) { - *ptr = 0; - ptr += channel_count; - frames++; - } - } -} - -#endif - const struct mix_func_map mix_func_map[] = { #if CONFIG_FORMAT_S16LE - { SOF_IPC_FRAME_S16_LE, normal_mix_channel_s16, mute_channel_s16}, + { SOF_IPC_FRAME_S16_LE, mix_s16 }, #endif #if CONFIG_FORMAT_S24LE - { SOF_IPC_FRAME_S24_4LE, normal_mix_channel_s24, mute_channel_s32}, + { SOF_IPC_FRAME_S24_4LE, mix_s24 }, #endif #if CONFIG_FORMAT_S32LE - { SOF_IPC_FRAME_S32_LE, normal_mix_channel_s32, mute_channel_s32} + { SOF_IPC_FRAME_S32_LE, mix_s32 } #endif }; diff --git a/src/audio/mixin_mixout/mixin_mixout_hifi3.c b/src/audio/mixin_mixout/mixin_mixout_hifi3.c index c5a44251e335..369ede78d36a 100644 --- a/src/audio/mixin_mixout/mixin_mixout_hifi3.c +++ b/src/audio/mixin_mixout/mixin_mixout_hifi3.c @@ -11,18 +11,11 @@ #ifdef MIXIN_MIXOUT_HIFI3 #if CONFIG_FORMAT_S16LE -/* Instead of using audio_stream_get_channels(sink) and audio_stream_get_channels(source), - * sink_channel_count and source_channel_count are supplied as parameters. This is done to reuse - * the function to also mix an entire stream. In this case the function is called with fake stream - * parameters: multichannel stream is treated as single channel and so the entire stream - * contents is mixed. - */ -static void normal_mix_channel_s16(struct audio_stream *sink, int32_t start_frame, - int32_t mixed_frames, - const struct audio_stream *source, - int32_t frame_count, uint16_t gain) +static void mix_s16(struct cir_buf_ptr *sink, int32_t start_sample, int32_t mixed_samples, + const struct cir_buf_ptr *source, + int32_t sample_count, uint16_t gain) { - int frames_to_mix, frames_to_copy, left_frames; + int samples_to_mix, samples_to_copy, left_samples; int n, nmax, i, m, left; ae_int16x4 in_sample; ae_int16x4 out_sample; @@ -31,22 +24,22 @@ static void normal_mix_channel_s16(struct audio_stream *sink, int32_t start_fram ae_valign inu = AE_ZALIGN64(); ae_valign outu1 = AE_ZALIGN64(); ae_valign outu2 = AE_ZALIGN64(); - /* audio_stream_wrap() is required and is done below in a loop */ - ae_int16 *dst = (ae_int16 *)audio_stream_get_wptr(sink) + start_frame; - ae_int16 *src = audio_stream_get_rptr(source); + /* cir_buf_wrap() is required and is done below in a loop */ + ae_int16 *dst = (ae_int16 *)sink->ptr + start_sample; + ae_int16 *src = source->ptr; - assert(mixed_frames >= start_frame); - frames_to_mix = AE_MIN_32_signed(mixed_frames - start_frame, frame_count); - frames_to_copy = frame_count - frames_to_mix; + assert(mixed_samples >= start_sample); + samples_to_mix = AE_MIN_32_signed(mixed_samples - start_sample, sample_count); + samples_to_copy = sample_count - samples_to_mix; n = 0; - for (left_frames = frames_to_mix; left_frames > 0; left_frames -= n) { - src = audio_stream_wrap(source, src + n); - dst = audio_stream_wrap(sink, dst + n); + for (left_samples = samples_to_mix; left_samples > 0; left_samples -= n) { + src = cir_buf_wrap(src + n, source->buf_start, source->buf_end); + dst = cir_buf_wrap(dst + n, sink->buf_start, sink->buf_end); /* calculate the remaining samples*/ - nmax = audio_stream_samples_without_wrap_s16(source, src); - n = AE_MIN_32_signed(left_frames, nmax); - nmax = audio_stream_samples_without_wrap_s16(sink, dst); + nmax = (ae_int16 *)source->buf_end - src; + n = AE_MIN_32_signed(left_samples, nmax); + nmax = (ae_int16 *)sink->buf_end - dst; n = AE_MIN_32_signed(n, nmax); in = (ae_int16x4 *)src; out = (ae_int16x4 *)dst; @@ -75,13 +68,13 @@ static void normal_mix_channel_s16(struct audio_stream *sink, int32_t start_fram } } - for (left_frames = frames_to_copy; left_frames > 0; left_frames -= n) { - src = audio_stream_wrap(source, src + n); - dst = audio_stream_wrap(sink, dst + n); + for (left_samples = samples_to_copy; left_samples > 0; left_samples -= n) { + src = cir_buf_wrap(src + n, source->buf_start, source->buf_end); + dst = cir_buf_wrap(dst + n, sink->buf_start, sink->buf_end); /* calculate the remaining samples*/ - nmax = audio_stream_samples_without_wrap_s16(source, src); - n = AE_MIN_32_signed(left_frames, nmax); - nmax = audio_stream_samples_without_wrap_s16(sink, dst); + nmax = (ae_int16 *)source->buf_end - src; + n = AE_MIN_32_signed(left_samples, nmax); + nmax = (ae_int16 *)sink->buf_end - dst; n = AE_MIN_32_signed(n, nmax); in = (ae_int16x4 *)src; out = (ae_int16x4 *)dst; @@ -104,49 +97,14 @@ static void normal_mix_channel_s16(struct audio_stream *sink, int32_t start_fram } } } - -static void mute_channel_s16(struct audio_stream *stream, int32_t channel_index, - int32_t start_frame, int32_t mixed_frames, int32_t frame_count) -{ - int skip_mixed_frames, left_frames; - int off = audio_stream_get_channels(stream) * sizeof(ae_int16); - ae_int16 *ptr; - ae_int16x4 zero = AE_ZERO16(); - - assert(mixed_frames >= start_frame); - skip_mixed_frames = mixed_frames - start_frame; - - if (frame_count <= skip_mixed_frames) - return; - frame_count -= skip_mixed_frames; - - AE_SETCBEGIN0(audio_stream_get_addr(stream)); - AE_SETCEND0(audio_stream_get_end_addr(stream)); - - /* audio_stream_wrap() is needed here and it is just below in a loop */ - ptr = (ae_int16 *)audio_stream_get_wptr(stream) + - mixed_frames * audio_stream_get_channels(stream) + - channel_index; - ptr = audio_stream_wrap(stream, ptr); - - for (left_frames = frame_count ; left_frames; left_frames--) - AE_S16_0_XC(zero, ptr, off); -} #endif /* CONFIG_FORMAT_S16LE */ #if CONFIG_FORMAT_S24LE -/* Instead of using audio_stream_get_channels(sink) and audio_stream_get_channels(source), - * sink_channel_count and source_channel_count are supplied as parameters. This is done to reuse - * the function to also mix an entire stream. In this case the function is called with fake stream - * parameters: multichannel stream is treated as single channel and so the entire stream - * contents is mixed. - */ -static void normal_mix_channel_s24(struct audio_stream *sink, int32_t start_frame, - int32_t mixed_frames, - const struct audio_stream *source, - int32_t frame_count, uint16_t gain) +static void mix_s24(struct cir_buf_ptr *sink, int32_t start_sample, int32_t mixed_samples, + const struct cir_buf_ptr *source, + int32_t sample_count, uint16_t gain) { - int frames_to_mix, frames_to_copy, left_frames; + int samples_to_mix, samples_to_copy, left_samples; int n, nmax, i, m, left; ae_int32x2 in_sample; ae_int32x2 out_sample; @@ -155,22 +113,22 @@ static void normal_mix_channel_s24(struct audio_stream *sink, int32_t start_fram ae_valign inu = AE_ZALIGN64(); ae_valign outu1 = AE_ZALIGN64(); ae_valign outu2 = AE_ZALIGN64(); - /* audio_stream_wrap() is required and is done below in a loop */ - int32_t *dst = (int32_t *)audio_stream_get_wptr(sink) + start_frame; - int32_t *src = audio_stream_get_rptr(source); + /* cir_buf_wrap() is required and is done below in a loop */ + int32_t *dst = (int32_t *)sink->ptr + start_sample; + int32_t *src = source->ptr; - assert(mixed_frames >= start_frame); - frames_to_mix = AE_MIN_32_signed(mixed_frames - start_frame, frame_count); - frames_to_copy = frame_count - frames_to_mix; + assert(mixed_samples >= start_sample); + samples_to_mix = AE_MIN_32_signed(mixed_samples - start_sample, sample_count); + samples_to_copy = sample_count - samples_to_mix; n = 0; - for (left_frames = frames_to_mix; left_frames > 0; left_frames -= n) { - src = audio_stream_wrap(source, src + n); - dst = audio_stream_wrap(sink, dst + n); + for (left_samples = samples_to_mix; left_samples > 0; left_samples -= n) { + src = cir_buf_wrap(src + n, source->buf_start, source->buf_end); + dst = cir_buf_wrap(dst + n, sink->buf_start, sink->buf_end); /* calculate the remaining samples*/ - nmax = audio_stream_samples_without_wrap_s24(source, src); - n = AE_MIN_32_signed(left_frames, nmax); - nmax = audio_stream_samples_without_wrap_s24(sink, dst); + nmax = (int32_t *)source->buf_end - src; + n = AE_MIN_32_signed(left_samples, nmax); + nmax = (int32_t *)sink->buf_end - dst; n = AE_MIN_32_signed(n, nmax); in = (ae_int32x2 *)src; out = (ae_int32x2 *)dst; @@ -197,12 +155,12 @@ static void normal_mix_channel_s24(struct audio_stream *sink, int32_t start_fram } } - for (left_frames = frames_to_copy; left_frames > 0; left_frames -= n) { - src = audio_stream_wrap(source, src + n); - dst = audio_stream_wrap(sink, dst + n); - nmax = audio_stream_samples_without_wrap_s24(source, src); - n = AE_MIN_32_signed(left_frames, nmax); - nmax = audio_stream_samples_without_wrap_s24(sink, dst); + for (left_samples = samples_to_copy; left_samples > 0; left_samples -= n) { + src = cir_buf_wrap(src + n, source->buf_start, source->buf_end); + dst = cir_buf_wrap(dst + n, sink->buf_start, sink->buf_end); + nmax = (int32_t *)source->buf_end - src; + n = AE_MIN_32_signed(left_samples, nmax); + nmax = (int32_t *)sink->buf_end - dst; n = AE_MIN_32_signed(n, nmax); in = (ae_int32x2 *)src; out = (ae_int32x2 *)dst; @@ -225,18 +183,11 @@ static void normal_mix_channel_s24(struct audio_stream *sink, int32_t start_fram #endif /* CONFIG_FORMAT_S24LE */ #if CONFIG_FORMAT_S32LE -/* Instead of using audio_stream_get_channels(sink) and audio_stream_get_channels(source), - * sink_channel_count and source_channel_count are supplied as parameters. This is done to reuse - * the function to also mix an entire stream. In this case the function is called with fake stream - * parameters: multichannel stream is treated as single channel and so the entire stream - * contents is mixed. - */ -static void normal_mix_channel_s32(struct audio_stream *sink, int32_t start_frame, - int32_t mixed_frames, - const struct audio_stream *source, - int32_t frame_count, uint16_t gain) +static void mix_s32(struct cir_buf_ptr *sink, int32_t start_sample, int32_t mixed_samples, + const struct cir_buf_ptr *source, + int32_t sample_count, uint16_t gain) { - int frames_to_mix, frames_to_copy, left_frames; + int samples_to_mix, samples_to_copy, left_samples; int n, nmax, i, m, left; ae_int32x2 in_sample; ae_int32x2 out_sample; @@ -245,22 +196,22 @@ static void normal_mix_channel_s32(struct audio_stream *sink, int32_t start_fram ae_valign inu = AE_ZALIGN64(); ae_valign outu1 = AE_ZALIGN64(); ae_valign outu2 = AE_ZALIGN64(); - /* audio_stream_wrap() is required and is done below in a loop */ - int32_t *dst = (int32_t *)audio_stream_get_wptr(sink) + start_frame; - int32_t *src = audio_stream_get_rptr(source); + /* cir_buf_wrap() is required and is done below in a loop */ + int32_t *dst = (int32_t *)sink->ptr + start_sample; + int32_t *src = source->ptr; - assert(mixed_frames >= start_frame); - frames_to_mix = AE_MIN_32_signed(mixed_frames - start_frame, frame_count); - frames_to_copy = frame_count - frames_to_mix; + assert(mixed_samples >= start_sample); + samples_to_mix = AE_MIN_32_signed(mixed_samples - start_sample, sample_count); + samples_to_copy = sample_count - samples_to_mix; n = 0; - for (left_frames = frames_to_mix; left_frames > 0; left_frames -= n) { - src = audio_stream_wrap(source, src + n); - dst = audio_stream_wrap(sink, dst + n); + for (left_samples = samples_to_mix; left_samples > 0; left_samples -= n) { + src = cir_buf_wrap(src + n, source->buf_start, source->buf_end); + dst = cir_buf_wrap(dst + n, sink->buf_start, sink->buf_end); /* calculate the remaining samples*/ - nmax = audio_stream_samples_without_wrap_s32(source, src); - n = AE_MIN_32_signed(left_frames, nmax); - nmax = audio_stream_samples_without_wrap_s32(sink, dst); + nmax = (int32_t *)source->buf_end - src; + n = AE_MIN_32_signed(left_samples, nmax); + nmax = (int32_t *)sink->buf_end - dst; n = AE_MIN_32_signed(n, nmax); in = (ae_int32x2 *)src; out = (ae_int32x2 *)dst; @@ -286,13 +237,13 @@ static void normal_mix_channel_s32(struct audio_stream *sink, int32_t start_fram } } - for (left_frames = frames_to_copy; left_frames > 0; left_frames -= n) { - src = audio_stream_wrap(source, src + n); - dst = audio_stream_wrap(sink, dst + n); + for (left_samples = samples_to_copy; left_samples > 0; left_samples -= n) { + src = cir_buf_wrap(src + n, source->buf_start, source->buf_end); + dst = cir_buf_wrap(dst + n, sink->buf_start, sink->buf_end); /* calculate the remaining samples*/ - nmax = audio_stream_samples_without_wrap_s32(source, src); - n = AE_MIN_32_signed(left_frames, nmax); - nmax = audio_stream_samples_without_wrap_s32(sink, dst); + nmax = (int32_t *)source->buf_end - src; + n = AE_MIN_32_signed(left_samples, nmax); + nmax = (int32_t *)sink->buf_end - dst; n = AE_MIN_32_signed(n, nmax); in = (ae_int32x2 *)src; out = (ae_int32x2 *)dst; @@ -315,46 +266,15 @@ static void normal_mix_channel_s32(struct audio_stream *sink, int32_t start_fram #endif /* CONFIG_FORMAT_S32LE */ -#if CONFIG_FORMAT_S32LE || CONFIG_FORMAT_S24LE -static void mute_channel_s32(struct audio_stream *stream, int32_t channel_index, - int32_t start_frame, int32_t mixed_frames, int32_t frame_count) -{ - int skip_mixed_frames, left_frames; - ae_int32 *ptr; - int off = audio_stream_get_channels(stream) * sizeof(ae_int32); - ae_int32x2 zero = AE_ZERO32(); - - assert(mixed_frames >= start_frame); - skip_mixed_frames = mixed_frames - start_frame; - - if (frame_count <= skip_mixed_frames) - return; - frame_count -= skip_mixed_frames; - - AE_SETCBEGIN0(audio_stream_get_addr(stream)); - AE_SETCEND0(audio_stream_get_end_addr(stream)); - - /* audio_stream_wrap() is needed here and it is just below in a loop */ - ptr = (ae_int32 *)audio_stream_get_wptr(stream) + - mixed_frames * audio_stream_get_channels(stream) + - channel_index; - ptr = audio_stream_wrap(stream, ptr); - - for (left_frames = frame_count ; left_frames > 0; left_frames--) - AE_S32_L_XC(zero, ptr, off); -} - -#endif - const struct mix_func_map mix_func_map[] = { #if CONFIG_FORMAT_S16LE - { SOF_IPC_FRAME_S16_LE, normal_mix_channel_s16, mute_channel_s16}, + { SOF_IPC_FRAME_S16_LE, mix_s16 }, #endif #if CONFIG_FORMAT_S24LE - { SOF_IPC_FRAME_S24_4LE, normal_mix_channel_s24, mute_channel_s32}, + { SOF_IPC_FRAME_S24_4LE, mix_s24 }, #endif #if CONFIG_FORMAT_S32LE - { SOF_IPC_FRAME_S32_LE, normal_mix_channel_s32, mute_channel_s32} + { SOF_IPC_FRAME_S32_LE, mix_s32 } #endif }; diff --git a/src/audio/module_adapter/module_adapter.c b/src/audio/module_adapter/module_adapter.c index e30c6cbc51cb..a7753f9776c6 100644 --- a/src/audio/module_adapter/module_adapter.c +++ b/src/audio/module_adapter/module_adapter.c @@ -119,39 +119,6 @@ struct comp_dev *module_adapter_new(const struct comp_driver *drv, return NULL; } -static int module_adapter_sink_src_prepare(struct comp_dev *dev) -{ - struct processing_module *mod = comp_get_drvdata(dev); - struct list_item *blist; - int ret; - int i; - - /* acquire all sink and source buffers, get handlers to sink/source API */ - i = 0; - list_for_item(blist, &dev->bsink_list) { - struct comp_buffer *sink_buffer = - container_of(blist, struct comp_buffer, source_list); - mod->sinks[i] = audio_stream_get_sink(&sink_buffer->stream); - i++; - } - mod->num_of_sinks = i; - - i = 0; - list_for_item(blist, &dev->bsource_list) { - struct comp_buffer *source_buffer = - container_of(blist, struct comp_buffer, sink_list); - - mod->sources[i] = audio_stream_get_source(&source_buffer->stream); - i++; - } - mod->num_of_sources = i; - - /* Prepare module */ - ret = module_prepare(mod, mod->sources, mod->num_of_sources, mod->sinks, mod->num_of_sinks); - - return ret; -} - #if CONFIG_ZEPHYR_DP_SCHEDULER static int module_adapter_dp_queue_prepare(struct comp_dev *dev) { @@ -171,7 +138,7 @@ static int module_adapter_dp_queue_prepare(struct comp_dev *dev) list_init(&mod->dp_queue_ll_to_dp_list); list_init(&mod->dp_queue_dp_to_ll_list); - ret = module_adapter_sink_src_prepare(dev); + ret = module_prepare(mod, mod->sources, mod->num_of_sources, mod->sinks, mod->num_of_sinks); if (ret) return ret; @@ -198,7 +165,7 @@ static int module_adapter_dp_queue_prepare(struct comp_dev *dev) goto err; dp_queue_append_to_list(dp_queue, &mod->dp_queue_ll_to_dp_list); - /* it will override source pointers set by module_adapter_sink_src_prepare + /* it will override source pointers set before * module will use shadow dpQueue for processing */ mod->sources[i] = dp_queue_get_source(dp_queue); @@ -232,7 +199,7 @@ static int module_adapter_dp_queue_prepare(struct comp_dev *dev) goto err; dp_queue_append_to_list(dp_queue, &mod->dp_queue_dp_to_ll_list); - /* it will override sink pointers set by module_adapter_sink_src_prepare + /* it will override sink pointers set before * module will use shadow dpQueue for processing */ mod->sinks[i] = dp_queue_get_sink(dp_queue); @@ -328,7 +295,8 @@ int module_adapter_prepare(struct comp_dev *dev) else if (IS_PROCESSING_MODE_SINK_SOURCE(mod) && mod->dev->ipc_config.proc_domain == COMP_PROCESSING_DOMAIN_LL) - ret = module_adapter_sink_src_prepare(dev); + ret = module_prepare(mod, mod->sources, mod->num_of_sources, + mod->sinks, mod->num_of_sinks); else if ((IS_PROCESSING_MODE_RAW_DATA(mod) || IS_PROCESSING_MODE_AUDIO_STREAM(mod)) && mod->dev->ipc_config.proc_domain == COMP_PROCESSING_DOMAIN_LL) diff --git a/src/audio/module_adapter/module_adapter_ipc4.c b/src/audio/module_adapter/module_adapter_ipc4.c index 65ca8e806e3f..ad3617b1ca23 100644 --- a/src/audio/module_adapter/module_adapter_ipc4.c +++ b/src/audio/module_adapter/module_adapter_ipc4.c @@ -155,22 +155,35 @@ int module_adapter_get_attribute(struct comp_dev *dev, uint32_t type, void *valu return 0; } -static bool module_adapter_multi_sink_source_check(struct comp_dev *dev) +static bool module_adapter_multi_sink_source_prepare(struct comp_dev *dev) { struct processing_module *mod = comp_get_drvdata(dev); struct list_item *blist; - int num_sources = 0; - int num_sinks = 0; + int i; + + /* acquire all sink and source buffers, get handlers to sink/source API */ + i = 0; + list_for_item(blist, &dev->bsink_list) { + struct comp_buffer *sink_buffer = + container_of(blist, struct comp_buffer, source_list); + mod->sinks[i] = audio_stream_get_sink(&sink_buffer->stream); + i++; + } + mod->num_of_sinks = i; - list_for_item(blist, &dev->bsource_list) - num_sources++; + i = 0; + list_for_item(blist, &dev->bsource_list) { + struct comp_buffer *source_buffer = + container_of(blist, struct comp_buffer, sink_list); - list_for_item(blist, &dev->bsink_list) - num_sinks++; + mod->sources[i] = audio_stream_get_source(&source_buffer->stream); + i++; + } + mod->num_of_sources = i; - comp_dbg(dev, "num_sources=%d num_sinks=%d", num_sources, num_sinks); + comp_dbg(dev, "num_sources=%d num_sinks=%d", mod->num_of_sinks, mod->num_of_sinks); - if (num_sources != 1 || num_sinks != 1) + if (mod->num_of_sinks != 1 || mod->num_of_sinks != 1) return true; /* re-assign the source/sink modules */ @@ -190,7 +203,7 @@ int module_adapter_bind(struct comp_dev *dev, void *data) if (ret < 0) return ret; - mod->stream_copy_single_to_single = !module_adapter_multi_sink_source_check(dev); + mod->stream_copy_single_to_single = !module_adapter_multi_sink_source_prepare(dev); return 0; } @@ -204,7 +217,7 @@ int module_adapter_unbind(struct comp_dev *dev, void *data) if (ret < 0) return ret; - mod->stream_copy_single_to_single = !module_adapter_multi_sink_source_check(dev); + mod->stream_copy_single_to_single = !module_adapter_multi_sink_source_prepare(dev); return 0; } diff --git a/src/include/sof/audio/audio_stream.h b/src/include/sof/audio/audio_stream.h index 09bfb68a038d..cb2bcd4967db 100644 --- a/src/include/sof/audio/audio_stream.h +++ b/src/include/sof/audio/audio_stream.h @@ -984,6 +984,29 @@ static inline int audio_stream_set_zero(struct audio_stream *buffer, uint32_t by return 0; } +/** + * Writes zeros to circular buffer in range [ptr, ptr+bytes] with rollover if necessary. + * @param ptr Pointer inside circular biffer to start writing from. + * @param buf_addr Start of the circular buffer. + * @param buf_end End of the circular buffer. + * @param bytes Size of the fragment to write zeros. + */ +static inline void cir_buf_set_zero(void *ptr, void *buf_addr, void *buf_end, uint32_t bytes) +{ + uint32_t head_size = bytes; + uint32_t tail_size = 0; + + /* check for potential wrap */ + if ((char *)ptr + bytes > (char *)buf_end) { + head_size = (char *)buf_end - (char *)ptr; + tail_size = bytes - head_size; + } + + memset(ptr, 0, head_size); + if (tail_size) + memset(buf_addr, 0, tail_size); +} + static inline void audio_stream_fmt_conversion(enum ipc4_bit_depth depth, enum ipc4_bit_depth valid, enum sof_ipc_frame *frame_fmt, diff --git a/src/include/sof/audio/module_adapter/module/modules.h b/src/include/sof/audio/module_adapter/module/modules.h index ae514bcbf09e..bcfe2a6ae795 100644 --- a/src/include/sof/audio/module_adapter/module/modules.h +++ b/src/include/sof/audio/module_adapter/module/modules.h @@ -66,6 +66,8 @@ static inline void declare_dynamic_module_adapter(struct comp_driver *drv, drv->ops.set_large_config = module_set_large_config; drv->ops.get_large_config = module_get_large_config; drv->ops.get_attribute = module_adapter_get_attribute; + drv->ops.bind = module_adapter_bind; + drv->ops.unbind = module_adapter_unbind; } #endif /* __SOF_AUDIO_MODULES__ */