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 <damian.nikodem@intel.com>
This commit is contained in:
Damian Nikodem 2024-06-05 10:41:33 +02:00 committed by Kai Vehmanen
parent ff0635ee84
commit 213306433f
4 changed files with 79 additions and 19 deletions

View File

@ -534,11 +534,11 @@ 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,
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);

View File

@ -268,15 +268,55 @@ 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,
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;
@ -316,7 +356,7 @@ 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,
ret = stream_copy_from_no_consume(dd->dma_buffer,
sink, converter[j],
bytes, dd->chmap);
}
@ -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;

View File

@ -447,8 +447,7 @@ 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,
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);

View File

@ -534,11 +534,11 @@ 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,
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);