module_adapter: Add support for modules with multiple sources

Add support for modules with multiple sources such as the mixer.
Expand the scope of the simple_copy flag in struct processing_module to
include components that have multiple input buffers but only a single
output buffer and do not need any deep-buffering.

Make changes to the prepare, copy and trigger callbacks in the
module_adapter ops to add support for handling multiple input buffers.

Signed-off-by: Ranjani Sridharan <ranjani.sridharan@linux.intel.com>
This commit is contained in:
Ranjani Sridharan 2022-09-28 08:43:09 -07:00 committed by Kai Vehmanen
parent 6e7f31c141
commit 98e9d3f0f6
2 changed files with 117 additions and 30 deletions

View File

@ -158,6 +158,13 @@ int module_adapter_prepare(struct comp_dev *dev)
comp_dbg(dev, "module_adapter_prepare() start");
/*
* check if the component is already active. This could happen in the case of mixer when
* one of the sources is already active
*/
if (dev->state == COMP_STATE_ACTIVE)
return 0;
/* Are we already prepared? */
ret = comp_set_state(dev, COMP_TRIGGER_PREPARE);
if (ret < 0)
@ -182,6 +189,9 @@ int module_adapter_prepare(struct comp_dev *dev)
/* Prepare module */
ret = module_prepare(mod);
if (ret) {
if (ret == PPL_STATUS_PATH_STOP)
return ret;
comp_err(dev, "module_adapter_prepare() error %x: module prepare failed",
ret);
@ -596,38 +606,51 @@ int module_adapter_copy(struct comp_dev *dev)
struct processing_module *mod = comp_get_drvdata(dev);
struct module_data *md = &mod->priv;
struct comp_buffer *source, *sink;
struct comp_buffer __sparse_cache *source_c = NULL, *sink_c = NULL;
struct comp_buffer __sparse_cache *source_c[PLATFORM_MAX_STREAMS];
struct comp_buffer __sparse_cache *sink_c = NULL;
struct comp_copy_limits c;
struct list_item *blist;
size_t size = MAX(mod->deep_buff_bytes, mod->period_bytes);
uint32_t min_free_frames = UINT_MAX;
uint32_t num_input_buffers = 0;
int ret, i = 0;
comp_dbg(dev, "module_adapter_copy(): start");
/*
* Simplify calculation of bytes_to_process for modules that produce period_bytes every
* period and have only 1 source and 1 sink buffer
* period and have N sources and only 1 sink buffer
*/
if (mod->simple_copy) {
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);
comp_get_copy_limits_frame_aligned(source_c, sink_c, &c);
list_for_item(blist, &dev->bsource_list) {
source = container_of(blist, struct comp_buffer, sink_list);
source_c[i] = buffer_acquire(source);
buffer_stream_invalidate(source_c, c.frames * c.source_frame_bytes);
/* check if the source dev is in the same state as the dev */
if (!source_c[i]->source || source_c[i]->source->state != dev->state) {
i++;
continue;
}
comp_get_copy_limits_frame_aligned(source_c[i], sink_c, &c);
buffer_stream_invalidate(source_c[i], c.frames * c.source_frame_bytes);
/* note that the size is in number of frames not the number of bytes */
mod->input_buffers[num_input_buffers].size = c.frames;
mod->input_buffers[num_input_buffers].consumed = 0;
mod->input_buffers[num_input_buffers].data = &source_c[i]->stream;
num_input_buffers++;
i++;
}
/* note that the size is in number of frames not the number of bytes */
mod->input_buffers[0].size = c.frames;
mod->input_buffers[0].consumed = 0;
mod->output_buffers[0].size = 0;
mod->input_buffers[0].data = &source_c->stream;
mod->output_buffers[0].data = &sink_c->stream;
/* Keep source_c and sink_c, we'll use and release it below */
/* Keep source_c 's and sink_c, we'll use and release it below */
} else {
list_for_item(blist, &mod->sink_buffer_list) {
sink = container_of(blist, struct comp_buffer, sink_list);
@ -640,31 +663,39 @@ int module_adapter_copy(struct comp_dev *dev)
/* copy source samples into input buffer */
list_for_item(blist, &dev->bsource_list) {
struct comp_buffer __sparse_cache *src_c;
uint32_t bytes_to_process;
int frames, source_frame_bytes;
source = container_of(blist, struct comp_buffer, sink_list);
source_c = buffer_acquire(source);
src_c = buffer_acquire(source);
/* check if the source dev is in the same state as the dev */
if (!src_c->source || src_c->source->state != dev->state) {
buffer_release(src_c);
continue;
}
frames = MIN(min_free_frames,
audio_stream_get_avail_frames(&source_c->stream));
source_frame_bytes = audio_stream_frame_bytes(&source_c->stream);
audio_stream_get_avail_frames(&src_c->stream));
source_frame_bytes = audio_stream_frame_bytes(&src_c->stream);
bytes_to_process = MIN(frames * source_frame_bytes, md->mpd.in_buff_size);
buffer_stream_invalidate(source_c, bytes_to_process);
buffer_stream_invalidate(src_c, bytes_to_process);
mod->input_buffers[i].size = bytes_to_process;
mod->input_buffers[i].consumed = 0;
ca_copy_from_source_to_module(&source_c->stream, mod->input_buffers[i].data,
ca_copy_from_source_to_module(&src_c->stream, mod->input_buffers[i].data,
md->mpd.in_buff_size, bytes_to_process);
buffer_release(source_c);
buffer_release(src_c);
i++;
}
num_input_buffers = mod->num_input_buffers;
}
ret = module_process(mod, mod->input_buffers, mod->num_input_buffers,
ret = module_process(mod, mod->input_buffers, num_input_buffers,
mod->output_buffers, mod->num_output_buffers);
if (ret) {
if (ret != -ENOSPC && ret != -ENODATA) {
@ -677,20 +708,26 @@ int module_adapter_copy(struct comp_dev *dev)
}
if (mod->simple_copy) {
comp_update_buffer_consume(source_c, mod->input_buffers[0].consumed);
i = 0;
list_for_item(blist, &dev->bsource_list) {
comp_update_buffer_consume(source_c[i], mod->input_buffers[i].consumed);
buffer_release(source_c[i]);
mod->input_buffers[i].size = 0;
mod->input_buffers[i].consumed = 0;
i++;
}
buffer_release(sink_c);
buffer_release(source_c);
mod->input_buffers[0].size = 0;
mod->input_buffers[0].consumed = 0;
} else {
i = 0;
/* consume from all input buffers */
list_for_item(blist, &dev->bsource_list) {
source = container_of(blist, struct comp_buffer, sink_list);
source_c = buffer_acquire(source);
struct comp_buffer __sparse_cache *src_c;
comp_update_buffer_consume(source_c, mod->input_buffers[i].consumed);
buffer_release(source_c);
source = container_of(blist, struct comp_buffer, sink_list);
src_c = buffer_acquire(source);
comp_update_buffer_consume(src_c, mod->input_buffers[i].consumed);
buffer_release(src_c);
bzero((__sparse_force void *)mod->input_buffers[i].data, size);
mod->input_buffers[i].size = 0;
@ -706,7 +743,9 @@ int module_adapter_copy(struct comp_dev *dev)
out:
if (mod->simple_copy) {
buffer_release(sink_c);
buffer_release(source_c);
i = 0;
list_for_item(blist, &dev->bsource_list)
buffer_release(source_c[i++]);
}
for (i = 0; i < mod->num_output_buffers; i++)
@ -843,8 +882,37 @@ int module_adapter_cmd(struct comp_dev *dev, int cmd, void *data, int max_data_s
return ret;
}
static int module_source_status_count(struct comp_dev *dev, uint32_t status)
{
struct list_item *blist;
int count = 0;
/* count source with state == status */
list_for_item(blist, &dev->bsource_list) {
/*
* FIXME: this is racy, state can be changed by another core.
* This is implicitly protected by serialised IPCs. Even when
* IPCs are processed in the pipeline thread, the next IPC will
* not be sent until the thread has processed and replied to the
* current one.
*/
struct comp_buffer *source = container_of(blist, struct comp_buffer,
sink_list);
struct comp_buffer __sparse_cache *source_c = buffer_acquire(source);
if (source_c->source && source_c->source->state == status)
count++;
buffer_release(source_c);
}
return count;
}
int module_adapter_trigger(struct comp_dev *dev, int cmd)
{
struct processing_module *mod = comp_get_drvdata(dev);
int ret;
comp_dbg(dev, "module_adapter_trigger(): cmd %d", cmd);
/*
@ -856,6 +924,25 @@ int module_adapter_trigger(struct comp_dev *dev, int cmd)
return PPL_STATUS_PATH_STOP;
}
if (mod->num_input_buffers > 1) {
bool sources_active;
sources_active = module_source_status_count(dev, COMP_STATE_ACTIVE) ||
module_source_status_count(dev, COMP_STATE_PAUSED);
/* don't stop/start module if one of the sources is active/paused */
if ((cmd == COMP_TRIGGER_STOP || cmd == COMP_TRIGGER_PRE_START) && sources_active) {
dev->state = COMP_STATE_ACTIVE;
return PPL_STATUS_PATH_STOP;
}
ret = comp_set_state(dev, cmd);
if (ret == COMP_STATUS_STATE_ALREADY_SET)
return PPL_STATUS_PATH_STOP;
return ret;
}
return comp_set_state(dev, cmd);
}

View File

@ -171,7 +171,7 @@ struct processing_module {
uint32_t num_input_buffers; /**< number of input buffers */
uint32_t num_output_buffers; /**< number of output buffers */
/*
* flag set by a module when it has 1 input buffer and 1 output buffer and produces
* flag set by a module when it has N input buffer and 1 output buffer and produces
* period_bytes every copy
*/
bool simple_copy;