From d23f8e81d9cc41935f00b6f33ef53f65e440c5a4 Mon Sep 17 00:00:00 2001 From: Marcin Szkudlinski Date: Wed, 14 Aug 2024 15:55:28 +0200 Subject: [PATCH] buf: add secondary buffer support to struct audio_buffer secondary buffer mechanism is a feature independent of a buffer implementation, therefore it should be located in a base class for all buffers this commit intentionally is not removing the same feature from comp_buffer nor trying to use it anywhere Signed-off-by: Marcin Szkudlinski --- src/audio/CMakeLists.txt | 1 + src/audio/buffers/audio_buffer.c | 97 +++++++++++++++++ src/audio/source_api_helper.c | 1 + src/include/sof/audio/audio_buffer.h | 149 ++++++++++++++++++++++++--- zephyr/CMakeLists.txt | 1 + 5 files changed, 236 insertions(+), 13 deletions(-) create mode 100644 src/audio/buffers/audio_buffer.c diff --git a/src/audio/CMakeLists.txt b/src/audio/CMakeLists.txt index 2494c7ba5..76c7363a7 100644 --- a/src/audio/CMakeLists.txt +++ b/src/audio/CMakeLists.txt @@ -129,6 +129,7 @@ add_local_sources(sof component.c data_blob.c buffer.c + buffers/audio_buffer.c source_api_helper.c sink_api_helper.c sink_source_utils.c diff --git a/src/audio/buffers/audio_buffer.c b/src/audio/buffers/audio_buffer.c new file mode 100644 index 000000000..cca84a0a1 --- /dev/null +++ b/src/audio/buffers/audio_buffer.c @@ -0,0 +1,97 @@ +// SPDX-License-Identifier: BSD-3-Clause +// +// Copyright(c) 2024 Intel Corporation. All rights reserved. +// +// Author: Marcin Szkudlinski + +#include +#include +#include +#include +#include +#include +#include +#include + +#if CONFIG_PIPELINE_2_0 + +int audio_buffer_attach_secondary_buffer(struct sof_audio_buffer *buffer, bool at_input, + struct sof_audio_buffer *secondary_buffer) +{ + if (buffer->secondary_buffer_sink || buffer->secondary_buffer_source) + return -EINVAL; + + /* secondary buffer must share audio params with the primary buffer */ + secondary_buffer->audio_stream_params = buffer->audio_stream_params; + /* for performance reasons pointers to params are also kept in sink/src structures */ + secondary_buffer->_sink_api.audio_stream_params = buffer->audio_stream_params; + secondary_buffer->_source_api.audio_stream_params = buffer->audio_stream_params; + + if (at_input) + buffer->secondary_buffer_sink = secondary_buffer; + else + buffer->secondary_buffer_source = secondary_buffer; + + return 0; +} + +int audio_buffer_sync_secondary_buffer(struct sof_audio_buffer *buffer, size_t limit) +{ + int err; + + struct sof_source *data_src; + struct sof_sink *data_dst; + + if (buffer->secondary_buffer_sink) { + /* + * audio_buffer sink API is shadowed, that means there's a secondary_buffer + * at data input + * get data from secondary_buffer (use source API) + * copy to primary buffer (use sink API) + * note! can't use audio_buffer_get_sink because it will provide a shadowed + * sink handler (to a secondary buffer). + */ + data_src = audio_buffer_get_source(buffer->secondary_buffer_sink); + data_dst = &buffer->_sink_api; /* primary buffer's sink API */ + } else if (buffer->secondary_buffer_source) { + /* + * comp_buffer source API is shadowed, that means there's a secondary_buffer + * at data output + * get data from comp_buffer (use source API) + * copy to secondary_buffer (use sink API) + */ + data_src = &buffer->_source_api; + data_dst = audio_buffer_get_sink(buffer->secondary_buffer_source); + + } else { + return -EINVAL; + } + + /* + * keep data_available and free_size in local variables to avoid check_time/use_time + * race in MIN macro + */ + size_t data_available = source_get_data_available(data_src); + size_t free_size = sink_get_free_size(data_dst); + size_t to_copy = MIN(MIN(data_available, free_size), limit); + + err = source_to_sink_copy(data_src, data_dst, true, to_copy); + return err; +} + +#endif /* CONFIG_PIPELINE_2_0 */ + +void audio_buffer_free(struct sof_audio_buffer *buffer) +{ + if (!buffer) + return; + + CORE_CHECK_STRUCT(buffer); +#if CONFIG_PIPELINE_2_0 + audio_buffer_free(buffer->secondary_buffer_sink); + audio_buffer_free(buffer->secondary_buffer_source); +#endif /* CONFIG_PIPELINE_2_0 */ + if (buffer->free) + buffer->free(buffer); + rfree(buffer); +} diff --git a/src/audio/source_api_helper.c b/src/audio/source_api_helper.c index c7ca28c71..03d7b2169 100644 --- a/src/audio/source_api_helper.c +++ b/src/audio/source_api_helper.c @@ -3,6 +3,7 @@ * Copyright(c) 2023 Intel Corporation. All rights reserved. */ +#include #include #include diff --git a/src/include/sof/audio/audio_buffer.h b/src/include/sof/audio/audio_buffer.h index 356153924..bb8b48173 100644 --- a/src/include/sof/audio/audio_buffer.h +++ b/src/include/sof/audio/audio_buffer.h @@ -9,10 +9,11 @@ #include #include #include +#include +#include #define BUFFER_TYPE_LEGACY_BUFFER 1 -#define BUFFER_TYPE_LEGACY_RING_HYBRID 2 -#define BUFFER_TYPE_RING_BUFFER 3 +#define BUFFER_TYPE_RING_BUFFER 2 /* base class for all buffers, all buffers must inherit from it */ struct sof_audio_buffer { @@ -21,8 +22,34 @@ struct sof_audio_buffer { /* type of the buffer BUFFER_TYPE_* */ uint32_t buffer_type; - /* runtime stream params */ - struct sof_audio_stream_params audio_stream_params; +#if CONFIG_PIPELINE_2_0 + /** + * sink API of an additional buffer + * of any type at data input + * + * to be removed when hybrid buffers are no longer needed + */ + struct sof_audio_buffer *secondary_buffer_sink; + + /** + * source API of an additional buffer + * at data output + */ + struct sof_audio_buffer *secondary_buffer_source; + +#endif /* CONFIG_PIPELINE_2_0 */ + + /* effective runtime stream params + * before pipelin2.0 is ready, stream params may be kept in audio_stream structure + * also for hybrid buffering audio params need to be shared between primary and secondary + * buffers + * + * So currently only a pointer to effective stream params is here. + * Note that the same pointer MUST be set in source and sink api (kept there for + * performance reasons) + */ + struct sof_audio_stream_params *audio_stream_params; + /* private: */ struct sof_source _source_api; /**< src api handler */ @@ -36,6 +63,77 @@ struct sof_audio_buffer { void (*free)(struct sof_audio_buffer *buffer); }; +#if CONFIG_PIPELINE_2_0 +/* + * attach a secondary buffer (any type) before buffer (when at_input == true) or behind a buffer + * + * before buffer (at_input == true): + * 2.0 mod ==> (sink_API) secondary buffer ==> + * ==> comp_buffer (audio_stream or source API) ==> 1.0 mod + * + * after buffer (at_input == false): + * 1.0 mod ==> (audio_stream or sink API) ==> comp_buffer ==> + * ==> secondary buffer(source API) == 2.0 mod + * + * If a secondary buffer is attached, it replaces source or sink interface of audio_stream + * allowing the module connected to it using all properties of secondary buffer (like + * lockless cross-core connection in case of ring_buffer etc.) keeping legacy interface + * to other modules + * + * buffer_sync_secondary_buffer must be called every 1 ms to move data to/from + * secondary buffer to comp_buffer + * + * @param buffer pointer to a buffer + * @param at_input true indicates that a secondary buffer is located at data input, replacing + * sink API of audio_stream + * false indicates that a secondary buffer is located at data output, replacing + * source API of audio_stream + * @param secondary_buffer pointer to a buffer to be attached + * + * to be removed when hybrid buffers are no longer needed + */ +int audio_buffer_attach_secondary_buffer(struct sof_audio_buffer *buffer, bool at_input, + struct sof_audio_buffer *secondary_buffer); + +/* + * move data from/to secondary buffer, must be called periodically as described above + * + * @param buffer pointer to a buffer + * @param limit data copy limit. Indicates maximum amount of data that will be moved from/to + * secondary buffer in an operation + * + * to be removed when hybrid buffers are no longer needed + */ +int audio_buffer_sync_secondary_buffer(struct sof_audio_buffer *buffer, size_t limit); + +/** + * @brief return a handler to sink API of audio_buffer. + * the handler may be used by helper functions defined in sink_api.h + */ +static inline +struct sof_sink *audio_buffer_get_sink(struct sof_audio_buffer *buffer) +{ + CORE_CHECK_STRUCT(buffer); + return buffer->secondary_buffer_sink ? + audio_buffer_get_sink(buffer->secondary_buffer_sink) : + &buffer->_sink_api; +} + +/** + * @brief return a handler to source API of audio_buffer + * the handler may be used by helper functions defined in source_api.h + */ +static inline +struct sof_source *audio_buffer_get_source(struct sof_audio_buffer *buffer) +{ + CORE_CHECK_STRUCT(buffer); + return buffer->secondary_buffer_source ? + audio_buffer_get_source(buffer->secondary_buffer_source) : + &buffer->_source_api; +} + +#else /* CONFIG_PIPELINE_2_0 */ + /** * @brief return a handler to sink API of audio_buffer. * the handler may be used by helper functions defined in sink_api.h @@ -58,6 +156,17 @@ struct sof_source *audio_buffer_get_source(struct sof_audio_buffer *buffer) return &buffer->_source_api; } +#endif /* CONFIG_PIPELINE_2_0 */ + +/** + * @brief return a handler to stream params structure + */ +static inline +struct sof_audio_stream_params *audio_buffer_get_stream_params(struct sof_audio_buffer *buffer) +{ + return buffer->audio_stream_params; +} + /** * @brief return a pointer to struct sof_audio_buffer from sink pointer * NOTE! ensure that sink is really provided by sof_audio_buffer @@ -79,18 +188,32 @@ static inline struct sof_audio_buffer *sof_audo_buffer_from_source(struct sof_so } /** - * @brief free buffer and all allocated resources + * @brief initialize audio buffer structures + * + * @param buffer pointer to the audio_buffer + * @param buffer_type a type of the buffer, BUFFER_TYPE_* + * @param is_shared indicates if the buffer will be shared between cores + * @param source_ops pointer to virtual methods table for source API + * @param sink_ops pointer to virtual methods table for sink API + * @param audio_stream_params pointer to audio stream (currently kept in buffer implementation) */ static inline -void audio_buffer_free(struct sof_audio_buffer *buffer) +void audio_buffer_init(struct sof_audio_buffer *buffer, uint32_t buffer_type, bool is_shared, + const struct source_ops *source_ops, const struct sink_ops *sink_ops, + struct sof_audio_stream_params *audio_stream_params) { - if (!buffer) - return; - - CORE_CHECK_STRUCT(buffer); - if (buffer->free) - buffer->free(buffer); - rfree(buffer); + CORE_CHECK_STRUCT_INIT(&buffer, is_shared); + buffer->buffer_type = buffer_type; + buffer->audio_stream_params = audio_stream_params; + source_init(audio_buffer_get_source(buffer), source_ops, + audio_buffer_get_stream_params(buffer)); + sink_init(audio_buffer_get_sink(buffer), sink_ops, + audio_buffer_get_stream_params(buffer)); } +/** + * @brief free buffer and all allocated resources + */ +void audio_buffer_free(struct sof_audio_buffer *buffer); + #endif /* __SOF_AUDIO_BUFFER__ */ diff --git a/zephyr/CMakeLists.txt b/zephyr/CMakeLists.txt index c74596a06..bad33956f 100644 --- a/zephyr/CMakeLists.txt +++ b/zephyr/CMakeLists.txt @@ -416,6 +416,7 @@ zephyr_library_sources( # SOF mandatory audio processing ${SOF_AUDIO_PATH}/channel_map.c ${SOF_AUDIO_PATH}/buffer.c + ${SOF_AUDIO_PATH}/buffers/audio_buffer.c ${SOF_AUDIO_PATH}/source_api_helper.c ${SOF_AUDIO_PATH}/sink_api_helper.c ${SOF_AUDIO_PATH}/sink_source_utils.c