From 9c2589004898f8589b88e9f49c61aac7dee8090b Mon Sep 17 00:00:00 2001 From: Adrian Warecki Date: Fri, 13 Oct 2023 17:28:58 +0200 Subject: [PATCH] sof_api: sink: source: Move sink/source api headers to sof_api Moved header files to the sof_api directory to separate an shared interface used by sof and native loadable modules. Signed-off-by: Adrian Warecki --- src/audio/sink_api_helper.c | 86 --------- src/audio/source_api_helper.c | 78 -------- src/include/ipc/stream.h | 15 +- src/include/sof/audio/audio_stream.h | 40 +--- src/include/sof/audio/format.h | 38 +--- src/include/sof/audio/sink_api.h | 99 +--------- .../sof/audio/sink_api_implementation.h | 67 +------ src/include/sof/audio/source_api.h | 113 +---------- .../sof/audio/source_api_implementation.h | 69 +------ src/include/sof_api/audio/audio_stream.h | 54 ++++++ src/include/sof_api/audio/format.h | 51 +++++ src/include/sof_api/audio/sink_api.h | 178 +++++++++++++++++ .../sof_api/audio/sink_api_implementation.h | 83 ++++++++ src/include/sof_api/audio/source_api.h | 181 ++++++++++++++++++ .../sof_api/audio/source_api_implementation.h | 85 ++++++++ src/include/sof_api/ipc/stream.h | 25 +++ 16 files changed, 667 insertions(+), 595 deletions(-) create mode 100644 src/include/sof_api/audio/audio_stream.h create mode 100644 src/include/sof_api/audio/format.h create mode 100644 src/include/sof_api/audio/sink_api.h create mode 100644 src/include/sof_api/audio/sink_api_implementation.h create mode 100644 src/include/sof_api/audio/source_api.h create mode 100644 src/include/sof_api/audio/source_api_implementation.h create mode 100644 src/include/sof_api/ipc/stream.h diff --git a/src/audio/sink_api_helper.c b/src/audio/sink_api_helper.c index 46ffbfd6b860..12d633e1d815 100644 --- a/src/audio/sink_api_helper.c +++ b/src/audio/sink_api_helper.c @@ -14,47 +14,6 @@ void sink_init(struct sof_sink *sink, const struct sink_ops *ops, sink->audio_stream_params = audio_stream_params; } -size_t sink_get_free_size(struct sof_sink *sink) -{ - return sink->ops->get_free_size(sink); -} - -int sink_get_buffer(struct sof_sink *sink, size_t req_size, - void **data_ptr, void **buffer_start, size_t *buffer_size) -{ - int ret; - - if (sink->requested_write_frag_size) - return -EBUSY; - - ret = sink->ops->get_buffer(sink, req_size, data_ptr, - buffer_start, buffer_size); - - if (!ret) - sink->requested_write_frag_size = req_size; - return ret; -} - -int sink_commit_buffer(struct sof_sink *sink, size_t commit_size) -{ - int ret; - - /* check if there was a buffer obtained for writing by sink_get_buffer */ - if (!sink->requested_write_frag_size) - return -ENODATA; - - /* limit size of data to be committed to previously obtained size */ - if (commit_size > sink->requested_write_frag_size) - commit_size = sink->requested_write_frag_size; - - ret = sink->ops->commit_buffer(sink, commit_size); - - if (!ret) - sink->requested_write_frag_size = 0; - - sink->num_of_bytes_processed += commit_size; - return ret; -} size_t sink_get_num_of_processed_bytes(struct sof_sink *sink) { @@ -66,45 +25,11 @@ void sink_reset_num_of_processed_bytes(struct sof_sink *sink) sink->num_of_bytes_processed = 0; } -enum sof_ipc_frame sink_get_frm_fmt(struct sof_sink *sink) -{ - return sink->audio_stream_params->frame_fmt; -} - -enum sof_ipc_frame sink_get_valid_fmt(struct sof_sink *sink) -{ - return sink->audio_stream_params->valid_sample_fmt; -} - -uint32_t sink_get_rate(struct sof_sink *sink) -{ - return sink->audio_stream_params->rate; -} - -uint32_t sink_get_channels(struct sof_sink *sink) -{ - return sink->audio_stream_params->channels; -} - -uint32_t sink_get_buffer_fmt(struct sof_sink *sink) -{ - return sink->audio_stream_params->buffer_fmt; -} - bool sink_get_overrun(struct sof_sink *sink) { return sink->audio_stream_params->overrun_permitted; } -int sink_set_frm_fmt(struct sof_sink *sink, enum sof_ipc_frame frame_fmt) -{ - sink->audio_stream_params->frame_fmt = frame_fmt; - - /* notify the implementation */ - if (sink->ops->on_audio_format_set) - return sink->ops->on_audio_format_set(sink); - return 0; -} int sink_set_valid_fmt(struct sof_sink *sink, enum sof_ipc_frame valid_sample_fmt) @@ -147,17 +72,6 @@ int sink_set_overrun(struct sof_sink *sink, bool overrun_permitted) return 0; } -size_t sink_get_frame_bytes(struct sof_sink *sink) -{ - return get_frame_bytes(sink_get_frm_fmt(sink), - sink_get_channels(sink)); -} - -size_t sink_get_free_frames(struct sof_sink *sink) -{ - return sink_get_free_size(sink) / - sink_get_frame_bytes(sink); -} int sink_set_params(struct sof_sink *sink, struct sof_ipc_stream_params *params, bool force_update) diff --git a/src/audio/source_api_helper.c b/src/audio/source_api_helper.c index 91eb026812a9..a5870e9d9fa0 100644 --- a/src/audio/source_api_helper.c +++ b/src/audio/source_api_helper.c @@ -15,47 +15,6 @@ void source_init(struct sof_source *source, const struct source_ops *ops, source->audio_stream_params = audio_stream_params; } -size_t source_get_data_available(struct sof_source *source) -{ - return source->ops->get_data_available(source); -} - -int source_get_data(struct sof_source *source, size_t req_size, - void const **data_ptr, void const **buffer_start, size_t *buffer_size) -{ - int ret; - - if (source->requested_read_frag_size) - return -EBUSY; - - ret = source->ops->get_data(source, req_size, data_ptr, buffer_start, buffer_size); - - if (!ret) - source->requested_read_frag_size = req_size; - return ret; -} - -int source_release_data(struct sof_source *source, size_t free_size) -{ - int ret; - - /* Check if anything was obtained before for reading by source_get_data */ - if (!source->requested_read_frag_size) - return -ENODATA; - - /* limit size of data to be freed to previously obtained size */ - if (free_size > source->requested_read_frag_size) - free_size = source->requested_read_frag_size; - - ret = source->ops->release_data(source, free_size); - - if (!ret) - source->requested_read_frag_size = 0; - - source->num_of_bytes_processed += free_size; - return ret; -} - size_t source_get_num_of_processed_bytes(struct sof_source *source) { return source->num_of_bytes_processed; @@ -66,31 +25,6 @@ void source_reset_num_of_processed_bytes(struct sof_source *source) source->num_of_bytes_processed = 0; } -enum sof_ipc_frame source_get_frm_fmt(struct sof_source *source) -{ - return source->audio_stream_params->frame_fmt; -} - -enum sof_ipc_frame source_get_valid_fmt(struct sof_source *source) -{ - return source->audio_stream_params->valid_sample_fmt; -} - -unsigned int source_get_rate(struct sof_source *source) -{ - return source->audio_stream_params->rate; -} - -unsigned int source_get_channels(struct sof_source *source) -{ - return source->audio_stream_params->channels; -} - -uint32_t source_get_buffer_fmt(struct sof_source *source) -{ - return source->audio_stream_params->buffer_fmt; -} - bool source_get_underrun(struct sof_source *source) { return source->audio_stream_params->underrun_permitted; @@ -137,18 +71,6 @@ int source_set_underrun(struct sof_source *source, bool underrun_permitted) return 0; } -size_t source_get_frame_bytes(struct sof_source *source) -{ - return get_frame_bytes(source_get_frm_fmt(source), - source_get_channels(source)); -} - -size_t source_get_data_frames_available(struct sof_source *source) -{ - return source_get_data_available(source) / - source_get_frame_bytes(source); -} - int source_set_params(struct sof_source *source, struct sof_ipc_stream_params *params, bool force_update) { diff --git a/src/include/ipc/stream.h b/src/include/ipc/stream.h index 1c9bd7a824ac..95ea6f223292 100644 --- a/src/include/ipc/stream.h +++ b/src/include/ipc/stream.h @@ -1,6 +1,6 @@ /* SPDX-License-Identifier: BSD-3-Clause * - * Copyright(c) 2018 Intel Corporation. All rights reserved. + * Copyright(c) 2023 Intel Corporation. All rights reserved. * * Author: Liam Girdwood * Keyon Jie @@ -16,6 +16,7 @@ #ifndef __IPC_STREAM_H__ #define __IPC_STREAM_H__ +#include #include #include @@ -48,18 +49,6 @@ /* generic PCM flags for runtime settings */ #define SOF_PCM_FLAG_XRUN_STOP (1 << 0) /**< Stop on any XRUN */ -/* stream PCM frame format */ -enum sof_ipc_frame { - SOF_IPC_FRAME_S16_LE = 0, - SOF_IPC_FRAME_S24_4LE, - SOF_IPC_FRAME_S32_LE, - SOF_IPC_FRAME_FLOAT, - /* other formats here */ - SOF_IPC_FRAME_S24_3LE, - SOF_IPC_FRAME_S24_4LE_MSB, - SOF_IPC_FRAME_U8, -}; - /* stream buffer format */ enum sof_ipc_buffer_format { SOF_IPC_BUFFER_INTERLEAVED, diff --git a/src/include/sof/audio/audio_stream.h b/src/include/sof/audio/audio_stream.h index 49f3dab09245..afd1382ede53 100644 --- a/src/include/sof/audio/audio_stream.h +++ b/src/include/sof/audio/audio_stream.h @@ -1,6 +1,6 @@ /* SPDX-License-Identifier: BSD-3-Clause * - * Copyright(c) 2020 Intel Corporation. All rights reserved. + * Copyright(c) 2023 Intel Corporation. All rights reserved. * * Author: Karol Trzcinski */ @@ -26,6 +26,7 @@ #include #include #include +#include #include #include @@ -34,43 +35,6 @@ * @{ */ -/** - * set of parameters describing audio stream - * this structure is shared between audio_stream.h and sink/source interface - * TODO: compressed formats - */ -struct sof_audio_stream_params { - enum sof_ipc_frame frame_fmt; /**< Sample data format */ - enum sof_ipc_frame valid_sample_fmt; - - uint32_t rate; /**< Number of data frames per second [Hz] */ - uint16_t channels; /**< Number of samples in each frame */ - - /** - * align_frame_cnt indicates minimum number of frames that satisfies both byte - * align and frame align requirements. E.g: Consider an algorithm that processes - * in blocks of 3 frames configured to process 16-bit stereo using xtensa HiFi3 - * SIMD. Therefore with 16-bit stereo we have a frame size of 4 bytes, and - * SIMD intrinsic requirement of 8 bytes(2 frames) for HiFi3 and an algorithim - * requirement of 3 frames. Hence the common processing block size has to align - * with frame(1), intrinsic(2) and algorithm (3) giving us an optimum processing - * block size of 6 frames. - */ - uint16_t align_frame_cnt; - - /** - * the free/available bytes of sink/source right shift align_shift_idx, the result - * multiplied by align_frame_cnt is the frame count free/available that can meet - * the align requirement. - */ - uint16_t align_shift_idx; - - bool overrun_permitted; /**< indicates whether overrun is permitted */ - bool underrun_permitted; /**< indicates whether underrun is permitted */ - - uint32_t buffer_fmt; /**< enum sof_ipc_buffer_format */ -}; - /** * Audio stream is a circular buffer aware of audio format of the data * in the buffer so provides API for reading and writing not only bytes, diff --git a/src/include/sof/audio/format.h b/src/include/sof/audio/format.h index a33d3c60fce4..161d2fff773a 100644 --- a/src/include/sof/audio/format.h +++ b/src/include/sof/audio/format.h @@ -1,6 +1,6 @@ /* SPDX-License-Identifier: BSD-3-Clause * - * Copyright(c) 2016 Intel Corporation. All rights reserved. + * Copyright(c) 2023 Intel Corporation. All rights reserved. * * Author: Seppo Ingalsuo * Liam Girdwood @@ -28,6 +28,7 @@ #include #include +#include /* Maximum and minimum values for 24 bit */ #define INT24_MAXVALUE 8388607 @@ -165,39 +166,4 @@ static inline int32_t sign_extend_s24(int32_t x) return (x << 8) >> 8; } -static inline uint32_t get_sample_bytes(enum sof_ipc_frame fmt) -{ - switch (fmt) { - case SOF_IPC_FRAME_S16_LE: - return 2; - case SOF_IPC_FRAME_S24_3LE: - return 3; - case SOF_IPC_FRAME_U8: - return 1; - default: - return 4; - } -} - -static inline uint32_t get_sample_bitdepth(enum sof_ipc_frame fmt) -{ - switch (fmt) { - case SOF_IPC_FRAME_S16_LE: - return 16; - case SOF_IPC_FRAME_S24_4LE: - case SOF_IPC_FRAME_S24_3LE: - return 24; - case SOF_IPC_FRAME_U8: - return 8; - default: - return 32; - } -} - -static inline uint32_t get_frame_bytes(enum sof_ipc_frame fmt, - uint32_t channels) -{ - return get_sample_bytes(fmt) * channels; -} - #endif /* __SOF_AUDIO_FORMAT_H__ */ diff --git a/src/include/sof/audio/sink_api.h b/src/include/sof/audio/sink_api.h index bb279166c167..39b4f61834f4 100644 --- a/src/include/sof/audio/sink_api.h +++ b/src/include/sof/audio/sink_api.h @@ -7,96 +7,7 @@ #ifndef __SOF_SINK_API_H__ #define __SOF_SINK_API_H__ -#include -#include -#include -#include - -/** - * this is a definition of API to sink of audio data - * - * THE SINK is any component that can store data somehow and provide a buffer to be filled - * with data at request. The sink API does not define how the data will be processed/used - * - * The user - a module - sees this API as a destination it must send data to - * The IMPLEMENTATION - audio_stream, DP Queue - sees this as a producer that - * PROVIDES data for processing - * - * Examples of components that should expose SINK api - * - /dev/null - * all the data stored in sink buffer are just simply discarded - * - I2S sender - * Data stored in sink buffer will be sent to the external world - * - a memory ring buffer - * data stored in the buffer will be sent to another module (usually using source API, but it - * does not matter in fact). - * - * The main advantage of using sink API instead of just taking pointers to the buffers is that - * the buffer may be prepared at the moment the data producer is requesting it. i.e. - * - cache may be written back/invalidated if necessary - * - data may be moved to make linear space - * - part of the buffer may be locked to prevent reading - * etc.etc. it depends on implementation of the data sink - * - * NOTE: the module should get a complete portion of space it needs for processing, fill it - * than release. The reason is - the depending on the implementation, the calls may be - * expensive - may involve some data moving in memory, cache writebacks, etc. - * - */ - -/** definition of obfsfucated handler of sink API */ -struct sof_sink; - -/* forward def */ -struct sof_ipc_stream_params; - -/** - * Retrieves size of free space available in sink (in bytes) - * return number of free bytes in buffer available to immediate filling - */ -size_t sink_get_free_size(struct sof_sink *sink); - -/** - * Retrieves size of free space available in sink (in frames) - * return number of free bytes in buffer available to immediate filling - */ -size_t sink_get_free_frames(struct sof_sink *sink); - -/** - * Get a circular buffer to operate on (to write). - * - * Retrieves a fragment of circular data to be used by the caller - * After calling get_buffer, the space for data is guaranteed to be available - * for exclusive use on the caller core through provided pointer - * if the provided pointers are cached, it is guaranteed that the caller may safely use it without - * any additional cache operations - * The caller MUST take care of data circularity based on provided pointers - * - * @param sink a handler to sink - * @param [in] req_size requested size of space - * @param [out] data_ptr a pointer to the space will be provided there - * @param [out] buffer_start pointer to circular buffer start - * @param [out] buffer_size size of circular buffer - * - * @retval -ENODATA if req_size is bigger than free space - * - */ -int sink_get_buffer(struct sof_sink *sink, size_t req_size, - void **data_ptr, void **buffer_start, size_t *buffer_size); - -/** - * Commits that the buffer previously obtained by get_buffer is filled with data - * and ready to be used - * - * @param sink a handler to sink - * @param commit_size amount of data that the caller declares as valid - * if commit_size is bigger than the amount of data obtained before by get_buffer(), only - * the amount obtained before will be committed. That means - if somebody obtained a buffer, - * filled it with data and wants to commit it in whole, it may simple call - * commit_buffer with commit_size==MAXINT - * @return proper error code (0 on success) - */ -int sink_commit_buffer(struct sof_sink *sink, size_t commit_size); +#include /** * Get total number of bytes processed by the sink (meaning - committed by sink_commit_buffer()) @@ -111,15 +22,7 @@ size_t sink_get_num_of_processed_bytes(struct sof_sink *sink); */ void sink_reset_num_of_processed_bytes(struct sof_sink *sink); -/** get size of a single audio frame (in bytes) */ -size_t sink_get_frame_bytes(struct sof_sink *sink); - /** set of functions for retrieve audio parameters */ -enum sof_ipc_frame sink_get_frm_fmt(struct sof_sink *sink); -enum sof_ipc_frame sink_get_valid_fmt(struct sof_sink *sink); -uint32_t sink_get_rate(struct sof_sink *sink); -uint32_t sink_get_channels(struct sof_sink *sink); -uint32_t sink_get_buffer_fmt(struct sof_sink *sink); bool sink_get_overrun(struct sof_sink *sink); /** set of functions for setting audio parameters */ diff --git a/src/include/sof/audio/sink_api_implementation.h b/src/include/sof/audio/sink_api_implementation.h index 23cec8dbb30e..01b79c7de2ae 100644 --- a/src/include/sof/audio/sink_api_implementation.h +++ b/src/include/sof/audio/sink_api_implementation.h @@ -11,72 +11,7 @@ #include #include -/* forward def */ -struct sof_audio_stream_params; - -/** - * this is a definition of internals of sink API - * - * this file should be included by the implementations of sink API - * - * The clients of stream API should use functions provided in sink_api.h ONLY - * - */ - -struct sink_ops { - /** - * see comment of sink_get_free_size() - */ - size_t (*get_free_size)(struct sof_sink *sink); - - /** - * see comment of sink_get_buffer() - */ - int (*get_buffer)(struct sof_sink *sink, size_t req_size, - void **data_ptr, void **buffer_start, size_t *buffer_size); - - /** - * see comment of sink_commit_buffer() - */ - int (*commit_buffer)(struct sof_sink *sink, size_t commit_size); - - /** - * OPTIONAL: Notification to the sink implementation about changes in audio format - * - * Once any of *audio_stream_params elements changes, the implementation of - * sink may need to perform some extra operations. - * This callback will be called immediately after any change - * - * @retval 0 if success, negative if new parameters are not supported - */ - int (*on_audio_format_set)(struct sof_sink *sink); - - /** - * OPTIONAL - * see sink_set_params comments - */ - int (*audio_set_ipc_params)(struct sof_sink *sink, - struct sof_ipc_stream_params *params, bool force_update); - - /** - * OPTIONAL - * see comment for sink_set_alignment_constants - */ - int (*set_alignment_constants)(struct sof_sink *sink, - const uint32_t byte_align, - const uint32_t frame_align_req); -}; - -/** internals of sink API. NOT TO BE MODIFIED OUTSIDE OF sink_api_helper.h */ -struct sof_sink { - const struct sink_ops *ops; /** operations interface */ - size_t requested_write_frag_size; /** keeps number of bytes requested by get_buffer() */ - size_t num_of_bytes_processed; /** processed bytes counter */ - size_t min_free_space; /** minimum buffer space required by the module using sink - * it is module's OBS as declared in module bind IPC - */ - struct sof_audio_stream_params *audio_stream_params; /** pointer to audio params */ -}; +#include /** * Init of the API, must be called before any operation diff --git a/src/include/sof/audio/source_api.h b/src/include/sof/audio/source_api.h index 70b3ce38c909..726a69406b33 100644 --- a/src/include/sof/audio/source_api.h +++ b/src/include/sof/audio/source_api.h @@ -7,110 +7,7 @@ #ifndef __SOF_SOURCE_API_H__ #define __SOF_SOURCE_API_H__ -#include -#include -#include -#include - -/** - * this is a definition of API to source of audio data - * - * THE SOURCE is any component in the system that have data stored somehow and can give the - * data outside at request. The source API does not define who and how has produced the data - * - * The user - a module - sees this as a producer that PROVIDES data for processing - * The IMPLEMENTATION - audio_stream, DP Queue - sees this API as a destination it must send data to - * * - * Examples of components that should expose source API: - * - DMIC - * Data are coming from the outside world, stores in tmp buffer and can be presented - * to the rest of the system using source_api - * - a memory ring buffer - * Data are coming from other module (usually using sink_api, but it does not matter in fact) - * - * The main advantage of using source API instead of just taking pointers to the data is that - * the data may be prepared at the moment the data receiver is requesting it. i.e. - * - cache may be written back/invalidated if necessary - * - data may be moved from circular to linear space - * - part of the buffer may be locked to prevent writing - * etc.etc. it depends on implementation of the data source - * - * Data in general are provided as a circular buffer and the data receiver should be able to - * deal with it. Of course if needed an implementation of source providing linear data can be - * implemented and used as a mid-layer for modules needing it. - * - * NOTE: the module should get a complete portion of data it needs for processing, process it - * than release. The reason is - the depending on the implementation, the calls may be - * expensive - may involve some data moving in memory, cache writebacks, etc. - */ - -/** definition of obfsfucated handler of source API */ -struct sof_source; - -/* forward def */ -struct sof_ipc_stream_params; - -/** - * Retrieves size of available data (in bytes) - * return number of bytes that are available for immediate use - */ -size_t source_get_data_available(struct sof_source *source); - -/** - * Retrieves size of available data (in frames) - * return number of bytes that are available for immediate use - */ -size_t source_get_data_frames_available(struct sof_source *source); - -/** - * Retrieves a fragment of circular data to be used by the caller (to read) - * After calling get_data, the data are guaranteed to be available - * for exclusive use (read only) - * if the provided pointers are cached, it is guaranteed that the caller may safely use it without - * any additional cache operations - * - * The caller MUST take care of data circularity based on provided pointers - * - * Depending on implementation - there may be a way to have several receivers of the same - * data, as long as the receiver respects that data are read-only and won'do anything - * fancy with cache handling itself - * - * some implementation data may be stored in linear buffer - * in that case: - * data_ptr = buffer_start - * buffer_end = data_ptr + req_size - * buffer_size = req_size - * - * and the data receiver may use it as usual, rollover will simple never occur - * NOTE! the caller MUST NOT assume that pointers to start/end of the circular buffer - * are constant. They may change between calls - * - * @param source a handler to source - * @param [in] req_size requested size of data. - * @param [out] data_ptr a pointer to data will be provided there - * @param [out] buffer_start pointer to circular buffer start - * @param [out] buffer_size size of circular buffer - * - * @retval -ENODATA if req_size is bigger than available data - */ -int source_get_data(struct sof_source *source, size_t req_size, - void const **data_ptr, void const **buffer_start, size_t *buffer_size); - -/** - * Releases fragment previously obtained by source_get_data() - * Once called, the data are no longer available for the caller - * - * @param source a handler to source - * @param free_size amount of data that the caller declares as "never needed again" - * if free_size == 0 the source implementation MUST keep all data in memory and make them - * available again at next get_data() call - * if free_size is bigger than the amount of data obtained before by get_data(), only - * the amount obtained before will be freed. That means - if somebody obtained some data, - * processed it and won't need it again, it may simple call put_data with free_size==MAXINT - * - * @return proper error code (0 on success) - */ -int source_release_data(struct sof_source *source, size_t free_size); +#include /** * Get total number of bytes processed by the source (meaning - freed by source_release_data()) @@ -122,15 +19,7 @@ size_t source_get_num_of_processed_bytes(struct sof_source *source); */ void source_reset_num_of_processed_bytes(struct sof_source *source); -/** get size of a single audio frame (in bytes) */ -size_t source_get_frame_bytes(struct sof_source *source); - /** set of functions for retrieve audio parameters */ -enum sof_ipc_frame source_get_frm_fmt(struct sof_source *source); -enum sof_ipc_frame source_get_valid_fmt(struct sof_source *source); -unsigned int source_get_rate(struct sof_source *source); -unsigned int source_get_channels(struct sof_source *source); -uint32_t source_get_buffer_fmt(struct sof_source *source); bool source_get_underrun(struct sof_source *source); /** set of functions for setting audio parameters */ diff --git a/src/include/sof/audio/source_api_implementation.h b/src/include/sof/audio/source_api_implementation.h index 606141c92dfb..c0e86a753b65 100644 --- a/src/include/sof/audio/source_api_implementation.h +++ b/src/include/sof/audio/source_api_implementation.h @@ -11,74 +11,7 @@ #include #include -/* forward def */ -struct sof_audio_stream_params; - -/** - * this is a definition of internals of source API - * - * this file should be included by the implementations of source API - * - * The clients of stream API should use functions provided in source_api.h ONLY - * - */ - -struct source_ops { - /** - * see comment of source_get_data_available() - */ - size_t (*get_data_available)(struct sof_source *source); - - /** - * see comment of source_get_data_available() - */ - int (*get_data)(struct sof_source *source, size_t req_size, - void const **data_ptr, void const **buffer_start, size_t *buffer_size); - - /** - * see comment of source_release_data() - */ - int (*release_data)(struct sof_source *source, size_t free_size); - - /** - * OPTIONAL: Notification to the source implementation about changes in audio format - * - * Once any of *audio_stream_params elements changes, the implementation of - * source may need to perform some extra operations. - * This callback will be called immediately after any change - * - * @retval 0 if success, negative if new parameteres are not supported - */ - int (*on_audio_format_set)(struct sof_source *source); - - /** - * OPTIONAL - * see source_set_params comments - */ - int (*audio_set_ipc_params)(struct sof_source *source, - struct sof_ipc_stream_params *params, bool force_update); - - /** - * OPTIONAL - * see comment for source_set_alignment_constants - */ - int (*set_alignment_constants)(struct sof_source *source, - const uint32_t byte_align, - const uint32_t frame_align_req); -}; - -/** internals of source API. NOT TO BE MODIFIED OUTSIDE OF source_api_helper.h */ -struct sof_source { - const struct source_ops *ops; - size_t requested_read_frag_size; /** keeps size of data obtained by get_data() */ - size_t num_of_bytes_processed; /** processed bytes counter */ - size_t min_available; /** minimum data available required by the module using - * source - * it is module's IBS as declared in module bind IPC - */ - - struct sof_audio_stream_params *audio_stream_params; -}; +#include /** * Init of the API, must be called before any operation diff --git a/src/include/sof_api/audio/audio_stream.h b/src/include/sof_api/audio/audio_stream.h new file mode 100644 index 000000000000..21466420fb66 --- /dev/null +++ b/src/include/sof_api/audio/audio_stream.h @@ -0,0 +1,54 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * + * Copyright(c) 2023 Intel Corporation. All rights reserved. + * + * Author: Karol Trzcinski + * Adrian Warecki + */ + +#ifndef __SOF_API_AUDIO_AUDIO_STREAM_H__ +#define __SOF_API_AUDIO_AUDIO_STREAM_H__ + +#include +#include +#include "../ipc/stream.h" + +/** + * set of parameters describing audio stream + * this structure is shared between audio_stream.h and sink/source interface + * TODO: compressed formats + */ +struct sof_audio_stream_params { + enum sof_ipc_frame frame_fmt; /**< Sample data format */ + enum sof_ipc_frame valid_sample_fmt; + + uint32_t rate; /**< Number of data frames per second [Hz] */ + uint16_t channels; /**< Number of samples in each frame */ + + /** + * align_frame_cnt indicates minimum number of frames that satisfies both byte + * align and frame align requirements. E.g: Consider an algorithm that processes + * in blocks of 3 frames configured to process 16-bit stereo using xtensa HiFi3 + * SIMD. Therefore with 16-bit stereo we have a frame size of 4 bytes, and + * SIMD intrinsic requirement of 8 bytes(2 frames) for HiFi3 and an algorithim + * requirement of 3 frames. Hence the common processing block size has to align + * with frame(1), intrinsic(2) and algorithm (3) giving us an optimum processing + * block size of 6 frames. + */ + uint16_t align_frame_cnt; + + /** + * the free/available bytes of sink/source right shift align_shift_idx, the result + * multiplied by align_frame_cnt is the frame count free/available that can meet + * the align requirement. + */ + uint16_t align_shift_idx; + + bool overrun_permitted; /**< indicates whether overrun is permitted */ + bool underrun_permitted; /**< indicates whether underrun is permitted */ + + uint32_t buffer_fmt; /**< enum sof_ipc_buffer_format */ +}; + + +#endif /* __SOF_API_AUDIO_AUDIO_STREAM_H__ */ diff --git a/src/include/sof_api/audio/format.h b/src/include/sof_api/audio/format.h new file mode 100644 index 000000000000..e34693d3a90c --- /dev/null +++ b/src/include/sof_api/audio/format.h @@ -0,0 +1,51 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * + * Copyright(c) 2023 Intel Corporation. All rights reserved. + * + * Author: Seppo Ingalsuo + * Liam Girdwood + * Keyon Jie + * Adrian Warecki + */ + +#ifndef __SOF_API_AUDIO_FORMAT_H__ +#define __SOF_API_AUDIO_FORMAT_H__ + +#include +#include "../ipc/stream.h" + +static inline uint32_t get_sample_bytes(enum sof_ipc_frame fmt) +{ + switch (fmt) { + case SOF_IPC_FRAME_S16_LE: + return 2; + case SOF_IPC_FRAME_S24_3LE: + return 3; + case SOF_IPC_FRAME_U8: + return 1; + default: + return 4; + } +} + +static inline uint32_t get_sample_bitdepth(enum sof_ipc_frame fmt) +{ + switch (fmt) { + case SOF_IPC_FRAME_S16_LE: + return 16; + case SOF_IPC_FRAME_S24_4LE: + case SOF_IPC_FRAME_S24_3LE: + return 24; + case SOF_IPC_FRAME_U8: + return 8; + default: + return 32; + } +} + +static inline uint32_t get_frame_bytes(enum sof_ipc_frame fmt, uint32_t channels) +{ + return get_sample_bytes(fmt) * channels; +} + +#endif /* __SOF_API_AUDIO_FORMAT_H__ */ diff --git a/src/include/sof_api/audio/sink_api.h b/src/include/sof_api/audio/sink_api.h new file mode 100644 index 000000000000..42d2e68b36fd --- /dev/null +++ b/src/include/sof_api/audio/sink_api.h @@ -0,0 +1,178 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * + * Copyright(c) 2023 Intel Corporation. All rights reserved. + * + */ + +#ifndef __SOF_API_AUDIO_SINK_API_H__ +#define __SOF_API_AUDIO_SINK_API_H__ + +#include +#include +#include +#include + +#include "sink_api_implementation.h" +#include "audio_stream.h" +#include "format.h" + +/** + * this is a definition of API to sink of audio data + * + * THE SINK is any component that can store data somehow and provide a buffer to be filled + * with data at request. The sink API does not define how the data will be processed/used + * + * The user - a module - sees this API as a destination it must send data to + * The IMPLEMENTATION - audio_stream, DP Queue - sees this as a producer that + * PROVIDES data for processing + * + * Examples of components that should expose SINK api + * - /dev/null + * all the data stored in sink buffer are just simply discarded + * - I2S sender + * Data stored in sink buffer will be sent to the external world + * - a memory ring buffer + * data stored in the buffer will be sent to another module (usually using source API, but it + * does not matter in fact). + * + * The main advantage of using sink API instead of just taking pointers to the buffers is that + * the buffer may be prepared at the moment the data producer is requesting it. i.e. + * - cache may be written back/invalidated if necessary + * - data may be moved to make linear space + * - part of the buffer may be locked to prevent reading + * etc.etc. it depends on implementation of the data sink + * + * NOTE: the module should get a complete portion of space it needs for processing, fill it + * than release. The reason is - the depending on the implementation, the calls may be + * expensive - may involve some data moving in memory, cache writebacks, etc. + * + */ + +/** + * Retrieves size of free space available in sink (in bytes) + * return number of free bytes in buffer available to immediate filling + */ +static inline size_t sink_get_free_size(struct sof_sink *sink) +{ + return sink->ops->get_free_size(sink); +} + +static inline enum sof_ipc_frame sink_get_frm_fmt(struct sof_sink *sink) +{ + return sink->audio_stream_params->frame_fmt; +} + +static inline uint32_t sink_get_channels(struct sof_sink *sink) +{ + return sink->audio_stream_params->channels; +} + +/** get size of a single audio frame (in bytes) */ +static inline size_t sink_get_frame_bytes(struct sof_sink *sink) +{ + return get_frame_bytes(sink_get_frm_fmt(sink), sink_get_channels(sink)); +} + +/** + * Retrieves size of free space available in sink (in frames) + * return number of free frames in buffer available to immediate filling + */ +static inline size_t sink_get_free_frames(struct sof_sink *sink) +{ + return sink_get_free_size(sink) / sink_get_frame_bytes(sink); +} + +/** + * Get a circular buffer to operate on (to write). + * + * Retrieves a fragment of circular data to be used by the caller + * After calling get_buffer, the space for data is guaranteed to be available + * for exclusive use on the caller core through provided pointer + * if the provided pointers are cached, it is guaranteed that the caller may safely use it without + * any additional cache operations + * The caller MUST take care of data circularity based on provided pointers + * + * @param sink a handler to sink + * @param [in] req_size requested size of space + * @param [out] data_ptr a pointer to the space will be provided there + * @param [out] buffer_start pointer to circular buffer start + * @param [out] buffer_size size of circular buffer + * + * @retval -ENODATA if req_size is bigger than free space + * + */ +static inline int sink_get_buffer(struct sof_sink *sink, size_t req_size, + void **data_ptr, void **buffer_start, size_t *buffer_size) +{ + int ret; + + if (sink->requested_write_frag_size) + return -EBUSY; + + ret = sink->ops->get_buffer(sink, req_size, data_ptr, buffer_start, buffer_size); + + if (!ret) + sink->requested_write_frag_size = req_size; + return ret; +} + +/** + * Commits that the buffer previously obtained by get_buffer is filled with data + * and ready to be used + * + * @param sink a handler to sink + * @param commit_size amount of data that the caller declares as valid + * if commit_size is bigger than the amount of data obtained before by get_buffer(), only + * the amount obtained before will be committed. That means - if somebody obtained a buffer, + * filled it with data and wants to commit it in whole, it may simple call + * commit_buffer with commit_size==MAXINT + * @return proper error code (0 on success) + */ +static inline int sink_commit_buffer(struct sof_sink *sink, size_t commit_size) +{ + int ret; + + /* check if there was a buffer obtained for writing by sink_get_buffer */ + if (!sink->requested_write_frag_size) + return -ENODATA; + + /* limit size of data to be committed to previously obtained size */ + if (commit_size > sink->requested_write_frag_size) + commit_size = sink->requested_write_frag_size; + + ret = sink->ops->commit_buffer(sink, commit_size); + + if (!ret) + sink->requested_write_frag_size = 0; + + sink->num_of_bytes_processed += commit_size; + return ret; +} + +/** set of functions for retrieve audio parameters */ +static inline int sink_set_frm_fmt(struct sof_sink *sink, enum sof_ipc_frame frame_fmt) +{ + sink->audio_stream_params->frame_fmt = frame_fmt; + + /* notify the implementation */ + if (sink->ops->on_audio_format_set) + return sink->ops->on_audio_format_set(sink); + return 0; +} + +static inline enum sof_ipc_frame sink_get_valid_fmt(struct sof_sink *sink) +{ + return sink->audio_stream_params->valid_sample_fmt; +} + +static inline uint32_t sink_get_rate(struct sof_sink *sink) +{ + return sink->audio_stream_params->rate; +} + +static inline uint32_t sink_get_buffer_fmt(struct sof_sink *sink) +{ + return sink->audio_stream_params->buffer_fmt; +} + +#endif /* __SOF_API_AUDIO_SINK_API_H__ */ diff --git a/src/include/sof_api/audio/sink_api_implementation.h b/src/include/sof_api/audio/sink_api_implementation.h new file mode 100644 index 000000000000..a581ea09d32f --- /dev/null +++ b/src/include/sof_api/audio/sink_api_implementation.h @@ -0,0 +1,83 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * + * Copyright(c) 2023 Intel Corporation. All rights reserved. + * + */ + +#ifndef __SOF_API_AUDIO_SINK_API_IMPLEMENTATION_H__ +#define __SOF_API_AUDIO_SINK_API_IMPLEMENTATION_H__ + +#include +#include +#include + +/* forward def */ +struct sof_sink; +struct sof_audio_stream_params; +struct sof_ipc_stream_params; + +/** + * this is a definition of internals of sink API + * + * this file should be included by the implementations of sink API + * + * The clients of stream API should use functions provided in sink_api.h ONLY + * + */ + +struct sink_ops { + /** + * see comment of sink_get_free_size() + */ + size_t (*get_free_size)(struct sof_sink *sink); + + /** + * see comment of sink_get_buffer() + */ + int (*get_buffer)(struct sof_sink *sink, size_t req_size, + void **data_ptr, void **buffer_start, size_t *buffer_size); + + /** + * see comment of sink_commit_buffer() + */ + int (*commit_buffer)(struct sof_sink *sink, size_t commit_size); + + /** + * OPTIONAL: Notification to the sink implementation about changes in audio format + * + * Once any of *audio_stream_params elements changes, the implementation of + * sink may need to perform some extra operations. + * This callback will be called immediately after any change + * + * @retval 0 if success, negative if new parameters are not supported + */ + int (*on_audio_format_set)(struct sof_sink *sink); + + /** + * OPTIONAL + * see sink_set_params comments + */ + int (*audio_set_ipc_params)(struct sof_sink *sink, + struct sof_ipc_stream_params *params, bool force_update); + + /** + * OPTIONAL + * see comment for sink_set_alignment_constants + */ + int (*set_alignment_constants)(struct sof_sink *sink, + const uint32_t byte_align, + const uint32_t frame_align_req); +}; + +/** internals of sink API. NOT TO BE MODIFIED OUTSIDE OF sink_api_helper.h */ +struct sof_sink { + const struct sink_ops *ops; /** operations interface */ + size_t requested_write_frag_size; /** keeps number of bytes requested by get_buffer() */ + size_t num_of_bytes_processed; /** processed bytes counter */ + size_t min_free_space; /** minimum buffer space required by the module using sink + * it is module's OBS as declared in module bind IPC + */ + struct sof_audio_stream_params *audio_stream_params; /** pointer to audio params */ +}; + +#endif /* __SOF_API_AUDIO_SINK_API_IMPLEMENTATION_H__ */ diff --git a/src/include/sof_api/audio/source_api.h b/src/include/sof_api/audio/source_api.h new file mode 100644 index 000000000000..a59366f14315 --- /dev/null +++ b/src/include/sof_api/audio/source_api.h @@ -0,0 +1,181 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * + * Copyright(c) 2023 Intel Corporation. All rights reserved. + * + */ + +#ifndef __SOF_API_AUDIO_SOURCE_API_H__ +#define __SOF_API_AUDIO_SOURCE_API_H__ + +#include +#include +#include + +#include "source_api_implementation.h" +#include "audio_stream.h" +#include "format.h" + +/** + * this is a definition of API to source of audio data + * + * THE SOURCE is any component in the system that have data stored somehow and can give the + * data outside at request. The source API does not define who and how has produced the data + * + * The user - a module - sees this as a producer that PROVIDES data for processing + * The IMPLEMENTATION - audio_stream, DP Queue - sees this API as a destination it must send data to + * * + * Examples of components that should expose source API: + * - DMIC + * Data are coming from the outside world, stores in tmp buffer and can be presented + * to the rest of the system using source_api + * - a memory ring buffer + * Data are coming from other module (usually using sink_api, but it does not matter in fact) + * + * The main advantage of using source API instead of just taking pointers to the data is that + * the data may be prepared at the moment the data receiver is requesting it. i.e. + * - cache may be written back/invalidated if necessary + * - data may be moved from circular to linear space + * - part of the buffer may be locked to prevent writing + * etc.etc. it depends on implementation of the data source + * + * Data in general are provided as a circular buffer and the data receiver should be able to + * deal with it. Of course if needed an implementation of source providing linear data can be + * implemented and used as a mid-layer for modules needing it. + * + * NOTE: the module should get a complete portion of data it needs for processing, process it + * than release. The reason is - the depending on the implementation, the calls may be + * expensive - may involve some data moving in memory, cache writebacks, etc. + */ + +/** + * Retrieves size of available data (in bytes) + * return number of bytes that are available for immediate use + */ +static inline size_t source_get_data_available(struct sof_source *source) +{ + return source->ops->get_data_available(source); +} + +static inline enum sof_ipc_frame source_get_frm_fmt(struct sof_source *source) +{ + return source->audio_stream_params->frame_fmt; +} + +static inline unsigned int source_get_channels(struct sof_source *source) +{ + return source->audio_stream_params->channels; +} + +/** get size of a single audio frame (in bytes) */ +static inline size_t source_get_frame_bytes(struct sof_source *source) +{ + return get_frame_bytes(source_get_frm_fmt(source), source_get_channels(source)); +} + +/** + * Retrieves size of available data (in frames) + * return number of frames that are available for immediate use + */ +static inline size_t source_get_data_frames_available(struct sof_source *source) +{ + return source_get_data_available(source) / source_get_frame_bytes(source); +} + +/** + * Retrieves a fragment of circular data to be used by the caller (to read) + * After calling get_data, the data are guaranteed to be available + * for exclusive use (read only) + * if the provided pointers are cached, it is guaranteed that the caller may safely use it without + * any additional cache operations + * + * The caller MUST take care of data circularity based on provided pointers + * + * Depending on implementation - there may be a way to have several receivers of the same + * data, as long as the receiver respects that data are read-only and won'do anything + * fancy with cache handling itself + * + * some implementation data may be stored in linear buffer + * in that case: + * data_ptr = buffer_start + * buffer_end = data_ptr + req_size + * buffer_size = req_size + * + * and the data receiver may use it as usual, rollover will simple never occur + * NOTE! the caller MUST NOT assume that pointers to start/end of the circular buffer + * are constant. They may change between calls + * + * @param source a handler to source + * @param [in] req_size requested size of data. + * @param [out] data_ptr a pointer to data will be provided there + * @param [out] buffer_start pointer to circular buffer start + * @param [out] buffer_size size of circular buffer + * + * @retval -ENODATA if req_size is bigger than available data + */ +static inline int source_get_data(struct sof_source *source, size_t req_size, + void const **data_ptr, void const **buffer_start, + size_t *buffer_size) +{ + int ret; + + if (source->requested_read_frag_size) + return -EBUSY; + + ret = source->ops->get_data(source, req_size, data_ptr, buffer_start, buffer_size); + + if (!ret) + source->requested_read_frag_size = req_size; + return ret; +} + +/** + * Releases fragment previously obtained by source_get_data() + * Once called, the data are no longer available for the caller + * + * @param source a handler to source + * @param free_size amount of data that the caller declares as "never needed again" + * if free_size == 0 the source implementation MUST keep all data in memory and make them + * available again at next get_data() call + * if free_size is bigger than the amount of data obtained before by get_data(), only + * the amount obtained before will be freed. That means - if somebody obtained some data, + * processed it and won't need it again, it may simple call put_data with free_size==MAXINT + * + * @return proper error code (0 on success) + */ +static inline int source_release_data(struct sof_source *source, size_t free_size) +{ + int ret; + + /* Check if anything was obtained before for reading by source_get_data */ + if (!source->requested_read_frag_size) + return -ENODATA; + + /* limit size of data to be freed to previously obtained size */ + if (free_size > source->requested_read_frag_size) + free_size = source->requested_read_frag_size; + + ret = source->ops->release_data(source, free_size); + + if (!ret) + source->requested_read_frag_size = 0; + + source->num_of_bytes_processed += free_size; + return ret; +} + +/** set of functions for retrieve audio parameters */ +static inline enum sof_ipc_frame source_get_valid_fmt(struct sof_source *source) +{ + return source->audio_stream_params->valid_sample_fmt; +} +static inline unsigned int source_get_rate(struct sof_source *source) +{ + return source->audio_stream_params->rate; +} + +static inline uint32_t source_get_buffer_fmt(struct sof_source *source) +{ + return source->audio_stream_params->buffer_fmt; +} + +#endif /* __SOF_API_AUDIO_SOURCE_API_H__ */ diff --git a/src/include/sof_api/audio/source_api_implementation.h b/src/include/sof_api/audio/source_api_implementation.h new file mode 100644 index 000000000000..db3ad181671e --- /dev/null +++ b/src/include/sof_api/audio/source_api_implementation.h @@ -0,0 +1,85 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * + * Copyright(c) 2023 Intel Corporation. All rights reserved. + * + */ + +#ifndef __SOF_API_AUDIO_SOURCE_API_IMPLEMENTATION_H__ +#define __SOF_API_AUDIO_SOURCE_API_IMPLEMENTATION_H__ + +#include +#include +#include + +/* forward def */ +struct sof_source; +struct sof_audio_stream_params; +struct sof_ipc_stream_params; + +/** + * this is a definition of internals of source API + * + * this file should be included by the implementations of source API + * + * The clients of stream API should use functions provided in source_api.h ONLY + * + */ + +struct source_ops { + /** + * see comment of source_get_data_available() + */ + size_t (*get_data_available)(struct sof_source *source); + + /** + * see comment of source_get_data_available() + */ + int (*get_data)(struct sof_source *source, size_t req_size, + void const **data_ptr, void const **buffer_start, size_t *buffer_size); + + /** + * see comment of source_release_data() + */ + int (*release_data)(struct sof_source *source, size_t free_size); + + /** + * OPTIONAL: Notification to the source implementation about changes in audio format + * + * Once any of *audio_stream_params elements changes, the implementation of + * source may need to perform some extra operations. + * This callback will be called immediately after any change + * + * @retval 0 if success, negative if new parameteres are not supported + */ + int (*on_audio_format_set)(struct sof_source *source); + + /** + * OPTIONAL + * see source_set_params comments + */ + int (*audio_set_ipc_params)(struct sof_source *source, + struct sof_ipc_stream_params *params, bool force_update); + + /** + * OPTIONAL + * see comment for source_set_alignment_constants + */ + int (*set_alignment_constants)(struct sof_source *source, + const uint32_t byte_align, + const uint32_t frame_align_req); +}; + +/** internals of source API. NOT TO BE MODIFIED OUTSIDE OF source_api_helper.h */ +struct sof_source { + const struct source_ops *ops; + size_t requested_read_frag_size; /** keeps size of data obtained by get_data() */ + size_t num_of_bytes_processed; /** processed bytes counter */ + size_t min_available; /** minimum data available required by the module using + * source + * it is module's IBS as declared in module bind IPC + */ + + struct sof_audio_stream_params *audio_stream_params; +}; + +#endif /* __SOF_API_AUDIO_SOURCE_API_IMPLEMENTATION_H__ */ diff --git a/src/include/sof_api/ipc/stream.h b/src/include/sof_api/ipc/stream.h new file mode 100644 index 000000000000..21fe8855e402 --- /dev/null +++ b/src/include/sof_api/ipc/stream.h @@ -0,0 +1,25 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * + * Copyright(c) 2023 Intel Corporation. All rights reserved. + * + * Author: Liam Girdwood + * Keyon Jie + * Adrian Warecki + */ + +#ifndef __SOF_API_IPC_STREAM_H__ +#define __SOF_API_IPC_STREAM_H__ + +/* stream PCM frame format */ +enum sof_ipc_frame { + SOF_IPC_FRAME_S16_LE = 0, + SOF_IPC_FRAME_S24_4LE, + SOF_IPC_FRAME_S32_LE, + SOF_IPC_FRAME_FLOAT, + /* other formats here */ + SOF_IPC_FRAME_S24_3LE, + SOF_IPC_FRAME_S24_4LE_MSB, + SOF_IPC_FRAME_U8, +}; + +#endif /* __SOF_API_IPC_STREAM_H__ */