From 8466d49cf30dd9ffae926d64c7dc16c5ea70982a Mon Sep 17 00:00:00 2001 From: Serhiy Katsyuba Date: Tue, 11 Jun 2024 13:07:01 +0200 Subject: [PATCH 1/8] ipc4: dai-zephyr: Do not reuse process func as multi-gateway channel copy The multi-gateway channel copy function and the DAI process function serve distinct purposes. Although they currently share the same number of arguments of the same type, this similarity is coincidental and might be changed during future refactoring. Signed-off-by: Serhiy Katsyuba --- src/audio/copier/copier_dai.c | 4 ++-- src/audio/dai-zephyr.c | 11 +++++++---- src/include/sof/lib/dai-zephyr.h | 9 +++++++++ 3 files changed, 18 insertions(+), 6 deletions(-) diff --git a/src/audio/copier/copier_dai.c b/src/audio/copier/copier_dai.c index e2c56b831b9c..66e621f0eccf 100644 --- a/src/audio/copier/copier_dai.c +++ b/src/audio/copier/copier_dai.c @@ -502,10 +502,10 @@ int copier_dai_params(struct copier_data *cd, struct comp_dev *dev, switch (container_size) { case 2: - cd->dd[dai_index]->process = copy_single_channel_c16; + cd->dd[dai_index]->channel_copy = copy_single_channel_c16; break; case 4: - cd->dd[dai_index]->process = copy_single_channel_c32; + cd->dd[dai_index]->channel_copy = copy_single_channel_c32; break; default: comp_err(dev, "Unexpected container size: %d", container_size); diff --git a/src/audio/dai-zephyr.c b/src/audio/dai-zephyr.c index 2dee890d9653..cf3b68fc9606 100644 --- a/src/audio/dai-zephyr.c +++ b/src/audio/dai-zephyr.c @@ -379,16 +379,19 @@ dai_dma_multi_endpoint_cb(struct dai_data *dd, struct comp_dev *dev, uint32_t fr if (dev->direction == SOF_IPC_STREAM_CAPTURE) audio_stream_invalidate(&dd->dma_buffer->stream, bytes); + assert(dd->channel_copy); + /* copy all channels one by one */ for (i = 0; i < audio_stream_get_channels(&dd->dma_buffer->stream); i++) { uint32_t multi_buf_channel = dd->dma_buffer->chmap[i]; if (dev->direction == SOF_IPC_STREAM_PLAYBACK) - dd->process(&multi_endpoint_buffer->stream, multi_buf_channel, - &dd->dma_buffer->stream, i, frames); + dd->channel_copy(&multi_endpoint_buffer->stream, multi_buf_channel, + &dd->dma_buffer->stream, i, frames); else - dd->process(&dd->dma_buffer->stream, i, &multi_endpoint_buffer->stream, - multi_buf_channel, frames); + dd->channel_copy(&dd->dma_buffer->stream, i, + &multi_endpoint_buffer->stream, multi_buf_channel, + frames); } if (dev->direction == SOF_IPC_STREAM_PLAYBACK) { diff --git a/src/include/sof/lib/dai-zephyr.h b/src/include/sof/lib/dai-zephyr.h index 98e174a43c8d..f43ec21be446 100644 --- a/src/include/sof/lib/dai-zephyr.h +++ b/src/include/sof/lib/dai-zephyr.h @@ -106,6 +106,10 @@ struct llp_slot_info { uint32_t reg_offset; }; +typedef int (*channel_copy_func)(const struct audio_stream *src, unsigned int src_channel, + struct audio_stream *dst, unsigned int dst_channel, + unsigned int frames); + /** * \brief DAI runtime data */ @@ -126,6 +130,11 @@ struct dai_data { pcm_converter_func process; /* processing function */ + channel_copy_func channel_copy; /* channel copy func used by multi-endpoint + * gateway to mux/demux stream from/to multiple + * DMA buffers + */ + uint32_t period_bytes; /* number of bytes per one period */ uint64_t total_data_processed; From a41809fb755a7e870bb99005d256b66f9e281e66 Mon Sep 17 00:00:00 2001 From: Serhiy Katsyuba Date: Thu, 27 Jun 2024 21:07:33 +0200 Subject: [PATCH 2/8] dai-zephyr: Fix to avoid using buffers with uninitialized stream params Copier may have multiple sinks connected to different pipelines. While the copier pipeline might already be running, the sink pipeline has not yet initialized stream parameters of the buffer connected to copier's sink. It appears that checking for the sink component state is not enough. Signed-off-by: Serhiy Katsyuba --- src/audio/dai-zephyr.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/audio/dai-zephyr.c b/src/audio/dai-zephyr.c index cf3b68fc9606..661d4101d97b 100644 --- a/src/audio/dai-zephyr.c +++ b/src/audio/dai-zephyr.c @@ -314,7 +314,8 @@ dai_dma_cb(struct dai_data *dd, struct comp_dev *dev, uint32_t bytes, continue; } - if (sink_dev && sink_dev->state == COMP_STATE_ACTIVE) + if (sink_dev && sink_dev->state == COMP_STATE_ACTIVE && + sink->hw_params_configured) ret = dma_buffer_copy_from_no_consume(dd->dma_buffer, sink, converter[j], bytes); @@ -1555,7 +1556,8 @@ int dai_common_copy(struct dai_data *dd, struct comp_dev *dev, pcm_converter_fun sink = container_of(sink_list, struct comp_buffer, source_list); sink_dev = sink->sink; - if (sink_dev && sink_dev->state == COMP_STATE_ACTIVE) { + if (sink_dev && sink_dev->state == COMP_STATE_ACTIVE && + sink->hw_params_configured) { sink_samples = audio_stream_get_free_samples(&sink->stream); samples = MIN(samples, sink_samples); From 4df0a69fab97f18b1cc64b406c47cf83b65066e3 Mon Sep 17 00:00:00 2001 From: Serhiy Katsyuba Date: Fri, 14 Jun 2024 21:32:58 +0200 Subject: [PATCH 3/8] dai-zephyr: Use frames, not samples, for DMA copy bytes calculation Prepare DAI gateway to support channel remapping conversion functions that can modify number of channels. Consequently, frames, not samples, should be used for DMA copy bytes calculation. Signed-off-by: Serhiy Katsyuba --- src/audio/dai-zephyr.c | 40 ++++++++++++++++---------------- src/audio/host-zephyr.c | 8 +++++++ src/include/sof/lib/dai-zephyr.h | 4 +--- 3 files changed, 29 insertions(+), 23 deletions(-) diff --git a/src/audio/dai-zephyr.c b/src/audio/dai-zephyr.c index 661d4101d97b..6e6fb30d1917 100644 --- a/src/audio/dai-zephyr.c +++ b/src/audio/dai-zephyr.c @@ -908,7 +908,6 @@ static int dai_set_dma_buffer(struct dai_data *dd, struct comp_dev *dev, */ hw_params.frame_fmt = dev->ipc_config.frame_fmt; buffer_set_params(dd->dma_buffer, &hw_params, BUFFER_UPDATE_FORCE); - dd->sampling = get_sample_bytes(hw_params.frame_fmt); } *pc = audio_stream_get_size(&dd->dma_buffer->stream) / period_bytes; @@ -1393,11 +1392,10 @@ int dai_zephyr_multi_endpoint_copy(struct dai_data **dd, struct comp_dev *dev, frames = MIN(src_frames, sink_frames); /* limit bytes per copy to one period for the whole pipeline in order to avoid high load - * spike if FAST_MODE is enabled, then one period limitation is omitted. All dd's have the - * same period_bytes, so use the period_bytes from dd[0] + * spike if FAST_MODE is enabled, then one period limitation is omitted. */ if (!(dd[0]->ipc_config.feature_mask & BIT(IPC4_COPIER_FAST_MODE))) - frames = MIN(frames, dd[0]->period_bytes / frame_bytes); + frames = MIN(frames, dev->frames); comp_dbg(dev, "dai_zephyr_multi_endpoint_copy(), dir: %d copy frames= 0x%x", dev->direction, frames); @@ -1485,14 +1483,13 @@ static void set_new_local_buffer(struct dai_data *dd, struct comp_dev *dev) /* copy and process stream data from source to sink buffers */ int dai_common_copy(struct dai_data *dd, struct comp_dev *dev, pcm_converter_func *converter) { - uint32_t sampling = dd->sampling; struct dma_status stat; uint32_t avail_bytes; uint32_t free_bytes; uint32_t copy_bytes; - uint32_t src_samples; - uint32_t sink_samples; - uint32_t samples = UINT32_MAX; + uint32_t src_frames; + uint32_t sink_frames; + uint32_t frames = UINT32_MAX; int ret; /* get data sizes from DMA */ @@ -1526,23 +1523,26 @@ int dai_common_copy(struct dai_data *dd, struct comp_dev *dev, pcm_converter_fun } } + assert(audio_stream_get_channels(&dd->dma_buffer->stream)); + assert(audio_stream_get_channels(&dd->local_buffer->stream)); + /* calculate minimum size to copy */ if (dev->direction == SOF_IPC_STREAM_PLAYBACK) { - src_samples = audio_stream_get_avail_samples(&dd->local_buffer->stream); - sink_samples = free_bytes / sampling; - samples = MIN(src_samples, sink_samples); + src_frames = audio_stream_get_avail_frames(&dd->local_buffer->stream); + sink_frames = free_bytes / audio_stream_frame_bytes(&dd->dma_buffer->stream); + frames = MIN(src_frames, sink_frames); } else { struct list_item *sink_list; - src_samples = avail_bytes / sampling; + src_frames = avail_bytes / audio_stream_frame_bytes(&dd->dma_buffer->stream); /* * there's only one sink buffer in the case of endpoint DAI devices created by * a DAI copier and it is chosen as the dd->local buffer */ if (!converter) { - sink_samples = audio_stream_get_free_samples(&dd->local_buffer->stream); - samples = MIN(samples, sink_samples); + sink_frames = audio_stream_get_free_frames(&dd->local_buffer->stream); + frames = sink_frames; } else { /* * In the case of capture DAI's with multiple sink buffers, compute the @@ -1558,14 +1558,14 @@ int dai_common_copy(struct dai_data *dd, struct comp_dev *dev, pcm_converter_fun if (sink_dev && sink_dev->state == COMP_STATE_ACTIVE && sink->hw_params_configured) { - sink_samples = - audio_stream_get_free_samples(&sink->stream); - samples = MIN(samples, sink_samples); + sink_frames = + audio_stream_get_free_frames(&sink->stream); + frames = MIN(frames, sink_frames); } } } - samples = MIN(samples, src_samples); + frames = MIN(frames, src_frames); } /* limit bytes per copy to one period for the whole pipeline @@ -1573,9 +1573,9 @@ int dai_common_copy(struct dai_data *dd, struct comp_dev *dev, pcm_converter_fun * if FAST_MODE is enabled, then one period limitation is omitted */ if (!dd->fast_mode) - samples = MIN(samples, dd->period_bytes / sampling); + frames = MIN(frames, dev->frames); - copy_bytes = samples * sampling; + copy_bytes = frames * audio_stream_frame_bytes(&dd->dma_buffer->stream); comp_dbg(dev, "dai_common_copy(), dir: %d copy_bytes= 0x%x", dev->direction, copy_bytes); diff --git a/src/audio/host-zephyr.c b/src/audio/host-zephyr.c index fa72b95557a8..82ecc9749a68 100644 --- a/src/audio/host-zephyr.c +++ b/src/audio/host-zephyr.c @@ -409,6 +409,14 @@ static uint32_t host_get_copy_bytes_normal(struct host_data *hd, struct comp_dev /* dma_copy_bytes should be aligned to minimum possible chunk of * data to be copied by dma. + * + * FIXME: WARNING: For some frame sizes, this can lead to a split first and/or last frame: + * one part of the frame is processed during one LL cycle, while the remaining portion + * is processed in the subsequent LL cycle. This could be a problem for components + * that assume the first sample in the buffer belongs to the first channel. Even + * if such components consume full frames, they could be bound on a fly as additional + * copier sinks or additional mixin sources or sinks, causing them to start processing + * from the wrong channel. */ return ALIGN_DOWN(dma_copy_bytes, hd->dma_copy_align); } diff --git a/src/include/sof/lib/dai-zephyr.h b/src/include/sof/lib/dai-zephyr.h index f43ec21be446..e909bfd40e05 100644 --- a/src/include/sof/lib/dai-zephyr.h +++ b/src/include/sof/lib/dai-zephyr.h @@ -135,7 +135,7 @@ struct dai_data { * DMA buffers */ - uint32_t period_bytes; /* number of bytes per one period */ + uint32_t period_bytes; /* number of DMA bytes per one period */ uint64_t total_data_processed; struct ipc_config_dai ipc_config; /* generic common config */ @@ -154,8 +154,6 @@ struct dai_data { /* llp slot info in memory windows */ struct llp_slot_info slot_info; - /* save current sampling for current dai device */ - uint32_t sampling; /* fast mode, use one byte memory to save repreated cycles */ bool fast_mode; }; From db2ac2aa338e122ef7b9c704d9a3ad62eaeac5d7 Mon Sep 17 00:00:00 2001 From: Serhiy Katsyuba Date: Wed, 26 Jun 2024 17:03:29 +0200 Subject: [PATCH 4/8] pcm_converter: Add channel map parameter Adds a channel map parameter to conversion functions, allowing for the introduction of conversions that can handle both format conversion and channel remapping. Signed-off-by: Serhiy Katsyuba --- posix/include/sof/lib/dma.h | 13 +- src/audio/copier/copier.c | 12 +- src/audio/dai-legacy.c | 4 +- src/audio/dai-zephyr.c | 6 +- src/audio/host-legacy.c | 4 +- src/audio/host-zephyr.c | 4 +- src/audio/pcm_converter/pcm_converter.c | 6 + .../pcm_converter/pcm_converter_generic.c | 71 ++++----- src/audio/pcm_converter/pcm_converter_hifi3.c | 60 ++++---- src/include/sof/audio/pcm_converter.h | 14 +- src/lib/dma.c | 141 +++++++++++++++--- .../src/audio/pcm_converter/pcm_float.c | 2 +- xtos/include/sof/lib/dma.h | 13 +- 13 files changed, 233 insertions(+), 117 deletions(-) diff --git a/posix/include/sof/lib/dma.h b/posix/include/sof/lib/dma.h index af9e4191cbbb..4b6b2ae66e01 100644 --- a/posix/include/sof/lib/dma.h +++ b/posix/include/sof/lib/dma.h @@ -254,7 +254,7 @@ struct dma_info { struct audio_stream; typedef int (*dma_process_func)(const struct audio_stream __sparse_cache *source, uint32_t ioffset, struct audio_stream __sparse_cache *sink, - uint32_t ooffset, uint32_t frames); + uint32_t ooffset, uint32_t source_samples, uint32_t chmap); /** * \brief API to initialize a platform DMA controllers. @@ -523,19 +523,15 @@ static inline uint32_t dma_sg_get_size(struct dma_sg_elem_array *ea) return size; } -struct audio_stream; -typedef void (*dma_process)(const struct audio_stream *, - struct audio_stream *, uint32_t); - /* copies data from DMA buffer using provided processing function */ int dma_buffer_copy_from(struct comp_buffer __sparse_cache *source, struct comp_buffer __sparse_cache *sink, - dma_process_func process, uint32_t source_bytes); + dma_process_func process, uint32_t source_bytes, uint32_t chmap); /* copies data to DMA buffer using provided processing function */ int dma_buffer_copy_to(struct comp_buffer __sparse_cache *source, struct comp_buffer __sparse_cache *sink, - dma_process_func process, uint32_t sink_bytes); + dma_process_func process, uint32_t sink_bytes, uint32_t chmap); /* * Used when copying DMA buffer bytes into multiple sink buffers, one at a time using the provided @@ -544,7 +540,8 @@ int dma_buffer_copy_to(struct comp_buffer __sparse_cache *source, */ int dma_buffer_copy_from_no_consume(struct comp_buffer __sparse_cache *source, struct comp_buffer __sparse_cache *sink, - dma_process_func process, uint32_t source_bytes); + dma_process_func process, + uint32_t source_bytes, uint32_t chmap); /* generic DMA DSP <-> Host copier */ diff --git a/src/audio/copier/copier.c b/src/audio/copier/copier.c index 178f7cb25846..c070152f47ae 100644 --- a/src/audio/copier/copier.c +++ b/src/audio/copier/copier.c @@ -440,7 +440,8 @@ static int do_conversion_copy(struct comp_dev *dev, buffer_stream_invalidate(src, processed_data->source_bytes); cd->converter[i](&src->stream, 0, &sink->stream, 0, - processed_data->frames * audio_stream_get_channels(&sink->stream)); + processed_data->frames * audio_stream_get_channels(&src->stream), + DUMMY_CHMAP); buffer_stream_writeback(sink, processed_data->sink_bytes); comp_update_buffer_produce(sink, processed_data->sink_bytes); @@ -509,7 +510,7 @@ static int copier_module_copy(struct processing_module *mod, sink_dev = sink_c->sink; processed_data.sink_bytes = 0; if (sink_dev->state == COMP_STATE_ACTIVE) { - uint32_t samples; + uint32_t source_samples; int sink_queue_id; sink_queue_id = IPC4_SINK_QUEUE_ID(buf_get_id(sink_c)); @@ -518,10 +519,11 @@ static int copier_module_copy(struct processing_module *mod, comp_get_copy_limits(src_c, sink_c, &processed_data); - samples = processed_data.frames * - audio_stream_get_channels(output_buffers[i].data); + source_samples = processed_data.frames * + audio_stream_get_channels(input_buffers[0].data); cd->converter[sink_queue_id](input_buffers[0].data, 0, - output_buffers[i].data, 0, samples); + output_buffers[i].data, 0, + source_samples, DUMMY_CHMAP); output_buffers[i].size = processed_data.sink_bytes; cd->output_total_data_processed += processed_data.sink_bytes; diff --git a/src/audio/dai-legacy.c b/src/audio/dai-legacy.c index 273fa5eee9d5..af28b8616d9c 100644 --- a/src/audio/dai-legacy.c +++ b/src/audio/dai-legacy.c @@ -122,10 +122,10 @@ static void dai_dma_cb(void *arg, enum notify_id type, void *data) if (dev->direction == SOF_IPC_STREAM_PLAYBACK) { ret = dma_buffer_copy_to(dd->local_buffer, dd->dma_buffer, - dd->process, bytes); + dd->process, bytes, DUMMY_CHMAP); } else { ret = dma_buffer_copy_from(dd->dma_buffer, dd->local_buffer, - dd->process, bytes); + dd->process, bytes, DUMMY_CHMAP); } /* assert dma_buffer_copy succeed */ diff --git a/src/audio/dai-zephyr.c b/src/audio/dai-zephyr.c index 6e6fb30d1917..745f0c7d40f7 100644 --- a/src/audio/dai-zephyr.c +++ b/src/audio/dai-zephyr.c @@ -269,7 +269,7 @@ dai_dma_cb(struct dai_data *dd, struct comp_dev *dev, uint32_t bytes, if (dev->direction == SOF_IPC_STREAM_PLAYBACK) { ret = dma_buffer_copy_to(dd->local_buffer, dd->dma_buffer, - dd->process, bytes); + dd->process, bytes, DUMMY_CHMAP); } else { audio_stream_invalidate(&dd->dma_buffer->stream, bytes); /* @@ -277,7 +277,7 @@ dai_dma_cb(struct dai_data *dd, struct comp_dev *dev, uint32_t bytes, * so no need to check the return value of dma_buffer_copy_from_no_consume(). */ ret = dma_buffer_copy_from_no_consume(dd->dma_buffer, dd->local_buffer, - dd->process, bytes); + dd->process, bytes, DUMMY_CHMAP); #if CONFIG_IPC_MAJOR_4 struct list_item *sink_list; /* Skip in case of endpoint DAI devices created by the copier */ @@ -318,7 +318,7 @@ dai_dma_cb(struct dai_data *dd, struct comp_dev *dev, uint32_t bytes, sink->hw_params_configured) ret = dma_buffer_copy_from_no_consume(dd->dma_buffer, sink, converter[j], - bytes); + bytes, DUMMY_CHMAP); } } #endif diff --git a/src/audio/host-legacy.c b/src/audio/host-legacy.c index 9c52c5bd85ab..5326845fe021 100644 --- a/src/audio/host-legacy.c +++ b/src/audio/host-legacy.c @@ -233,11 +233,11 @@ void host_common_update(struct host_data *hd, struct comp_dev *dev, uint32_t byt if (dev->direction == SOF_IPC_STREAM_PLAYBACK) { source = hd->dma_buffer; sink = hd->local_buffer; - ret = dma_buffer_copy_from(source, sink, hd->process, bytes); + ret = dma_buffer_copy_from(source, sink, hd->process, bytes, DUMMY_CHMAP); } else { source = hd->local_buffer; sink = hd->dma_buffer; - ret = dma_buffer_copy_to(source, sink, hd->process, bytes); + ret = dma_buffer_copy_to(source, sink, hd->process, bytes, DUMMY_CHMAP); } /* assert dma_buffer_copy succeed */ diff --git a/src/audio/host-zephyr.c b/src/audio/host-zephyr.c index 82ecc9749a68..d92dbd24f340 100644 --- a/src/audio/host-zephyr.c +++ b/src/audio/host-zephyr.c @@ -247,11 +247,11 @@ void host_common_update(struct host_data *hd, struct comp_dev *dev, uint32_t byt if (dev->direction == SOF_IPC_STREAM_PLAYBACK) { source = hd->dma_buffer; sink = hd->local_buffer; - ret = dma_buffer_copy_from(source, sink, hd->process, bytes); + ret = dma_buffer_copy_from(source, sink, hd->process, bytes, DUMMY_CHMAP); } else { source = hd->local_buffer; sink = hd->dma_buffer; - ret = dma_buffer_copy_to(source, sink, hd->process, bytes); + ret = dma_buffer_copy_to(source, sink, hd->process, bytes, DUMMY_CHMAP); } if (ret < 0) { diff --git a/src/audio/pcm_converter/pcm_converter.c b/src/audio/pcm_converter/pcm_converter.c index 5335ee295b51..b489cc6e664b 100644 --- a/src/audio/pcm_converter/pcm_converter.c +++ b/src/audio/pcm_converter/pcm_converter.c @@ -58,3 +58,9 @@ int pcm_convert_as_linear(const struct audio_stream *source, uint32_t ioffset, return samples; } + +int just_copy(const struct audio_stream *source, uint32_t ioffset, + struct audio_stream *sink, uint32_t ooffset, uint32_t samples, uint32_t chmap) +{ + return audio_stream_copy(source, ioffset, sink, ooffset, samples); +} diff --git a/src/audio/pcm_converter/pcm_converter_generic.c b/src/audio/pcm_converter/pcm_converter_generic.c index 6de32bd52495..3d4110c57165 100644 --- a/src/audio/pcm_converter/pcm_converter_generic.c +++ b/src/audio/pcm_converter/pcm_converter_generic.c @@ -36,7 +36,7 @@ #if CONFIG_PCM_CONVERTER_FORMAT_U8 && CONFIG_PCM_CONVERTER_FORMAT_S32LE static int pcm_convert_u8_to_s32(const struct audio_stream *source, uint32_t ioffset, struct audio_stream *sink, - uint32_t ooffset, uint32_t samples) + uint32_t ooffset, uint32_t samples, uint32_t chmap) { uint8_t *src = audio_stream_get_rptr(source); int32_t *dst = audio_stream_get_wptr(sink); @@ -65,7 +65,7 @@ static int pcm_convert_u8_to_s32(const struct audio_stream *source, static int pcm_convert_s32_to_u8(const struct audio_stream *source, uint32_t ioffset, struct audio_stream *sink, - uint32_t ooffset, uint32_t samples) + uint32_t ooffset, uint32_t samples, uint32_t chmap) { int32_t *src = audio_stream_get_rptr(source); uint8_t *dst = audio_stream_get_wptr(sink); @@ -97,7 +97,7 @@ static int pcm_convert_s32_to_u8(const struct audio_stream *source, static int pcm_convert_s16_to_s24(const struct audio_stream *source, uint32_t ioffset, struct audio_stream *sink, - uint32_t ooffset, uint32_t samples) + uint32_t ooffset, uint32_t samples, uint32_t chmap) { int16_t *src = audio_stream_get_rptr(source); int32_t *dst = audio_stream_get_wptr(sink); @@ -126,7 +126,7 @@ static int pcm_convert_s16_to_s24(const struct audio_stream *source, static int pcm_convert_s24_to_s16(const struct audio_stream *source, uint32_t ioffset, struct audio_stream *sink, - uint32_t ooffset, uint32_t samples) + uint32_t ooffset, uint32_t samples, uint32_t chmap) { int32_t *src = audio_stream_get_rptr(source); int16_t *dst = audio_stream_get_wptr(sink); @@ -159,7 +159,7 @@ static int pcm_convert_s24_to_s16(const struct audio_stream *source, static int pcm_convert_s16_to_s32(const struct audio_stream *source, uint32_t ioffset, struct audio_stream *sink, - uint32_t ooffset, uint32_t samples) + uint32_t ooffset, uint32_t samples, uint32_t chmap) { int16_t *src = audio_stream_get_rptr(source); int32_t *dst = audio_stream_get_wptr(sink); @@ -188,7 +188,7 @@ static int pcm_convert_s16_to_s32(const struct audio_stream *source, static int pcm_convert_s32_to_s16(const struct audio_stream *source, uint32_t ioffset, struct audio_stream *sink, - uint32_t ooffset, uint32_t samples) + uint32_t ooffset, uint32_t samples, uint32_t chmap) { int32_t *src = audio_stream_get_rptr(source); int16_t *dst = audio_stream_get_wptr(sink); @@ -221,7 +221,7 @@ static int pcm_convert_s32_to_s16(const struct audio_stream *source, static int pcm_convert_s24_to_s32(const struct audio_stream *source, uint32_t ioffset, struct audio_stream *sink, - uint32_t ooffset, uint32_t samples) + uint32_t ooffset, uint32_t samples, uint32_t chmap) { int32_t *src = audio_stream_get_rptr(source); int32_t *dst = audio_stream_get_wptr(sink); @@ -250,7 +250,7 @@ static int pcm_convert_s24_to_s32(const struct audio_stream *source, static int pcm_convert_s32_to_s24(const struct audio_stream *source, uint32_t ioffset, struct audio_stream *sink, - uint32_t ooffset, uint32_t samples) + uint32_t ooffset, uint32_t samples, uint32_t chmap) { int32_t *src = audio_stream_get_rptr(source); int32_t *dst = audio_stream_get_wptr(sink); @@ -279,7 +279,7 @@ static int pcm_convert_s32_to_s24(const struct audio_stream *source, static int pcm_convert_s32_to_s24_be(const struct audio_stream *source, uint32_t ioffset, struct audio_stream *sink, - uint32_t ooffset, uint32_t samples) + uint32_t ooffset, uint32_t samples, uint32_t chmap) { int32_t *src = audio_stream_get_rptr(source); int32_t *dst = audio_stream_get_wptr(sink); @@ -444,7 +444,7 @@ static void pcm_convert_f_to_s16_lin(const void *psrc, void *pdst, static int pcm_convert_s16_to_f(const struct audio_stream *source, uint32_t ioffset, struct audio_stream *sink, - uint32_t ooffset, uint32_t samples) + uint32_t ooffset, uint32_t samples, uint32_t chmap) { return pcm_convert_as_linear(source, ioffset, sink, ooffset, samples, pcm_convert_s16_to_f_lin); @@ -452,7 +452,7 @@ static int pcm_convert_s16_to_f(const struct audio_stream *source, static int pcm_convert_f_to_s16(const struct audio_stream *source, uint32_t ioffset, struct audio_stream *sink, - uint32_t ooffset, uint32_t samples) + uint32_t ooffset, uint32_t samples, uint32_t chmap) { return pcm_convert_as_linear(source, ioffset, sink, ooffset, samples, pcm_convert_f_to_s16_lin); @@ -488,7 +488,7 @@ static void pcm_convert_f_to_s24_lin(const void *psrc, void *pdst, static int pcm_convert_s24_to_f(const struct audio_stream *source, uint32_t ioffset, struct audio_stream *sink, - uint32_t ooffset, uint32_t samples) + uint32_t ooffset, uint32_t samples, uint32_t chmap) { return pcm_convert_as_linear(source, ioffset, sink, ooffset, samples, pcm_convert_s24_to_f_lin); @@ -496,7 +496,7 @@ static int pcm_convert_s24_to_f(const struct audio_stream *source, static int pcm_convert_f_to_s24(const struct audio_stream *source, uint32_t ioffset, struct audio_stream *sink, - uint32_t ooffset, uint32_t samples) + uint32_t ooffset, uint32_t samples, uint32_t chmap) { return pcm_convert_as_linear(source, ioffset, sink, ooffset, samples, pcm_convert_f_to_s24_lin); @@ -532,7 +532,7 @@ static void pcm_convert_f_to_s32_lin(const void *psrc, void *pdst, static int pcm_convert_s32_to_f(const struct audio_stream *source, uint32_t ioffset, struct audio_stream *sink, - uint32_t ooffset, uint32_t samples) + uint32_t ooffset, uint32_t samples, uint32_t chmap) { return pcm_convert_as_linear(source, ioffset, sink, ooffset, samples, pcm_convert_s32_to_f_lin); @@ -540,7 +540,7 @@ static int pcm_convert_s32_to_f(const struct audio_stream *source, static int pcm_convert_f_to_s32(const struct audio_stream *source, uint32_t ioffset, struct audio_stream *sink, - uint32_t ooffset, uint32_t samples) + uint32_t ooffset, uint32_t samples, uint32_t chmap) { return pcm_convert_as_linear(source, ioffset, sink, ooffset, samples, pcm_convert_f_to_s32_lin); @@ -549,27 +549,27 @@ static int pcm_convert_f_to_s32(const struct audio_stream *source, const struct pcm_func_map pcm_func_map[] = { #if CONFIG_PCM_CONVERTER_FORMAT_U8 - { SOF_IPC_FRAME_U8, SOF_IPC_FRAME_U8, audio_stream_copy }, + { SOF_IPC_FRAME_U8, SOF_IPC_FRAME_U8, just_copy }, #endif /* CONFIG_PCM_CONVERTER_FORMAT_U8 */ #if CONFIG_PCM_CONVERTER_FORMAT_U8 && CONFIG_PCM_CONVERTER_FORMAT_S32LE { SOF_IPC_FRAME_U8, SOF_IPC_FRAME_S32_LE, pcm_convert_u8_to_s32 }, { SOF_IPC_FRAME_S32_LE, SOF_IPC_FRAME_U8, pcm_convert_s32_to_u8 }, #endif /* CONFIG_PCM_CONVERTER_FORMAT_U8 && CONFIG_PCM_CONVERTER_FORMAT_S32LE */ #if CONFIG_PCM_CONVERTER_FORMAT_S16LE - { SOF_IPC_FRAME_S16_LE, SOF_IPC_FRAME_S16_LE, audio_stream_copy }, + { SOF_IPC_FRAME_S16_LE, SOF_IPC_FRAME_S16_LE, just_copy }, #endif /* CONFIG_PCM_CONVERTER_FORMAT_S16LE */ #if CONFIG_PCM_CONVERTER_FORMAT_S24LE - { SOF_IPC_FRAME_S24_4LE, SOF_IPC_FRAME_S24_4LE, audio_stream_copy }, + { SOF_IPC_FRAME_S24_4LE, SOF_IPC_FRAME_S24_4LE, just_copy }, #endif /* CONFIG_PCM_CONVERTER_FORMAT_S24LE */ #if CONFIG_PCM_CONVERTER_FORMAT_S24_3LE - { SOF_IPC_FRAME_S24_3LE, SOF_IPC_FRAME_S24_3LE, audio_stream_copy }, + { SOF_IPC_FRAME_S24_3LE, SOF_IPC_FRAME_S24_3LE, just_copy }, #endif /* CONFIG_PCM_CONVERTER_FORMAT_S24_3LE */ #if CONFIG_PCM_CONVERTER_FORMAT_S24LE && CONFIG_PCM_CONVERTER_FORMAT_S16LE { SOF_IPC_FRAME_S16_LE, SOF_IPC_FRAME_S24_4LE, pcm_convert_s16_to_s24 }, { SOF_IPC_FRAME_S24_4LE, SOF_IPC_FRAME_S16_LE, pcm_convert_s24_to_s16 }, #endif /* CONFIG_PCM_CONVERTER_FORMAT_S24LE && CONFIG_PCM_CONVERTER_FORMAT_S16LE */ #if CONFIG_PCM_CONVERTER_FORMAT_S32LE - { SOF_IPC_FRAME_S32_LE, SOF_IPC_FRAME_S32_LE, audio_stream_copy }, + { SOF_IPC_FRAME_S32_LE, SOF_IPC_FRAME_S32_LE, just_copy }, #endif /* CONFIG_PCM_CONVERTER_FORMAT_S32LE */ #if CONFIG_PCM_CONVERTER_FORMAT_S32LE && CONFIG_PCM_CONVERTER_FORMAT_S16LE { SOF_IPC_FRAME_S16_LE, SOF_IPC_FRAME_S32_LE, pcm_convert_s16_to_s32 }, @@ -580,7 +580,7 @@ const struct pcm_func_map pcm_func_map[] = { { SOF_IPC_FRAME_S32_LE, SOF_IPC_FRAME_S24_4LE, pcm_convert_s32_to_s24 }, #endif /* CONFIG_PCM_CONVERTER_FORMAT_S32LE && CONFIG_PCM_CONVERTER_FORMAT_S24LE */ #if CONFIG_PCM_CONVERTER_FORMAT_FLOAT - { SOF_IPC_FRAME_FLOAT, SOF_IPC_FRAME_FLOAT, audio_stream_copy }, + { SOF_IPC_FRAME_FLOAT, SOF_IPC_FRAME_FLOAT, just_copy }, #endif /* CONFIG_PCM_CONVERTER_FORMAT_FLOAT */ #if CONFIG_PCM_CONVERTER_FORMAT_FLOAT && CONFIG_PCM_CONVERTER_FORMAT_S16LE { SOF_IPC_FRAME_S16_LE, SOF_IPC_FRAME_FLOAT, pcm_convert_s16_to_f }, @@ -601,7 +601,7 @@ const size_t pcm_func_count = ARRAY_SIZE(pcm_func_map); #if CONFIG_PCM_CONVERTER_FORMAT_S16_C16_AND_S16_C32 static int pcm_convert_s16_c16_to_s16_c32(const struct audio_stream *source, uint32_t ioffset, struct audio_stream *sink, - uint32_t ooffset, uint32_t samples) + uint32_t ooffset, uint32_t samples, uint32_t chmap) { int16_t *src = audio_stream_get_rptr(source); int32_t *dst = audio_stream_get_wptr(sink); @@ -630,7 +630,7 @@ static int pcm_convert_s16_c16_to_s16_c32(const struct audio_stream *source, static int pcm_convert_s16_c32_to_s16_c16(const struct audio_stream *source, uint32_t ioffset, struct audio_stream *sink, - uint32_t ooffset, uint32_t samples) + uint32_t ooffset, uint32_t samples, uint32_t chmap) { int32_t *src = audio_stream_get_rptr(source); int16_t *dst = audio_stream_get_wptr(sink); @@ -660,7 +660,7 @@ static int pcm_convert_s16_c32_to_s16_c16(const struct audio_stream *source, #if CONFIG_PCM_CONVERTER_FORMAT_S16_C32_AND_S32_C32 static int pcm_convert_s16_c32_to_s32_c32(const struct audio_stream *source, uint32_t ioffset, struct audio_stream *sink, - uint32_t ooffset, uint32_t samples) + uint32_t ooffset, uint32_t samples, uint32_t chmap) { int32_t *src = audio_stream_get_rptr(source); int32_t *dst = audio_stream_get_wptr(sink); @@ -689,7 +689,7 @@ static int pcm_convert_s16_c32_to_s32_c32(const struct audio_stream *source, static int pcm_convert_s32_c32_to_s16_c32(const struct audio_stream *source, uint32_t ioffset, struct audio_stream *sink, - uint32_t ooffset, uint32_t samples) + uint32_t ooffset, uint32_t samples, uint32_t chmap) { int32_t *src = audio_stream_get_rptr(source); int32_t *dst = audio_stream_get_wptr(sink); @@ -719,7 +719,7 @@ static int pcm_convert_s32_c32_to_s16_c32(const struct audio_stream *source, #if CONFIG_PCM_CONVERTER_FORMAT_S16_C32_AND_S24_C32 static int pcm_convert_s16_c32_to_s24_c32(const struct audio_stream *source, uint32_t ioffset, struct audio_stream *sink, - uint32_t ooffset, uint32_t samples) + uint32_t ooffset, uint32_t samples, uint32_t chmap) { int32_t *src = audio_stream_get_rptr(source); int32_t *dst = audio_stream_get_wptr(sink); @@ -748,7 +748,7 @@ static int pcm_convert_s16_c32_to_s24_c32(const struct audio_stream *source, static int pcm_convert_s24_c32_to_s16_c32(const struct audio_stream *source, uint32_t ioffset, struct audio_stream *sink, - uint32_t ooffset, uint32_t samples) + uint32_t ooffset, uint32_t samples, uint32_t chmap) { int32_t *src = audio_stream_get_rptr(source); int32_t *dst = audio_stream_get_wptr(sink); @@ -779,7 +779,7 @@ static int pcm_convert_s24_c32_to_s16_c32(const struct audio_stream *source, #if CONFIG_PCM_CONVERTER_FORMAT_S24_C24_AND_S24_C32 static int pcm_convert_s24_c24_to_s24_c32(const struct audio_stream *source, uint32_t ioffset, struct audio_stream *sink, - uint32_t ooffset, uint32_t samples) + uint32_t ooffset, uint32_t samples, uint32_t chmap) { uint8_t *src = audio_stream_get_rptr(source); int32_t *dst = audio_stream_get_wptr(sink); @@ -809,7 +809,7 @@ static int pcm_convert_s24_c24_to_s24_c32(const struct audio_stream *source, static int pcm_convert_s24_c32_to_s24_c24(const struct audio_stream *source, uint32_t ioffset, struct audio_stream *sink, - uint32_t ooffset, uint32_t samples) + uint32_t ooffset, uint32_t samples, uint32_t chmap) { int32_t *src = audio_stream_get_rptr(source); uint8_t *dst = audio_stream_get_wptr(sink); @@ -843,7 +843,8 @@ static int pcm_convert_s24_c32_to_s24_c24(const struct audio_stream *source, /* 2x24bit samples are packed into 3x16bit samples for hda link dma */ static int pcm_convert_s24_c32_to_s24_c24_link_gtw(const struct audio_stream *source, uint32_t ioffset, struct audio_stream *sink, - uint32_t ooffset, uint32_t samples) + uint32_t ooffset, uint32_t samples, + uint32_t chmap) { int32_t *src = audio_stream_get_rptr(source); uint16_t *dst = audio_stream_get_wptr(sink); @@ -904,11 +905,11 @@ const struct pcm_func_vc_map pcm_func_vc_map[] = { #endif #if CONFIG_PCM_CONVERTER_FORMAT_U8 && CONFIG_PCM_CONVERTER_FORMAT_S16LE { SOF_IPC_FRAME_S16_LE, SOF_IPC_FRAME_U8, SOF_IPC_FRAME_S16_LE, SOF_IPC_FRAME_U8, - audio_stream_copy }, + just_copy }, #endif /* CONFIG_PCM_CONVERTER_FORMAT_U8 && CONFIG_PCM_CONVERTER_FORMAT_S16LE */ #if CONFIG_PCM_CONVERTER_FORMAT_S32LE && CONFIG_PCM_CONVERTER_FORMAT_S24LE { SOF_IPC_FRAME_S32_LE, SOF_IPC_FRAME_S24_4LE, SOF_IPC_FRAME_S32_LE, SOF_IPC_FRAME_S24_4LE, - audio_stream_copy}, + just_copy}, { SOF_IPC_FRAME_S32_LE, SOF_IPC_FRAME_S24_4LE, SOF_IPC_FRAME_S32_LE, SOF_IPC_FRAME_S32_LE, pcm_convert_s24_to_s32}, { SOF_IPC_FRAME_S32_LE, SOF_IPC_FRAME_S32_LE, SOF_IPC_FRAME_S32_LE, SOF_IPC_FRAME_S24_4LE, @@ -930,7 +931,7 @@ const struct pcm_func_vc_map pcm_func_vc_map[] = { #endif #if CONFIG_PCM_CONVERTER_FORMAT_S16_C32_AND_S16_C32 { SOF_IPC_FRAME_S32_LE, SOF_IPC_FRAME_S16_LE, SOF_IPC_FRAME_S32_LE, SOF_IPC_FRAME_S16_LE, - audio_stream_copy }, + just_copy }, #endif #if CONFIG_PCM_CONVERTER_FORMAT_S24_4LE_MSB && CONFIG_PCM_CONVERTER_FORMAT_S24LE @@ -939,14 +940,14 @@ const struct pcm_func_vc_map pcm_func_vc_map[] = { { SOF_IPC_FRAME_S32_LE, SOF_IPC_FRAME_S24_4LE_MSB, SOF_IPC_FRAME_S32_LE, SOF_IPC_FRAME_S24_4LE, pcm_convert_s32_to_s24}, { SOF_IPC_FRAME_S32_LE, SOF_IPC_FRAME_S24_4LE_MSB, SOF_IPC_FRAME_S32_LE, - SOF_IPC_FRAME_S24_4LE_MSB, audio_stream_copy}, + SOF_IPC_FRAME_S24_4LE_MSB, just_copy}, #endif #if CONFIG_PCM_CONVERTER_FORMAT_S32LE && CONFIG_PCM_CONVERTER_FORMAT_S24_4LE_MSB { SOF_IPC_FRAME_S32_LE, SOF_IPC_FRAME_S32_LE, SOF_IPC_FRAME_S32_LE, SOF_IPC_FRAME_S24_4LE_MSB, pcm_convert_s32_to_s24_be}, { SOF_IPC_FRAME_S32_LE, SOF_IPC_FRAME_S24_4LE_MSB, SOF_IPC_FRAME_S32_LE, - SOF_IPC_FRAME_S32_LE, audio_stream_copy}, + SOF_IPC_FRAME_S32_LE, just_copy}, #endif #if CONFIG_PCM_CONVERTER_FORMAT_S24_4LE_MSB && CONFIG_PCM_CONVERTER_FORMAT_S16LE diff --git a/src/audio/pcm_converter/pcm_converter_hifi3.c b/src/audio/pcm_converter/pcm_converter_hifi3.c index da7e2ff1c7d1..1759e66ce149 100644 --- a/src/audio/pcm_converter/pcm_converter_hifi3.c +++ b/src/audio/pcm_converter/pcm_converter_hifi3.c @@ -38,7 +38,7 @@ */ static int pcm_convert_s16_to_s24(const struct audio_stream *source, uint32_t ioffset, struct audio_stream *sink, - uint32_t ooffset, uint32_t samples) + uint32_t ooffset, uint32_t samples, uint32_t chmap) { ae_int16x4 sample = AE_ZERO16(); uint32_t nmax, i, n, m, left, left_samples; @@ -112,7 +112,7 @@ static ae_int32x2 pcm_shift_s24_to_s16(ae_int32x2 sample) */ static int pcm_convert_s24_to_s16(const struct audio_stream *source, uint32_t ioffset, struct audio_stream *sink, - uint32_t ooffset, uint32_t samples) + uint32_t ooffset, uint32_t samples, uint32_t chmap) { ae_int16x4 sample = AE_ZERO16(); ae_int32x2 sample_1 = AE_ZERO32(); @@ -183,7 +183,7 @@ static int pcm_convert_s24_to_s16(const struct audio_stream *source, */ static int pcm_convert_s16_to_s32(const struct audio_stream *source, uint32_t ioffset, struct audio_stream *sink, - uint32_t ooffset, uint32_t samples) + uint32_t ooffset, uint32_t samples, uint32_t chmap) { int16_t *src = audio_stream_get_rptr(source); int32_t *dst = audio_stream_get_wptr(sink); @@ -239,7 +239,7 @@ static int pcm_convert_s16_to_s32(const struct audio_stream *source, */ static int pcm_convert_s32_to_s16(const struct audio_stream *source, uint32_t ioffset, struct audio_stream *sink, - uint32_t ooffset, uint32_t samples) + uint32_t ooffset, uint32_t samples, uint32_t chmap) { int32_t *src = audio_stream_get_rptr(source); int16_t *dst = audio_stream_get_wptr(sink); @@ -305,7 +305,7 @@ static int pcm_convert_s32_to_s16(const struct audio_stream *source, */ static int pcm_convert_s24_to_s32(const struct audio_stream *source, uint32_t ioffset, struct audio_stream *sink, - uint32_t ooffset, uint32_t samples) + uint32_t ooffset, uint32_t samples, uint32_t chmap) { int32_t *src = audio_stream_get_rptr(source); int32_t *dst = audio_stream_get_wptr(sink); @@ -370,7 +370,7 @@ static ae_int32x2 pcm_shift_s32_to_s24(ae_int32x2 sample) */ static int pcm_convert_s32_to_s24(const struct audio_stream *source, uint32_t ioffset, struct audio_stream *sink, - uint32_t ooffset, uint32_t samples) + uint32_t ooffset, uint32_t samples, uint32_t chmap) { int32_t *src = audio_stream_get_rptr(source); int32_t *dst = audio_stream_get_wptr(sink); @@ -415,7 +415,7 @@ static int pcm_convert_s32_to_s24(const struct audio_stream *source, static int pcm_convert_s32_to_s24_be(const struct audio_stream *source, uint32_t ioffset, struct audio_stream *sink, - uint32_t ooffset, uint32_t samples) + uint32_t ooffset, uint32_t samples, uint32_t chmap) { int32_t *src = audio_stream_get_rptr(source); int32_t *dst = audio_stream_get_wptr(sink); @@ -543,7 +543,7 @@ static void pcm_convert_f_to_s16_lin(const void *psrc, void *pdst, */ static int pcm_convert_s16_to_f(const struct audio_stream *source, uint32_t ioffset, struct audio_stream *sink, - uint32_t ooffset, uint32_t samples) + uint32_t ooffset, uint32_t samples, uint32_t chmap) { return pcm_convert_as_linear(source, ioffset, sink, ooffset, samples, pcm_convert_s16_to_f_lin); @@ -558,7 +558,7 @@ static int pcm_convert_s16_to_f(const struct audio_stream *source, */ static int pcm_convert_f_to_s16(const struct audio_stream *source, uint32_t ioffset, struct audio_stream *sink, - uint32_t ooffset, uint32_t samples) + uint32_t ooffset, uint32_t samples, uint32_t chmap) { return pcm_convert_as_linear(source, ioffset, sink, ooffset, samples, pcm_convert_f_to_s16_lin); @@ -644,7 +644,7 @@ static void pcm_convert_f_to_s24_lin(const void *psrc, void *pdst, */ static int pcm_convert_s24_to_f(const struct audio_stream *source, uint32_t ioffset, struct audio_stream *sink, - uint32_t ooffset, uint32_t samples) + uint32_t ooffset, uint32_t samples, uint32_t chmap) { return pcm_convert_as_linear(source, ioffset, sink, ooffset, samples, pcm_convert_s24_to_f_lin); @@ -659,7 +659,7 @@ static int pcm_convert_s24_to_f(const struct audio_stream *source, */ static int pcm_convert_f_to_s24(const struct audio_stream *source, uint32_t ioffset, struct audio_stream *sink, - uint32_t ooffset, uint32_t samples) + uint32_t ooffset, uint32_t samples, uint32_t chmap) { return pcm_convert_as_linear(source, ioffset, sink, ooffset, samples, pcm_convert_f_to_s24_lin); @@ -741,7 +741,7 @@ static void pcm_convert_f_to_s32_lin(const void *psrc, void *pdst, */ static int pcm_convert_s32_to_f(const struct audio_stream *source, uint32_t ioffset, struct audio_stream *sink, - uint32_t ooffset, uint32_t samples) + uint32_t ooffset, uint32_t samples, uint32_t chmap) { return pcm_convert_as_linear(source, ioffset, sink, ooffset, samples, pcm_convert_s32_to_f_lin); @@ -756,7 +756,7 @@ static int pcm_convert_s32_to_f(const struct audio_stream *source, */ static int pcm_convert_f_to_s32(const struct audio_stream *source, uint32_t ioffset, struct audio_stream *sink, - uint32_t ooffset, uint32_t samples) + uint32_t ooffset, uint32_t samples, uint32_t chmap) { return pcm_convert_as_linear(source, ioffset, sink, ooffset, samples, pcm_convert_f_to_s32_lin); @@ -766,20 +766,20 @@ static int pcm_convert_f_to_s32(const struct audio_stream *source, const struct pcm_func_map pcm_func_map[] = { #if CONFIG_PCM_CONVERTER_FORMAT_S16LE - { SOF_IPC_FRAME_S16_LE, SOF_IPC_FRAME_S16_LE, audio_stream_copy }, + { SOF_IPC_FRAME_S16_LE, SOF_IPC_FRAME_S16_LE, just_copy }, #endif /* CONFIG_PCM_CONVERTER_FORMAT_S16LE */ #if CONFIG_PCM_CONVERTER_FORMAT_S24LE - { SOF_IPC_FRAME_S24_4LE, SOF_IPC_FRAME_S24_4LE, audio_stream_copy }, + { SOF_IPC_FRAME_S24_4LE, SOF_IPC_FRAME_S24_4LE, just_copy }, #endif /* CONFIG_PCM_CONVERTER_FORMAT_S24LE */ #if CONFIG_PCM_CONVERTER_FORMAT_S24_3LE - { SOF_IPC_FRAME_S24_3LE, SOF_IPC_FRAME_S24_3LE, audio_stream_copy }, + { SOF_IPC_FRAME_S24_3LE, SOF_IPC_FRAME_S24_3LE, just_copy }, #endif /* CONFIG_PCM_CONVERTER_FORMAT_S24_3LE */ #if CONFIG_PCM_CONVERTER_FORMAT_S24LE && CONFIG_PCM_CONVERTER_FORMAT_S16LE { SOF_IPC_FRAME_S16_LE, SOF_IPC_FRAME_S24_4LE, pcm_convert_s16_to_s24 }, { SOF_IPC_FRAME_S24_4LE, SOF_IPC_FRAME_S16_LE, pcm_convert_s24_to_s16 }, #endif /* CONFIG_PCM_CONVERTER_FORMAT_S24LE && CONFIG_PCM_CONVERTER_FORMAT_S16LE */ #if CONFIG_PCM_CONVERTER_FORMAT_S32LE - { SOF_IPC_FRAME_S32_LE, SOF_IPC_FRAME_S32_LE, audio_stream_copy }, + { SOF_IPC_FRAME_S32_LE, SOF_IPC_FRAME_S32_LE, just_copy }, #endif /* CONFIG_PCM_CONVERTER_FORMAT_S32LE */ #if CONFIG_PCM_CONVERTER_FORMAT_S32LE && CONFIG_PCM_CONVERTER_FORMAT_S16LE { SOF_IPC_FRAME_S16_LE, SOF_IPC_FRAME_S32_LE, pcm_convert_s16_to_s32 }, @@ -791,7 +791,7 @@ const struct pcm_func_map pcm_func_map[] = { #endif /* CONFIG_PCM_CONVERTER_FORMAT_S32LE && CONFIG_PCM_CONVERTER_FORMAT_S24LE */ #if XCHAL_HAVE_FP #if CONFIG_PCM_CONVERTER_FORMAT_FLOAT - { SOF_IPC_FRAME_FLOAT, SOF_IPC_FRAME_FLOAT, audio_stream_copy }, + { SOF_IPC_FRAME_FLOAT, SOF_IPC_FRAME_FLOAT, just_copy }, #endif /* CONFIG_PCM_CONVERTER_FORMAT_FLOAT */ #if CONFIG_PCM_CONVERTER_FORMAT_FLOAT && CONFIG_PCM_CONVERTER_FORMAT_S16LE { SOF_IPC_FRAME_S16_LE, SOF_IPC_FRAME_FLOAT, pcm_convert_s16_to_f }, @@ -813,7 +813,7 @@ const size_t pcm_func_count = ARRAY_SIZE(pcm_func_map); static int pcm_convert_s16_c16_to_s16_c32(const struct audio_stream *source, uint32_t ioffset, struct audio_stream *sink, - uint32_t ooffset, uint32_t samples) + uint32_t ooffset, uint32_t samples, uint32_t chmap) { int16_t *src = audio_stream_get_rptr(source); int32_t *dst = audio_stream_get_wptr(sink); @@ -863,7 +863,7 @@ static int pcm_convert_s16_c16_to_s16_c32(const struct audio_stream *source, static int pcm_convert_s16_c32_to_s16_c16(const struct audio_stream *source, uint32_t ioffset, struct audio_stream *sink, - uint32_t ooffset, uint32_t samples) + uint32_t ooffset, uint32_t samples, uint32_t chmap) { int32_t *src = audio_stream_get_rptr(source); int16_t *dst = audio_stream_get_wptr(sink); @@ -922,7 +922,7 @@ static int pcm_convert_s16_c32_to_s16_c16(const struct audio_stream *source, static int pcm_convert_s16_c32_to_s32_c32(const struct audio_stream *source, uint32_t ioffset, struct audio_stream *sink, - uint32_t ooffset, uint32_t samples) + uint32_t ooffset, uint32_t samples, uint32_t chmap) { int32_t *src = audio_stream_get_rptr(source); int32_t *dst = audio_stream_get_wptr(sink); @@ -965,7 +965,7 @@ static int pcm_convert_s16_c32_to_s32_c32(const struct audio_stream *source, static int pcm_convert_s32_c32_to_s16_c32(const struct audio_stream *source, uint32_t ioffset, struct audio_stream *sink, - uint32_t ooffset, uint32_t samples) + uint32_t ooffset, uint32_t samples, uint32_t chmap) { int32_t *src = audio_stream_get_rptr(source); int32_t *dst = audio_stream_get_wptr(sink); @@ -1010,7 +1010,7 @@ static int pcm_convert_s32_c32_to_s16_c32(const struct audio_stream *source, static int pcm_convert_s16_c32_to_s24_c32(const struct audio_stream *source, uint32_t ioffset, struct audio_stream *sink, - uint32_t ooffset, uint32_t samples) + uint32_t ooffset, uint32_t samples, uint32_t chmap) { int32_t *src = audio_stream_get_rptr(source); int32_t *dst = audio_stream_get_wptr(sink); @@ -1065,7 +1065,7 @@ static ae_int32x2 pcm_shift_s24_c32_to_s16(ae_int32x2 sample) static int pcm_convert_s24_c32_to_s16_c32(const struct audio_stream *source, uint32_t ioffset, struct audio_stream *sink, - uint32_t ooffset, uint32_t samples) + uint32_t ooffset, uint32_t samples, uint32_t chmap) { int32_t *src = audio_stream_get_rptr(source); int32_t *dst = audio_stream_get_wptr(sink); @@ -1112,7 +1112,7 @@ static int pcm_convert_s24_c32_to_s16_c32(const struct audio_stream *source, static int pcm_convert_s24_c24_to_s24_c32(const struct audio_stream *source, uint32_t ioffset, struct audio_stream *sink, - uint32_t ooffset, uint32_t samples) + uint32_t ooffset, uint32_t samples, uint32_t chmap) { uint8_t *src = audio_stream_get_rptr(source); int32_t *dst = audio_stream_get_wptr(sink); @@ -1159,7 +1159,7 @@ static int pcm_convert_s24_c24_to_s24_c32(const struct audio_stream *source, static int pcm_convert_s24_c32_to_s24_c24(const struct audio_stream *source, uint32_t ioffset, struct audio_stream *sink, - uint32_t ooffset, uint32_t samples) + uint32_t ooffset, uint32_t samples, uint32_t chmap) { int32_t *src = audio_stream_get_rptr(source); uint8_t *dst = audio_stream_get_wptr(sink); @@ -1227,7 +1227,7 @@ const struct pcm_func_vc_map pcm_func_vc_map[] = { #endif #if CONFIG_PCM_CONVERTER_FORMAT_S32LE && CONFIG_PCM_CONVERTER_FORMAT_S24LE { SOF_IPC_FRAME_S32_LE, SOF_IPC_FRAME_S24_4LE, SOF_IPC_FRAME_S32_LE, SOF_IPC_FRAME_S24_4LE, - audio_stream_copy}, + just_copy}, { SOF_IPC_FRAME_S32_LE, SOF_IPC_FRAME_S24_4LE, SOF_IPC_FRAME_S32_LE, SOF_IPC_FRAME_S32_LE, pcm_convert_s24_to_s32}, { SOF_IPC_FRAME_S32_LE, SOF_IPC_FRAME_S32_LE, SOF_IPC_FRAME_S32_LE, SOF_IPC_FRAME_S24_4LE, @@ -1249,7 +1249,7 @@ const struct pcm_func_vc_map pcm_func_vc_map[] = { #endif #if CONFIG_PCM_CONVERTER_FORMAT_S16_C32_AND_S16_C32 { SOF_IPC_FRAME_S32_LE, SOF_IPC_FRAME_S16_LE, SOF_IPC_FRAME_S32_LE, SOF_IPC_FRAME_S16_LE, - audio_stream_copy }, + just_copy }, #endif #if CONFIG_PCM_CONVERTER_FORMAT_S24_4LE_MSB && CONFIG_PCM_CONVERTER_FORMAT_S24LE @@ -1258,14 +1258,14 @@ const struct pcm_func_vc_map pcm_func_vc_map[] = { { SOF_IPC_FRAME_S32_LE, SOF_IPC_FRAME_S24_4LE_MSB, SOF_IPC_FRAME_S32_LE, SOF_IPC_FRAME_S24_4LE, pcm_convert_s32_to_s24}, { SOF_IPC_FRAME_S32_LE, SOF_IPC_FRAME_S24_4LE_MSB, SOF_IPC_FRAME_S32_LE, - SOF_IPC_FRAME_S24_4LE_MSB, audio_stream_copy}, + SOF_IPC_FRAME_S24_4LE_MSB, just_copy}, #endif #if CONFIG_PCM_CONVERTER_FORMAT_S32LE && CONFIG_PCM_CONVERTER_FORMAT_S24_4LE_MSB { SOF_IPC_FRAME_S32_LE, SOF_IPC_FRAME_S32_LE, SOF_IPC_FRAME_S32_LE, SOF_IPC_FRAME_S24_4LE_MSB, pcm_convert_s32_to_s24_be}, { SOF_IPC_FRAME_S32_LE, SOF_IPC_FRAME_S24_4LE_MSB, SOF_IPC_FRAME_S32_LE, - SOF_IPC_FRAME_S32_LE, audio_stream_copy}, + SOF_IPC_FRAME_S32_LE, just_copy}, #endif #if CONFIG_PCM_CONVERTER_FORMAT_S24_4LE_MSB && CONFIG_PCM_CONVERTER_FORMAT_S16LE diff --git a/src/include/sof/audio/pcm_converter.h b/src/include/sof/audio/pcm_converter.h index a06dc79f632a..04808987b637 100644 --- a/src/include/sof/audio/pcm_converter.h +++ b/src/include/sof/audio/pcm_converter.h @@ -42,12 +42,16 @@ struct audio_stream; * \param ioffset offset to first sample in source stream * \param sink output buffer, write pointer is not modified * \param ooffset offset to first sample in sink stream - * \param samples number of samples to convert - * \return error code or number of processed samples. + * \param source_samples number of samples to convert, for remapping -- number of source samples + * \param chmap channel map for remapping, ignored by non-remapping conversion func + * \return error code or number of processed samples (source samples in case of remapping). */ typedef int (*pcm_converter_func)(const struct audio_stream *source, uint32_t ioffset, struct audio_stream *sink, - uint32_t ooffset, uint32_t samples); + uint32_t ooffset, uint32_t source_samples, uint32_t chmap); + +/* A channel map that does not perform any remapping. */ +#define DUMMY_CHMAP 0x76543210 /** * \brief PCM conversion function interface for data in linear buffer @@ -160,4 +164,8 @@ int pcm_convert_as_linear(const struct audio_stream *source, uint32_t ioffset, struct audio_stream *sink, uint32_t ooffset, uint32_t samples, pcm_converter_lin_func converter); +/* Copy stream without conversion. chmap parameter is ignored. */ +int just_copy(const struct audio_stream *source, uint32_t ioffset, + struct audio_stream *sink, uint32_t ooffset, uint32_t samples, uint32_t chmap); + #endif /* __SOF_AUDIO_PCM_CONVERTER_H__ */ diff --git a/src/lib/dma.c b/src/lib/dma.c index 185e9b72694c..d889d1e3da47 100644 --- a/src/lib/dma.c +++ b/src/lib/dma.c @@ -321,20 +321,55 @@ void dma_sg_free(struct dma_sg_elem_array *elem_array) int dma_buffer_copy_from(struct comp_buffer *source, struct comp_buffer *sink, - dma_process_func process, uint32_t source_bytes) + dma_process_func process, uint32_t source_bytes, uint32_t chmap) { + int source_channels = audio_stream_get_channels(&source->stream); + int sink_channels = audio_stream_get_channels(&sink->stream); + int source_samples; + int sink_bytes; struct audio_stream *istream = &source->stream; - uint32_t samples = source_bytes / - audio_stream_sample_bytes(istream); - uint32_t sink_bytes = audio_stream_sample_bytes(&sink->stream) * - samples; int ret; + /* WORKAROUND: Given that remapping conversion can alter the number of channels, it's + * necessary to use frames, not samples, to calculate sink_bytes for writeback/produce. + * Unfortunately, the Host DMA imposes size alignment requirement for chunks of data + * being copied. For certain frame sizes, this alignment constraint results in splitting + * the first and/or last frame in the buffer. Consequently, frame-based calculations + * cannot be used with Host DMA. Fortunately, remapping conversion is specifically + * designed for use with IPC4 DAI gateway's device posture feature. IPC4 DAI gateway + * does not have the same size alignment limitations. Therefore, frame-based calculations + * are employed only when necessary —- in the case of IPC4 DAI gateway with remapping + * conversion that modifies number of channels. + */ + if (source_channels == sink_channels) { + /* Sample-based calculations can be used here since the source and sink have + * the same number of samples. Frame-based calculations, however, cannot be used + * in this scenario, as it might involve a gateway that does not supply full frames + * (e.g., the Host gateway). + */ + source_samples = source_bytes / audio_stream_sample_bytes(istream); + sink_bytes = source_samples * audio_stream_sample_bytes(&sink->stream); + } else { + int frames; + + /* Sample-based calculations cannot be used here since source and sink have + * different number of samples. Fortunately, only IPC4 DAI gateway supports + * remapping conversion -- it's safe to use frame-based calculations in this + * context. + */ + assert(source_channels); + assert(sink_channels); + + frames = source_bytes / audio_stream_frame_bytes(istream); + sink_bytes = audio_stream_frame_bytes(&sink->stream) * frames; + source_samples = frames * source_channels; + } + /* source buffer contains data copied by DMA */ audio_stream_invalidate(istream, source_bytes); /* process data */ - ret = process(istream, 0, &sink->stream, 0, samples); + ret = process(istream, 0, &sink->stream, 0, source_samples, chmap); buffer_stream_writeback(sink, sink_bytes); @@ -350,19 +385,54 @@ int dma_buffer_copy_from(struct comp_buffer *source, int dma_buffer_copy_to(struct comp_buffer *source, struct comp_buffer *sink, - dma_process_func process, uint32_t sink_bytes) + dma_process_func process, uint32_t sink_bytes, uint32_t chmap) { + int source_channels = audio_stream_get_channels(&source->stream); + int sink_channels = audio_stream_get_channels(&sink->stream); + int source_samples; + int source_bytes; struct audio_stream *ostream = &sink->stream; - uint32_t samples = sink_bytes / - audio_stream_sample_bytes(ostream); - uint32_t source_bytes = audio_stream_sample_bytes(&source->stream) * - samples; int ret; + /* WORKAROUND: Given that remapping conversion can alter the number of channels, it's + * necessary to use frames, not samples, to calculate source_bytes for invalidate/consume. + * Unfortunately, the Host DMA imposes size alignment requirement for chunks of data + * being copied. For certain frame sizes, this alignment constraint results in splitting + * the first and/or last frame in the buffer. Consequently, frame-based calculations + * cannot be used with Host DMA. Fortunately, remapping conversion is specifically + * designed for use with IPC4 DAI gateway's device posture feature. IPC4 DAI gateway + * does not have the same size alignment limitations. Therefore, frame-based calculations + * are employed only when necessary —- in the case of IPC4 DAI gateway with remapping + * conversion that modifies number of channels. + */ + if (source_channels == sink_channels) { + /* Sample-based calculations can be used here since the source and sink have + * the same number of samples. Frame-based calculations, however, cannot be used + * in this scenario, as it might involve a gateway that does not supply full frames + * (e.g., the Host gateway). + */ + source_samples = sink_bytes / audio_stream_sample_bytes(ostream); + source_bytes = source_samples * audio_stream_sample_bytes(&source->stream); + } else { + int frames; + + /* Sample-based calculations cannot be used here since source and sink have + * different number of samples. Fortunately, only IPC4 DAI gateway supports + * remapping conversion -- it's safe to use frame-based calculations in this + * context. + */ + assert(source_channels); + assert(sink_channels); + + frames = sink_bytes / audio_stream_frame_bytes(ostream); + source_bytes = audio_stream_frame_bytes(&source->stream) * frames; + source_samples = frames * source_channels; + } + buffer_stream_invalidate(source, source_bytes); /* process data */ - ret = process(&source->stream, 0, ostream, 0, samples); + ret = process(&source->stream, 0, ostream, 0, source_samples, chmap); /* sink buffer contains data meant to copied to DMA */ audio_stream_writeback(ostream, sink_bytes); @@ -379,17 +449,52 @@ int dma_buffer_copy_to(struct comp_buffer *source, int dma_buffer_copy_from_no_consume(struct comp_buffer *source, struct comp_buffer *sink, - dma_process_func process, uint32_t source_bytes) + dma_process_func process, uint32_t source_bytes, uint32_t chmap) { + int source_channels = audio_stream_get_channels(&source->stream); + int sink_channels = audio_stream_get_channels(&sink->stream); + int source_samples; + int sink_bytes; struct audio_stream *istream = &source->stream; - uint32_t samples = source_bytes / - audio_stream_sample_bytes(istream); - uint32_t sink_bytes = audio_stream_sample_bytes(&sink->stream) * - samples; int ret; + /* WORKAROUND: Given that remapping conversion can alter the number of channels, it's + * necessary to use frames, not samples, to calculate sink_bytes for writeback/produce. + * Unfortunately, the Host DMA imposes size alignment requirement for chunks of data + * being copied. For certain frame sizes, this alignment constraint results in splitting + * the first and/or last frame in the buffer. Consequently, frame-based calculations + * cannot be used with Host DMA. Fortunately, remapping conversion is specifically + * designed for use with IPC4 DAI gateway's device posture feature. IPC4 DAI gateway + * does not have the same size alignment limitations. Therefore, frame-based calculations + * are employed only when necessary —- in the case of IPC4 DAI gateway with remapping + * conversion that modifies number of channels. + */ + if (source_channels == sink_channels) { + /* Sample-based calculations can be used here since the source and sink have + * the same number of samples. Frame-based calculations, however, cannot be used + * in this scenario, as it might involve a gateway that does not supply full frames + * (e.g., the Host gateway). + */ + source_samples = source_bytes / audio_stream_sample_bytes(istream); + sink_bytes = source_samples * audio_stream_sample_bytes(&sink->stream); + } else { + int frames; + + /* Sample-based calculations cannot be used here since source and sink have + * different number of samples. Fortunately, only IPC4 DAI gateway supports + * remapping conversion -- it's safe to use frame-based calculations in this + * context. + */ + assert(source_channels); + assert(sink_channels); + + frames = source_bytes / audio_stream_frame_bytes(istream); + sink_bytes = audio_stream_frame_bytes(&sink->stream) * frames; + source_samples = frames * source_channels; + } + /* process data */ - ret = process(istream, 0, &sink->stream, 0, samples); + ret = process(istream, 0, &sink->stream, 0, source_samples, chmap); buffer_stream_writeback(sink, sink_bytes); diff --git a/test/cmocka/src/audio/pcm_converter/pcm_float.c b/test/cmocka/src/audio/pcm_converter/pcm_float.c index acd98a7f35b6..70ccd3621758 100644 --- a/test/cmocka/src/audio/pcm_converter/pcm_float.c +++ b/test/cmocka/src/audio/pcm_converter/pcm_float.c @@ -99,7 +99,7 @@ static struct comp_buffer *_test_pcm_convert(enum sof_ipc_frame frm_in, enum sof /* run conversion */ fun = pcm_get_conversion_function(frm_in, frm_out); assert_non_null(fun); - fun(&source->stream, 0, &sink->stream, 0, samples); + fun(&source->stream, 0, &sink->stream, 0, samples, DUMMY_CHMAP); /* assert last value in sink is untouched */ assert_int_equal(((uint8_t *)sink->stream.w_ptr)[outbytes - 1], fillval); diff --git a/xtos/include/sof/lib/dma.h b/xtos/include/sof/lib/dma.h index 6ae18f24a1bd..bf333d198d39 100644 --- a/xtos/include/sof/lib/dma.h +++ b/xtos/include/sof/lib/dma.h @@ -259,7 +259,7 @@ struct dma_info { struct audio_stream; typedef int (*dma_process_func)(const struct audio_stream *source, uint32_t ioffset, struct audio_stream *sink, - uint32_t ooffset, uint32_t frames); + uint32_t ooffset, uint32_t source_samples, uint32_t chmap); /** * \brief API to initialize a platform DMA controllers. @@ -528,14 +528,10 @@ static inline uint32_t dma_sg_get_size(struct dma_sg_elem_array *ea) return size; } -struct audio_stream; -typedef void (*dma_process)(const struct audio_stream *, - struct audio_stream *, uint32_t); - /* copies data from DMA buffer using provided processing function */ int dma_buffer_copy_from(struct comp_buffer *source, struct comp_buffer *sink, - dma_process_func process, uint32_t source_bytes); + dma_process_func process, uint32_t source_bytes, uint32_t chmap); /* * Used when copying DMA buffer bytes into multiple sink buffers, one at a time using the provided @@ -544,12 +540,13 @@ int dma_buffer_copy_from(struct comp_buffer *source, */ int dma_buffer_copy_from_no_consume(struct comp_buffer *source, struct comp_buffer *sink, - dma_process_func process, uint32_t source_bytes); + dma_process_func process, + uint32_t source_bytes, uint32_t chmap); /* copies data to DMA buffer using provided processing function */ int dma_buffer_copy_to(struct comp_buffer *source, struct comp_buffer *sink, - dma_process_func process, uint32_t sink_bytes); + dma_process_func process, uint32_t sink_bytes, uint32_t chmap); /* generic DMA DSP <-> Host copier */ From 1065a201d87f4b10442569e85efc5d1d2b346f1a Mon Sep 17 00:00:00 2001 From: Serhiy Katsyuba Date: Thu, 13 Jun 2024 13:52:23 +0200 Subject: [PATCH 5/8] ipc4: pcm_converter: Add channel remapping conversion functions Adds a set of conversion functions that perform both format conversion and channel remapping. These are required to swap channels for the device posture feature. Signed-off-by: Serhiy Katsyuba --- src/audio/Kconfig | 15 + src/audio/pcm_converter/CMakeLists.txt | 4 + src/audio/pcm_converter/pcm_remap.c | 477 +++++++++++++++++++++++++ src/include/module/ipc/stream.h | 1 + src/include/sof/audio/pcm_converter.h | 32 ++ zephyr/CMakeLists.txt | 12 +- 6 files changed, 538 insertions(+), 3 deletions(-) create mode 100644 src/audio/pcm_converter/pcm_remap.c diff --git a/src/audio/Kconfig b/src/audio/Kconfig index 9b35b0c92af8..42ca5e51f9c0 100644 --- a/src/audio/Kconfig +++ b/src/audio/Kconfig @@ -251,6 +251,13 @@ config PCM_CONVERTER_FORMAT_S32LE help Support 32 bit processing data format with sign and in little endian format +config PCM_CONVERTER_FORMAT_S16_4LE + bool "Support S16_4LE" + default y + help + Support the format of signed 16-bit little-endian in the 2 lower bytes + of a 32-bit container. This format is used, for example, by the SSP gateway. + config PCM_CONVERTER_FORMAT_FLOAT bool "Support float" default y @@ -305,6 +312,14 @@ config PCM_CONVERTER_FORMAT_CONVERT_HIFI3 help Use HIFI3 extensions for optimized format conversion (experimental). +config PCM_REMAPPING_CONVERTERS + bool "Channel remapping conversions" + default y + depends on IPC_MAJOR_4 + help + Enable conversion functions that perform both format conversion + and channel remapping simultaneously. + config TRACE_CHANNEL int "TRACE DMA Channel configuration" default 0 diff --git a/src/audio/pcm_converter/CMakeLists.txt b/src/audio/pcm_converter/CMakeLists.txt index 36fd7eafc414..4f09a5a779c7 100644 --- a/src/audio/pcm_converter/CMakeLists.txt +++ b/src/audio/pcm_converter/CMakeLists.txt @@ -4,3 +4,7 @@ add_local_sources(sof pcm_converter.c pcm_converter_generic.c pcm_converter_hifi3.c) + +if(CONFIG_PCM_REMAPPING_CONVERTERS) + add_local_sources(sof pcm_remap.c) +endif() diff --git a/src/audio/pcm_converter/pcm_remap.c b/src/audio/pcm_converter/pcm_remap.c new file mode 100644 index 000000000000..9204b21ee8ab --- /dev/null +++ b/src/audio/pcm_converter/pcm_remap.c @@ -0,0 +1,477 @@ +// SPDX-License-Identifier: BSD-3-Clause +/* + * (c) 2024 Intel Corporation. All rights reserved. + */ + +#include +#include + +static void mute_channel_c16(struct audio_stream *stream, int channel, int frames) +{ + int num_channels = audio_stream_get_channels(stream); + int16_t *ptr = (int16_t *)audio_stream_get_wptr(stream) + channel; + + while (frames) { + int samples_wo_wrap, n, i; + + ptr = audio_stream_wrap(stream, ptr); + + samples_wo_wrap = audio_stream_samples_without_wrap_s16(stream, ptr); + n = SOF_DIV_ROUND_UP(samples_wo_wrap, num_channels); + n = MIN(n, frames); + + for (i = 0; i < n; i++) { + *ptr = 0; + ptr += num_channels; + } + + frames -= n; + } +} + +static void mute_channel_c32(struct audio_stream *stream, int channel, int frames) +{ + int num_channels = audio_stream_get_channels(stream); + int32_t *ptr = (int32_t *)audio_stream_get_wptr(stream) + channel; + + while (frames) { + int samples_wo_wrap, n, i; + + ptr = audio_stream_wrap(stream, ptr); + + samples_wo_wrap = audio_stream_samples_without_wrap_s32(stream, ptr); + n = SOF_DIV_ROUND_UP(samples_wo_wrap, num_channels); + n = MIN(n, frames); + + for (i = 0; i < n; i++) { + *ptr = 0; + ptr += num_channels; + } + + frames -= n; + } +} + +static int remap_c16(const struct audio_stream *source, uint32_t dummy1, + struct audio_stream *sink, uint32_t dummy2, + uint32_t source_samples, uint32_t chmap) +{ + int src_channel, sink_channel; + int num_src_channels = audio_stream_get_channels(source); + int num_sink_channels = audio_stream_get_channels(sink); + int frames = source_samples / num_src_channels; + + for (sink_channel = 0; sink_channel < num_sink_channels; sink_channel++) { + int16_t *src, *dst; + int frames_left; + + src_channel = chmap & 0xf; + chmap >>= 4; + + if (src_channel == 0xf) { + mute_channel_c16(sink, sink_channel, frames); + continue; + } + + assert(src_channel < num_src_channels); + + src = (int16_t *)audio_stream_get_rptr(source) + src_channel; + dst = (int16_t *)audio_stream_get_wptr(sink) + sink_channel; + + frames_left = frames; + + while (frames_left) { + int src_samples_wo_wrap, dst_samples_wo_wrap; + int src_loops, dst_loops, n, i; + + src = audio_stream_wrap(source, src); + dst = audio_stream_wrap(sink, dst); + + src_samples_wo_wrap = audio_stream_samples_without_wrap_s16(source, src); + src_loops = SOF_DIV_ROUND_UP(src_samples_wo_wrap, num_src_channels); + + dst_samples_wo_wrap = audio_stream_samples_without_wrap_s16(sink, dst); + dst_loops = SOF_DIV_ROUND_UP(dst_samples_wo_wrap, num_sink_channels); + + n = MIN(src_loops, dst_loops); + n = MIN(n, frames_left); + + for (i = 0; i < n; i++) { + *dst = *src; + src += num_src_channels; + dst += num_sink_channels; + } + + frames_left -= n; + } + } + + return source_samples; +} + +static inline int remap_c32_left_shift(const struct audio_stream *source, + struct audio_stream *sink, + uint32_t source_samples, uint32_t chmap, + int shift) +{ + int src_channel, sink_channel; + int num_src_channels = audio_stream_get_channels(source); + int num_sink_channels = audio_stream_get_channels(sink); + int frames = source_samples / num_src_channels; + + for (sink_channel = 0; sink_channel < num_sink_channels; sink_channel++) { + int32_t *src, *dst; + int frames_left; + + src_channel = chmap & 0xf; + chmap >>= 4; + + if (src_channel == 0xf) { + mute_channel_c32(sink, sink_channel, frames); + continue; + } + + assert(src_channel < num_src_channels); + + src = (int32_t *)audio_stream_get_rptr(source) + src_channel; + dst = (int32_t *)audio_stream_get_wptr(sink) + sink_channel; + + frames_left = frames; + + while (frames_left) { + int src_samples_wo_wrap, dst_samples_wo_wrap; + int src_loops, dst_loops, n, i; + + src = audio_stream_wrap(source, src); + dst = audio_stream_wrap(sink, dst); + + src_samples_wo_wrap = audio_stream_samples_without_wrap_s32(source, src); + src_loops = SOF_DIV_ROUND_UP(src_samples_wo_wrap, num_src_channels); + + dst_samples_wo_wrap = audio_stream_samples_without_wrap_s32(sink, dst); + dst_loops = SOF_DIV_ROUND_UP(dst_samples_wo_wrap, num_sink_channels); + + n = MIN(src_loops, dst_loops); + n = MIN(n, frames_left); + + for (i = 0; i < n; i++) { + *dst = *src << shift; + src += num_src_channels; + dst += num_sink_channels; + } + + frames_left -= n; + } + } + + return source_samples; +} + +static inline int remap_c32_right_shift(const struct audio_stream *source, + struct audio_stream *sink, + uint32_t source_samples, uint32_t chmap, + int shift) +{ + int src_channel, sink_channel; + int num_src_channels = audio_stream_get_channels(source); + int num_sink_channels = audio_stream_get_channels(sink); + int frames = source_samples / num_src_channels; + + for (sink_channel = 0; sink_channel < num_sink_channels; sink_channel++) { + int32_t *src, *dst; + int frames_left; + + src_channel = chmap & 0xf; + chmap >>= 4; + + if (src_channel == 0xf) { + mute_channel_c32(sink, sink_channel, frames); + continue; + } + + assert(src_channel < num_src_channels); + + src = (int32_t *)audio_stream_get_rptr(source) + src_channel; + dst = (int32_t *)audio_stream_get_wptr(sink) + sink_channel; + + frames_left = frames; + + while (frames_left) { + int src_samples_wo_wrap, dst_samples_wo_wrap; + int src_loops, dst_loops, n, i; + + src = audio_stream_wrap(source, src); + dst = audio_stream_wrap(sink, dst); + + src_samples_wo_wrap = audio_stream_samples_without_wrap_s32(source, src); + src_loops = SOF_DIV_ROUND_UP(src_samples_wo_wrap, num_src_channels); + + dst_samples_wo_wrap = audio_stream_samples_without_wrap_s32(sink, dst); + dst_loops = SOF_DIV_ROUND_UP(dst_samples_wo_wrap, num_sink_channels); + + n = MIN(src_loops, dst_loops); + n = MIN(n, frames_left); + + for (i = 0; i < n; i++) { + *dst = *src >> shift; + src += num_src_channels; + dst += num_sink_channels; + } + + frames_left -= n; + } + } + + return source_samples; +} + +static inline int remap_c16_to_c32(const struct audio_stream *source, + struct audio_stream *sink, + uint32_t source_samples, uint32_t chmap, + int shift) +{ + int src_channel, sink_channel; + int num_src_channels = audio_stream_get_channels(source); + int num_sink_channels = audio_stream_get_channels(sink); + int frames = source_samples / num_src_channels; + + for (sink_channel = 0; sink_channel < num_sink_channels; sink_channel++) { + int16_t *src; + int32_t *dst; + int frames_left; + + src_channel = chmap & 0xf; + chmap >>= 4; + + if (src_channel == 0xf) { + mute_channel_c32(sink, sink_channel, frames); + continue; + } + + assert(src_channel < num_src_channels); + + src = (int16_t *)audio_stream_get_rptr(source) + src_channel; + dst = (int32_t *)audio_stream_get_wptr(sink) + sink_channel; + + frames_left = frames; + + while (frames_left) { + int src_samples_wo_wrap, dst_samples_wo_wrap; + int src_loops, dst_loops, n, i; + + src = audio_stream_wrap(source, src); + dst = audio_stream_wrap(sink, dst); + + src_samples_wo_wrap = audio_stream_samples_without_wrap_s16(source, src); + src_loops = SOF_DIV_ROUND_UP(src_samples_wo_wrap, num_src_channels); + + dst_samples_wo_wrap = audio_stream_samples_without_wrap_s32(sink, dst); + dst_loops = SOF_DIV_ROUND_UP(dst_samples_wo_wrap, num_sink_channels); + + n = MIN(src_loops, dst_loops); + n = MIN(n, frames_left); + + for (i = 0; i < n; i++) { + *dst = (int32_t)*src << shift; + src += num_src_channels; + dst += num_sink_channels; + } + + frames_left -= n; + } + } + + return source_samples; +} + +static inline int remap_c32_to_c16(const struct audio_stream *source, + struct audio_stream *sink, + uint32_t source_samples, uint32_t chmap, + int shift) +{ + int src_channel, sink_channel; + int num_src_channels = audio_stream_get_channels(source); + int num_sink_channels = audio_stream_get_channels(sink); + int frames = source_samples / num_src_channels; + + for (sink_channel = 0; sink_channel < num_sink_channels; sink_channel++) { + int32_t *src; + int16_t *dst; + int frames_left; + + src_channel = chmap & 0xf; + chmap >>= 4; + + if (src_channel == 0xf) { + mute_channel_c16(sink, sink_channel, frames); + continue; + } + + assert(src_channel < num_src_channels); + + src = (int32_t *)audio_stream_get_rptr(source) + src_channel; + dst = (int16_t *)audio_stream_get_wptr(sink) + sink_channel; + + frames_left = frames; + + while (frames_left) { + int src_samples_wo_wrap, dst_samples_wo_wrap; + int src_loops, dst_loops, n, i; + + src = audio_stream_wrap(source, src); + dst = audio_stream_wrap(sink, dst); + + src_samples_wo_wrap = audio_stream_samples_without_wrap_s32(source, src); + src_loops = SOF_DIV_ROUND_UP(src_samples_wo_wrap, num_src_channels); + + dst_samples_wo_wrap = audio_stream_samples_without_wrap_s16(sink, dst); + dst_loops = SOF_DIV_ROUND_UP(dst_samples_wo_wrap, num_sink_channels); + + n = MIN(src_loops, dst_loops); + n = MIN(n, frames_left); + + for (i = 0; i < n; i++) { + *dst = *src >> shift; + src += num_src_channels; + dst += num_sink_channels; + } + + frames_left -= n; + } + } + + return source_samples; +} + +static int remap_c32(const struct audio_stream *source, uint32_t dummy1, + struct audio_stream *sink, uint32_t dummy2, + uint32_t source_samples, uint32_t chmap) +{ + return remap_c32_left_shift(source, sink, source_samples, chmap, 0); +} + +static int remap_c32_to_c16_right_shift_16(const struct audio_stream *source, uint32_t dummy1, + struct audio_stream *sink, uint32_t dummy2, + uint32_t source_samples, uint32_t chmap) +{ + return remap_c32_to_c16(source, sink, source_samples, chmap, 16); +} + +static int remap_c16_to_c32_left_shift_16(const struct audio_stream *source, uint32_t dummy1, + struct audio_stream *sink, uint32_t dummy2, + uint32_t source_samples, uint32_t chmap) +{ + return remap_c16_to_c32(source, sink, source_samples, chmap, 16); +} + +static int remap_c32_to_c16_right_shift_8(const struct audio_stream *source, uint32_t dummy1, + struct audio_stream *sink, uint32_t dummy2, + uint32_t source_samples, uint32_t chmap) +{ + return remap_c32_to_c16(source, sink, source_samples, chmap, 8); +} + +static int remap_c16_to_c32_left_shift_8(const struct audio_stream *source, uint32_t dummy1, + struct audio_stream *sink, uint32_t dummy2, + uint32_t source_samples, uint32_t chmap) +{ + return remap_c16_to_c32(source, sink, source_samples, chmap, 8); +} + +static int remap_c32_right_shift_8(const struct audio_stream *source, uint32_t dummy1, + struct audio_stream *sink, uint32_t dummy2, + uint32_t source_samples, uint32_t chmap) +{ + return remap_c32_right_shift(source, sink, source_samples, chmap, 8); +} + +static int remap_c32_left_shift_8(const struct audio_stream *source, uint32_t dummy1, + struct audio_stream *sink, uint32_t dummy2, + uint32_t source_samples, uint32_t chmap) +{ + return remap_c32_left_shift(source, sink, source_samples, chmap, 8); +} + +static int remap_c32_right_shift_16(const struct audio_stream *source, uint32_t dummy1, + struct audio_stream *sink, uint32_t dummy2, + uint32_t source_samples, uint32_t chmap) +{ + return remap_c32_right_shift(source, sink, source_samples, chmap, 16); +} + +static int remap_c32_left_shift_16(const struct audio_stream *source, uint32_t dummy1, + struct audio_stream *sink, uint32_t dummy2, + uint32_t source_samples, uint32_t chmap) +{ + return remap_c32_left_shift(source, sink, source_samples, chmap, 16); +} + +static int remap_c32_to_c16_no_shift(const struct audio_stream *source, uint32_t dummy1, + struct audio_stream *sink, uint32_t dummy2, + uint32_t source_samples, uint32_t chmap) +{ + return remap_c32_to_c16(source, sink, source_samples, chmap, 0); +} + +static int remap_c16_to_c32_no_shift(const struct audio_stream *source, uint32_t dummy1, + struct audio_stream *sink, uint32_t dummy2, + uint32_t source_samples, uint32_t chmap) +{ + return remap_c16_to_c32(source, sink, source_samples, chmap, 0); +} + +/* Unfortunately, all these nice "if"s were commented out to suppress + * CI "defined but not used" warnings. + */ +const struct pcm_func_map pcm_remap_func_map[] = { +/* #if CONFIG_PCM_CONVERTER_FORMAT_S16LE */ + { SOF_IPC_FRAME_S16_LE, SOF_IPC_FRAME_S16_LE, remap_c16}, +/* #endif */ +/* #if CONFIG_PCM_CONVERTER_FORMAT_S16LE && CONFIG_PCM_CONVERTER_FORMAT_S24_4LE */ + { SOF_IPC_FRAME_S16_LE, SOF_IPC_FRAME_S24_4LE, remap_c16_to_c32_left_shift_8}, + { SOF_IPC_FRAME_S24_4LE, SOF_IPC_FRAME_S16_LE, remap_c32_to_c16_right_shift_8}, +/* #endif */ +/* #if CONFIG_PCM_CONVERTER_FORMAT_S16LE && CONFIG_PCM_CONVERTER_FORMAT_S24_4LE_MSB */ + { SOF_IPC_FRAME_S16_LE, SOF_IPC_FRAME_S24_4LE_MSB, remap_c16_to_c32_left_shift_16}, + { SOF_IPC_FRAME_S24_4LE_MSB, SOF_IPC_FRAME_S16_LE, remap_c32_to_c16_right_shift_16}, +/* #endif */ +/* #if CONFIG_PCM_CONVERTER_FORMAT_S16LE && CONFIG_PCM_CONVERTER_FORMAT_S32LE */ + { SOF_IPC_FRAME_S16_LE, SOF_IPC_FRAME_S32_LE, remap_c16_to_c32_left_shift_16}, + { SOF_IPC_FRAME_S32_LE, SOF_IPC_FRAME_S16_LE, remap_c32_to_c16_right_shift_16}, +/* #endif */ +/* #if CONFIG_PCM_CONVERTER_FORMAT_S16LE && CONFIG_PCM_CONVERTER_FORMAT_S16_4LE */ + { SOF_IPC_FRAME_S16_LE, SOF_IPC_FRAME_S16_4LE, remap_c16_to_c32_no_shift}, + { SOF_IPC_FRAME_S16_4LE, SOF_IPC_FRAME_S16_LE, remap_c32_to_c16_no_shift}, +/* #endif */ +/* #if CONFIG_PCM_CONVERTER_FORMAT_S24_4LE */ + { SOF_IPC_FRAME_S24_4LE, SOF_IPC_FRAME_S24_4LE, remap_c32}, +/* #endif */ +/* #if CONFIG_PCM_CONVERTER_FORMAT_S24_4LE && CONFIG_PCM_CONVERTER_FORMAT_S24_4LE_MSB */ + { SOF_IPC_FRAME_S24_4LE, SOF_IPC_FRAME_S24_4LE_MSB, remap_c32_left_shift_8}, + { SOF_IPC_FRAME_S24_4LE_MSB, SOF_IPC_FRAME_S24_4LE, remap_c32_right_shift_8}, +/* #endif */ +/* #if CONFIG_PCM_CONVERTER_FORMAT_S24_4LE && CONFIG_PCM_CONVERTER_FORMAT_S32LE */ + { SOF_IPC_FRAME_S24_4LE, SOF_IPC_FRAME_S32_LE, remap_c32_left_shift_8}, + { SOF_IPC_FRAME_S32_LE, SOF_IPC_FRAME_S24_4LE, remap_c32_right_shift_8}, +/* #endif */ +/* #if CONFIG_PCM_CONVERTER_FORMAT_S24_4LE && CONFIG_PCM_CONVERTER_FORMAT_S16_4LE */ + { SOF_IPC_FRAME_S24_4LE, SOF_IPC_FRAME_S16_4LE, remap_c32_right_shift_8}, + { SOF_IPC_FRAME_S16_4LE, SOF_IPC_FRAME_S24_4LE, remap_c32_left_shift_8}, +/* #endif */ +/* #if CONFIG_PCM_CONVERTER_FORMAT_S24_4LE_MSB && CONFIG_PCM_CONVERTER_FORMAT_S32LE */ + { SOF_IPC_FRAME_S24_4LE_MSB, SOF_IPC_FRAME_S32_LE, remap_c32}, + { SOF_IPC_FRAME_S32_LE, SOF_IPC_FRAME_S24_4LE_MSB, remap_c32}, +/* #endif */ +/* #if CONFIG_PCM_CONVERTER_FORMAT_S32LE */ + { SOF_IPC_FRAME_S32_LE, SOF_IPC_FRAME_S32_LE, remap_c32}, +/* #endif */ +/* #if CONFIG_PCM_CONVERTER_FORMAT_S32LE && CONFIG_PCM_CONVERTER_FORMAT_S16_4LE */ + { SOF_IPC_FRAME_S32_LE, SOF_IPC_FRAME_S16_4LE, remap_c32_right_shift_16}, + { SOF_IPC_FRAME_S16_4LE, SOF_IPC_FRAME_S32_LE, remap_c32_left_shift_16}, +/* #endif */ +/* #if CONFIG_PCM_CONVERTER_FORMAT_S16_4LE */ + { SOF_IPC_FRAME_S16_4LE, SOF_IPC_FRAME_S16_4LE, remap_c32}, +/* #endif */ +}; + +const size_t pcm_remap_func_count = ARRAY_SIZE(pcm_remap_func_map); diff --git a/src/include/module/ipc/stream.h b/src/include/module/ipc/stream.h index 86837d7ea302..c3d05d903075 100644 --- a/src/include/module/ipc/stream.h +++ b/src/include/module/ipc/stream.h @@ -20,6 +20,7 @@ enum sof_ipc_frame { SOF_IPC_FRAME_S24_3LE, SOF_IPC_FRAME_S24_4LE_MSB, SOF_IPC_FRAME_U8, + SOF_IPC_FRAME_S16_4LE /* 16-bit in 32-bit container */ }; #endif /* __MODULE_IPC_STREAM_H__ */ diff --git a/src/include/sof/audio/pcm_converter.h b/src/include/sof/audio/pcm_converter.h index 04808987b637..3563a0d6557e 100644 --- a/src/include/sof/audio/pcm_converter.h +++ b/src/include/sof/audio/pcm_converter.h @@ -75,6 +75,14 @@ extern const struct pcm_func_map pcm_func_map[]; /** \brief Number of conversion functions. */ extern const size_t pcm_func_count; +#if CONFIG_PCM_REMAPPING_CONVERTERS +/** \brief Map of formats with dedicated remap with conversion functions. */ +extern const struct pcm_func_map pcm_remap_func_map[]; + +/** \brief Number of remap with conversion functions. */ +extern const size_t pcm_remap_func_count; +#endif + /** * \brief Retrieves PCM conversion function. * \param[in] in Source frame format. @@ -98,6 +106,30 @@ pcm_get_conversion_function(enum sof_ipc_frame in, return NULL; } +#if CONFIG_PCM_REMAPPING_CONVERTERS +/** + * \brief Retrieves PCM remap with conversion function. + * \param[in] in Source frame format. + * \param[in] out Sink frame format. + */ +static inline pcm_converter_func +pcm_get_remap_function(enum sof_ipc_frame in, enum sof_ipc_frame out) +{ + int i; + + for (i = 0; i < pcm_remap_func_count; i++) { + if (in != pcm_remap_func_map[i].source) + continue; + if (out != pcm_remap_func_map[i].sink) + continue; + + return pcm_remap_func_map[i].func; + } + + return NULL; +} +#endif + /** \brief PCM conversion functions mapfor different size of valid bit and container. */ struct pcm_func_vc_map { enum sof_ipc_frame source; /**< source frame container format */ diff --git a/zephyr/CMakeLists.txt b/zephyr/CMakeLists.txt index c9de5f9b5cbb..0caa462c39d3 100644 --- a/zephyr/CMakeLists.txt +++ b/zephyr/CMakeLists.txt @@ -412,9 +412,6 @@ zephyr_library_sources( # SOF mandatory audio processing ${SOF_AUDIO_PATH}/channel_map.c - ${SOF_AUDIO_PATH}/pcm_converter/pcm_converter_hifi3.c - ${SOF_AUDIO_PATH}/pcm_converter/pcm_converter.c - ${SOF_AUDIO_PATH}/pcm_converter/pcm_converter_generic.c ${SOF_AUDIO_PATH}/buffer.c ${SOF_AUDIO_PATH}/source_api_helper.c ${SOF_AUDIO_PATH}/sink_api_helper.c @@ -704,6 +701,15 @@ zephyr_library_sources_ifdef(CONFIG_COMP_COPIER ${SOF_AUDIO_PATH}/copier/copier_dai.c ) +zephyr_library_sources( + ${SOF_AUDIO_PATH}/pcm_converter/pcm_converter_hifi3.c + ${SOF_AUDIO_PATH}/pcm_converter/pcm_converter.c + ${SOF_AUDIO_PATH}/pcm_converter/pcm_converter_generic.c +) +zephyr_library_sources_ifdef(CONFIG_PCM_REMAPPING_CONVERTERS + ${SOF_AUDIO_PATH}/pcm_converter/pcm_remap.c +) + zephyr_library_sources_ifdef(CONFIG_MAXIM_DSM ${SOF_AUDIO_PATH}/smart_amp/smart_amp.c ${SOF_AUDIO_PATH}/smart_amp/smart_amp_generic.c From a073840965d8d43d5ef06817e2bd6c4caeee4532 Mon Sep 17 00:00:00 2001 From: Serhiy Katsyuba Date: Fri, 14 Jun 2024 18:55:34 +0200 Subject: [PATCH 6/8] dai-zephyr: Prioritize HW params channels over base config params When the hardware is able to return a valid number of DMA buffer audio channels (e.g., extracted from a blob), give the returned number of channels higher precedence over the number supplied via the base config params. Signed-off-by: Serhiy Katsyuba --- src/audio/dai-zephyr.c | 28 ++++++++++++++++++++++++---- 1 file changed, 24 insertions(+), 4 deletions(-) diff --git a/src/audio/dai-zephyr.c b/src/audio/dai-zephyr.c index 745f0c7d40f7..c4ad228e4b40 100644 --- a/src/audio/dai-zephyr.c +++ b/src/audio/dai-zephyr.c @@ -794,7 +794,8 @@ static int dai_set_dma_config(struct dai_data *dd, struct comp_dev *dev) } static int dai_set_dma_buffer(struct dai_data *dd, struct comp_dev *dev, - struct sof_ipc_stream_params *params, uint32_t *pb, uint32_t *pc) + const struct sof_ipc_stream_params *params, + uint32_t *pb, uint32_t *pc) { struct sof_ipc_stream_params hw_params = *params; uint32_t frame_size; @@ -916,8 +917,10 @@ static int dai_set_dma_buffer(struct dai_data *dd, struct comp_dev *dev, } int dai_common_params(struct dai_data *dd, struct comp_dev *dev, - struct sof_ipc_stream_params *params) + struct sof_ipc_stream_params *base_cfg_params) { + struct sof_ipc_stream_params params = *base_cfg_params; + struct sof_ipc_stream_params hw_params; struct dma_sg_config *config = &dd->config; uint32_t period_bytes = 0; uint32_t period_count = 0; @@ -932,13 +935,30 @@ int dai_common_params(struct dai_data *dd, struct comp_dev *dev, return err; } - err = dai_verify_params(dd, dev, params); + /* When the hardware is able to return a valid number of DMA buffer audio channels + * (e.g., extracted from a blob), give the returned number of channels higher precedence + * over the number supplied via the base config params. + */ + memset(&hw_params, 0, sizeof(hw_params)); + err = dai_common_get_hw_params(dd, dev, &hw_params, params.direction); + if (err < 0) { + comp_err(dev, "dai_common_get_hw_params() failed: %d", err); + return err; + } + + if (hw_params.channels != 0 && hw_params.channels != params.channels) { + params.channels = hw_params.channels; + comp_info(dev, "Replacing %d base config channels with %d hw params channels.", + base_cfg_params->channels, params.channels); + } + + err = dai_verify_params(dd, dev, ¶ms); if (err < 0) { comp_err(dev, "dai_zephyr_params(): pcm params verification failed."); return -EINVAL; } - err = dai_set_dma_buffer(dd, dev, params, &period_bytes, &period_count); + err = dai_set_dma_buffer(dd, dev, ¶ms, &period_bytes, &period_count); if (err < 0) { comp_err(dev, "dai_zephyr_params(): alloc dma buffer failed."); goto out; From 7661c96d027f8899f67d59d23c9d1051fd318dae Mon Sep 17 00:00:00 2001 From: Serhiy Katsyuba Date: Mon, 17 Jun 2024 12:13:43 +0200 Subject: [PATCH 7/8] ipc4: copier: Extend get_convertion_func() to support remapping Adds channel map parameter to get_convertion_func() to support remapping conversion functions. Signed-off-by: Serhiy Katsyuba --- src/audio/copier/copier.c | 6 +- src/audio/copier/copier.h | 4 +- src/audio/copier/copier_dai.c | 104 +++++++++++++++++++++--------- src/audio/copier/copier_generic.c | 28 +++++++- src/audio/copier/copier_host.c | 3 +- src/audio/copier/copier_ipcgtw.c | 3 +- 6 files changed, 110 insertions(+), 38 deletions(-) diff --git a/src/audio/copier/copier.c b/src/audio/copier/copier.c index c070152f47ae..29a3943905a5 100644 --- a/src/audio/copier/copier.c +++ b/src/audio/copier/copier.c @@ -164,6 +164,8 @@ static int copier_init(struct processing_module *mod) dev->direction_set = true; } else { + cd->gtw_type = ipc4_gtw_none; + /* set max sink count for module copier */ mod->max_sinks = IPC4_COPIER_MODULE_OUTPUT_PINS_COUNT; } @@ -244,7 +246,7 @@ static int copier_prepare(struct processing_module *mod, */ cd->converter[0] = get_converter_func(&cd->config.base.audio_fmt, &cd->config.out_fmt, ipc4_gtw_none, - ipc4_bidirection); + ipc4_bidirection, DUMMY_CHMAP); if (!cd->converter[0]) { comp_err(dev, "can't support for in format %d, out format %d", cd->config.base.audio_fmt.depth, cd->config.out_fmt.depth); @@ -686,7 +688,7 @@ static int copier_set_sink_fmt(struct comp_dev *dev, const void *data, cd->out_fmt[sink_fmt->sink_id] = sink_fmt->sink_fmt; cd->converter[sink_fmt->sink_id] = get_converter_func(&sink_fmt->source_fmt, &sink_fmt->sink_fmt, ipc4_gtw_none, - ipc4_bidirection); + ipc4_bidirection, DUMMY_CHMAP); return 0; } diff --git a/src/audio/copier/copier.h b/src/audio/copier/copier.h index 550219a2aa83..3f210e4d630e 100644 --- a/src/audio/copier/copier.h +++ b/src/audio/copier/copier.h @@ -232,6 +232,7 @@ struct copier_data { */ struct ipc4_copier_module_cfg config; void *gtw_cfg; + enum ipc4_gateway_type gtw_type; struct comp_dev *endpoint[IPC4_COPIER_MODULE_OUTPUT_PINS_COUNT]; struct comp_buffer *endpoint_buffer[IPC4_COPIER_MODULE_OUTPUT_PINS_COUNT]; uint32_t endpoint_num; @@ -267,7 +268,8 @@ int apply_attenuation(struct comp_dev *dev, struct copier_data *cd, pcm_converter_func get_converter_func(const struct ipc4_audio_format *in_fmt, const struct ipc4_audio_format *out_fmt, enum ipc4_gateway_type type, - enum ipc4_direction_type dir); + enum ipc4_direction_type dir, + uint32_t chmap); struct comp_ipc_config; int create_endpoint_buffer(struct comp_dev *dev, diff --git a/src/audio/copier/copier_dai.c b/src/audio/copier/copier_dai.c index 66e621f0eccf..0228f095f9be 100644 --- a/src/audio/copier/copier_dai.c +++ b/src/audio/copier/copier_dai.c @@ -234,7 +234,6 @@ int copier_dai_create(struct comp_dev *dev, struct copier_data *cd, struct comp_ipc_config *config = &dev->ipc_config; int dai_index[IPC4_ALH_MAX_NUMBER_OF_GTW]; union ipc4_connector_node_id node_id; - enum ipc4_gateway_type type; struct ipc_config_dai dai; int dai_count; int i, ret; @@ -255,13 +254,13 @@ int copier_dai_create(struct comp_dev *dev, struct copier_data *cd, case ipc4_hda_link_input_class: dai.type = SOF_DAI_INTEL_HDA; dai.is_config_blob = true; - type = ipc4_gtw_link; + cd->gtw_type = ipc4_gtw_link; break; case ipc4_i2s_link_output_class: case ipc4_i2s_link_input_class: dai.type = SOF_DAI_INTEL_SSP; dai.is_config_blob = true; - type = ipc4_gtw_ssp; + cd->gtw_type = ipc4_gtw_ssp; ret = ipc4_find_dma_config(&dai, (uint8_t *)cd->gtw_cfg, copier->gtw_cfg.config_length * 4); if (ret != 0) { @@ -275,11 +274,11 @@ int copier_dai_create(struct comp_dev *dev, struct copier_data *cd, #if ACE_VERSION > ACE_VERSION_1_5 dai.type = SOF_DAI_INTEL_HDA; dai.is_config_blob = true; - type = ipc4_gtw_link; + cd->gtw_type = ipc4_gtw_link; #else dai.type = SOF_DAI_INTEL_ALH; dai.is_config_blob = true; - type = ipc4_gtw_alh; + cd->gtw_type = ipc4_gtw_alh; #endif /* ACE_VERSION > ACE_VERSION_1_5 */ ret = copier_alh_assign_dai_index(dev, cd->gtw_cfg, node_id, &dai, dai_index, &dai_count); @@ -289,7 +288,7 @@ int copier_dai_create(struct comp_dev *dev, struct copier_data *cd, case ipc4_dmic_link_input_class: dai.type = SOF_DAI_INTEL_DMIC; dai.is_config_blob = true; - type = ipc4_gtw_dmic; + cd->gtw_type = ipc4_gtw_dmic; ret = ipc4_find_dma_config(&dai, (uint8_t *)cd->gtw_cfg, copier->gtw_cfg.config_length * 4); if (ret != 0) { @@ -304,7 +303,7 @@ int copier_dai_create(struct comp_dev *dev, struct copier_data *cd, for (i = 0; i < dai_count; i++) { dai.dai_index = dai_index[i]; - ret = copier_dai_init(dev, config, copier, pipeline, &dai, type, i, + ret = copier_dai_init(dev, config, copier, pipeline, &dai, cd->gtw_type, i, dai_count); if (ret) { comp_err(dev, "failed to create dai"); @@ -313,11 +312,11 @@ int copier_dai_create(struct comp_dev *dev, struct copier_data *cd, } cd->converter[IPC4_COPIER_GATEWAY_PIN] = - get_converter_func(&copier->base.audio_fmt, &copier->out_fmt, type, - IPC4_DIRECTION(dai.direction)); + get_converter_func(&copier->base.audio_fmt, &copier->out_fmt, cd->gtw_type, + IPC4_DIRECTION(dai.direction), DUMMY_CHMAP); if (!cd->converter[IPC4_COPIER_GATEWAY_PIN]) { comp_err(dev, "failed to get converter type %d, dir %d", - type, dai.direction); + cd->gtw_type, dai.direction); return -EINVAL; } @@ -450,40 +449,81 @@ static int copy_single_channel_c32(const struct audio_stream *src, return 0; } +static void copier_dai_adjust_params(const struct copier_data *cd, + struct ipc4_audio_format *in_fmt, + struct ipc4_audio_format *out_fmt) +{ + struct comp_buffer *dma_buf; + int dma_buf_channels; + int dma_buf_container_bits, dma_buf_valid_bits; + + /* Call this func only for DAI gateway with already setup DMA buffer */ + assert(cd->dd[0] && cd->dd[0]->dma_buffer); + dma_buf = cd->dd[0]->dma_buffer; + + /* Unfortunately, configuring the gateway DMA buffer format is somewhat confusing. + * The number of channels can come from hardware parameters (extracted from a blob?) + * and also appears in the copier's input/output format. In case the value returned + * by the hardware looks valid, it should take precedence over the value from the + * copier's input/output format. + * + * The frame format comes from the topology as dev->ipc_config.frame_fmt and also + * comes as the copier's input/output format. The logic is confusing: the format + * from the topology takes priority, except when the copier's format container and + * valid sample size are different. Perhaps this is to support the 16-bit valid + * in the 32-bit container format used by SSP, as such a format cannot be specified + * in the topology? + */ + dma_buf_channels = audio_stream_get_channels(&dma_buf->stream); + dma_buf_container_bits = audio_stream_sample_bytes(&dma_buf->stream) * 8; + dma_buf_valid_bits = get_sample_bitdepth(audio_stream_get_frm_fmt(&dma_buf->stream)); + + if (cd->direction == SOF_IPC_STREAM_PLAYBACK) { + out_fmt->channels_count = dma_buf_channels; + + if (!(dma_buf_container_bits == out_fmt->depth && + out_fmt->depth != out_fmt->valid_bit_depth)) { + out_fmt->depth = dma_buf_container_bits; + out_fmt->valid_bit_depth = dma_buf_valid_bits; + } + } else { + in_fmt->channels_count = dma_buf_channels; + + if (!(dma_buf_container_bits == in_fmt->depth && + in_fmt->depth != in_fmt->valid_bit_depth)) { + in_fmt->depth = dma_buf_container_bits; + in_fmt->valid_bit_depth = dma_buf_valid_bits; + } + } +} + int copier_dai_params(struct copier_data *cd, struct comp_dev *dev, struct sof_ipc_stream_params *params, int dai_index) { struct sof_ipc_stream_params demuxed_params = *params; - const struct ipc4_audio_format *in_fmt = &cd->config.base.audio_fmt; - const struct ipc4_audio_format *out_fmt = &cd->config.out_fmt; - enum sof_ipc_frame in_bits, in_valid_bits, out_bits, out_valid_bits; int container_size; int j, ret; if (cd->endpoint_num == 1) { + struct ipc4_audio_format in_fmt = cd->config.base.audio_fmt; + struct ipc4_audio_format out_fmt = cd->config.out_fmt; + enum ipc4_direction_type dir; + ret = dai_common_params(cd->dd[0], dev, params); + if (ret < 0) + return ret; + + copier_dai_adjust_params(cd, &in_fmt, &out_fmt); + + dir = (cd->direction == SOF_IPC_STREAM_PLAYBACK) ? + ipc4_playback : ipc4_capture; + + cd->dd[0]->process = + get_converter_func(&in_fmt, &out_fmt, cd->gtw_type, dir, DUMMY_CHMAP); - /* - * dai_zephyr_params assigns the conversion function - * based on the input/output formats but does not take - * the valid bits into account. So change the conversion - * function if the valid bits are different from the - * container size. - */ - audio_stream_fmt_conversion(in_fmt->depth, - in_fmt->valid_bit_depth, - &in_bits, &in_valid_bits, - in_fmt->s_type); - audio_stream_fmt_conversion(out_fmt->depth, - out_fmt->valid_bit_depth, - &out_bits, &out_valid_bits, - out_fmt->s_type); - - if (in_bits != in_valid_bits || out_bits != out_valid_bits) - cd->dd[0]->process = - cd->converter[IPC4_COPIER_GATEWAY_PIN]; return ret; } + /* For ALH multi-gateway case, params->channels is a total multiplexed * number of channels. Demultiplexed number of channels for each individual * gateway comes in blob's struct ipc4_alh_multi_gtw_cfg. diff --git a/src/audio/copier/copier_generic.c b/src/audio/copier/copier_generic.c index ed31fb7414e7..4cb480ebe3f9 100644 --- a/src/audio/copier/copier_generic.c +++ b/src/audio/copier/copier_generic.c @@ -249,10 +249,26 @@ static bool use_no_container_convert_function(enum sof_ipc_frame in, return false; } +static bool is_remapping_chmap(uint32_t chmap, size_t out_channel_count) +{ + size_t i; + + assert(out_channel_count <= 8); + + for (i = 0; i < out_channel_count; i++) { + if ((chmap & 0xf) != i) + return true; + chmap >>= 4; + } + + return false; +} + pcm_converter_func get_converter_func(const struct ipc4_audio_format *in_fmt, const struct ipc4_audio_format *out_fmt, enum ipc4_gateway_type type, - enum ipc4_direction_type dir) + enum ipc4_direction_type dir, + uint32_t chmap) { enum sof_ipc_frame in, in_valid, out, out_valid; @@ -301,6 +317,16 @@ pcm_converter_func get_converter_func(const struct ipc4_audio_format *in_fmt, } } + if (in_fmt->channels_count != out_fmt->channels_count || + is_remapping_chmap(chmap, out_fmt->channels_count)) { + if (in_valid == SOF_IPC_FRAME_S16_LE && in == SOF_IPC_FRAME_S32_LE) + in = SOF_IPC_FRAME_S16_4LE; + if (out_valid == SOF_IPC_FRAME_S16_LE && out == SOF_IPC_FRAME_S32_LE) + out = SOF_IPC_FRAME_S16_4LE; + + return pcm_get_remap_function(in, out); + } + /* check container & sample size */ if (use_no_container_convert_function(in, in_valid, out, out_valid)) return pcm_get_conversion_function(in, out); diff --git a/src/audio/copier/copier_host.c b/src/audio/copier/copier_host.c index a7eafac04eaa..b61af44bfe0e 100644 --- a/src/audio/copier/copier_host.c +++ b/src/audio/copier/copier_host.c @@ -136,6 +136,7 @@ int copier_host_create(struct comp_dev *dev, struct copier_data *cd, enum sof_ipc_frame in_valid_fmt, out_valid_fmt; config->type = SOF_COMP_HOST; + cd->gtw_type = ipc4_gtw_host; audio_stream_fmt_conversion(copier_cfg->base.audio_fmt.depth, copier_cfg->base.audio_fmt.valid_bit_depth, @@ -195,7 +196,7 @@ int copier_host_create(struct comp_dev *dev, struct copier_data *cd, cd->converter[IPC4_COPIER_GATEWAY_PIN] = get_converter_func(&copier_cfg->base.audio_fmt, &copier_cfg->out_fmt, - ipc4_gtw_host, IPC4_DIRECTION(dir)); + ipc4_gtw_host, IPC4_DIRECTION(dir), DUMMY_CHMAP); if (!cd->converter[IPC4_COPIER_GATEWAY_PIN]) { comp_err(dev, "failed to get converter for host, dir %d", dir); ret = -EINVAL; diff --git a/src/audio/copier/copier_ipcgtw.c b/src/audio/copier/copier_ipcgtw.c index cdac60e98249..b5dccbd12986 100644 --- a/src/audio/copier/copier_ipcgtw.c +++ b/src/audio/copier/copier_ipcgtw.c @@ -229,6 +229,7 @@ int copier_ipcgtw_create(struct comp_dev *dev, struct copier_data *cd, * IPC gateway should be handled similarly as host gateway. */ config->type = SOF_COMP_HOST; + cd->gtw_type = ipc4_gtw_host; ret = create_endpoint_buffer(dev, cd, copier, false); if (ret < 0) @@ -255,7 +256,7 @@ int copier_ipcgtw_create(struct comp_dev *dev, struct copier_data *cd, cd->converter[IPC4_COPIER_GATEWAY_PIN] = get_converter_func(&copier->base.audio_fmt, &copier->out_fmt, - ipc4_gtw_host, IPC4_DIRECTION(cd->direction)); + ipc4_gtw_host, IPC4_DIRECTION(cd->direction), DUMMY_CHMAP); if (!cd->converter[IPC4_COPIER_GATEWAY_PIN]) { comp_err(dev, "failed to get converter for IPC gateway, dir %d", cd->direction); From cecd8a63cd4f27f2f877431f98f8724fd11a0b07 Mon Sep 17 00:00:00 2001 From: Serhiy Katsyuba Date: Mon, 17 Jun 2024 17:36:48 +0200 Subject: [PATCH 8/8] ipc4: copier: Add IPC4 channel map handler Adds IPC4_COPIER_MODULE_CFG_PARAM_CHANNEL_MAP handler that applies channel map to DAI gateway audio conversion function. Signed-off-by: Serhiy Katsyuba --- src/audio/copier/copier.c | 87 +++++++++++++++++++++++++++++++- src/audio/copier/copier.h | 14 ++++- src/audio/copier/copier_dai.c | 13 +++-- src/audio/copier/dai_copier.h | 4 ++ src/audio/dai-zephyr.c | 8 +-- src/include/sof/lib/dai-zephyr.h | 1 + 6 files changed, 118 insertions(+), 9 deletions(-) diff --git a/src/audio/copier/copier.c b/src/audio/copier/copier.c index 29a3943905a5..7c8d53726d20 100644 --- a/src/audio/copier/copier.c +++ b/src/audio/copier/copier.c @@ -661,6 +661,7 @@ static int copier_set_sink_fmt(struct comp_dev *dev, const void *data, const struct ipc4_copier_config_set_sink_format *sink_fmt = data; struct processing_module *mod = comp_mod(dev); struct copier_data *cd = module_get_private_data(mod); + uint32_t chmap; if (max_data_size < sizeof(*sink_fmt)) { comp_err(dev, "error: max_data_size %d should be bigger than %d", max_data_size, @@ -686,9 +687,15 @@ static int copier_set_sink_fmt(struct comp_dev *dev, const void *data, } cd->out_fmt[sink_fmt->sink_id] = sink_fmt->sink_fmt; + + if (cd->endpoint_num > 0 && dev->ipc_config.type == SOF_COMP_DAI) + chmap = cd->dd[0]->chmap; + else + chmap = DUMMY_CHMAP; + cd->converter[sink_fmt->sink_id] = get_converter_func(&sink_fmt->source_fmt, &sink_fmt->sink_fmt, ipc4_gtw_none, - ipc4_bidirection, DUMMY_CHMAP); + ipc4_bidirection, chmap); return 0; } @@ -728,6 +735,82 @@ static int set_attenuation(struct comp_dev *dev, uint32_t data_offset, const cha return 0; } +static int set_chmap(struct comp_dev *dev, const void *data, size_t data_size) +{ + const struct ipc4_copier_config_channel_map *chmap_cfg = data; + struct processing_module *mod = comp_mod(dev); + struct copier_data *cd = module_get_private_data(mod); + enum ipc4_direction_type dir; + struct ipc4_audio_format in_fmt = cd->config.base.audio_fmt; + struct ipc4_audio_format out_fmt = cd->config.out_fmt; + pcm_converter_func process; + pcm_converter_func converters[IPC4_COPIER_MODULE_OUTPUT_PINS_COUNT]; + int i; + uint32_t irq_flags; + + if (data_size < sizeof(*chmap_cfg)) { + comp_err(dev, "Wrong payload size: %d", data_size); + return -EINVAL; + } + + if (cd->endpoint_num == 0 || dev->ipc_config.type != SOF_COMP_DAI) { + comp_err(dev, "Only DAI gateway supports changing chmap"); + return -EINVAL; + } + + comp_info(dev, "New chmap requested: %x", chmap_cfg->channel_map); + + if (!cd->dd[0]->dma_buffer) { + /* DMA buffer not yet created. Remember the chmap, it will be used + * later in .params() handler. + * + * The assignment should be atomic as LL thread can preempt this IPC thread. + */ + cd->dd[0]->chmap = chmap_cfg->channel_map; + return 0; + } + + copier_dai_adjust_params(cd, &in_fmt, &out_fmt); + + dir = (cd->direction == SOF_IPC_STREAM_PLAYBACK) ? + ipc4_playback : ipc4_capture; + + process = get_converter_func(&in_fmt, &out_fmt, cd->gtw_type, dir, chmap_cfg->channel_map); + + if (!process) { + comp_err(dev, "No gtw converter func found!"); + return -EINVAL; + } + + /* Channel map is same for all sinks. However, as sinks allowed to have different + * sample formats, get new convert/remap function for each sink. + */ + for (i = 0; i < IPC4_COPIER_MODULE_OUTPUT_PINS_COUNT; i++) { + if (cd->converter[i]) { + converters[i] = get_converter_func(&in_fmt, &cd->out_fmt[i], + ipc4_gtw_none, ipc4_bidirection, + chmap_cfg->channel_map); + /* Do not report an error if converter not found as sinks could be + * bound/unbound on a fly and out_fmt[i] may contain obsolete data. + */ + } else { + converters[i] = NULL; + } + } + + /* Atomically update chmap, process and converters */ + irq_local_disable(irq_flags); + + cd->dd[0]->chmap = chmap_cfg->channel_map; + cd->dd[0]->process = process; + for (i = 0; i < IPC4_COPIER_MODULE_OUTPUT_PINS_COUNT; i++) + cd->converter[i] = converters[i]; + + irq_local_enable(irq_flags); + + return 0; +} + static int copier_set_configuration(struct processing_module *mod, uint32_t config_id, enum module_cfg_fragment_position pos, @@ -745,6 +828,8 @@ static int copier_set_configuration(struct processing_module *mod, return copier_set_sink_fmt(dev, fragment, fragment_size); case IPC4_COPIER_MODULE_CFG_ATTENUATION: return set_attenuation(dev, fragment_size, (const char *)fragment); + case IPC4_COPIER_MODULE_CFG_PARAM_CHANNEL_MAP: + return set_chmap(dev, fragment, fragment_size); default: return -EINVAL; } diff --git a/src/audio/copier/copier.h b/src/audio/copier/copier.h index 3f210e4d630e..41bca7afc287 100644 --- a/src/audio/copier/copier.h +++ b/src/audio/copier/copier.h @@ -180,7 +180,12 @@ enum ipc4_copier_module_config_params { * uint32_t. Config is only allowed when output pin is set up for 32bit and * source is connected to Gateway */ - IPC4_COPIER_MODULE_CFG_ATTENUATION = 6 + IPC4_COPIER_MODULE_CFG_ATTENUATION = 6, + /* Use LARGE_CONFIG_SET to setup new channel map, which allows to map channels + * from gateway buffer to copier with any order. + * Same mapping will be applied for all copier sinks. + */ + IPC4_COPIER_MODULE_CFG_PARAM_CHANNEL_MAP = 7 }; struct ipc4_copier_config_timestamp_init_data { @@ -201,6 +206,13 @@ struct ipc4_copier_config_set_sink_format { struct ipc4_audio_format sink_fmt; } __attribute__((packed, aligned(4))); +struct ipc4_copier_config_channel_map { + /* Each half-byte of the channel map is an index of the DMA stream channel that + * should be copied to the position determined by this half-byte index. + */ + uint32_t channel_map; +} __attribute__((packed, aligned(4))); + #define IPC4_COPIER_DATA_SEGMENT_DISABLE (0 << 0) #define IPC4_COPIER_DATA_SEGMENT_ENABLE (1 << 0) #define IPC4_COPIER_DATA_SEGMENT_RESTART (1 << 1) diff --git a/src/audio/copier/copier_dai.c b/src/audio/copier/copier_dai.c index 0228f095f9be..80866f6933c1 100644 --- a/src/audio/copier/copier_dai.c +++ b/src/audio/copier/copier_dai.c @@ -164,6 +164,7 @@ static int copier_dai_init(struct comp_dev *dev, { struct processing_module *mod = comp_mod(dev); struct copier_data *cd = module_get_private_data(mod); + uint32_t chmap; struct dai_data *dd; int ret; @@ -178,6 +179,7 @@ static int copier_dai_init(struct comp_dev *dev, config->frame_fmt = out_frame_fmt; pipeline->sink_comp = dev; cd->bsource_buffer = true; + chmap = copier->base.audio_fmt.ch_map; } else { enum sof_ipc_frame in_frame_fmt, in_valid_fmt; @@ -187,6 +189,7 @@ static int copier_dai_init(struct comp_dev *dev, copier->base.audio_fmt.s_type); config->frame_fmt = in_frame_fmt; pipeline->source_comp = dev; + chmap = copier->out_fmt.ch_map; } /* save the channel map and count for ALH multi-gateway */ @@ -205,6 +208,8 @@ static int copier_dai_init(struct comp_dev *dev, if (ret < 0) goto free_dd; + dd->chmap = chmap; + pipeline->sched_id = config->id; cd->dd[index] = dd; @@ -449,9 +454,9 @@ static int copy_single_channel_c32(const struct audio_stream *src, return 0; } -static void copier_dai_adjust_params(const struct copier_data *cd, - struct ipc4_audio_format *in_fmt, - struct ipc4_audio_format *out_fmt) +void copier_dai_adjust_params(const struct copier_data *cd, + struct ipc4_audio_format *in_fmt, + struct ipc4_audio_format *out_fmt) { struct comp_buffer *dma_buf; int dma_buf_channels; @@ -519,7 +524,7 @@ int copier_dai_params(struct copier_data *cd, struct comp_dev *dev, ipc4_playback : ipc4_capture; cd->dd[0]->process = - get_converter_func(&in_fmt, &out_fmt, cd->gtw_type, dir, DUMMY_CHMAP); + get_converter_func(&in_fmt, &out_fmt, cd->gtw_type, dir, cd->dd[0]->chmap); return ret; } diff --git a/src/audio/copier/dai_copier.h b/src/audio/copier/dai_copier.h index 4694b48ff1f2..a03970288b1b 100644 --- a/src/audio/copier/dai_copier.h +++ b/src/audio/copier/dai_copier.h @@ -83,6 +83,10 @@ void copier_dai_free(struct copier_data *cd); int copier_dai_prepare(struct comp_dev *dev, struct copier_data *cd); +void copier_dai_adjust_params(const struct copier_data *cd, + struct ipc4_audio_format *in_fmt, + struct ipc4_audio_format *out_fmt); + int copier_dai_params(struct copier_data *cd, struct comp_dev *dev, struct sof_ipc_stream_params *params, int dai_index); diff --git a/src/audio/dai-zephyr.c b/src/audio/dai-zephyr.c index c4ad228e4b40..c289b517e8d2 100644 --- a/src/audio/dai-zephyr.c +++ b/src/audio/dai-zephyr.c @@ -269,7 +269,7 @@ dai_dma_cb(struct dai_data *dd, struct comp_dev *dev, uint32_t bytes, if (dev->direction == SOF_IPC_STREAM_PLAYBACK) { ret = dma_buffer_copy_to(dd->local_buffer, dd->dma_buffer, - dd->process, bytes, DUMMY_CHMAP); + dd->process, bytes, dd->chmap); } else { audio_stream_invalidate(&dd->dma_buffer->stream, bytes); /* @@ -277,7 +277,7 @@ dai_dma_cb(struct dai_data *dd, struct comp_dev *dev, uint32_t bytes, * so no need to check the return value of dma_buffer_copy_from_no_consume(). */ ret = dma_buffer_copy_from_no_consume(dd->dma_buffer, dd->local_buffer, - dd->process, bytes, DUMMY_CHMAP); + dd->process, bytes, dd->chmap); #if CONFIG_IPC_MAJOR_4 struct list_item *sink_list; /* Skip in case of endpoint DAI devices created by the copier */ @@ -318,7 +318,7 @@ dai_dma_cb(struct dai_data *dd, struct comp_dev *dev, uint32_t bytes, sink->hw_params_configured) ret = dma_buffer_copy_from_no_consume(dd->dma_buffer, sink, converter[j], - bytes, DUMMY_CHMAP); + bytes, dd->chmap); } } #endif @@ -468,6 +468,8 @@ static struct comp_dev *dai_new(const struct comp_driver *drv, if (ret < 0) goto error; + dd->chmap = DUMMY_CHMAP; + dev->state = COMP_STATE_READY; return dev; diff --git a/src/include/sof/lib/dai-zephyr.h b/src/include/sof/lib/dai-zephyr.h index e909bfd40e05..b7f2f0f5c6f1 100644 --- a/src/include/sof/lib/dai-zephyr.h +++ b/src/include/sof/lib/dai-zephyr.h @@ -129,6 +129,7 @@ struct dai_data { int xrun; /* true if we are doing xrun recovery */ pcm_converter_func process; /* processing function */ + uint32_t chmap; channel_copy_func channel_copy; /* channel copy func used by multi-endpoint * gateway to mux/demux stream from/to multiple