mixin/mixout all topologies support

Adds possibility to connect single mixin to multiple
mixouts. This allows for all possible mixin/mixout
topologies.

Signed-off-by: Serhiy Katsyuba <serhiy.katsyuba@intel.com>
This commit is contained in:
Serhiy Katsyuba 2022-07-11 17:19:32 +02:00 committed by Liam Girdwood
parent 2d252c965c
commit 9d2857fe37
4 changed files with 1063 additions and 263 deletions

View File

@ -1,5 +1,11 @@
# SPDX-License-Identifier: BSD-3-Clause
if(CONFIG_IPC_MAJOR_3)
set(mixer_src mixer.c)
elseif(CONFIG_IPC_MAJOR_4)
set(mixer_src mixin_mixout.c)
endif()
if(NOT CONFIG_LIBRARY)
add_local_sources(sof
host-legacy.c
@ -41,7 +47,7 @@ if(NOT CONFIG_LIBRARY)
endif()
if(CONFIG_COMP_MIXER)
add_local_sources(sof
mixer.c
${mixer_src}
)
endif()
if(CONFIG_COMP_MUX)
@ -200,7 +206,7 @@ set(sof_audio_modules mixer volume src asrc eq-fir eq-iir dcblock crossover tdfb
# sources for each module
set(volume_sources module_adapter/module_adapter.c module_adapter/module/generic.c module_adapter/module/volume/volume.c module_adapter/module/volume/volume_generic.c)
set(mixer_sources mixer.c)
set(mixer_sources ${mixer_src})
set(src_sources src/src.c src/src_generic.c)
set(asrc_sources asrc/asrc.c asrc/asrc_farrow.c asrc/asrc_farrow_generic.c)
set(eq-fir_sources eq_fir/eq_fir.c eq_fir/eq_fir_generic.c)

View File

@ -34,32 +34,14 @@ static const struct comp_driver comp_mixer;
LOG_MODULE_REGISTER(mixer, CONFIG_SOF_LOG_LEVEL);
#if CONFIG_IPC_MAJOR_3
/* bc06c037-12aa-417c-9a97-89282e321a76 */
DECLARE_SOF_RT_UUID("mixer", mixer_uuid, 0xbc06c037, 0x12aa, 0x417c,
0x9a, 0x97, 0x89, 0x28, 0x2e, 0x32, 0x1a, 0x76);
#else
/* mixout 3c56505a-24d7-418f-bddc-c1f5a3ac2ae0 */
DECLARE_SOF_RT_UUID("mixer", mixer_uuid, 0x3c56505a, 0x24d7, 0x418f,
0xbd, 0xdc, 0xc1, 0xf5, 0xa3, 0xac, 0x2a, 0xe0);
/* mixin 39656eb2-3b71-4049-8d3f-f92cd5c43c09 */
DECLARE_SOF_RT_UUID("mix_in", mixin_uuid, 0x39656eb2, 0x3b71, 0x4049,
0x8d, 0x3f, 0xf9, 0x2c, 0xd5, 0xc4, 0x3c, 0x09);
DECLARE_TR_CTX(mixin_tr, SOF_UUID(mixin_uuid), LOG_LEVEL_INFO);
#endif
DECLARE_TR_CTX(mixer_tr, SOF_UUID(mixer_uuid), LOG_LEVEL_INFO);
/* mixer component private data */
struct mixer_data {
#if CONFIG_IPC_MAJOR_4
/* Must be the 1st field, function ipc4_comp_get_base_module_cfg casts components
* private data as ipc4_base_module_cfg!
*/
struct ipc4_base_module_cfg base_cfg;
#endif
bool sources_inactive;
void (*mix_func)(struct comp_dev *dev, struct audio_stream __sparse_cache *sink,
@ -207,7 +189,6 @@ static void mix_n_s32(struct comp_dev *dev, struct audio_stream __sparse_cache *
}
#endif /* CONFIG_FORMAT_S32LE */
#if CONFIG_IPC_MAJOR_3
static struct comp_dev *mixer_new(const struct comp_driver *drv,
struct comp_ipc_config *config,
void *spec)
@ -232,7 +213,6 @@ static struct comp_dev *mixer_new(const struct comp_driver *drv,
dev->state = COMP_STATE_READY;
return dev;
}
#endif
static void mixer_free(struct comp_dev *dev)
{
@ -522,26 +502,6 @@ static int mixer_prepare_common(struct comp_dev *dev)
return 0;
}
/* In IPC3 the simplest pipeline with mixer will like
* host1 -> mixer -> volume -> dai, pipeline 1.
* |
* host2 ---- pipeline 2
*
* For IPC4, it will be like
* copier1(host) -> mixin1 ----> mixout(mixer) -> gain(volume) -> copier2(dai)
* pipeline 1 | pipline 2
* copier3(host) -> mixin2 ------- pipeline 3
*
* mixin and mixout will be in different pipelines.
* Now we combine mixin and mixout into mixer, but
* the pipelines count is unchange. Ipc4 pipeline
* can't be stopped at mixer component since pipeline
* design is different, or gain and copier2 will not
* be triggered. Since mixer will be in a different
* pipeline other than host pipeline, it will not be
* triggered second time.
*/
#if CONFIG_IPC_MAJOR_3
static int mixer_source_status_count(struct comp_dev *mixer, uint32_t status)
{
struct list_item *blist;
@ -675,224 +635,6 @@ static const struct comp_driver comp_mixer = {
.reset = mixer_reset,
},
};
#else
static struct comp_dev *mixinout_new(const struct comp_driver *drv,
struct comp_ipc_config *config,
void *spec)
{
struct comp_dev *dev;
struct mixer_data *md;
enum sof_ipc_frame __sparse_cache frame_fmt, valid_fmt;
comp_cl_dbg(&comp_mixer, "mixinout_new()");
dev = comp_alloc(drv, sizeof(*dev));
if (!dev)
return NULL;
dev->ipc_config = *config;
md = rzalloc(SOF_MEM_ZONE_RUNTIME, 0, SOF_MEM_CAPS_RAM, sizeof(*md));
if (!md) {
rfree(dev);
return NULL;
}
memcpy_s(&md->base_cfg, sizeof(md->base_cfg), spec, sizeof(md->base_cfg));
comp_set_drvdata(dev, md);
audio_stream_fmt_conversion(md->base_cfg.audio_fmt.depth,
md->base_cfg.audio_fmt.valid_bit_depth,
&frame_fmt, &valid_fmt,
md->base_cfg.audio_fmt.s_type);
dev->ipc_config.frame_fmt = frame_fmt;
dev->state = COMP_STATE_READY;
return dev;
}
static int mixin_trigger(struct comp_dev *dev, int cmd)
{
int ret;
comp_dbg(dev, "mixin_trigger()");
ret = comp_set_state(dev, cmd);
if (ret < 0)
return ret;
if (ret == COMP_STATUS_STATE_ALREADY_SET)
return PPL_STATUS_PATH_STOP;
return ret;
}
/* do copy in mixer component */
static int mixin_copy(struct comp_dev *dev)
{
return 0;
}
static inline bool mixer_stop_reset(struct comp_dev *dev, struct comp_dev *source)
{
return dev->pipeline == source->pipeline && source->state > COMP_STATE_PAUSED;
}
/* params are derived from base config for ipc4 path */
static int mixout_params(struct comp_dev *dev,
struct sof_ipc_stream_params *params)
{
struct mixer_data *md = comp_get_drvdata(dev);
struct comp_buffer *sink;
struct comp_buffer __sparse_cache *sink_c;
int i;
memset(params, 0, sizeof(*params));
params->channels = md->base_cfg.audio_fmt.channels_count;
params->rate = md->base_cfg.audio_fmt.sampling_frequency;
params->sample_container_bytes = md->base_cfg.audio_fmt.depth;
params->sample_valid_bytes = md->base_cfg.audio_fmt.valid_bit_depth;
params->frame_fmt = dev->ipc_config.frame_fmt;
params->buffer_fmt = md->base_cfg.audio_fmt.interleaving_style;
params->buffer.size = md->base_cfg.ibs;
/* update each sink format based on base_cfg initialized by
* host driver. There is no hw_param ipc message for ipc4, instead
* all module params are built into module initialization data by
* host driver based on runtime hw_params and topology setting.
*/
sink = list_first_item(&dev->bsink_list, struct comp_buffer, source_list);
sink_c = buffer_acquire(sink);
sink_c->stream.channels = md->base_cfg.audio_fmt.channels_count;
sink_c->stream.rate = md->base_cfg.audio_fmt.sampling_frequency;
audio_stream_fmt_conversion(md->base_cfg.audio_fmt.depth,
md->base_cfg.audio_fmt.valid_bit_depth,
&sink_c->stream.frame_fmt,
&sink_c->stream.valid_sample_fmt,
md->base_cfg.audio_fmt.s_type);
sink_c->buffer_fmt = md->base_cfg.audio_fmt.interleaving_style;
/* 8 ch stream is supported by ch_map and each channel
* is mapped by 4 bits. The first channel will be mapped
* by the bits of 0 ~ 3 and the 2th channel will be mapped
* by bits 4 ~ 7. The N channel will be mapped by bits
* N*4 ~ N*4 + 3
*/
for (i = 0; i < SOF_IPC_MAX_CHANNELS; i++)
sink_c->chmap[i] = (md->base_cfg.audio_fmt.ch_map >> i * 4) & 0xf;
buffer_release(sink_c);
return mixer_params(dev, params);
}
/* the original ipc4 pipeline is : buffer0 -> mixin -> buffer1 -> mixout -> ...
* Since ipc4 mixin & mixout are supported by current mixer which is
* named mixout in ipc4 case, fw will convert it to : buffer0 -> mixout (mixer)
*/
static int mixin_bind(struct comp_dev *dev, void *data)
{
struct ipc4_module_bind_unbind *bu;
struct comp_buffer *source_buf;
struct comp_buffer *sink_buf = NULL;
struct comp_dev *sink;
struct list_item *blist;
int src_id, sink_id;
bu = (struct ipc4_module_bind_unbind *)data;
src_id = IPC4_COMP_ID(bu->primary.r.module_id, bu->primary.r.instance_id);
sink_id = IPC4_COMP_ID(bu->extension.r.dst_module_id, bu->extension.r.dst_instance_id);
/* mixin -> mixout */
if (dev->ipc_config.id == src_id) {
/* mixin is not bound to its source component so mixout
* can't be connected to source component
*/
if (list_is_empty(&dev->bsource_list))
return 0;
sink = ipc4_get_comp_dev(sink_id);
if (!sink) {
comp_err(dev, "mixin_bind: no sink with ID %d found", sink_id);
return -EINVAL;
}
} else { /* xxx -> mixin */
/* mixin is not bound to mixout so mixout can't be
* connected to the source component of mixin
*/
if (list_is_empty(&dev->bsink_list))
return 0;
sink_buf = buffer_from_list(dev->bsink_list.next, struct comp_buffer,
PPL_DIR_DOWNSTREAM);
sink = buffer_get_comp(sink_buf, PPL_DIR_DOWNSTREAM);
}
/* disconnect mixin to mixout (mixer) */
list_for_item(blist, &sink->bsource_list) {
sink_buf = container_of(blist, struct comp_buffer, sink_list);
if (sink_buf->source == dev) {
pipeline_disconnect(sink, sink_buf, PPL_CONN_DIR_BUFFER_TO_COMP);
break;
}
}
if (!sink_buf) {
comp_err(dev, "mixin_bind: no sink buffer found");
return -EINVAL;
}
/* connect mixout (mixer) to source component of mixin */
source_buf = list_first_item(&dev->bsource_list, struct comp_buffer, sink_list);
pipeline_disconnect(dev, source_buf, PPL_CONN_DIR_BUFFER_TO_COMP);
pipeline_connect(sink, source_buf, PPL_CONN_DIR_BUFFER_TO_COMP);
pipeline_connect(dev, sink_buf, PPL_CONN_DIR_BUFFER_TO_COMP);
return 0;
}
static const struct comp_driver comp_mixin = {
.uid = SOF_RT_UUID(mixin_uuid),
.tctx = &mixer_tr,
.ops = {
.create = mixinout_new,
.free = mixer_free,
.trigger = mixin_trigger,
.copy = mixin_copy,
.bind = mixin_bind,
},
};
static SHARED_DATA struct comp_driver_info comp_mixin_info = {
.drv = &comp_mixin,
};
UT_STATIC void sys_comp_mixin_init(void)
{
comp_register(platform_shared_get(&comp_mixin_info,
sizeof(comp_mixin_info)));
}
DECLARE_MODULE(sys_comp_mixin_init);
static const struct comp_driver comp_mixer = {
.type = SOF_COMP_MIXER,
.uid = SOF_RT_UUID(mixer_uuid),
.tctx = &mixer_tr,
.ops = {
.create = mixinout_new,
.free = mixer_free,
.params = mixout_params,
.prepare = mixer_prepare_common,
.trigger = mixer_trigger_common,
.copy = mixer_copy,
.reset = mixer_reset,
},
};
#endif
static SHARED_DATA struct comp_driver_info comp_mixer_info = {
.drv = &comp_mixer,

1046
src/audio/mixin_mixout.c Normal file

File diff suppressed because it is too large Load Diff

View File

@ -646,9 +646,15 @@ zephyr_library_sources_ifdef(CONFIG_COMP_SWITCH
${SOF_AUDIO_PATH}/switch.c
)
zephyr_library_sources_ifdef(CONFIG_COMP_MIXER
${SOF_AUDIO_PATH}/mixer.c
)
if(CONFIG_IPC_MAJOR_3)
zephyr_library_sources_ifdef(CONFIG_COMP_MIXER
${SOF_AUDIO_PATH}/mixer.c
)
elseif(CONFIG_IPC_MAJOR_4)
zephyr_library_sources_ifdef(CONFIG_COMP_MIXER
${SOF_AUDIO_PATH}/mixin_mixout.c
)
endif()
zephyr_library_sources_ifdef(CONFIG_COMP_TONE
${SOF_AUDIO_PATH}/tone.c