From 213306433f9bd967a0ae90f9ae2e3714ba88abc0 Mon Sep 17 00:00:00 2001 From: Damian Nikodem Date: Wed, 5 Jun 2024 10:41:33 +0200 Subject: [PATCH] src: dai-zephyr: copy data to all available sinks In the case where the copier has more than one output and, additionally, we will be using a pin other than pin 0 (for example, when we want to copy data from pin 1 of a gateway-type copier to the next pipeline), it is necessary to copy data in playback path from the source to the output for all possible active sinks. Signed-off-by: Damian Nikodem --- posix/include/sof/lib/dma.h | 10 ++--- src/audio/dai-zephyr.c | 73 ++++++++++++++++++++++++++++++++++--- src/lib/dma.c | 5 +-- xtos/include/sof/lib/dma.h | 10 ++--- 4 files changed, 79 insertions(+), 19 deletions(-) diff --git a/posix/include/sof/lib/dma.h b/posix/include/sof/lib/dma.h index 4b6b2ae66..e1d7c2b75 100644 --- a/posix/include/sof/lib/dma.h +++ b/posix/include/sof/lib/dma.h @@ -534,14 +534,14 @@ int dma_buffer_copy_to(struct comp_buffer __sparse_cache *source, 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 + * Used when copying stream audio into multiple sink buffers, one at a time using the provided * conversion function. DMA buffer consume should be performed after the data has been copied * to all sinks. */ -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, uint32_t chmap); +int stream_copy_from_no_consume(struct comp_buffer __sparse_cache *source, + struct comp_buffer __sparse_cache *sink, + dma_process_func process, + uint32_t source_bytes, uint32_t chmap); /* generic DMA DSP <-> Host copier */ diff --git a/src/audio/dai-zephyr.c b/src/audio/dai-zephyr.c index c289b517e..90683aa58 100644 --- a/src/audio/dai-zephyr.c +++ b/src/audio/dai-zephyr.c @@ -268,16 +268,56 @@ dai_dma_cb(struct dai_data *dd, struct comp_dev *dev, uint32_t bytes, } if (dev->direction == SOF_IPC_STREAM_PLAYBACK) { +#if CONFIG_IPC_MAJOR_4 + struct list_item *sink_list; + /* + * copy from local buffer to all sinks that are not gateway buffers + * using the right PCM converter function. + */ + list_for_item(sink_list, &dev->bsink_list) { + struct comp_dev *sink_dev; + struct comp_buffer *sink; + int j; + + sink = container_of(sink_list, struct comp_buffer, source_list); + + if (sink == dd->dma_buffer) + continue; + + sink_dev = sink->sink; + + j = IPC4_SRC_QUEUE_ID(buf_get_id(sink)); + + if (j >= IPC4_COPIER_MODULE_OUTPUT_PINS_COUNT) { + comp_err(dev, "Sink queue ID: %d >= max output pin count: %d\n", + j, IPC4_COPIER_MODULE_OUTPUT_PINS_COUNT); + ret = -EINVAL; + continue; + } + + if (!converter[j]) { + comp_err(dev, "No PCM converter for sink queue %d\n", j); + ret = -EINVAL; + continue; + } + + if (sink_dev && sink_dev->state == COMP_STATE_ACTIVE && + sink->hw_params_configured) { + ret = stream_copy_from_no_consume(dd->local_buffer, sink, + converter[j], bytes, dd->chmap); + } + } +#endif ret = dma_buffer_copy_to(dd->local_buffer, dd->dma_buffer, dd->process, bytes, dd->chmap); } else { audio_stream_invalidate(&dd->dma_buffer->stream, bytes); /* * The PCM converter functions used during DMA buffer copy can never fail, - * so no need to check the return value of dma_buffer_copy_from_no_consume(). + * so no need to check the return value of stream_copy_from_no_consume(). */ - ret = dma_buffer_copy_from_no_consume(dd->dma_buffer, dd->local_buffer, - dd->process, bytes, dd->chmap); + ret = stream_copy_from_no_consume(dd->dma_buffer, dd->local_buffer, + 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 */ @@ -316,9 +356,9 @@ dai_dma_cb(struct dai_data *dd, struct comp_dev *dev, uint32_t bytes, 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, dd->chmap); + ret = stream_copy_from_no_consume(dd->dma_buffer, + sink, converter[j], + bytes, dd->chmap); } } #endif @@ -1553,6 +1593,27 @@ int dai_common_copy(struct dai_data *dd, struct comp_dev *dev, pcm_converter_fun 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); + + struct list_item *sink_list; + /* + * In the case of playback DAI's with multiple sink buffers, compute the + * minimum number of frames based on the DMA avail_bytes and the free + * samples in all active sink buffers. + */ + list_for_item(sink_list, &dev->bsink_list) { + struct comp_dev *sink_dev; + struct comp_buffer *sink; + + sink = container_of(sink_list, struct comp_buffer, source_list); + sink_dev = sink->sink; + + if (sink_dev && sink_dev->state == COMP_STATE_ACTIVE && + sink->hw_params_configured) { + sink_frames = + audio_stream_get_free_frames(&sink->stream); + frames = MIN(frames, sink_frames); + } + } } else { struct list_item *sink_list; diff --git a/src/lib/dma.c b/src/lib/dma.c index d889d1e3d..639bca473 100644 --- a/src/lib/dma.c +++ b/src/lib/dma.c @@ -447,9 +447,8 @@ int dma_buffer_copy_to(struct comp_buffer *source, return ret; } -int dma_buffer_copy_from_no_consume(struct comp_buffer *source, - struct comp_buffer *sink, - dma_process_func process, uint32_t source_bytes, uint32_t chmap) +int stream_copy_from_no_consume(struct comp_buffer *source, struct comp_buffer *sink, + 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); diff --git a/xtos/include/sof/lib/dma.h b/xtos/include/sof/lib/dma.h index bf333d198..8999fab16 100644 --- a/xtos/include/sof/lib/dma.h +++ b/xtos/include/sof/lib/dma.h @@ -534,14 +534,14 @@ int dma_buffer_copy_from(struct comp_buffer *source, 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 + * Used when copying stream audio into multiple sink buffers, one at a time using the provided * conversion function. DMA buffer consume should be performed after the data has been copied * to all sinks. */ -int dma_buffer_copy_from_no_consume(struct comp_buffer *source, - struct comp_buffer *sink, - dma_process_func process, - uint32_t source_bytes, uint32_t chmap); +int stream_copy_from_no_consume(struct comp_buffer *source, + struct comp_buffer *sink, + 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,